Projetar tools
Uma tool que o modelo nunca chama é pior que tool nenhuma: custa contexto a cada turno e não faz nada. A maioria dos problemas de tool é problema de descrição.
A descrição é prompt
O modelo decide a partir dela, literalmente.
description: "Operações de arquivo."; // vago
description: "Lê um arquivo do projeto. Use antes de responder sobre código."; // decidívelEscreva como instrução para um colega que não vê o seu código: o que ela faz, e quando recorrer a ela. O .describe() nos campos do schema também é lido:
schema: z.object({
path: z.string().describe("caminho relativo à raiz do projeto, ex.: src/main.ts"),
});Faça o schema estreito
Cada restrição que você expressa é uma classe de falha que o modelo não consegue produzir, pega antes de o seu código rodar:
schema: z.object({
path: z.string(),
linhas: z.number().int().min(1).max(500).default(100),
modo: z.enum(["ler", "stat"]),
});Um enum é melhor que uma string livre. Um default remove uma decisão. Argumento inválido nunca chega no execute — o modelo é informado do erro e tenta de novo.
Devolva um orçamento, não uma mangueira
Saída de tool é a forma mais rápida de entupir a janela de contexto, e é o que envelhece pior: o modelo raramente precisa de um arquivo inteiro dez turnos depois.
const MAX_CHARS = 4000;
async execute({ path }: { path: string }) {
const texto = await readFile(path, "utf8");
return texto.length <= MAX_CHARS
? texto
: `${texto.slice(0, MAX_CHARS)}\n… [truncado, ${texto.length} chars no total]`;
}Dizer que truncou importa — senão o modelo trata um arquivo parcial como o arquivo inteiro.
Escreva o erro que o modelo lê
return { content: `Não existe arquivo em "${path}". Confira o caminho.`, isError: true };ENOENT: no such file or directory, open 'READMEE.md' descreve uma syscall. A versão acima diz ao modelo o que fazer em seguida. Veja Erros.
E para o que o modelo não conserta, FatalToolError — que também mantém a mensagem de um driver fora do contexto do modelo e do seu disco.
Uma tool, um verbo
Uma tool gerenciar_arquivos com um parâmetro acao força o modelo a tomar duas decisões de uma vez, e a segunda é invisível na lista de tools. Prefira:
read_file · write_file · list_filesA exceção é quando as operações realmente compartilham argumentos e só uma é correta — uma busca com um filtro tipo, por exemplo.
Mantenha função pura onde der
Por padrão o execute recebe só os argumentos validados, o que torna a tool trivial de testar:
expect(await new ReadFileTool().execute({ path: "x.txt" })).toBe("olá");Cada @context() e @state() que você acrescenta abre mão disso. Acrescente quando precisar — repassar um signal, gravar no estado do fluxo, disparar uma execução aninhada — e não por padrão.
Repasse o signal
Qualquer coisa que demore:
async execute(@input() { url }: { url: string }, @context() ctx: Context) {
const res = await fetch(url, { signal: ctx.signal });
return res.text();
}Sem isso, o cancelamento só tem efeito entre os passos.
data para o que o modelo não deve ler
return {
content: `Encontrei 42 ocorrências.`, // o que o modelo vê
data: { ocorrencias, queryMs: 18 }, // para hooks, report, telemetria
};Detalhe estruturado pertence aqui, e não serializado na observação.
Entregue só o necessário
O array tools é a fronteira de segurança — o agente faz exatamente o que está nele, e nada além. Um agente que lê conteúdo não confiável e segura uma tool com efeito colateral é superfície de ataque. Uma tool de shell é o exemplo mais claro — veja o aviso dela em Receitas de tools.
Prefira uma tool estreita a uma genérica: reiniciar_servico(nome) com um enum de serviços conhecidos é melhor que rodar_shell(comando).
Diagnosticando "ele não usou minha tool"
- Leia a
descriptioncomo o modelo lê. Ela diz quando? - Confira se o prompt manda agir. "Antes de responder, leia os arquivos relevantes."
- Confira o
toolCallSourcenos nóschatdo report."rescued"significa que o modelo escreveu a chamada como texto e o framework recuperou — funciona, mas você está no limite do que aquele modelo dá conta. - Conte as tools. Vinte tools é uma escolha difícil para um modelo pequeno.
