Se trabalhas com agentes de codificação em ferramentas como o Open Code, usando modelos como o Qwen ou parecidos, já deves ter reparado na facilidade com que a janela de contexto desaparece.
Basta pedires uma alteração simples de duas linhas numa função para o sistema:
Ler o ficheiro de 1.000 linhas na íntegra.
Processar o histórico todo de novo.
Reescrever o ficheiro inteiro do início ao fim só para mudar um
if.
Resultado? Milhares de tokens gastos em poucos minutos, latência desnecessária e, pior, o modelo começa a perder o fio à meada (lost in the middle) devido ao tamanho do histórico.
Para resolver isto, tive de mudar a forma como a arquitetura lida com o código. Em vez de tratar o LLM como um programador que precisa de reler o livro todo para mudar uma página, passei a usar uma abordagem modular baseada em referências e edições cirúrgicas.
O Problema: A Leitura e Reescrita Integral
O comportamento padrão da maior parte dos agentes é ingénuo. Pedes uma correção e o fluxo é este:
[Ficheiro Completo (2000 linhas)] ──> [LLM processa tudo] ──> [LLM reescreve 2000 linhas]
Isto era o meu inicio e acontecia porque a LLM dava-me o bloco de código a corrigir, mas eu não sabia onde o aplicar, então pedia para me dar o ficheiro na integra.
Isto consome tokens em duas frentes: input (leitura do ficheiro gigante) e output (reescrita desnecessária de código que não mudou).
A Solução: Agente de Memória e Edição por Blocos
A lógica para poupar 80% dos tokens assenta em não deixar o agente executor tocar no ficheiro completo. Em vez disso, introduz-se uma camada intermédia (um agente de contexto ou uma estrutura de indexação).
1. O Agente Guardião de Referências
Em vez de passar o código bruto para a IA, mantém-se um registo (uma espécie de mapa de inventário) do projeto. Este agente sabe exatamente em que linhas ou blocos residem as funções, as interfaces e os contratos do código.
2. Edições Cirúrgicas (Patching em vez de Overwrite)
Quando é necessária uma alteração:
O utilizador pede a modificação.
O agente de consulta vai ao mapa de referências e extrai apenas o bloco relevante (100 a 200 linhas).
O executor recebe esse bloco isolado, sabe onde mexer no meio do ficheiro, substitui o bloco e não necessita de ler ou reescrever o resto.
O output do modelo é apenas o diff/patch (as linhas a alterar), e não o ficheiro todo.
[Pedido] ──> [Agente de Referências extrai Bloco X (150 linhas)] ──> [LLM gera Diff de 10 linhas] ──> [Aplicação local do Patch]
Na Prática: Como Estruturar Isto no Workflow
A. Trocar Ficheiros por "Esqueletos" (AST- arvore sintática )
Para o agente perceber o contexto global do projeto, não precisa de ler a implementação das funções. Basta-lhe a assinatura. Extrair a árvore sintática (AST) do ficheiro e passar apenas o "esqueleto" (nomes de funções, parâmetros e tipos) reduz o input em cerca de 90%.
{
"target_file": "src/services/auth.py",
"block_id": "validate_token",
"action": "replace_lines",
"lines": [45, 52],
"code": "new_implementation_here"
}
O Resultado
Ao deixar de tratar o código como um texto contínuo e passar a tratá-lo como blocos endereçáveis:
Consumo de Input: Cai drasticamente porque o modelo só lê o contexto estritamente necessário (o "esqueleto" + o bloco a alterar).
Consumo de Output: Cai para uma fração, já que o modelo responde apenas com as linhas alteradas e não com a reescrita total do ficheiro.
Velocidade: A resposta é quase instantânea, pois gerar 15 linhas de diff demora uma fração do tempo de gerar 1.000 linhas de código.
No fim do dia, o ideal não é ter uma janela de contexto maior, mas sim ter a inteligência de não a encher com lixo ou ruido desnecessários.
