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
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:
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