Lição 2: Anatomia do contexto: system prompt, ferramentas e exemplos
Objetivos de aprendizado:
- Desmontar o contexto de uma única requisição a um LLM (system prompt, definições de ferramentas, exemplos, histórico de mensagens) e explicar por que os quatro gastam do mesmo orçamento de atenção
- Diagnosticar o problema de “altitude” em um system prompt — hardcoded e frágil de um lado, vago e sem sinal do outro — e reescrevê-lo na altitude certa
- Auditar definições de ferramentas e exemplos pela lente do custo de contexto: fundir funcionalidades sobrepostas, podar o que volta, e trocar uma lista de casos de borda por alguns exemplos canônicos
Pré-requisitos: Você concluiu a Lição 1 e aceita a premissa de que o contexto é um recurso finito | Anterior: Lição 1 << | Próxima: Lição 3 >>
Abra o capô: o que de fato é carregado numa requisição
A Lição 1 tomou emprestada a definição da Anthropic: context engineering é "the set of strategies for curating and maintaining the optimal set of tokens (information) during LLM inference"1 (o conjunto de estratégias para curar e manter o conjunto ótimo de tokens (informação) durante a inferência de um LLM). Isso ainda é abstrato — de quais tokens “o conjunto ótimo” é de fato feito? Esta lição faz uma coisa só: abre o capô para você ver o que é carregado na janela toda vez que uma requisição sai.
Você escreveu à mão um loop de harness lá em “Fundamentos do Harness de Agente: Laços e Controle”, então o formato de uma requisição deve ser familiar. Ordenado pelo que carrega, o contexto de uma única requisição é mais ou menos estes quatro blocos:
Eis o que importa: esses quatro não são quatro compartimentos lacrados, são vizinhos em uma mesma janela. "LLMs have an "attention budget" that they draw on when parsing large volumes of context," e "Every new token introduced depletes this budget by some amount"1 (LLMs têm um “orçamento de atenção” do qual sacam ao processar grandes volumes de contexto, e cada novo token introduzido esgota esse orçamento em alguma medida). Um parágrafo a mais de enchimento no system prompt é atenção que o histórico de mensagens não recebe; dez ferramentas paradas no manifesto que ninguém nunca chama afinam a fatia que sobra para os exemplos. E, como a Lição 1 cobriu, "as the number of tokens in the context window increases, the model's ability to accurately recall information from that context decreases"1 (conforme o número de tokens na janela de contexto aumenta, a capacidade do modelo de recuperar com precisão informações desse contexto diminui) — uma degradação que chega como uma ladeira, não como uma queda, já que "These factors create a performance gradient rather than a hard cliff"1 (esses fatores criam um gradiente de desempenho, não um penhasco abrupto). É por isso que o desperdício em qualquer um dos blocos nunca se anuncia com um erro. Ele apenas deixa o conjunto todo um pouco mais burro, em silêncio, e quando você percebe já não consegue apontar a linha que fez aquilo.
Os quatro blocos também crescem em ritmos diferentes. System prompt, definições de ferramentas e exemplos são basicamente estáticos — do tamanho que você escreveu, é do tamanho que ficam. O histórico de mensagens, esse incha dentro do loop, porque "An agent running in a loop generates more and more data that could be relevant for the next turn of inference"1 (um agente rodando em loop gera cada vez mais dados que poderiam ser relevantes para o próximo turno de inferência). No harness que você construiu em “Fundamentos do Harness de Agente: Laços e Controle”, a linha que empurra o resultado de ferramenta de cada turno para o array messages é esse inchaço, ao vivo. O que fazer com o histórico não é tarefa desta lição — a Lição 4, “Compactação e notas: gestão de contexto para tarefas longas”, é dedicada a isso. Esta lição põe sob controle os três blocos estáticos, porque eles são o custo fixo que você paga em cada turno, sem exceção.
Transformar "context, therefore, must be treated as a finite resource with diminishing marginal returns"1 (o contexto, portanto, precisa ser tratado como um recurso finito com retornos marginais decrescentes) em algo acionável significa fazer a cada bloco a mesma pergunta: quanta melhoria de comportamento esses tokens compraram? Vamos bloco a bloco.
A altitude de um system prompt: duas formas de falhar
O artigo de engenharia da Anthropic usa “altitude” para o nível de abstração em que um system prompt se situa, e nomeia dois extremos de falha. De um lado, "engineers hardcoding complex, brittle logic in their prompts to elicit exact agentic behavior"1 (engenheiros deixando lógica complexa e frágil hardcoded em seus prompts para arrancar um comportamento agêntico exato). Do outro, "vague, high-level guidance that fails to give the LLM concrete signals for desired outputs"1 (orientação vaga e de alto nível que não dá ao LLM sinais concretos das saídas desejadas). Vamos escrever três versões de um system prompt para o mesmo agente de suporte a pedidos, para deixar as duas armadilhas e a boa resposta lado a lado.
Voando baixo demais — a lógica fica hardcoded:
Cada regra cobre exatamente o caso que ela soletra. E quando o usuário escreve “a caixa veio amassada” em vez de “danificado”? Nenhuma regra pega isso, então cai na regra 20 e o agente se faz de bobo. Pior, as regras começam a brigar entre si, então você acrescenta a regra 19 para apitar o jogo — e a essa altura você está escrevendo um interpretador de if-else em linguagem natural. Cada acréscimo deixa o prompt mais longo, mais frágil e mais caro em atenção, enquanto os casos que você não escreveu sempre vão ser mais numerosos do que os que escreveu.
Flutuando alto demais — só palavra de ordem:
Você economizou os tokens, mas o modelo não recebe sinal concreto nenhum. Onde fica a fronteira dos reembolsos? Quanta compensação ele pode autorizar? O que tem de ir para um humano? É tudo chute. “Mantenha os usuários felizes”, levado ao limite, pode significar devolver dinheiro que jamais deveria ter sido devolvido — e isso não é desobediência, é você não tendo dito nada.
A altitude certa — o padrão da Anthropic é um prompt "specific enough to guide behavior effectively, yet flexible enough to provide the model with strong heuristics"1 (específico o bastante para guiar o comportamento com eficácia, e ainda assim flexível o bastante para dar ao modelo heurísticas fortes):
Olhe a estrutura dessa versão: os princípios fazem a generalização, as linhas vermelhas fazem a conformidade. “A caixa veio amassada” não está escrito literalmente em regra nenhuma, e ainda assim cai naturalmente sob “dano é culpa nossa”; as coisas que de fato não são negociáveis (o teto de compensação, disputas jurídicas) ficam fixadas como um punhado de limites rígidos. Tem menos da metade do comprimento da versão de 20 regras e cobre estritamente mais terreno.
Existe uma pergunta-atalho para julgar altitude: diante de um caso que você não escreveu, este prompt dá ao modelo uma direção a partir da qual raciocinar? A versão baixa não dá (ela só sabe cair no pega-tudo), a versão alta dá uma direção vazia (“felizes”), e a versão na altitude certa dá princípios que transferem.
A camada sempre carregada: a disciplina do CLAUDE.md
O system prompt não é só a string que você digitou. Muitos harnesses estacionam configuração de nível de projeto permanentemente na camada de sistema, e o CLAUDE.md do Claude Code é o caso canônico: a documentação diz que "CLAUDE.md is a special file that Claude reads at the start of every conversation."2 (o CLAUDE.md é um arquivo especial que o Claude lê no início de cada conversa.) “Lido toda vez” significa que cada linha dele gasta orçamento de atenção em cada sessão, e é por isso que a disciplina que a documentação impõe sobre ele é rigorosa.
Regra um: coloque ali só o que se aplica de forma ampla — "CLAUDE.md is loaded every session, so only include things that apply broadly."2 (o CLAUDE.md é carregado a cada sessão, então inclua apenas coisas que se aplicam de forma ampla.) Um comando de build de que só um subdiretório precisa, uma convenção de que só um tipo de tarefa precisa: nenhum dos dois conquistou uma cadeira na camada sempre carregada.
Regra dois: rode um teste de remoção linha a linha. "Keep it concise. For each line, ask: "Would removing this cause Claude to make mistakes?" If not, cut it."2 (Seja conciso. Para cada linha, pergunte: remover isto faria o Claude cometer erros? Se não, corte.) Isso não é frescura. A documentação alerta de forma direta que "Bloated CLAUDE.md files cause Claude to ignore your actual instructions!"2 (arquivos CLAUDE.md inchados fazem o Claude ignorar as suas instruções de verdade!) É o orçamento de atenção tornado concreto — cada linha opcional que você enfia ali dilui as poucas linhas que genuinamente importam. A mesma página vai a ponto de chamar a janela de contexto de "the most important resource to manage," (o recurso mais importante a gerenciar) observando que "Claude's context window fills up fast, and performance degrades as it fills."2 (a janela de contexto do Claude enche rápido, e o desempenho se degrada conforme ela enche.)
Então onde mora o material raramente necessário mas ocasionalmente essencial? A resposta do Claude Code são as Skills: carregadas sob demanda, já que "Claude loads them on demand without bloating every conversation."2 (o Claude as carrega sob demanda sem inchar cada conversa.) Esse par — mantenha a camada residente mínima, busque o resto quando precisar — é exatamente o assunto da Lição 3, então vamos só reservar o lugar aqui.
Um aparte: se o seu próprio projeto tem um AGENTS.md, um system_prompt.txt ou qualquer coisa parecida morando permanentemente no contexto, rode o mesmo teste de remoção nele. Inchaço na camada sempre carregada é o tipo mais traiçoeiro — ele nunca aparece em nenhum turno específico da conversa, e taxa todos eles.
Ferramentas são contexto: a definição custa, e o retorno também
Uma ferramenta aparece no contexto duas vezes: a definição pega carona em cada requisição, e o valor de retorno entra no histórico de mensagens. As duas pontas gastam orçamento.
O curso anterior “Tool calling de agentes: fazendo agentes agirem de verdade” cobriu o lado funcional do design de ferramentas — como definir parâmetros, como tratar erros. Esta lição pega outro ângulo: cada definição de ferramenta é um trecho de tokens que o modelo tem de ler e entender. A régua da Anthropic é que "tools should be self-contained, robust to error, and extremely clear with respect to their intended use"1 (as ferramentas devem ser autocontidas, robustas a erro e extremamente claras quanto ao uso pretendido), e que você está "building tools that are well understood by LLMs and have minimal overlap in functionality"1 (construindo ferramentas que sejam bem compreendidas por LLMs e tenham sobreposição mínima de funcionalidade). Aqui está um par que falha nas duas coisas (schemas abreviados para facilitar a leitura):
As duas ferramentas conseguem consultar um pedido, as duas descrições são vagas, e a fronteira entre elas não é algo que nem o próprio autor fixou. É esse o ponto inteiro da exigência de "minimal overlap in functionality"1 (sobreposição mínima de funcionalidade): empilhe ferramentas de fronteiras difusas e você entregou ao modelo a pergunta “qual delas eu uso?” fresquinha a cada turno. Funda as duas em uma só e enuncie o propósito e o comportamento com clareza, e a pergunta desaparece:
Essa descrição diz mais do que “o que ela faz” — ela soletra o formato do que volta e o que acontece quando não há nada a retornar, que é o "robust to error"1 (robusta a erro) tornado literal: o modelo não precisa adivinhar como é uma consulta sem resultado, então é bem menos provável que ele invente alguma recuperação estranha quando a busca vier vazia.
Agora o lado do retorno. A Anthropic pede ferramentas "returning information that is token efficient and by encouraging efficient agent behaviors"1 (que retornem informação eficiente em tokens e que estimulem comportamentos eficientes do agente). Uma ferramenta que despeja de volta os mais de quarenta campos internos de um pedido junto com o log de auditoria completo derrama um balde de tokens de baixo valor no histórico de mensagens a cada chamada — e esses tokens ficam no histórico, taxados de novo em cada turno seguinte. “Podar por padrão, detail=true sob demanda”, como no exemplo acima, é o formato padrão da correção.
Por fim, o próprio manifesto de ferramentas precisa de subtração. Dez ferramentas no contexto que nunca são chamadas continuam sendo cobradas por inteiro a cada turno pelas suas definições. Auditar uma lista de ferramentas e auditar um CLAUDE.md são o mesmo movimento — remover isto causaria erros? Se não, corte.
Exemplos: escolha os canônicos, não empilhe uma lista
Exemplos (few-shot) são o terceiro custo estático. O apodrecimento típico deles é assim: cada caso ruim que aparece em produção ganha um exemplo correspondente acrescentado ao prompt, e seis meses depois você é dono de um catálogo de 30 casos de borda. A Anthropic é direta a respeito — não "stuff a laundry list of edge cases into a prompt"1 (enfie uma lista de lavanderia de casos de borda em um prompt); em vez disso, "curate a set of diverse, canonical examples that effectively portray the expected behavior of the agent"1 (cure um conjunto de exemplos diversos e canônicos que retratem com eficácia o comportamento esperado do agente).
“Canônico” significa que um exemplo representa uma classe de comportamento, não uma situação específica. De volta ao agente de suporte: três exemplos bastam para emoldurar todo o espaço de comportamento.
- O fluxo padrão: o caminho completo de consultar o pedido, atribuir a culpa, oferecer uma solução.
- Assumir a responsabilidade de saída: despachamos o item errado, e a compensação é oferecida antes de o usuário pedir.
- Escalonamento: está além da alçada do agente, então ele explica com educação e passa para um humano.
“Diversos” significa que esses três cobrem ramos diferentes do julgamento, em vez de serem três variações do mesmo comportamento.
E onde ficam os casos de borda? A maioria deles deveria ser promovida de volta à camada de princípios do system prompt. “E se o usuário for agressivo” não precisa de um exemplo de conversa completa com 300 tokens; um princípio — “quando um usuário estiver irritado, mantenha o tom equilibrado e o foco em resolver o problema” — dá conta do recado. Exemplos ensinam qual é a cara do comportamento esperado; princípios ensinam em que direção raciocinar quando algo novo aparece. Você talvez já tenha notado: acrescentar um caso de borda à lista de exemplos e acrescentar um ramo ao system prompt são duas faces da mesma moeda — as duas são remendos em altitude baixa, e só subir para a camada de princípios de fato veda a brecha.
Um checklist bloco a bloco: pondo a anatomia para trabalhar
Condensando esta lição em algo executável. Antes de acrescentar qualquer coisa ao contexto, rode a pergunta correspondente:
Há mais um princípio que vale levar desta lição, além da tabela. Escrevendo sobre a construção de sistemas de agentes, a Anthropic oferece um senso de proporção: "you should consider adding complexity only when it demonstrably improves outcomes."3 (você deveria considerar adicionar complexidade apenas quando ela comprovadamente melhora os resultados.) O contexto original é arquitetura de sistemas, mas vale igualmente para cada bloco do contexto — mais uma ferramenta, mais uma regra, mais um exemplo é tudo complexidade adicionada. Exija de cada acréscimo a prova de que ele compra melhoria de comportamento antes de deixá-lo embarcar.
Isso é uma passada por todos os três blocos estáticos. Mas há outra pergunta esperando: parte da informação não deveria ser carregada na janela de antemão de jeito nenhum — em vez de adivinhar do que o modelo vai precisar, deixe o agente ir buscar em tempo de execução. É disso que trata a próxima lição.
Recapitulação
- O contexto de uma requisição são quatro blocos — system prompt, definições de ferramentas, exemplos, histórico de mensagens. Eles compartilham um único orçamento de atenção, e cada novo token o esgota em alguma medida1.
- O contexto é um recurso finito com retornos marginais decrescentes1; perguntar bloco a bloco “o que esses tokens compraram” é bem mais acionável do que vagamente “ajustar o prompt”.
- Um system prompt tem dois extremos de falha — ramos hardcoded e frágeis, e palavras de ordem vagas que não carregam sinal. A altitude certa é específica o bastante para guiar o comportamento e ainda flexível o bastante para deixar heurísticas fortes ao modelo1, e “princípios mais limites rígidos” é a estrutura prática para chegar lá.
- Conteúdo sempre carregado como o CLAUDE.md é lido no início de cada conversa: inclua apenas o que se aplica de forma ampla, e rode o teste de remoção em cada linha, porque arquivos inchados fazem o modelo ignorar as suas instruções de verdade2.
- Ferramentas gastam orçamento nas duas pontas, definição e retorno: mantenha o uso pretendido extremamente claro, a sobreposição mínima e os retornos eficientes em tokens1; ferramentas que nunca são chamadas continuam sendo cobradas por inteiro a cada turno.
- Cure alguns exemplos diversos e canônicos em vez de enfiar uma lista de lavanderia de casos de borda1; a maioria dos casos de borda pertence de volta à camada de princípios.
- Antes de acrescentar qualquer complexidade ao contexto, lembre o senso de proporção da Anthropic: acrescente apenas quando ela comprovadamente melhora os resultados3.
>> Lição 3: Recuperação just-in-time: deixando o agente buscar o próprio contexto