LangGraph: Como Construir um Agente com Chamada de Ferramentas e Execução Limitada para Verificação de Código
Aprenda a construir um agente com estado no LangGraph utilizando tool calling, limites de passos e verificação automatizada de testes para alterações em repositórios de código.
Nesta página
A modificação autônoma de código exige muito mais do que uma cadeia linear de prompts padrão. Quando um agente altera um repositório, ele precisa ler arquivos, aplicar edições, executar suítes de testes, inspecionar saídas e se autocorrigir diante de regressões. No entanto, padrões cíclicos de agentes — com frequência baseados no paradigma ReAct (Reasoning and Acting) — trazem riscos operacionais se não forem devidamente limitados. Um agente que se depare com dependências quebradas ou falhas persistentes em testes pode entrar em loops de execução caros e intermináveis.
Com base na arquitetura ReAct documentada pelo Google AI para LangGraph, este guia adapta a mecânica essencial de grafos de estado em um agente de programação especializado e delimitado. A implementação executa alterações de código, valida as modificações contra suítes automatizadas de testes e impõe limites rígidos de iterações.
Arquitetura Central: Estado, Nós e Arestas Condicionais
O LangGraph modela fluxos de trabalho de agentes como grafos direcionados. Diferente dos grafos acíclicos direcionados (DAGs) estáticos, o LangGraph suporta ciclos de forma nativa, o que é fundamental para o raciocínio iterativo do agente.
[Entrypoint]
│
▼
┌─────────────┐
│ call_model │◄────────────┐
└──────┬──────┘ │
│ │
[should_continue] │
/ \ │
(has tools) (done / max) │
/ \ │
▼ ▼ │
┌───────────┐ ┌─────┐ │
│ call_tool │ │ END │ │
└─────┬─────┘ └─────┘ │
│ │
└─────────────────────────────┘
O grafo apoia-se em três elementos arquiteturais fundamentais:
- Estado (State): Uma estrutura de dados tipada e centralizada que armazena o histórico de mensagens, metadados de execução e contadores de passos explícitos.
- Nós (Nodes): Funções Python simples que recebem o estado atual, executam computações isoladas (chamando o modelo ou acionando uma ferramenta) e retornam atributos de estado atualizados.
- Arestas Condicionais (Conditional Edges): Funções de decisão que inspecionam o estado (como a presença de chamadas de ferramentas ou o alcance do teto de iterações) para decidir se devem encaminhar a execução para a ferramenta ou finalizar em
END.
Pré-requisitos e Dependências
Certifique-se de que o seu ambiente de desenvolvimento contenha os pacotes necessários de orquestração de grafos e drivers de modelos:
pip install langgraph langchain-core langchain-openai
Para conectar o agente aos provedores de inferência por meio de um gateway compatível com OpenAI, configure suas variáveis de ambiente. Usar o OneMux simplifica o gerenciamento unificado de chaves e o controle de gastos entre múltiplos modelos:
export ONEMUX_API_KEY="your_onemux_api_key"
export ONEMUX_BASE_URL="https://api.onemux.net/v1"
(Observação: certifique-se sempre de que o modelo de destino escolhido suporte parâmetros de tool calling estruturados por meio de endpoints compatíveis com a OpenAI).
Passo 1: Definindo o Estado Bounded do Agente
Em fluxos de conversa padrão, o MessagesState gerencia a inclusão do histórico de mensagens. Para tarefas de programação, definimos explicitamente o AgentState com o TypedDict do Python para rastrear sequências de mensagens junto com um contador explícito (step_count) e um teto máximo (max_steps).
from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
step_count: int
max_steps: int
O redutor add_messages assegura que as novas listas de mensagens sejam anexadas de forma limpa ao histórico da conversa, em vez de sobrescrever observações anteriores.
Passo 2: Implementando Ferramentas de Sistema de Arquivos e Verificação
O agente necessita de ferramentas para inspecionar arquivos-fonte, aplicar atualizações e executar os testes do repositório. Encapsulamos essas operações utilizando o decorador @tool do LangChain.
import subprocess
from langchain_core.tools import tool
@tool
def read_file(filepath: str) -> str:
"""Reads contents of a file from the repository."""
try:
with open(filepath, "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
return f"Error reading {filepath}: {str(e)}"
@tool
def write_file(filepath: str, content: str) -> str:
"""Overwrites a file with modified source code."""
try:
with open(filepath, "w", encoding="utf-8") as f:
f.write(content)
return f"Successfully updated {filepath}"
except Exception as e:
return f"Error writing {filepath}: {str(e)}"
@tool
def run_test_suite(test_target: str) -> str:
"""Runs pytest on a specific file or test target."""
try:
result = subprocess.run(
["pytest", test_target],
capture_output=True,
text=True,
timeout=30
)
return f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}\nExit Code: {result.returncode}"
except subprocess.TimeoutExpired:
return "Error: Test execution timed out after 30 seconds."
except Exception as e:
return f"Error executing tests: {str(e)}"
tools = [read_file, write_file, run_test_suite]
tools_by_name = {t.name: t for t in tools}
Passo 3: Configuração do Modelo via API Unificada
Inicializamos o modelo utilizando ChatOpenAI, apontando para o endpoint proxy do provedor unificado. Consulte a Documentação do OneMux e o Guia de Início Rápido para verificar a compatibilidade de parâmetros para function calling.
import os
from langchain_openai import ChatOpenAI
api_key = os.getenv("ONEMUX_API_KEY")
base_url = os.getenv("ONEMUX_BASE_URL", "https://api.onemux.net/v1")
llm = ChatOpenAI(
model="gpt-4o",
temperature=0.0,
api_key=api_key,
base_url=base_url
)
# Bind tools to the model instance
model = llm.bind_tools(tools)
Passo 4: Construindo os Nós do Grafo e Guardas de Loop
Os nós executam a lógica e incrementam os limites. Caso um agente entre em loop contínuo sem conseguir corrigir um teste com falha, a lógica da aresta detecta que step_count >= max_steps e faz o roteamento direto para o encerramento do grafo.
from langchain_core.messages import ToolMessage, AIMessage
from langchain_core.runnables import RunnableConfig
def call_model(state: AgentState, config: RunnableConfig):
"""Calls the model and increments the iteration step count."""
response = model.invoke(state["messages"], config)
current_steps = state.get("step_count", 0) + 1
return {
"messages": [response],
"step_count": current_steps
}
def call_tool(state: AgentState):
"""Executes tool calls generated by the most recent model response."""
last_message = state["messages"][-1]
outputs = []
for tool_call in getattr(last_message, "tool_calls", []):
tool_inst = tools_by_name.get(tool_call["name"])
if tool_inst:
result = tool_inst.invoke(tool_call["args"])
else:
result = f"Error: Tool {tool_call['name']} not found."
outputs.append(
ToolMessage(
content=str(result),
name=tool_call["name"],
tool_call_id=tool_call["id"]
)
)
return {"messages": outputs}
def should_continue(state: AgentState):
"""Evaluates tool requests and halts execution if boundaries are crossed."""
messages = state["messages"]
last_message = messages[-1]
step_count = state.get("step_count", 0)
max_steps = state.get("max_steps", 5)
# Boundary check: Halt if loop budget exceeded
if step_count >= max_steps:
return "end"
# Continue if the model requested another tool call
if getattr(last_message, "tool_calls", None):
return "continue"
return "end"
Passo 5: Compilação e Montagem do Grafo
Junte os componentes usando StateGraph e compile o fluxo de trabalho:
from langgraph.graph import StateGraph, END
workflow = StateGraph(AgentState)
# Register Nodes
workflow.add_node("agent", call_model)
workflow.add_node("tools", call_tool)
# Set Entrypoint
workflow.set_entry_point("agent")
# Define Conditional and Static Edges
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "tools",
"end": END
}
)
workflow.add_edge("tools", "agent")
# Compile Graph
app = workflow.compile()
Passo 6: Executando Modificações de Código com Verificação por Testes
Para executar o fluxo de trabalho, defina uma tarefa de programação em conjunto com limites estritos de execução:
initial_input = {
"messages": [(
"user",
"Fix the bug in utils/math_lib.py where divide_numbers fails on zero values. "
"Verify your fix by running the test suite on tests/test_math_lib.py. "
"Only stop once all tests pass."
)],
"step_count": 0,
"max_steps": 6
}
for event in app.stream(initial_input, stream_mode="values"):
latest = event["messages"][-1]
if isinstance(latest, AIMessage) and latest.tool_calls:
print(f"[Action] Invoking tools: {[t['name'] for t in latest.tool_calls]}")
elif isinstance(latest, ToolMessage):
print(f"[Observation] {latest.name} -> {latest.content[:100]}...")
else:
print(f"[Agent] {latest.content}")
[Action] Invoking tools: ['read_file']
[Observation] read_file -> def divide_numbers(a, b):
return a / b...
[Action] Invoking tools: ['write_file']
[Observation] write_file -> Successfully updated utils/math_lib.py...
[Action] Invoking tools: ['run_test_suite']
[Observation] run_test_suite -> STDOUT:
============================= test session starts ==============================
... 1 passed in 0.02s...
[Agent] The divide_numbers function has been updated to handle zero division safely, and all tests in tests/test_math_lib.py pass.
Limitações e Preparação para Produção
Ao implantar agentes que alteram código em ambientes de produção, considere as seguintes medidas de proteção:
- Execução em Sandbox: Executar comandos shell arbitrários como
pytestlocalmente traz riscos de corrupção do ambiente ou execução de scripts inseguros. Isole a execução de testes em contêineres Docker efêmeros ou sandboxes protegidas. - Limites de Tokens no Estado: Saídas extensas de ferramentas — como stack traces de várias páginas — podem esgotar rapidamente a janela de contexto. Trunque as mensagens de saída de testes antes de gravá-las no histórico de estado.
- Gerenciamento de Custos do Modelo: Loops iterativos ReAct multiplicam o consumo de tokens. Acompanhe o uso pelo painel de Preços do OneMux e avalie modelos de raciocínio mais econômicos na página de Modelos do OneMux para otimizar o custo por tarefa.
Fontes
- Google AI for Developers: ReAct agent from scratch with Gemini and LangGraph (Atualizado em 2 de setembro de 2026).
Perguntas frequentes
Qual é a principal vantagem do LangGraph em relação a cadeias lineares de agentes padrão?
O LangGraph suporta grafos cíclicos de forma nativa, permitindo que os agentes executem ferramentas iterativamente, analisem as observações de saída e autocorrijam suas ações até que a tarefa passe na verificação.
Por que a execução delimitada (bounded execution) é indispensável para agentes que modificam código?
Sem um contador de passos ou um teto obrigatório, um agente que não consiga corrigir um teste com falha pode permanecer preso em um loop infinito de chamadas de ferramentas, esgotando o orçamento de tokens e recursos computacionais.
Posso usar o LangGraph com modelos acessados por meio do OneMux?
Sim. Ao utilizar o cliente ChatOpenAI do LangChain apontado para a base URL do OneMux e informando sua chave de API do OneMux, você pode orquestrar agentes LangGraph com qualquer modelo suportado que possua capacidades de tool calling.
Artigos relacionados
Guides
Crie um agente de suporte ao cliente com LangGraph, chamadas de ferramentas, aprovação humana e limites de execução
Um padrão prático de LangGraph para triagem de suporte ao cliente: encaminhe solicitações, chame ferramentas de consulta, pause reembolsos para aprovação humana e limite a execução do grafo.
Guides
Crie um agente LangGraph com limites para extração validada por esquema
Crie um fluxo de trabalho LangGraph que chama uma ferramenta quando necessário, encerra dentro de um limite de execução definido e retorna dados estruturados validados com um esquema Pydantic.
Guides
RAG agêntico com LangGraph: chamadas de ferramentas, atribuição de fontes e execução limitada
Crie um agente LangGraph para perguntas e respostas sobre documentos que decide quando buscar informações, avalia o contexto, tenta novamente após buscas pouco relevantes e retorna respostas com atribuição de fontes, sem execução ilimitada.
Guides
Benchmarks do Gemini 3.6 Flash: O Que as Alegações Agênticas Significam para a Arquitetura de Backends de Chatbots
Um framework prático para avaliar o Gemini 3.6 Flash no backend de chatbots de IA, com orientações de roteamento, loops de ferramentas, controle de custos e rollout.