Tool use na prática: desenhando ferramentas que o LLM realmente consegue usar
Você plugou doze tools no seu agente. Conectou banco, calendário, busca interna, API de pagamento, CRM. Rodou um teste. O agente chamou a tool errada, inventou um user_id que não existe e devolveu uma resposta confiante e errada.
A culpa não é do modelo. É do design das tools.
Neste post você vai entender por que descrição mal escrita destrói tool use, quais são os princípios concretos para desenhar uma ferramenta que o LLM realmente sabe chamar, e como aplicar isso hoje no seu código — Claude, OpenAI, Gemini, qualquer modelo decente em 2026.
TL;DR
- O que é: boas práticas de design de tools (functions, function calls, tool use) para LLMs.
- Stack/Modelos: Claude (Anthropic Tool Use API), OpenAI Function Calling, Gemini Tools. Pydantic/Zod para validação.
- Custo/Acesso: ideias aplicáveis em qualquer SDK; exemplos em Python e TypeScript.
- Repositório/Link útil: Writing tools for agents — Anthropic Engineering.
O contexto — por que tool design é o gargalo silencioso
Tem uma frase da Anthropic que vale tatuar:
"Tool access is one of the highest-leverage primitives you can give an agent."
Tradução prática: o que decide se o seu agente é útil em produção não é o tamanho do modelo. É a qualidade das ferramentas que você expõe para ele.
E aqui mora o detalhe que muita gente ignora. Tunar prompt rende ganho marginal. Tunar tool rende ganho de degrau.
A própria Anthropic relatou que refinamentos precisos em descrições de tools levaram o Claude Sonnet 3.5 ao SOTA no SWE-bench Verified. Não trocaram modelo. Não mudaram prompt do agente. Reescreveram descrição de tool.
Outro número que mostra a escala do problema. Com a Tool Search Tool lançada em 2025, a Anthropic mostrou que carregar 50+ tools no system prompt derruba a precisão do agente. Quando o modelo descobre tools sob demanda em vez de receber tudo de uma vez, a acurácia do Opus 4.5 saltou de 79.5% para 88.1% numa bateria de tarefas reais. Mais tool não é mais capacidade. Mais tool é mais ruído.
Resumo: agente fraco quase nunca é problema de modelo. É problema de tool mal desenhada e tool demais.
Pré-requisitos
Antes de aplicar isso no seu projeto, garanta:
- [ ] SDK de algum provider com tool use estável (Anthropic, OpenAI, Vertex). API recente — Tool Use Examples e Strict Mode são diferenciais grandes.
- [ ] Validação de schema no servidor (Pydantic em Python, Zod em TypeScript). Não confie só no
strict: truedo provider. - [ ] Um eval realista. Pelo menos 10–20 cenários do seu domínio com a tool correta esperada. Sem isso você afina no escuro.
- [ ] Um log de cada
tool_callque o agente fez em desenvolvimento. Você vai precisar olhar.
Se você ainda não tem o eval, comece por aí. Tudo o que vem abaixo só faz sentido se você consegue medir.
Mão na massa — anatomia de uma tool que o modelo entende
Cinco coisas. Nome, descrição, schema, exemplos, erros. Todas importam, e nessa ordem.
Passo 1: Nome — verbo + objeto, com namespace
A regra é boba. E quase ninguém segue.
ruim: doStuff, helper, processData, action
ok: searchUsers, sendEmail, createOrder
bom: crm_search_users, gmail_send_email, shopify_create_order
Por que namespace importa. Quando você tem search em três sistemas diferentes (CRM, base interna, Slack), o modelo precisa de um sinal claro pra escolher. A própria Anthropic recomenda prefixos consistentes tipo asana_search vs asana_projects_search — e mediu que a escolha do estilo de namespacing mexe na acurácia.
E o nome dos parâmetros também importa. user_id é melhor que user. start_date_iso é melhor que date. Você está escrevendo para um leitor que não pode te perguntar.
Passo 2: Descrição — passe o teste do estagiário
A descrição é o documento que o modelo lê pra decidir quando chamar e quando não chamar sua tool. Trate ela com o mesmo carinho de um docstring de biblioteca pública.
A heurística da Anthropic:
"Think of how you would describe your tool to a new hire on your team. Consider the context that you might implicitly bring... and make it explicit."
Compara as duas:
RUIM
"Search for users."
BOM
"Search active users in the CRM by full name, email or phone.
Returns up to 20 results sorted by last interaction.
Use this when the request mentions a person who is likely a customer.
Do NOT use to look up internal employees — use `hr_search_employees` for that.
If the user only provided a partial name, prefer this tool over guessing an ID."
A diferença não está no número de palavras. Está em quatro coisas:
- O que faz — busca usuários ativos no CRM.
- Como retorna — até 20 resultados, ordenados por interação recente.
- Quando usar — pessoa que provavelmente é cliente.
- Quando NÃO usar — funcionário interno tem outra tool.
Esse último ponto é o que mais falta nas tools que vejo em código alheio. Modelo bom, principalmente Claude Opus, costuma pedir esclarecimento se o nome da tool deixar ambíguo. Modelos menores como Sonnet ou Haiku tendem a chutar. Cobrir o "quando não usar" é o que blinda contra o chute.
Passo 3: Schema — strict mode + invalid state unrepresentable
Esquema permissivo é convite pra alucinação. Duas regras que economizam horas de debug:
Regra 1: ative strict mode.
tools = [{
"type": "function",
"name": "create_order",
"description": "Create a paid order for an existing customer.",
"strict": True,
"parameters": {
"type": "object",
"additionalProperties": False,
"required": ["customer_id", "items", "currency"],
"properties": {
"customer_id": {"type": "string", "description": "Internal CRM ID, format: CUS-XXXXXX."},
"items": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": False,
"required": ["sku", "quantity"],
"properties": {
"sku": {"type": "string"},
"quantity": {"type": "integer", "minimum": 1}
}
}
},
"currency": {"type": "string", "enum": ["BRL", "USD", "EUR"]}
}
}
}]
Com strict: true, a OpenAI garante que a chamada respeita o schema. Anthropic tem a feature equivalente. Não é opcional pra produção — é o mínimo.
Regra 2: torne estados inválidos impossíveis de representar.
Em vez de dois booleanos is_express e is_economy que podem ser ambos true, use um enum. Em vez de unit: string aceitando qualquer coisa, use unit: "celsius" | "fahrenheit". Em vez de date: string, force ISO 8601 no schema e deixe claro na description.
E por último, a regra que mais gente quebra: não peça ao modelo argumentos que você já tem. Se o usuário está logado e você sabe o user_id, não exponha esse parâmetro pro modelo preencher. Passe via código. A própria OpenAI cita isso explicitamente: "Don't make the model fill arguments you already know."
Cada parâmetro a mais é uma chance a mais de o modelo errar.
Passo 4: Exemplos — o que JSON schema não consegue dizer
Schema diz tipo. Não diz convenção. Não diz padrão. Não diz como combinar parâmetros opcionais.
A Anthropic lançou em 2025 um recurso específico pra isso: Tool Use Examples. Em testes internos, exemplos few-shot levaram a acurácia em parâmetros complexos de 72% para 90%.
Como aplicar mesmo se o seu provider não tiver feature dedicada — coloca exemplo na description:
"description": """
Schedule a meeting in the user's primary calendar.
Examples:
- "amanha as 14h, 30 min" -> {"start": "2026-04-26T14:00:00-03:00", "duration_minutes": 30}
- "quinta de manha com o time de produto" -> {"start": "2026-04-30T10:00:00-03:00", "duration_minutes": 60, "attendees_group": "product"}
- "reuniao recorrente toda segunda" -> use `schedule_recurring_meeting` instead.
"""
Três exemplos cobrem mais ambiguidade do que três parágrafos de prosa.
Passo 5: Erros — devolva instrução, não stack trace
Quando a tool falha, o que o modelo recebe vira o próximo prompt dele. Stack trace cru não ajuda. Mensagem genérica também não.
RUIM
{"error": "ValidationError: 'customer_id' is required"}
BOM
{
"error": "missing_customer_id",
"message": "Required parameter customer_id was not provided.",
"hint": "If you don't have a customer_id yet, call `crm_search_users` with the customer's name or email first to retrieve it."
}
A Anthropic é explícita: erros devem dar guidance acionável, não opaque error codes. O agente que recebe um erro útil corrige na próxima iteração. O agente que recebe um stack trace desiste ou alucina.
Antipadrões que destroem tool use
Vi todos esses em código real, várias vezes. Não faça.
- Tool genérica que faz tudo.
execute(action, payload)parece elegante. Pro modelo, é uma caixa preta. Quebra em tools específicas. - 50 tools no system prompt. Acima de ~20 funções por turno, a OpenAI recomenda usar tool search. A Anthropic mostrou queda concreta de acurácia. Se você precisa de mais, paginar via tool search.
- Descrição copiada do README da API. README é pra humano que vai ler em ordem. Description é pra modelo que vai ler em isolamento. Reescreve.
- Confiar no modelo pra preencher ID que você já tem. Tenant ID, user ID, workspace ID — passe via código.
- Schema sem
additionalProperties: false. O modelo vai inventar campos. Você vai descobrir em produção. - Sem eval. Você está afinando no escuro. Antes de mexer em prompt, monte 10 cenários e meça.
Limitações e pontos de atenção
Tool use bem desenhado custa contexto. Cada tool exposta gasta tokens só por estar lá. A própria Anthropic cobra um system prompt extra de 346 tokens por requisição com tools. Multiplica por agente, por chamada, por dia — vira custo real.
Modelos menores erram mais. Claude Opus tende a perguntar quando falta parâmetro; Sonnet tende a chutar. Se sua aplicação roda em Haiku ou GPT-4o-mini por custo, você precisa de exemplos e descrições mais redundantes — não menos.
E a parte chata. Não tem atalho. Eval realista, com tarefas multi-step e métricas além de acurácia (latência, número de tool calls, tokens consumidos), é o que separa quem afina ferramenta de quem reza pra dar certo. A Anthropic recomenda olhar total runtime, total tool calls, total tokens, tool errors. Acurácia sozinha esconde agente que acerta a resposta gastando dez vezes mais.
Quer construir agente que aguenta produção?
O Clã Beer & Code está focado exatamente nisso: dev PHP/Laravel saindo da fase de "usar IA" para a fase de construir produto com IA que sustenta usuário real.
Tool design é só uma das peças. Tem retrieval, eval, observabilidade, custo, segurança. Se você quer estar num grupo onde essa discussão acontece toda semana com gente que está enviando código pra produção, entra no Clã.
FAQ rápido
Quantas tools posso expor sem prejudicar performance?
Até ~20 tools simultâneas costuma funcionar bem em modelos top de linha. Acima disso, considere tool search ou agrupamento por contexto. A queda de acurácia em libraries grandes é documentada pela Anthropic.
Devo sempre usar strict mode?
Em produção, sim. Em prototipagem, pode atrapalhar exploração — modelo pode recusar chamada por um campo opcional faltando. Comece sem strict, ative quando for fechar a API.
Tool description ou system prompt: onde colocar a regra de negócio?
Regras gerais ("seja conciso", "responda em PT-BR") vão no system prompt. Regras específicas de quando usar uma tool ("não use isso para funcionário interno") vão na description da tool. Modelo lê os dois — mas description da tool fica colada à decisão de chamada.
Vale a pena MCP em vez de tools custom?
MCP é ótimo pra padronizar acesso a sistemas externos (Slack, GitHub, Drive). Pra tool de domínio do seu produto, custom continua sendo o caminho — você controla schema, description e error handling, que é exatamente o que a maioria dos servidores MCP de terceiros faz mal.
Conclusão
Resumo prático. Tool use só funciona quando o design respeita o leitor — e o leitor aqui é o modelo, que lê em isolamento, sem contexto implícito, e decide em poucos tokens.
Nome explícito com namespace. Descrição que cobre quando usar e quando não usar. Schema strict com estado inválido impossível. Exemplos few-shot pros casos ambíguos. Erros que ensinam o agente a se corrigir.
A próxima geração de agentes — programmatic tool calling, tool search dinâmico, eval automatizada de tools — só vai render pra quem já fez o básico bem. Comece pelo básico.
Agora que você tem o que checar nas suas tools, veja como estruturar contexto e RAG no Beer & Code — porque tool boa com retrieval ruim ainda entrega resposta errada.
{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.
Você também pode gostar
Chatbot não é agente: o teste dos 3 turnos que separa brinquedo de produto
Três perguntas simples sobre um produto real — preço hoje, reviews recentes, disponibilidade no CEP — quebram qualquer chatbot cru. O que separa brinquedo de produto não é o modelo. É o harness: a camada que transforma um LLM em agente confiável, com tool use, estado e validação contra o mundo real.
Alucinação em e-commerce é caro: quando a IA inventa especificação, cupom e estoque
Air Canada, DPD e Chevrolet mostraram em escala global o custo de deixar o LLM virar fonte de verdade no atendimento. Especificação inventada, cupom que não existe, estoque que não bate — vira chargeback, processo e dano de marca. O caminho técnico passa por retrieval grounded e tool use validando cada promessa.
Anatomia de um Agent Harness: state, tool execution, feedback loops e guardrails
Harness é o software que envolve o LLM e separa um demo bonito de um agente que aguenta produção. Quebro a anatomia em cinco peças obrigatórias: estado persistente, roteador de ferramentas, validação de I/O, loop de raciocínio e limites de segurança. É o mapa mental que abre a série de posts sobre engenharia de agentes.
Seu LLM não sabe o preço de nada: o problema do conhecimento congelado em apps de compra
Seu modelo foi treinado há meses, mas o mercado muda em horas. O LLM responde com a mesma confiança de sempre — só que com preço errado, produto descontinuado e estoque do ano passado. Esse é o conhecimento congelado, e ele mata qualquer app sério de recomendação. Veja por que perguntar "qual o melhor notebook até 5 mil?" direto pro LLM é receita pra demo bonita e cliente bravo — e como a arquitetura certa (tool use + RAG) resolve em Laravel.