Agent Mentor Learn
Tool calling de agentes: fazendo agentes agirem de verdade · Lição 3 de 6

Lição 3: Cinco tipos comuns de ferramenta: ler, escrever, executar, buscar, chamar

Objetivos de aprendizado:

  • Classificar as ferramentas comuns em cinco categorias pelo tanto de estrago que podem causar, e nomear a assinatura típica de cada uma
  • Explicar por que ferramentas de execução de comando ficam numa classe de risco diferente das outras quatro
  • Explicar por que ferramentas de busca retornam trechos correspondentes em vez de arquivos inteiros

Pré-requisitos: concluiu a Lição 2, você entende o formato de ida e volta de uma chamada de ferramenta | Anterior: Lição 2 << | Próxima: Lição 4 >>

Comece com uma tabela

FerramentaEntrada típicaO que retornaPior caso quando dá errado
Ler arquivopathConteúdo do arquivo (string)Lê um arquivo que não deveria, vaza informação
Escrever arquivopath, contentStatus de sucesso/falhaSobrescreve um trabalho que alguém ainda não salvou
Executar comandocommandstdout/stderr/código de saídaApaga um banco de dados, envia requisições, instala um pacote envenenado — irreversível
Buscarquery, pathLista de locais de correspondência + trechosRetorna tanto que estoura o contexto, ou perde o resultado principal
Chamar API externaParâmetros estruturados (variam por serviço)Objeto JSON/de erroGasta o dinheiro de alguém, envia a mensagem errada, obtém dados desatualizados

O que ordena esta tabela? Não é o alfabeto. É “que amplitude de dano uma única chamada consegue causar” — o raio de impacto dessa chamada. Uma ferramenta somente de leitura tem raio de impacto próximo de zero: ler o arquivo errado só descarrila este turno da conversa. Escrever um arquivo pode sobrescrever conteúdo existente. Executar um comando pode fazer absolutamente qualquer coisa com o sistema inteiro. Ao percorrermos cada categoria, você vai ver que, além do “o que ela consegue fazer”, cada uma carrega uma armadilha em que só aquela categoria tropeça.

Ler: a mais segura, mas não de risco zero

Uma ferramenta de leitura de arquivo costuma ter uma assinatura assim:

O valor de retorno é o próprio conteúdo do arquivo, normalmente com números de linha para que o modelo consiga referenciá-las depois:

1  export function add(a, b) {2    return a + b;3  }

Ler um arquivo não muda estado nenhum. Se o modelo ler a coisa errada, ou ler demais, o pior desfecho é algum conteúdo irrelevante neste único turno — e o modelo tende a perceber que leu errado e ler de novo. É por isso que ela é chamada de a categoria “mais segura”: não que não tenha risco, mas que o risco não consegue escapar dos limites desta conversa.

O risco de verdade é ler um arquivo em que jamais se deveria ter tocado. Se o agente tem permissão para ler ~/.ssh/id_rsa ou o .env do projeto, um inocente “me mostre o que tem neste diretório” pode erguer uma chave secreta na íntegra para dentro do contexto da conversa. Daí em diante, o vazamento já aconteceu no momento em que esse contexto é emitido pelo modelo, escrito num log, ou levado para fora por alguma ferramenta posterior de “chamar API externa”. É por isso que ferramentas de leitura de arquivo quase sempre vêm acompanhadas de uma lista de permissões de caminhos ou de um sandbox, em vez de “é só leitura, pode entregar as chaves”. A Lição 5 cobre em detalhe como estabelecer esse tipo de fronteira.

Escrever: onde as consequências deixam de ser simétricas

Uma ferramenta de escrita de arquivo tem um parâmetro a mais que a de leitura, e um tanto a menos de segurança:

O valor de retorno costuma ser simples, apenas um status:

O problema não é o valor de retorno, é a chamada em si. Se uma leitura dá errado, você lê de novo e nada mudou. Se uma escrita dá errado — digamos que o modelo preencha o path errado, ou que o content esteja faltando metade do que deveria —, o conteúdo original do arquivo já foi sobrescrito e não pode ser recuperado, a não ser que haja controle de versão ou backup. Esta é a “assimetria entre ferramentas de leitura e ferramentas de escrita”: os dois formatos de chamada parecem quase idênticos (um path mais um par de parâmetros), mas uma pode ser repetida à vontade e a outra aposta a cada chamada.

Por isso uma ferramenta de escrita responsável acrescenta uma camada de proteção — por exemplo, exigir que o arquivo tenha sido lido antes de poder ser editado (para impedir o modelo de editar de memória), ou retornar um diff entre o conteúdo antigo e o novo em vez de um mero “sucesso”, para que quem chama (o aplicativo host) tenha a chance de mostrar a mudança antes que ela de fato chegue ao disco. Isso não é o foco aqui; a Lição 4 abre esses pontos quando trata de projeto de interface.

