SISTEMA DE ACESSO COMPUTACIONAL

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:

  1. Qual ferramenta chamar — guiado pelo name e description da ferramenta
  2. Quais argumentos passar — guiado pelo input_schema da 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 enum para qualquer campo com um conjunto fixo de valores válidos
  • Defina minimum/maximum em campos numéricos para evitar entradas fora do intervalo
  • Marque campos como required apenas 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 json
from dataclasses import dataclass, asdict
from typing import Any, Optional
@dataclass
class 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 result

Para 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

  1. Comece com o esquema — escreva seu input_schema antes do corpo da função
  2. Adicione o wrapper ToolResult a cada ferramenta existente
  3. Incorpore safe_tool_call para fortalecer seu loop de agente
  4. Configure validação de resultados para ferramentas que chamam APIs externas

Guias relacionados: