Back

Context Engineering: A habilidade de IA mais importante que ninguém tá ensinando

Todo tutorial ensina prompt engineering. Escreva instruções claras. Use exemplos few-shot. Adicione uma mensagem de sistema. Pra demos simples, tá ótimo.

Mas na hora que você tenta construir algo real — um agente de suporte que lembra o histórico, um assistente de código que entende todo o codebase, um pipeline de análise que processa PDFs de 200 páginas — prompt engineering não dá conta. Não porque seus prompts são ruins, mas porque você tá resolvendo o problema errado.

O verdadeiro desafio nunca foi o que dizer pro modelo. É a que informação ele tem acesso na hora de gerar a resposta. Essa disciplina tem nome: context engineering.

Se prompt engineering é escolher as palavras certas, context engineering é escolher o conhecimento certo. É a diferença entre perguntar algo pra um consultor brilhante sem dar nada, e montar a mesa dele com os documentos, histórico e ferramentas exatas antes de responder.

Este guia cobre tudo que você precisa saber: o que é context engineering, por que importa mais que prompt engineering, e as técnicas concretas usadas em produção hoje.

O que é Context Engineering, afinal?

Context engineering é a prática sistemática de selecionar, estruturar e gerenciar a informação que entra no context window de um LLM pra maximizar a qualidade do output dentro dos limites de tokens e orçamento.

Pense no context window como uma mesa de trabalho. Prompt engineering é escrever um bom memo pra colocar nessa mesa. Context engineering é curar tudo que tá nessa mesa — documentos de referência, ferramentas, histórico de conversas, exemplos — pra que a pessoa sentada ali possa dar a melhor resposta possível.

┌─────────────────────────────────────────┐
│           CONTEXT WINDOW                │
│                                         │
│  ┌─────────────────────────────────┐    │
│  │  Instruções do sistema          │    │
│  │  (Papel, restrições, formato)   │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │  Conhecimento recuperado (RAG)  │    │
│  │  (Documentos, código, dados)    │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │  Definições de ferramentas      │    │
│  │  (Funções/APIs disponíveis)     │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │  Histórico de conversa          │    │
│  │  (Mensagens anteriores)         │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │  Query atual do usuário         │    │
│  │  (O que acabou de perguntar)    │    │
│  └─────────────────────────────────┘    │
│                                         │
│  Total: Precisa caber em N tokens       │
│  (ex: 128K, 200K, 1M, 2M)              │
└─────────────────────────────────────────┘

Cada componente compete pelo mesmo espaço finito. Coloca muito histórico e empurra o conhecimento recuperado pra fora. Carrega muitas definições de ferramenta e não sobra espaço pra exemplos. Coloca tudo e estoura o orçamento de tokens (e a conta da API).

Context engineering é a arte de fazer esses trade-offs bem.

Por que Prompt Engineering sozinho não basta

Vamos a um cenário concreto.

Você tá montando um agente de suporte pra e-commerce. Um cliente escreve: "O pedido que fiz semana passada ainda não chegou. Já é a terceira vez. Quero reembolso."

Um sistema com bom prompt engineering acerta o tom — empático, profissional. Mas sem context engineering, ele não tem ideia de:

  • Qual pedido o cliente tá falando
  • O que o histórico real de pedidos mostra
  • Se o cliente já reclamou antes (e como foi resolvido)
  • Qual a política de reembolso pra casos recorrentes
  • O que o rastreio da transportadora diz

O prompt tá bom. O contexto tá vazio. O modelo inventa uma resposta genérica e o cliente fica mais irritado.

Context engineering resolve isso garantindo que a informação certa esteja no window antes do modelo gerar:

