Ferramentas Básicas
Aprenda como definir ferramentas com @tool, vinculá-las a LLMs e executar ferramentas dentro de nós LangGraph.
Ferramentas dão aos LLMs a capacidade de interagir com o mundo exterior: pesquisar na web, executar cálculos, consultar bancos de dados e mais. Esta lição cobre como definir, vincular e executar ferramentas em LangGraph.
Definindo Ferramentas com @tool
O decorador @tool do LangChain converte uma função Python em uma ferramenta que LLMs podem usar:
from langchain_core.tools import tool
@tool
def get_weather(location: str) -> str:
"""Get the current weather for a location."""
# Em produção, chamar uma API de clima
return f"The weather in {location} is sunny, 72°F."
@tool
def calculator(expression: str) -> str:
"""Evaluate a mathematical expression. Use Python syntax."""
try:
return str(eval(expression, {"__builtins__": {}}, {}))
except Exception as e:
return f"Error: {e}"Estrutura da Ferramenta
Cada ferramenta tem:
Componente | Descrição | Fonte |
|---|---|---|
Nome | O nome da função (ex.: get_weather) | Gerado do nome da função |
Descrição | Docstring explicando quando usar | De """docstring""" |
Parâmetros | Argumentos da função com tipagem | Da assinatura da função |
Corpo | A lógica de implementação | O código da função |
A docstring é crítica. O LLM a lê para decidir quando e como chamar a ferramenta. Seja descritivo e inclua exemplos de quando a ferramenta é apropriada.
Vinculação de Ferramentas
Vincule ferramentas a um LLM para que ele saiba que elas existem:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
# Vincular ferramentas ao LLM
llm_with_tools = llm.bind_tools([get_weather, calculator])Como a Vinculação Funciona
bind_tools() envia os schemas das ferramentas (nome, descrição, parâmetros) para o LLM como parte da chamada de API. O LLM pode então decidir:
- Responder normalmente com texto se nenhuma ferramenta for necessária
- Solicitar uma chamada de ferramenta retornando um objeto
tool_callsestruturado
# LLM pode responder sem ferramenta
response = llm_with_tools.invoke("Hello!")
print(response.content) # "Hi! How can I help you?"
# LLM pode solicitar uma ferramenta
response = llm_with_tools.invoke("What is 2+2?")
print(response.tool_calls)
# [{'name': 'calculator', 'args': {'expression': '2+2'}, 'id': '...'}]O LLM não executa a ferramenta. Ele apenas gera uma requisição de chamada de ferramenta. Sua função de nó deve lidar com a execução.
Verificando Chamadas de Ferramenta
Após invocar um LLM habilitado para ferramentas, verifique se ele quer usar uma ferramenta:
response = llm_with_tools.invoke(messages)
if response.tool_calls:
# LLM quer chamar ferramentas
for tool_call in response.tool_calls:
tool_name = tool_call["name"]
tool_args = tool_call["args"]
tool_id = tool_call["id"]
print(f"Tool requested: {tool_name}({tool_args})")
else:
# LLM respondeu com texto
print(f"Response: {response.content}")Estrutura da Chamada de Ferramenta
# Cada tool_call é um dict com:
{
"name": "calculator", # Nome da ferramenta
"args": {"expression": "2+2"}, # Dict de argumentos
"id": "call_abc123", # ID único da chamada
"type": "tool_call" # Sempre "tool_call"
}Execução de Ferramenta em um Nó
O padrão padrão: invocar LLM, verificar chamadas de ferramenta, executar ferramentas, retornar resultados:
from langchain_core.messages import ToolMessage
class AgentState(TypedDict):
messages: list
tool_results: dict
def agent_node(state: AgentState) -> dict:
# 1. Chamar LLM com ferramentas
response = llm_with_tools.invoke(state["messages"])
# 2. Verificar se LLM quer usar ferramentas
if response.tool_calls:
results = {}
new_messages = state["messages"] + [response]
for tool_call in response.tool_calls:
# 3. Executar a ferramenta
tool_name = tool_call["name"]
tool_args = tool_call["args"]
if tool_name == "calculator":
result = calculator.invoke(tool_args)
elif tool_name == "get_weather":
result = get_weather.invoke(tool_args)
else:
result = f"Unknown tool: {tool_name}"
# 4. Armazenar resultado
tool_call_id = tool_call["id"]
results[tool_call_id] = result
# 5. Adicionar ToolMessage à conversa
new_messages.append(
ToolMessage(content=result, tool_call_id=tool_call_id)
)
return {"messages": new_messages, "tool_results": results}
# 6. Sem chamadas de ferramenta — retornar resposta LLM
return {"messages": state["messages"] + [response]}O padrão é: LLM decide → analisar chamadas de ferramenta → executar ferramentas → anexar resultados como ToolMessages → continuar.
Execução Simplificada com ToolExecutor
LangGraph fornece ToolExecutor para execução mais limpa de ferramentas:
from langgraph.prebuilt import ToolExecutor
# Criar executor a partir de suas ferramentas
tools = [get_weather, calculator]
tool_executor = ToolExecutor(tools)
def agent_node(state: AgentState) -> dict:
response = llm_with_tools.invoke(state["messages"])
if response.tool_calls:
new_messages = [response]
for tool_call in response.tool_calls:
# ToolExecutor lida com roteamento e invocação
result = tool_executor.invoke(tool_call)
new_messages.append(
ToolMessage(content=str(result), tool_call_id=tool_call["id"])
)
return {"messages": state["messages"] + new_messages}
return {"messages": state["messages"] + [response]}ToolExecutor automaticamente roteia chamadas de ferramenta para a função correta baseada no nome da ferramenta. Ele lida com o dicionário de mapeamento internamente.
Agente ReAct Completo com Ferramentas
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, ToolMessage
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolExecutor
from typing_extensions import TypedDict, List, Dict, Any
# 1. Definir ferramentas
@tool
def search(query: str) -> str:
"""Search the web. Use for general knowledge questions."""
return f"Search results for '{query}': LangGraph is a framework..."
@tool
def calculator(expression: str) -> str:
"""Evaluate math expressions. Use for calculations."""
return str(eval(expression, {"__builtins__": {}}, {}))
# 2. Configuração
tools = [search, calculator]
llm = ChatOpenAI(model="gpt-4o")
llm_with_tools = llm.bind_tools(tools)
tool_executor = ToolExecutor(tools)
# 3. Estado
class AgentState(TypedDict):
messages: List[Any]
# 4. Nó
def agent(state: AgentState) -> dict:
response = llm_with_tools.invoke(state["messages"])
if response.tool_calls:
new_messages = [response]
for tc in response.tool_calls:
result = tool_executor.invoke(tc)
new_messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))
return {"messages": state["messages"] + new_messages}
return {"messages": state["messages"] + [response]}
# 5. Roteador
def should_continue(state: AgentState) -> str:
last_message = state["messages"][-1]
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "continue"
return "end"
# 6. Grafo
builder = StateGraph(AgentState)
builder.add_node("agent", agent)
builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", should_continue, {
"continue": "agent", # Loop de volta — resultados de ferramentas alimentam de volta ao LLM
"end": END
})
app = builder.compile()
# 7. Executar
result = app.invoke({
"messages": [HumanMessage("What is 15 * 7 and search for LangGraph?")]
})
print(result["messages"][-1].content)Quando o roteador retorna "continue", o grafo faz loop de volta ao nó agente. O agente recebe os ToolMessages (resultados das ferramentas) e pode decidir se chama mais ferramentas ou responde. Sempre defina um recursion_limit para prevenir loops infinitos.
Múltiplas Chamadas de Ferramenta
O LLM pode solicitar múltiplas chamadas de ferramenta em uma única resposta:
# Exemplo: Resposta LLM com duas chamadas de ferramenta
response = llm_with_tools.invoke(
"What's the weather in Paris and calculate 2^10?"
)
print(len(response.tool_calls)) # 2
# Executar todas as chamadas de ferramenta
for tc in response.tool_calls:
result = tool_executor.invoke(tc)
print(f"{tc['name']} → {result}")Todas as chamadas de ferramenta de uma resposta LLM são executadas e seus resultados são retornados como ToolMessages para o LLM para processamento final.
Tratamento de Erro em Ferramentas
def safe_agent_node(state: AgentState) -> dict:
try:
response = llm_with_tools.invoke(state["messages"])
except Exception as e:
print(f"LLM call failed: {e}")
return {"messages": state["messages"] + [
AIMessage(content=f"I encountered an error: {str(e)}")
]}
if response.tool_calls:
new_messages = [response]
for tc in response.tool_calls:
try:
result = tool_executor.invoke(tc)
except Exception as e:
result = f"Tool execution error: {e}"
new_messages.append(
ToolMessage(content=str(result), tool_call_id=tc["id"])
)
return {"messages": state["messages"] + new_messages}
return {"messages": state["messages"] + [response]}Sempre envolva a execução de ferramenta em try/except. Uma ferramenta com falha não deve quebrar o grafo inteiro. Retorne uma mensagem de erro como resultado da ferramenta para que o LLM possa lidar com isso graciosamente.
Ferramentas vs Funções Embutidas
Aspecto | Decorador @tool | Função Simples |
|---|---|---|
Geração de schema | Automática a partir da assinatura | Manual |
Descoberta pelo LLM | Via bind_tools() | Não visível ao LLM |
Tratamento de erro | Pode ser configurado | Manual |
Caso de uso | LLM precisa chamá-la | Lógica interna do nó |
Perguntas de Prática
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
O que o decorador @tool faz?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
Qual método torna um LLM ciente das ferramentas disponíveis?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
O LLM executa ferramentas diretamente?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
Qual tipo de mensagem envolve resultados de execução de ferramenta para o LLM?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
O que ToolExecutor faz?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
Qual parte de uma função @tool é mais importante para a compreensão do LLM?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
O que acontece em um loop de agente ReAct?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
Como você deve lidar com erros de execução de ferramenta?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
Um LLM pode solicitar múltiplas chamadas de ferramenta em uma resposta?
Como responder
Questão de múltipla escolha com 4 opções. Selecione uma opção e escolha Verificar resposta.
Qual propriedade na resposta do LLM contém as requisições de chamada de ferramenta?
Principais Conclusões
@tooldecora uma função com metadados que o LLM usa para decidir quando chamá-lallm.bind_tools([...])torna o LLM ciente das ferramentas disponíveis- LLMs apenas solicitam chamadas de ferramenta: seu código de nó as executa
- Resultados de ferramentas vão em ToolMessages vinculados por tool_call_id
- ToolExecutor simplifica o roteamento e execução de múltiplas ferramentas
- O padrão ReAct faz loop: LLM → chamadas de ferramenta → executar → ToolMessages → LLM novamente
- Sempre trate erros de ferramenta com try/except
- Uma docstring clara é a parte mais importante de uma definição de ferramenta