Ferramentas Básicas
Iniciante⏱35 minutos📖4 min de leituraLição 7 de 10

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:

python
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
📌Importante

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:

python
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:

  1. Responder normalmente com texto se nenhuma ferramenta for necessária
  2. Solicitar uma chamada de ferramenta retornando um objeto tool_calls estruturado
python
# 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': '...'}]
ℹ️Nota

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:

python
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

python
# 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:

python
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]}
✅Sucesso

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:

python
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]}
💡Dica

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

python
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)
⚠️Aviso

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:

python
# 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

python
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]}
ℹ️Nota

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

Questão 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?

Questão de Prática
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?

Questão de Prática
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?

Questão de Prática
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?

Questão 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 ToolExecutor faz?

Questão de Prática
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?

Questão 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 acontece em um loop de agente ReAct?

Questão de Prática
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?

Questão de Prática
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?

Questão de Prática
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?


✅Sucesso

Principais Conclusões

  • @tool decora uma função com metadados que o LLM usa para decidir quando chamá-la
  • llm.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
Progresso70%