async function buildSupportContext(customerId: string, message: string) { // 1. Buscar dados do cliente const customer = await db.customers.findUnique({ where: { id: customerId } }); const recentOrders = await db.orders.findMany({ where: { customerId, createdAt: { gte: thirtyDaysAgo } }, include: { shipments: true }, }); // 2. Buscar documentos de política relevantes const policies = await vectorStore.search(message, { namespace: 'support-policies', topK: 3, }); // 3. Buscar interações de suporte anteriores const pastTickets = await db.supportTickets.findMany({ where: { customerId }, orderBy: { createdAt: 'desc' }, take: 5, }); // 4. Consultar status de envio em tempo real const trackingData = await shippingApi.getStatus( recentOrders[0]?.shipments[0]?.trackingNumber ); // 5. Montar o contexto return { systemPrompt: SUPPORT_AGENT_INSTRUCTIONS, context: [ { role: 'system', content: formatCustomerProfile(customer) }, { role: 'system', content: formatOrderHistory(recentOrders) }, { role: 'system', content: formatPolicies(policies) }, { role: 'system', content: formatPastTickets(pastTickets) }, { role: 'system', content: formatTrackingData(trackingData) }, ...conversationHistory, { role: 'user', content: message }, ], }; }

Agora o modelo tem tudo. O pedido exato, o rastreio, a política de reembolso pra reincidentes, o histórico de reclamações. Mesmo prompt, resultado radicalmente melhor.

Os cinco pilares do Context Engineering

Context engineering de produção exige dominar cinco disciplinas interligadas:

1. Seleção: O que entra

A primeira pergunta é sempre: que informação o modelo precisa pra responder bem essa query específica?

Parece óbvio, mas a maioria dos times ou enfia tudo (desperdiçando tokens e degradando qualidade) ou coloca muito pouco (forçando o modelo a chutar).

Princípio sinal-ruído: Cada token no context window precisa justificar sua presença. Informação irrelevante não só desperdiça tokens — degrada ativamente a qualidade.

// RUIM: Enfiar tudo const context = await db.documents.findMany(); // 50.000 tokens de ruído // BOM: Busca semântica com filtro de relevância const relevantDocs = await vectorStore.search(query, { topK: 10 }); const filtered = relevantDocs.filter(doc => doc.score > 0.78); // 2.000 tokens de sinal

Carga dinâmica de ferramentas também é crítica. Se seu agente tem 50 ferramentas mas só 3-5 são relevantes, carregar todas desperdiça milhares de tokens e confunde o modelo:

// RUIM: Carregar todas sempre const tools = getAllTools(); // 50 ferramentas, ~8.000 tokens // BOM: Selecionar por classificação de intenção const intent = await classifyIntent(userMessage); const tools = getToolsForIntent(intent); // 4 ferramentas, ~600 tokens // MELHOR: Abordagem de dois estágios const selectedToolNames = await selectRelevantTools(userMessage, allToolNames); const tools = selectedToolNames.map(name => toolRegistry.get(name));

2. Estruturação: Como organizar

A mesma informação, estruturada de forma diferente, produz resultados dramaticamente diferentes.

O viés posicional é real. Modelos prestam mais atenção ao início e ao fim do context window do que ao meio. É o problema "lost in the middle", demonstrado consistentemente em pesquisa. Informação crítica enterrada no meio de 100K tokens é como se não existisse.

function buildContext(systemPrompt, retrievedDocs, history, query) { return [ // INÍCIO — Zona de alta atenção { role: 'system', content: systemPrompt }, { role: 'system', content: '## DADOS DE REFERÊNCIA CRÍTICOS\n' + mostRelevantDoc }, // MEIO — Zona de baixa atenção ...history.slice(0, -3), ...supplementaryDocs, // FIM — Zona de alta atenção ...history.slice(-3), { role: 'user', content: query }, ]; }

Delimitadores de seção importam. Quando mistura tipos de informação, marcadores claros ajudam o modelo a distinguir:

const context = ` ## PERFIL DO CLIENTE Nome: ${customer.name} Status da conta: ${customer.tier} Total de pedidos: ${customer.orderCount} ## STATUS DO PEDIDO ATUAL Pedido #${order.id}${order.date} Status: ${order.status} Rastreio: ${tracking.status} — Última atualização: ${tracking.lastUpdate} ## POLÍTICAS APLICÁVEIS ${policies.map(p => `- ${p.title}: ${p.summary}`).join('\n')} ## AUTORIDADE DE RESOLUÇÃO Você pode emitir reembolsos até R$${agent.refundLimit} sem escalar. Acima disso, escale pra um supervisor. `;

3. Memória: Conectando passado e presente

Aplicações reais precisam lembrar entre conversas. Um usuário que explicou a arquitetura do projeto na segunda não deveria repetir tudo na terça.

O modelo de três camadas de memória:

┌───────────────────────────────────────┐
│  MEMÓRIA DE TRABALHO (Context Window) │
│  Conversa atual + dados ativos        │
│  Capacidade: Limite de tokens         │
│  Velocidade: Instantânea              │
├───────────────────────────────────────┤
│  MEMÓRIA DE CURTO PRAZO (Sessão)      │
│  Resumos de conversas recentes        │
│  Estado de sessão e variáveis         │
│  Capacidade: 10-50 entradas           │
│  Velocidade: Recuperação rápida       │
├───────────────────────────────────────┤
│  MEMÓRIA DE LONGO PRAZO (Persistente) │
│  Preferências e histórico             │
│  Conhecimento acumulado               │
│  Capacidade: Ilimitada                │
│  Velocidade: Requer busca             │
└───────────────────────────────────────┘
class MemoryManager { async buildMemoryContext(userId: string, currentQuery: string): Promise<string> { // Camada 1: Memória de trabalho — turnos recentes const recentTurns = this.conversationBuffer.slice(-6); // Camada 2: Curto prazo — resumos de sessão const sessionContext = await this.sessionStore.get(userId); // Camada 3: Longo prazo — conhecimento passado recuperado semanticamente const longTermMemories = await this.vectorStore.search(currentQuery, { filter: { userId }, topK: 5, }); return this.assembleMemory(recentTurns, sessionContext, longTermMemories); } }

Resumo é essencial. Não dá pra guardar cada turno pra sempre. A abordagem padrão é resumo rolante:

async function compressConversation(messages: Message[]): Promise<string> { if (messages.length <= 6) return ''; const toSummarize = messages.slice(0, -6); const summary = await llm.generate({ messages: [{ role: 'system', content: `Resuma esta conversa em 2-3 frases. Foco: decisões tomadas, fatos estabelecidos, preferências expressas. Ignore: cumprimentos, papo furado, informação repetida.` }, { role: 'user', content: toSummarize.map(m => `${m.role}: ${m.content}`).join('\n') }], model: 'gpt-4o-mini', maxTokens: 200, }); return summary; }

4. Compressão: Mais sinal em menos espaço

Mesmo com context windows de 2 milhões de tokens, compressão importa. Contextos maiores são mais lentos, mais caros e — paradoxalmente — muitas vezes produzem resultados piores.

async function compressDocuments(docs: Document[]): Promise<string> { const deduped = removeSimilarChunks(docs, similarityThreshold: 0.92); const compressed = await llm.generate({ messages: [{ role: 'system', content: `Comprima os documentos em referência densa. Preservar: números, datas, nomes, código, decisões. Remover: intros, transições, preenchimento, explicações repetidas. Alvo: 30% do comprimento original.` }, { role: 'user', content: deduped.map(d => d.content).join('\n---\n') }], model: 'claude-3-5-haiku', }); return compressed; }

Alocação adaptativa de orçamento:

function allocateContextBudget(totalTokens: number) { return { systemPrompt: Math.min(2000, totalTokens * 0.1), // 10% tools: Math.min(3000, totalTokens * 0.15), // 15% knowledge: Math.floor(totalTokens * 0.35), // 35% history: Math.floor(totalTokens * 0.30), // 30% query: 500, // Fixo buffer: Math.floor(totalTokens * 0.10), // 10% margem }; }

5. Avaliação: Medindo o que funciona

Não dá pra melhorar o que não mede. Context engineering precisa de métricas específicas:

MétricaO que medeAlvo
Relevância do contexto% de chunks usados na resposta> 70%
Eficiência de tokensTokens de output úteis / tokens de input> 0.15
Precisão de recuperação% de docs recuperados relevantes> 80%
Aderência ao orçamento% de requests dentro do budget> 95%
Grounding de resposta% de afirmações rastreáveis ao contexto> 90%
Impacto em latênciaLatência adicionada pela montagem< 500ms

Precisão de relevância — qual porcentagem do contexto realmente ajudou a responder?

async function measureContextRelevance( query: string, contextChunks: string[], expectedAnswer: string ): Promise<number> { const evaluations = await Promise.all( contextChunks.map(chunk => llm.generate({ messages: [{ role: 'system', content: `Avalie se este chunk de contexto é relevante pra responder a query. Responda 0 (irrelevante) ou 1 (relevante). Query: "${query}" Responda só 0 ou 1.` }, { role: 'user', content: chunk }], model: 'gpt-4o-mini', }) ) ); const relevant = evaluations.filter(e => e.trim() === '1').length; return relevant / contextChunks.length; }

Anti-padrões comuns

Anti-padrão 1: Pia da cozinha

Problema: Enfiar tudo no contexto porque "mais informação é sempre melhor."

Por que falha: Acima de 60-70% da capacidade declarada, a performance cai. O modelo começa a ignorar, confundir ou inventar sobre a informação que você deu.

Solução: Seja implacável com relevância. Se um documento não ajuda diretamente a query atual, não inclua.

Anti-padrão 2: Templates estáticos

Problema: Usar a mesma estrutura pra toda query independente de tipo ou complexidade.

Solução: Montagem dinâmica por classificação:

async function buildDynamicContext(query: string) { const queryType = await classifyQuery(query); switch (queryType) { case 'factual': return buildFactualContext(query); case 'conversational': return buildConversationalContext(query); case 'action': return buildActionContext(query); } }

Anti-padrão 3: Ignorar peso temporal

Problema: Tratar todo histórico igual sem importar quando aconteceu.

Solução: Peso temporal — contexto recente ganha mais espaço, antigo é comprimido:

function buildTemporalContext(history: Message[]): Message[] { const result: Message[] = []; // Últimos 4 turnos: intactos (mais relevantes) result.push(...history.slice(-4)); // Turnos 5-12: só mensagens importantes const middleHistory = history.slice(-12, -4); const important = middleHistory.filter( m => m.role === 'user' || containsDecision(m) || containsCodeChange(m) ); result.unshift(...important); // Turno 13+: resumo comprimido if (history.length > 12) { const oldHistory = history.slice(0, -12); const summary = await compressConversation(oldHistory); result.unshift({ role: 'system', content: `Contexto anterior: ${summary}` }); } return result; }

Anti-padrão 4: Sem orçamento de tokens

Problema: Sem limites por componente, um (geralmente histórico) expulsa o resto.

Solução: Orçamento explícito com enforcement:

class ContextBudget { constructor(totalLimit: number) { this.allocations = new Map([ ['system', Math.floor(totalLimit * 0.10)], ['knowledge', Math.floor(totalLimit * 0.35)], ['tools', Math.floor(totalLimit * 0.10)], ['history', Math.floor(totalLimit * 0.30)], ['query', Math.floor(totalLimit * 0.05)], ['buffer', Math.floor(totalLimit * 0.10)], ]); } fit(component: string, content: string): string { const limit = this.allocations.get(component) ?? 0; if (countTokens(content) <= limit) return content; return truncateToTokens(content, limit); } }

Context Engineering pra AI Agents

Sistemas agênticos adicionam outra camada. Um agente que roda múltiplos passos precisa gerenciar contexto ao longo de todo o ciclo de execução.

Padrão Scratchpad

Dê ao agente um espaço dedicado pra raciocínio intermediário sem poluir o contexto principal:

class AgentScratchpad { private thoughts: string[] = []; addThought(thought: string) { this.thoughts.push(thought); if (this.thoughts.length > 10) { const toSummarize = this.thoughts.splice(0, 5); this.thoughts.unshift(`[Resumo do raciocínio anterior: ${toSummarize.join('; ')}]`); } } }

Compressão de resultados de ferramentas

Ferramentas podem devolver payloads enormes. Uma query de DB pode retornar 500 linhas. Injetar tudo isso cru no contexto é desperdício:

async function compressToolResult(toolName: string, result: unknown, query: string) { const rawString = JSON.stringify(result); if (countTokens(rawString) < 500) return rawString; const summary = await llm.generate({ messages: [{ role: 'system', content: `A ferramenta "${toolName}" retornou dados. Resuma no contexto desta query: "${query}". Preserve números, IDs e fatos-chave.` }, { role: 'user', content: rawString.slice(0, 10000) }], model: 'gpt-4o-mini', maxTokens: 500, }); return `[Resultado de ${toolName} — resumido]\n${summary}`; }

Isolamento de contexto multi-agente

Quando múltiplos agentes colaboram, cada um precisa do seu contexto focado. Compartilhar tudo gera contaminação:

class MultiAgentContextManager { async buildAgentContext(agent: Agent, task: Task, sharedState: SharedState) { return [ { role: 'system', content: agent.systemPrompt }, { role: 'system', content: this.filterSharedState(sharedState, agent.role) }, { role: 'system', content: this.formatTask(task) }, ...this.compressUpstreamResults(task.previousResults, agent.role), ]; } }

O problema do "Context Window efetivo"

O que a maioria não sabe: o context window anunciado e o efetivo são muito diferentes.

Gemini 2.5 Pro anuncia 1 milhão de tokens. Claude 3.5 suporta 200K. GPT-4.1 aceita 1M. Mas pesquisa mostra que modelos ficam pouco confiáveis acima de 60-70% da capacidade declarada.

const EFFECTIVE_CONTEXT_RATIO = 0.65; function getEffectiveLimit(model: string): number { const statedLimits: Record<string, number> = { 'gpt-4.1': 1_000_000, 'claude-3.5-sonnet': 200_000, 'gemini-2.5-pro': 1_000_000, 'gpt-4o': 128_000, }; return Math.floor((statedLimits[model] ?? 128_000) * EFFECTIVE_CONTEXT_RATIO); }

A mudança de mentalidade

Se levar uma coisa só deste guia:

Para de pensar em prompts. Começa a pensar em contexto.

O prompt — instruções de sistema, exemplos few-shot, guias de formato — determina talvez 5-10% da qualidade do output. Os 90% restantes são se o modelo teve acesso à informação certa, na hora certa, estruturada do jeito certo.

Os melhores engenheiros de IA em 2026 não são os que escrevem os prompts mais espertos. São os que constroem os pipelines de contexto mais sofisticados — sistemas que montam dinamicamente a informação exata pra cada query, comprimem pra caber no orçamento, e medem se o contexto realmente ajudou.

Prompt engineering foi a entrada. Context engineering é o prato principal. Os times que descobrirem isso primeiro são os que vão lançar funcionalidades de IA que realmente funcionam em produção.

Conclusão

Context engineering responde uma pergunta enganosamente simples: "O que o modelo deveria saber quando gera essa resposta?"

Mas responder bem exige uma disciplina completa:

  1. Selecionar a informação certa pra cada query
  2. Estruturar com consciência posicional
  3. Lembrar entre conversas com sistemas de memória hierárquicos
  4. Comprimir pra caber no orçamento sem perder sinal
  5. Medir se o contexto realmente melhorou os resultados

As ferramentas tão aí. Bancos vetoriais pra recuperação. LLMs pra resumo e compressão. Contadores de tokens pra gestão de orçamento. Frameworks de avaliação.

O que faltava era o framework — o modelo mental pra ver todas essas peças como uma disciplina coerente. Isso é context engineering. E é a habilidade que separa os demos de IA dos produtos de IA.

Monte seu pipeline de contexto. Meça tudo. Itere sem piedade. É assim que se lança IA que funciona.

AILLMcontext-engineeringprompt-engineeringRAGAI-agentsproductionmachine-learning

Explore ferramentas relacionadas

Experimente estas ferramentas gratuitas do Pockit