Executar: uma classe de risco só dela

A ferramenta de execução de comando tem a assinatura de aparência mais simples das cinco:

Entra uma string; saem stdout, stderr e um código de saída:

O detalhe é que esse campo command é essencialmente um ponto de entrada aberto — ele não é uma operação específica e delimitada por um schema como “apague este arquivo” ou “leia esta linha”, é um script de shell arbitrário. rm -rf, um curl que despacha dados para um servidor externo, um npm install que puxa um pacote envenenado — tudo isso cabe dentro daquela única string. As outras quatro categorias (ler, escrever, buscar, chamar API), por mais que você projete as assinaturas delas, são limitadas no que podem fazer pela sua estrutura de parâmetros. A fronteira de capacidade de uma ferramenta de execução de comando é a fronteira de capacidade do sistema operacional inteiro. É por isso que ela fica numa classe só dela: não “um pouco mais arriscada”, mas uma ordem de magnitude diferente de risco.

Exatamente por essa razão, a documentação oficial projeta isolamento em nível de sistema operacional especificamente para esta categoria: acesso ao sistema de arquivos e acesso à rede são duas camadas separadas de sandbox, e mesmo que o modelo seja conduzido por uma injeção de prompt e insista em rodar um comando perigoso, a fronteira do SO se sustenta de qualquer forma — ela não depende de o modelo “querer” cooperar1. A motivação declarada é direta: a meta é que mesmo uma injeção de prompt bem-sucedida fique inteiramente contida e não consiga escapar do sandbox2. A Lição 5 cobre como configurar esse isolamento; por ora, guarde uma coisa: onde quer que a assinatura de “executar comando” apareça, trate-a por padrão como a categoria, entre as cinco, que mais precisa de restrição extra.

Buscar: retorna localizações, não o mundo inteiro

Uma ferramenta de busca (digamos, uma que encontra uma palavra-chave ou regex em uma base de código) costuma carregar na assinatura um parâmetro de “limite quanto volta”:

O valor de retorno não são os arquivos em si, é “onde está a correspondência e como é o contexto ao redor”:

Se essa ferramenta simplesmente enfiasse de volta o conteúdo completo de cada arquivo correspondente, dois problemas apareceriam. O primeiro é um problema de tokens: uma busca atinge 50 arquivos, cada um com algumas centenas de linhas, tudo despejado no contexto — e essa única chamada de ferramenta comeu o orçamento de entrada do turno inteiro, sem deixar nada com que o modelo continue trabalhando3. Escrever descrições de ferramenta e controlar os limites de entrada e saída é, por si só, um requisito básico para tornar uma ferramenta utilizável4. O segundo problema importa mais: o objetivo da busca não é “ler tudo o que possa ser relevante”, é “ajudar o modelo a descobrir onde olhar em seguida”. Retorne os locais das correspondências mais um trecho curto de contexto, e o modelo lê esses trechos e julga por conta própria — “destes resultados, o segundo parece ser o que eu procuro, deixa eu ler o conteúdo completo daquele arquivo separadamente”. É assim que uma ferramenta de busca e uma de leitura trabalham juntas: a busca estreita o alcance, a leitura traz o detalhe. Retornar “locais de correspondência” em vez de “arquivos inteiros” é exatamente a pista de continuidade de que o modelo precisa, em vez de um despejo único de tudo o que possa ser útil.

Chamar API externa: a falha é a norma, não a exceção

As quatro primeiras categorias em geral ficam dentro do sistema local. Chamar uma API externa é diferente — atravessa a rede, até um serviço que você não controla:

Um retorno normal fica assim:

Mas um serviço externo vai te limitar por rate limit, dar timeout, rejeitar uma requisição por falta de permissão e mudar a própria interface no intervalo entre as suas chamadas. Isso não são “situações inesperadas”, são as condições normais de operação desta categoria. O que de fato decide se a ferramenta presta não é “o que ela retorna quando está tudo bem”, é “o que ela retorna quando as coisas falham”:

Essa mensagem de erro não é para você, é para o modelo — se ele deve tentar de novo ou trocar de estratégia em seguida depende de ele conseguir ler aquele campo error. A especificação do MCP escreve isso direto no protocolo: os clientes devem fornecer os erros de execução de ferramenta aos modelos de linguagem para que o modelo tenha a chance de se autocorrigir e tentar de novo5. Em outras palavras, uma ferramenta que engole silenciosamente um 429 e não retorna nada além de “a chamada falhou” está roubando do modelo a chance de se corrigir; uma ferramenta que traz de volta um detalhe concreto como retry_after é a que projeta a “falha” como parte normal do fluxo de trabalho.

