Agentic Harness: o que é, como identificar um, e como mapear o seu
Tem um pedaço de todo sistema de agentes que até pouco tempo atrás não tinha nome. Todo time que construiu agente escreveu esse pedaço. Quase ninguém chamou de nada — no máximo, "o backend do chat".
Não é o modelo. Não é a interface. Não é o banco vetorial, nem o servidor MCP, nem o orquestrador de fila. E mesmo assim é onde mora praticamente toda a diferença entre a demo e o sistema que roda em produção sem ninguém ter medo dele.
Esse pedaço é o harness.
Este post é dividido em seis partes: o que é, onde se encaixa em relação ao agentic loop, como reconhecer um, onde ele aparece no mundo real, como um harness maduro é construído por dentro, e a parte que interessa se você tem projeto rodando, um método para mapear o harness dos seus sistemas, 1:1.
1. O que é
Harness é o runtime determinístico que executa o loop de um agente: monta o contexto, chama o modelo, executa a ação sob permissão e registro, persiste o estado entre passos e decide quando parar.
Versão de bolso, que é a que eu uso no dia a dia: loop, estado, portão, parada.
- Loop: depois que o modelo responde, alguém decide se o próximo passo é chamar tool, perguntar ao usuário, trocar de modelo ou entregar. Esse alguém é o harness.
- Estado: o passo 7 enxerga o passo 3. Sem isso são N chamadas independentes que por acaso compartilham um
chatId. - Portão: a saída vira ação, mas passa por validação de schema, permissão e registro. Dar acesso a tool não basta. O harness governa o acesso.
- Parada: orçamento de steps, condição de sucesso, escalonamento para humano. Agente que não sabe parar é incidente com data marcada.
Algo próximo da etimologia do conceito é sobre aparelhagem que envolve a unidade sob testes, onde se alimenta os inputs, controla o ambiente e captura a saída. Para exemplificar, quando trocamos "sob teste" para "modelo", entendemos que "o modelo" não sabe que está em harness, ele só recebe e devolve conforme o estabelecido.
E aqui está a inversão que costuma destravar o conceito:
O harness não é a camada inteligente. É a camada burra.
A inteligência está no modelo. O harness é if, while, validação de schema, try/catch, gravação no Postgres. Código determinístico, chato, previsível. Quem tenta fazer o harness "ser esperto" acaba colocando um segundo modelo dentro dele, e aí tem o mesmo problema um nível acima, com o dobro do custo.
Harness é arquitetural, como kernel ou controller. Ninguém vende um controller, mas todo app tem um e você sabe apontar qual arquivo é.
2. Camada de aplicabilidade: loop x harness
Os dois termos aparecem juntos e são confundidos direto. A diferença é de tamanho.
O agentic loop é o algoritmo. São umas vinte linhas:
enquanto não terminou:
contexto = montar(estado, memory, tools, objetivo)
decisão = modelo(contexto)
se decisão é resposta: sai
resultado = executar(decisão.tool) ← passa pelo portão
estado = atualizar(estado, decisão, resultado)
checar(orçamento, política, condição de parada)
O harness é tudo que faz essas vinte linhas serem seguras, retomáveis, observáveis e permissionadas.
Tire o loop do seu sistema e cole num script: ele roda. E é inútil em produção. O que torna aquilo um produto é o que está em volta.
Onde cada um mora na stack:
Interface (web, chat, IDE, mensageria, cron)
↓
┌────────────────────────────────────────┐
│ HARNESS │
│ ↳ agentic loop (o núcleo) │
│ ↳ estado · portão · parada │
│ ↳ router · observabilidade · guards │
└────────────────────────────────────────┘
↓ ↓ ↓
Modelo Tools Estado
(gera token) (efeito no mundo) (sessão, memory)
Repare no ponto que mais custou para eu entender: o modelo não está no topo. Ele é um serviço que o harness chama.
Consequência prática direta: o harness é o único ponto do sistema onde permissão, orçamento e auditoria podem ser aplicados uma vez só.
Ainda existe uma gradação de maturidade que vale ter no vocabulário:
| Forma | O que é | Exemplo típico |
|---|---|---|
| Biblioteca de harness | você monta o seu | SDKs de agente, grafos de estado |
| Produto com harness | o harness existe mas é acoplado à UX | agente de codificação em terminal |
| Harness como infraestrutura | runtime autônomo, a UI é só um cliente | plataforma interna com múltiplos canais |
Os três são harness. Só o terceiro é plataforma.
3. Os definidores: seu projeto é harness ou não?
Observei nos meus projetos quatro condições necessárias. Falta uma, não é harness — é outra coisa, possivelmente uma coisa boa.
1. É dono do loop. Depois da saída do modelo, é o seu código que decide o que vem a seguir? 2. Carrega estado entre passos. O passo 7 enxerga o passo 3? 3. Intermedeia o efeito. Existe um portão entre "o modelo pediu" e "o sistema fez"? 4. Decide quando parar. Existe orçamento, condição de sucesso, escalonamento?
E cinco perguntas de diagnóstico que separam rápido o que é harness do que só parece:
- Se eu fechar a aba no passo 4, o passo 5 acontece? Se não, seu estado é de sessão HTTP, não de agente.
- Se o modelo pedir uma tool que o usuário não pode usar, quem barra? Se a resposta for "o prompt pede para ele não fazer isso", você não tem portão.
- Quem decide que acabou? Se a resposta for "o modelo para de chamar tool", sua condição de parada é emergente. O emergente falha.
- Se eu trocar o provedor de modelo, quantos arquivos mudo? Se for mais que um punhado, sua camada de abstração de modelo vazou.
- Consigo responder "por que ele fez isso?" três dias depois? Se não, o sistema não é operável, é uma caixa preta com boa UX.
Não é harness (é dependência de um)
| Parece | É |
|---|---|
| vLLM, TGI, Ollama | serving de modelo |
| Roteadores/gateways de modelo | só a camada de abstração |
| pgvector, bancos vetoriais | só armazenamento |
| Servidor MCP | publica função, não governa |
| Bibliotecas de composição de prompt | montagem de input |
| Um modelo fine-tunado | continua sendo modelo |
O MCP é o que mais confunde: ele parece harness porque expõe capacidade, tem protocolo, tem descoberta, tem catálogo. Mas não sabe se você tem permissão, não mantém sessão, não decide o próximo passo. Quem transforma aquilo em comportamento governado, tipo OAuth por usuário, token cifrado, escopo por papel oou trace por invocação, é o harness do outro lado.
E o aviso que economiza dinheiro: workflow não é agente
Pipeline com caminho fixo: trigger, parse, chamada de API, notificação, não é agente e não precisa de harness. O caminho está codificado antes de rodar, e isso é bom! É determinístico, testável, idempotente.
Vira agentic quando o caminho é decidido em runtime. Aí você ganha flexibilidade e paga com não-determinismo.
A pergunta de projeto não é "como eu agentizo isso?". É: esse fluxo tem variabilidade suficiente para justificar não-determinismo? Na maior parte das integrações que eu escrevo, não tem. Forçar agente onde workflow resolve é injetar entropia justo onde eu queria idempotência.
4. Onde harness aparece no mundo real
Agentes de codding. O caso mais visível, porque expõe o loop na tela: inspeciona arquivo, planeja, edita, roda teste, lê o erro, corrige. Cada uma dessas transições é decisão do harness. É também onde a natureza corretiva do loop fica óbvia, o compilador é o verificador.
Agente de dados corporativos. Pergunta em linguagem natural, geração de query, execução, gráfico. Com harness, tem guard de leitura, permissão por tabela, limite injetado, e o erro do banco volta ao contexto para o modelo se corrigir.
Agente de atendimento com ação no ERP. Aqui o harness deixa de ser luxo. Consultar pedido é reversível. Cancelar pedido não é. O mesmo agente precisa de gates diferentes para as duas ações, e é o harness que aplica essa distinção, não o prompt.
Agente de compras e reposição. Analisa curva, sugere ordem de compra. Sugerir é reversível; emitir é irreversível e tem dinheiro atrás.
Padrão que se repete: o harness fica sempre na fronteira entre o que é reversível e o que não é.
5. Como um harness maduro é feito por dentro
Com base na minha experiência em desenvolvimento de sistema agênticos, posso trazer algumas decisões que podem auxiliar na interpretação e padronização replicável de QUALQUER STACK:
Isolamento por tenant no nível do schema. Cada empresa tem seu próprio schema no Postgres, e o identificador do tenant é o nome do schema. Isolamento por linha com filtro em query depende de todo mundo lembrar do filtro. Isolamento por schema depende do banco. Se usar base em algum Data Lake, fica intangível o resultado.
Montagem de tools por interseção. As tools disponíveis num turno não vêm de uma lista fixa. São a interseção de três conjuntos: o que o agente está configurado para usar, o que o usuário tem permissão de usar, e o que as feature flags habilitam. Interseção é a operação certa porque falha fechada, se qualquer um dos três negar, a tool não existe naquele turno. O modelo nem vê.
Guard de dados fail-closed. O acesso ao data lake passa por uma guarda: só SELECT, statement único, schemas de sistema bloqueados, prefixo interno bloqueado por nome, LIMIT injetado, validação de acesso por schema e por tabela. O efeito colateral é maior que a segurança. Toda query vira reversível. Não é preciso avaliar se aquele UPDATE é seguro, porque UPDATE não existe naquela superfície. Eliminar a classe de erro é sempre melhor que julgá-la caso a caso.
Contenção em vez de avaliação. Execução de código roda em microVM efêmera, uma por conversa, com egress restrito ao repositório de pacotes. Artefato interativo roda em iframe com CSP que proíbe requisição de rede, a comunicação acontece só por uma ponte tipada, com queries pré-aprovadas e binding no servidor.
Dois modos de execução sobre o mesmo pipeline. Um caminho síncrono, com streaming, para a conversa comum. Um caminho durável, que sobrevive ao usuário fechar a aba, para trabalho longo. O importante é que a preparação de contexto é a mesma nos dois, se cada modo montasse o contexto do seu jeito, seriam dois harnesses divergindo.
Roteamento de modelo por tier. Modelo leve, médio, pesado e um tier de raciocínio acionado explicitamente pelo usuário. A escolha usa heurística local primeiro e classificador só quando necessário. Fica atrás de flag, porque roteamento é a coisa mais fácil de piorar sem perceber.
Disciplina de terminação. Orçamento fixo de steps. Lembrete escalonado de conclusão nos últimos passos. E tool call desabilitada no passo final. O agente não decide entregar, a estrutura obriga ele a fechar respondendo.
Memory com gate por raio de dano. Memory de escopo individual é auto-aprovada: o dano é uma pessoa, a correção é trivial. Memory de escopo da empresa entra pendente e exige aprovação de admin, ela "contamina" o contexto de todo mundo, de forma persistente. Mesma feature, gates diferentes, decididos por reversibilidade. Tudo passa por um scanner que rejeita unicode invisível, tentativa de injection e credencial.
Observabilidade por step e por tool call. Registro por passo do loop e por invocação de ferramenta, fire-and-forget, com custo estimado e retenção definida. É o que permite responder "por que ele fez isso?" depois.
6. Como mapear o harness de um projeto
Essa é a parte prática. Método que dá para rodar em uma tarde, por projeto, e que produz um artefato.
Passo 0 — Isso é agente mesmo?
O caminho é decidido em runtime ou está codificado antes de rodar? Se está codificado, pare aqui. É workflow, está tudo bem, não precisa de harness e não deve ganhar um.
Passo 1 — Inventário de ações, classificado por reversibilidade
Liste toda ação que o sistema pode causar no mundo. Para cada uma, uma coluna só:
| Ação | Reversível? | Custo de errar | Gate atual | Gate correto |
|---|---|---|---|---|
| consultar pedido | sim | ~zero | nenhum | nenhum |
| enviar e-mail ao cliente | não | médio | nenhum | aprovação |
| emitir ordem de compra | não | alto | nenhum | aprovação |
Classifique por reversibilidade, nunca por sensação de risco. E a regra que governa a coluna final:
Nunca deixe um passo cuja corretude você não consegue checar produzir efeito irreversível.
Três saídas possíveis: eliminar a classe (a ação perigosa deixa de existir naquela superfície), conter o efeito (sandbox, CSP, egress restrito), ou humano no portão. Prompt não é saída. Prompt não é controle, é sugestão com boa reputação.
Passo 2 a 5 — Aponte o arquivo das quatro responsabilidades
Para cada uma, escreva o caminho do arquivo. Literalmente o caminho. Se você não consegue escrever, achou uma lacuna.
| Responsabilidade | Pergunta | Arquivo |
|---|---|---|
| Loop | quem decide o próximo passo depois da saída? | |
| Estado | onde vive o que o passo 7 precisa saber do passo 3? | |
| Portão | quem barra a tool não permitida? | |
| Parada | quem encerra, e por qual critério? |
Esse é o teste central deste post inteiro: cadê o harness? Se a resposta é um conceito, é arquitetura. A resposta certa é um caminho de arquivo.
Passo 6 — As três perguntas de corretude
Se o harness não julga mérito, como saber que está decidindo bem? No instante da decisão, isso é indecidível, você precisaria já conhecer o resultado. O que dá para fazer é quebrar a pergunta em três, cada uma verificável numa escala de tempo diferente:
| Pergunta | Quando | Mecanismo | Tenho? | |
|---|---|---|---|---|
| Validade | é permitido e bem-formado? | antes de executar | schema, permissão, orçamento | |
| Corretude do passo | era a ação certa? | no ciclo seguinte | o resultado real volta ao contexto | |
| Corretude do resultado | o objetivo foi cumprido? | fora do loop | eval, aprovação humana, ground truth |
A linha do meio é a razão de o loop existir. Ele não é só fluxo de controle, é estrutura corretora de erro. Pensa nisso: "O modelo escreve a query errada, o banco devolve erro de coluna, o modelo reescreve." O harness não julgou nada; só garantiu que a consequência voltasse ao contexto de forma fiel e barata.
E "barata" carrega o resto: loop corretivo só funciona se errar for reversível e de baixo custo. É por isso que o Passo 1 vem antes de tudo.
Na prática, quase todo projeto tem a linha 1, tem a 2 por acidente, e não tem a 3.
Passo 7 — Ordem de correção
Com o mapa na mão, corrija nesta ordem. Não é gosto, é dependência:
- Portão nas ações irreversíveis. É o único item onde a falha é externa e permanente.
- Estado. Sem estado confiável, o resto do loop está construído sobre areia. Sintoma típico: gravação por delete-and-reinsert, leitura-modificação-escrita sem transação, ausência de unicidade no registro de execução ativa.
- Parada e cancelamento. Cancelamento é condição de terminação. Botão de parar que não interrompe de verdade significa que a camada está incompleta.
- Abstração de modelo. Só depois que o resto está firme, porque roteamento é fácil de piorar.
- Eval sobre o trace que você já grava. Melhor razão esforço/valor de todas, e é sempre a última que alguém faz.
Uma dica sobre o item 5: mantenha o modelo-como-juiz fora do loop, offline, em cima de trace gravado. Colocar juiz dentro do loop é um erro recursivo, julgar mérito exige um modelo, e aí você tem o mesmo problema um nível acima, com custo dobrado e nenhuma garantia nova. Offline ele pode errar sem consequência, e você consegue medir o quanto ele erra.
Resumo em cinco linhas
- Loop, estado, portão, parada. Falta uma, não é harness.
- Harness é a camada determinística. Inteligência mora no modelo; ali mora o controle.
- O modelo é dependência do harness, é aliado das tools, sátilite delas, não o centro.
- Corretude não se verifica no instante da decisão. Verifica em três escalas de tempo.
- Nunca deixe passo não verificável produzir efeito irreversível. Elimine a classe, contenha o efeito, ou coloque humano no portão.
E o teste que eu passei a fazer em toda conversa sobre agente: cadê o harness?
Se a resposta não é um caminho de arquivo, ele ainda não existe.
Escrito a partir da leitura de Agentic Harnesses: The New Infrastructure Layer for AI Systems?, de Balaji Bal, que faz uma decomposição bem mais granular das camadas e vale a leitura inteira.