Padrões de Uso de Ferramentas: Interfaces Agente-Ferramenta Confiáveis
Seu agente chamou uma ferramenta e recebeu um JSON de 40 linhas — resposta bruta da API, objetos aninhados, códigos de erro enterrados dentro de um campo status. O modelo leu, escolheu um valor plausível e continuou. O valor estava errado. Três passos depois, o agente redigiu com confiança um relatório baseado em dados incorretos.
A ferramenta funcionou. A interface falhou.
O uso de ferramentas é o mecanismo que transforma um modelo de linguagem em um agente. Cada capacidade do seu agente — pesquisar bancos de dados, escrever arquivos, chamar APIs, consultar serviços — chega por meio de uma interface de ferramenta. Se a interface for mal projetada, o modelo toma decisões piores mesmo quando o serviço subjacente funciona corretamente. Este guia cobre cinco padrões para construir interfaces de ferramentas precisas, confiáveis e prontas para produção.
Pré-requisitos: Familiaridade com Python e a API Claude. Para contexto sobre MCP como camada de transporte de ferramentas, veja Construindo seu Primeiro Servidor MCP.
Por que o Design da Interface Importa
Quando um agente escolhe e usa uma ferramenta, toma duas decisões:
- Qual ferramenta chamar — guiado pelo
nameedescriptionda ferramenta - Quais argumentos passar — guiado pelo
input_schemada ferramenta
Descrições ambíguas levam à seleção incorreta de ferramentas. Esquemas soltos permitem que o modelo passe entradas malformadas. Resultados não estruturados fazem o modelo adivinhar o que aconteceu. A maioria dos bugs de agentes não vive no raciocínio — vive na fronteira da ferramenta.
Padrão 1: Design Esquema-Primeiro
Escreva o esquema JSON antes de escrever a implementação. Um esquema estrito restringe o comportamento do modelo na etapa de entrada — antes que qualquer coisa seja executada.
import anthropic
client = anthropic.Anthropic()
tools = [ { "name": "search_products", "description": ( "Pesquisa o catálogo de produtos por palavra-chave. " "Retorna uma lista de produtos correspondentes com IDs, nomes e preços. " "Use quando o usuário quiser encontrar ou navegar por produtos." ), "input_schema": { "type": "object", "properties": { "query": { "type": "string", "description": "Palavras-chave para pesquisar" }, "category": { "type": "string", "enum": ["electronics", "clothing", "food", "home", "all"], "description": "Categoria de produto para filtrar. Use 'all' se não especificado." }, "max_results": { "type": "integer", "minimum": 1, "maximum": 20, "description": "Número de resultados a retornar. Padrão: 5" } }, "required": ["query", "category"] } }]
response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, tools=tools, messages=[{"role": "user", "content": "Encontre eletrônicos abaixo de R$500"}])Regras de esquema que reduzem erros:
- Use
enumpara qualquer campo com um conjunto fixo de valores válidos - Defina
minimum/maximumem campos numéricos para evitar entradas fora do intervalo - Marque campos como
requiredapenas quando a ferramenta genuinamente não pode ser executada sem eles - Escreva descrições da perspectiva do modelo: “Use quando…” diz ao modelo quando chamar a ferramenta
Quando usar: Em cada definição de ferramenta.
Padrão 2: Resultados de Ferramenta Estruturados
Retorne resultados tipados e legíveis por máquina. Nunca retorne respostas brutas de API ou descrições em prosa.
import jsonfrom dataclasses import dataclass, asdictfrom typing import Any, Optional
@dataclassclass ToolResult: success: bool data: Optional[Any] = None error: Optional[str] = None
def to_content(self) -> str: return json.dumps(asdict(self))
def search_products( query: str, category: str, max_results: int = 5,) -> ToolResult: try: raw_results = _query_database(query, category, limit=max_results) products = [ {"id": r["product_id"], "name": r["title"], "price": r["price_usd"]} for r in raw_results ] return ToolResult(success=True, data={"products": products, "count": len(products)}) except ConnectionError as e: return ToolResult(success=False, error=f"Banco de dados indisponível: {e}") except Exception as e: return ToolResult(success=False, error=f"Pesquisa falhou: {type(e).__name__}: {e}")
def _query_database(query, category, limit): return []O envelope consistente {success, data, error} significa que o modelo sempre sabe onde procurar. Para tratamento gracioso de falhas, veja Padrões de Recuperação de Erros em Agentes.
Padrão 3: Chamadas de Ferramenta em Paralelo
Claude pode solicitar múltiplas ferramentas em uma única resposta. Processe-as em paralelo em vez de sequencialmente.
from concurrent.futures import ThreadPoolExecutor, as_completed
TOOL_REGISTRY = { "search_products": search_products,}
def dispatch_tool(name: str, inputs: dict) -> ToolResult: handler = TOOL_REGISTRY.get(name) if not handler: return ToolResult(success=False, error=f"Ferramenta desconhecida: {name}") return handler(**inputs)
def process_tool_calls(response: anthropic.types.Message) -> list[dict]: tool_uses = [ block for block in response.content if block.type == "tool_use" ] if not tool_uses: return []
def execute(tool_use): result = dispatch_tool(tool_use.name, tool_use.input) return { "type": "tool_result", "tool_use_id": tool_use.id, "content": result.to_content(), }
with ThreadPoolExecutor(max_workers=len(tool_uses)) as executor: futures = {executor.submit(execute, tu): tu for tu in tool_uses} results = [] for future in as_completed(futures): results.append(future.result())
return results
def run_agent(user_message: str) -> str: messages = [{"role": "user", "content": user_message}]
while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=4096, tools=tools, messages=messages, )
if response.stop_reason == "end_turn": for block in response.content: if hasattr(block, "text"): return block.text return ""
if response.stop_reason == "tool_use": tool_results = process_tool_calls(response) messages.append({"role": "assistant", "content": response.content}) messages.append({"role": "user", "content": tool_results}) else: break
return ""Para orquestrar múltiplos agentes que cada um chama ferramentas, veja Padrões Multi-Agente.
Padrão 4: Wrapper de Chamada de Ferramenta Segura
Nunca deixe exceções de ferramentas alcançarem o loop do agente sem tratamento.
import signal
def timeout_handler(signum, frame): raise TimeoutError("Execução da ferramenta excedeu o tempo limite")
def safe_tool_call( name: str, inputs: dict, timeout_seconds: int = 30,) -> ToolResult: """ Executa uma ferramenta com timeout, capturando todas as exceções. Sempre retorna um ToolResult — nunca lança exceções. """ signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(timeout_seconds) try: return dispatch_tool(name, inputs) except TimeoutError: return ToolResult( success=False, error=f"Ferramenta '{name}' excedeu o tempo de {timeout_seconds}s" ) except Exception as e: return ToolResult( success=False, error=f"Ferramenta '{name}' lançou {type(e).__name__}: {e}" ) finally: signal.alarm(0)Quando uma ferramenta retorna success: false, o modelo pode decidir se reenvia, tenta uma alternativa ou relata a falha. Para estratégias de retry mais amplas, veja Padrões de Recuperação de Erros.
Padrão 5: Validação e Truncamento de Resultados
Valide os resultados de ferramentas antes de retorná-los ao modelo.
MAX_TOOL_RESULT_CHARS = 8000
def validate_result(result: ToolResult, expected_keys: list[str]) -> ToolResult: if not result.success or not isinstance(result.data, dict): return result missing = [k for k in expected_keys if k not in result.data] if missing: return ToolResult( success=False, error=f"Campos esperados ausentes na resposta: {missing}" ) return result
def truncate_result(result: ToolResult) -> ToolResult: content = result.to_content() if len(content) <= MAX_TOOL_RESULT_CHARS: return result
truncated_data = { "truncated": True, "chars_omitted": len(content) - MAX_TOOL_RESULT_CHARS, "content": content[:MAX_TOOL_RESULT_CHARS], } return ToolResult( success=result.success, data=truncated_data, error="Resultado truncado — muito grande para a janela de contexto", )
def safe_tool_call_validated( name: str, inputs: dict, expected_keys: list[str] | None = None,) -> ToolResult: result = safe_tool_call(name, inputs) if expected_keys: result = validate_result(result, expected_keys) result = truncate_result(result) return resultPara observar e depurar essas falhas em produção, veja Depuração e Observabilidade.
Erros Comuns
Erro 1: Retornar Respostas Brutas de API
O modelo recebe um objeto aninhado com 30 campos, a maioria irrelevante. Escolhe o errado.
Solução: Formate a resposta antes de retorná-la. Retorne apenas o que o modelo precisa para tomar sua próxima decisão.
Erro 2: Ferramentas com Efeitos Colaterais sem Confirmação
Uma ferramenta que envia um email ou exclui um registro não deve ser executada silenciosamente.
Solução: Para ações irreversíveis, use um padrão de duas ferramentas: plan_email retorna uma prévia, send_email realmente envia.
Erro 3: Responsabilidades de Ferramentas Sobrepostas
Duas ferramentas que fazem coisas similares forçam o modelo a adivinhar qual usar.
Solução: Cada ferramenta deve ter um propósito distinto e não sobreposto.
Erro 4: Sem Timeout em Ferramentas Externas
Uma chamada API lenta de terceiros bloqueia indefinidamente todo o loop do agente.
Solução: Sempre defina um timeout (Padrão 4).
Lista de Verificação para Produção
- Cada ferramenta tem uma descrição da perspectiva do modelo (“Use quando…”)
- Campos enum para todas as entradas de valor fixo
- Cada ferramenta retorna
{success, data, error}— nunca respostas brutas - Chamadas de ferramenta envolvidas em
safe_tool_call - Execução paralela para respostas de múltiplas ferramentas
- Timeout definido em cada ferramenta externa
- Truncamento de resultados para cargas de tamanho variável
- Validação para ferramentas que chamam APIs externas
Próximos Passos
- Comece com o esquema — escreva seu
input_schemaantes do corpo da função - Adicione o wrapper
ToolResulta cada ferramenta existente - Incorpore
safe_tool_callpara fortalecer seu loop de agente - Configure validação de resultados para ferramentas que chamam APIs externas
Guias relacionados:
- Construindo seu Primeiro Servidor MCP
- Padrões Multi-Agente
- Sistemas de Memória para Agentes
- Padrões de Recuperação de Erros em Agentes
- Depuração e Observabilidade