A categoria de chamar API externa também arrasta consigo mais uma camada de risco: se este agente consegue ler dados privados ao mesmo tempo em que está exposto a conteúdo não confiável (um trecho de texto da web que um usuário colou, digamos) e também consegue enviar mensagens ou requisições para fora, esses três juntos são o que a pesquisa de segurança chama de “lethal trifecta” (a trinca letal) — o atacante não precisa invadir o seu sistema, ele só esconde uma instrução em um conteúdo que o agente vai ler e deixa o próprio agente carregar os dados privados para fora6. A Lição 5 abre este tema separadamente; por ora, saiba disto: chamar uma API externa é o último e mais crítico elo dessa corrente, porque é a saída pela qual os dados de fato deixam o seu sistema.

Recapitulação

  • O risco entre as cinco categorias não é distribuído por igual: ler arquivo tem as consequências mais leves, escrever arquivo é onde as coisas começam a ser irreversíveis, o raio de impacto de executar comando é igual ao do sistema operacional inteiro, e buscar e chamar API externa têm cada uma as suas próprias armadilhas
  • A diferença central entre ferramentas de leitura e de escrita é poder ou não repetir com segurança — leu errado, você lê de novo; escreveu errado, o conteúdo original pode ter ido embora de vez
  • Ferramentas de execução de comando precisam de um sandbox em nível de SO como último recurso porque o parâmetro command delas é uma string aberta, não delimitada por uma estrutura de schema como acontece com as outras quatro1 2
  • Ferramentas de busca retornam locais de correspondência mais trechos em vez de arquivos inteiros, primeiro para economizar tokens, e segundo para separar “localizar” de “ler o detalhe”, entregando ao modelo uma pista que ele pode seguir3
  • Ferramentas de chamada de API externa devem levar a informação de falha (tipo de erro, se pode ser repetida) de volta ao modelo tal como está, em vez de engoli-la — nesta categoria, a falha é a norma, não a exceção5

Na próxima lição, desmontamos as “assinaturas” dessas cinco categorias: como escrever um bom nome de ferramenta, descrição, schema de parâmetros e valor de retorno, para que o modelo a chame certo já na primeira vez.

>> Lição 4: Projetando interfaces de ferramentas: nome, descrição, parâmetros, valor de retorno

Footnotes

  1. Configure the sandboxed Bash tool - Claude Code Docs — https://code.claude.com/docs/en/sandboxing 2

  2. Making Claude Code more secure and autonomous with sandboxing - Anthropic Engineering — https://www.anthropic.com/engineering/claude-code-sandboxing 2

  3. Introducing advanced tool use on the Claude Developer Platform | Anthropic Engineering — https://www.anthropic.com/engineering/advanced-tool-use 2

  4. Writing effective tools for AI agents—using AI agents | Anthropic Engineering — https://www.anthropic.com/engineering/writing-tools-for-agents

  5. Tools - Model Context Protocol — https://modelcontextprotocol.io/docs/concepts/tools 2

  6. The lethal trifecta for AI agents - Simon Willison's Weblog — https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/

Exercícios

01

Abaixo estão três rascunhos de resultados de chamadas de ferramenta, cada um com um problema. Diga a que categoria de ferramenta o problema pertence (ler/escrever/executar/buscar/chamar API), explique por que o projeto não se encaixa bem, e apresente a mudança que você faria.

Nível 1: Escolher o valor de retorno de uma ferramenta
  1. search_code retorna: { "content": "<o código-fonte completo de 50 arquivos costurados, 8000 linhas no total>" }
  2. write_file retorna: { "success": true } (sem diff, sem informação do conteúdo antigo)
  3. send_email em caso de falha retorna: { "error": "failed" }
Critérios de conclusão · marcado localmente
02

Você precisa montar uma ferramenta para um agente: ele verifica periodicamente o status de remessa de uma API de logística de terceiros e, se o status virar “anômalo”, escreve o código de rastreio e o motivo em um arquivo local alerts.log.

Nível 2: Escolher os tipos de ferramenta para um cenário novo e projetar uma assinatura

Esta tarefa na verdade envolve mais de uma categoria de ferramenta. Escreva:

  1. De quais das cinco categorias desta lição ela precisa? Pelo que cada uma é responsável?
  2. Escreva um input_schema em JSON para a ferramenta de “chamar API externa para consultar o status da remessa”, com ao menos um parâmetro de código de rastreio (a abordagem sistemática de projeto de interface é a próxima lição; aqui só imite o formato de assinatura que apareceu nesta lição)
  3. Quando a consulta desta ferramenta falhar (código de rastreio não existe, requisição dá timeout), como deveria ser o valor de retorno?
Critérios de conclusão · marcado localmente