stamatios
← Voltar ao feed
Arreio de couro firme em cavalos de tração puxando um arado, arquitetura robusta para harnesses de agentes de IA
Agentes

Guia completo para construir harnesses confiáveis de agentes

resumo de ~3 min

A tese: complexidade precisa de um dono

O texto é um guia ("The Harness Playbook") de Can Bölük sobre como construir harnesses confiáveis de agentes, escrito como postmortem e manual a partir da experiência com omp e do redesign omp². A tese central: um loop em torno de um fetch parece simples, mas essa classe de software é nova, e a simplicidade superficial empurra a complexidade inevitável para extensões e usuários - a "conservação de complexidade" acaba tornando impossível escrever software confiável sobre omp ou Pi. Citando Dijkstra ("simplicidade é pré-requisito para confiabilidade") e Ousterhout ("embrace suffering": resolver problemas difíceis completamente dentro do módulo), o autor argumenta que a complexidade deve ser absorvida pelo núcleo, não replicada em cada chamador. A analogia com engines de jogos percorre o texto todo: um harness mantém um mundo autoritativo, registra mudanças, executa ações não confiáveis, replica estado, agenda atores e renderiza interface - responsabilidades que game engines como a Source Engine da Valve resolveram há décadas.

O envelope de design

Antes de projetar qualquer subsistema, o harness deve sobreviver a quatro modos de operação que funcionam como testes de arquitetura: workspace local multiplexado (vários agentes, uma pasta), driver remoto (cliente controlando agente na nuvem pelo celular), espectador (cliente web observando) e "Factorio" (fábrica de software autônoma com entrada hostil). Eles variam local/remoto, interativo/autônomo, fronteira de confiança e concorrência. Cinco consequências estruturam o resto: uma única sessão autoritativa; um plano de controle confiável; trabalho limitado e cancelável; compatibilidade explícita com peculiaridades de modelos; e visões como projeções do mesmo estado.

Estado: uma autoridade, não duas

O erro central do omp/Pi é ter duas fontes de verdade: o journal em .jsonl cobre só a árvore de mensagens, enquanto todo, retry, subagentes, closures, configurações e servidores MCP vivem fora dela. Assim, rewind, fork e resume "mentem" - a reprodução não reconstitui o estado original. A Source Engine, em contraste, trata tudo como deltas de entidade: replay do .dem é idêntico ao original, e a correção vem de tornar estado não-reproduzível irrepresentável, não da disciplina dos autores de extensões. A evidência: entre os 78 exemplos oficiais de extensões do Pi, 17 tinham estado e apenas 2 estavam corretos, com falhas como checkpoints perdidos, modos de plano que sobrevivem ao rewind e jogadas do jogo da velha que desaparecem após crash e resume.

A solução do omp² é materializar a sessão inteira como um DOM: a árvore é a autoridade, o journal armazena mudanças incrementais, e rewind vira um diff de DOM. Prompts, replicação e renderização tornam-se projeções do mesmo estado; o controlador e os atores (TUI, cliente remoto, inspetor de subagente) ficam separados.

Runtime: política no host, execução na sandbox

Colocar o executor dentro da VM não confiável leva a dilemas: uso programático de ferramentas exige acesso a todas, um gateway duplex enfraquece o isolamento, e mover o driver para dentro da VM vaza prompts e código-fonte. A solução é um único stub obediente dentro da sandbox, com limite de banda nos fluxos de retorno; o host detém estado de sessão, inferência, política, roteamento de ferramentas, aprovação, limites e journaling. Subagentes recebem visões copy-on-write do workspace (APFS, btrfs, ZFS, overlayfs ou fallback de cópia) e devolvem diffs. Ferramentas, por sua vez, devem ser fluxos de estado limitados e canceláveis - não funções assíncronas que retornam texto: o contrato de três callbacks do Pi (renderCall, execute, renderResult) duplica I/O e CPU, não tem truncamento central (1 MB pode ir direto ao modelo), e cada ferramenta reimplementa spawn, poll, kill e list. Tudo que roda em segundo plano converge para uma primitiva de "job" com stdin, stdout, status de saída e sinal. Cancelamento precisa de um limite de morte real (processo, worker, VM), não só AbortSignal. Para suavizar a fronteira, omp² escolheu Python para extensões, com um atributo @remote que transforma funções locais em RPC.

Plano de controle: convars e Directors

Para valores (modelo, tier, política), o texto propõe convars no estilo Source Engine: variáveis tipadas cujo escopo, persistência, replicação e arquivamento são flags declaradas no local de definição, eliminando o "god object" de configuração. Herança para subagentes sai de configs em camadas (subagent.cfg, .cfg), e binds/aliases ficam no mesmo fluxo de comandos. Para comportamentos (plan, goal, modos exclusivos), falta uma primitiva de loop: mutexes privados entre plugins do mesmo autor não fazem extensões independentes comporem. A proposta é a pilha de Directors, que podem Pass, Continue, Yield, Push, Done ou Fail sobre cada candidata a yield - o modo Plan, por exemplo, intercepta o yield e força a ferramenta write até o plano ser escrito.

Inferência: peculiaridades como conhecimento estruturado

No omp v1, a compatibilidade com OpenAI vivia num arquivo de 880 linhas cheio de branches por provedor (Cerebras, Zai, Kimi, Anthropic...). A recomendação é tratar quirks de modelo e provedor como conhecimento estruturado com precedência explícita, e não ramificações espalhadas pelos pontos de chamada - a camada de inferência traduz pedidos semânticos (forçar uma ferramenta, impor uma forma) para o que cada modelo e API suporta de fato.