Objetivo da Aula
Distinguir, com precisão arquitetural, o que é "motor de inferência" e o que é "harness" num sistema de IA
Explicar por que tratar o LLM como componente intercambiável é uma decisão de design, não um detalhe de implementação
Enumerar as responsabilidades que pertencem ao harness e nunca deveriam vazar para dentro do prompt
Justificar, com um exemplo concreto, por que trocar de modelo não deveria exigir reescrever a lógica de governança
Reconhecer os sintomas arquiteturais de um sistema onde harness e motor estão acoplados
Por que isso importa
A maioria dos sistemas de IA corporativos que falha em produção não falha porque o modelo é ruim. Falha porque alguém confundiu "escrever um prompt bom" com "construir um sistema confiável". São coisas diferentes, resolvidas por camadas diferentes, e a confusão entre elas é a causa raiz de boa parte dos incidentes que um arquiteto sênior vai precisar debugar.
Pense em qualquer sistema de software maduro: um servidor web não decide sozinho quem pode acessar qual rota — isso é responsabilidade de um middleware de autenticação. Um banco de dados não decide sozinho se uma transação pode ser commitada — isso é responsabilidade de um coordenador transacional. Em ambos os casos, o componente que faz o trabalho pesado (servir uma página, persistir uma linha) é deliberadamente mantido "burro" em relação a política. A política vive em outro lugar.
Com LLMs, essa separação não é opcional — é ainda mais crítica, porque o componente que faz o trabalho pesado (o modelo) é probabilístico, não determinístico. Um servidor web sempre serve a mesma página para a mesma requisição. Um LLM pode responder de forma diferente à mesma pergunta duas vezes seguidas. Se a governança do seu sistema — o que ele pode ler, escrever, decidir sozinho — estiver codificada dentro do comportamento do modelo (via prompt, via fine-tuning, via "confiar que ele vai se comportar"), sua camada de segurança herda a variância do modelo. Isso não é arquitetura, é aposta.
Impacto direto no seu trabalho: quando a Anthropic lança um modelo novo, ou quando você decide trocar de fornecedor por custo, a pergunta que separa uma arquitetura madura de uma frágil é: "quanto do meu sistema eu preciso reescrever?" Numa arquitetura bem separada, a resposta é "trocamos uma linha de configuração". Numa arquitetura acoplada, a resposta é "reescrevemos os prompts, retestamos as permissões, e rezamos". Você vai tomar essa decisão pelo menos uma vez por ano da sua carreira daqui pra frente — o resto deste livro assume que você escolheu o primeiro caminho.
Conceitos Fundamentais
Duas camadas, duas responsabilidades
Todo sistema de IA agentic — do assistente de código mais simples ao agente multi-etapas mais sofisticado — pode ser decomposto em exatamente duas camadas com responsabilidades que não deveriam se misturar:
HARNESS (camada de orquestração e governança — determinístico)
- Que ferramentas existem e quem pode chamá-las
- Que arquivos podem ser lidos, quais podem ser escritos
- Quando pedir aprovação humana (HITL)
- Como o estado é persistido entre turnos
- Qual contexto é injetado em cada chamada
- Quando parar o loop, quando continuar
- Como erros são tratados e reportados
O harness chama o motor de inferência passando contexto, instrução e ferramentas disponíveis; o motor responde com texto ou uma chamada de ferramenta, que volta para o harness decidir o que fazer com ela.
MOTOR DE INFERÊNCIA (LLM — probabilístico, intercambiável)
- Recebe: contexto + instrução + ferramentas disponíveis
- Decide: qual texto gerar, qual ferramenta chamar, com quais argumentos
- Não sabe: se tem permissão de fato para agir, não sabe se está sendo auditado, não sabe o histórico fora do que foi injetado
O motor de inferência — o LLM — é o componente que "pensa": recebe um contexto e produz uma próxima ação plausível. É poderoso, mas não tem memória própria entre chamadas, não sabe quem está autorizado a fazer o quê, e não impõe suas próprias regras de segurança de forma confiável. O harness é tudo o que envolve o modelo: a orquestração que decide o que colocar no contexto, quais ferramentas o modelo pode ver, o que fazer com a resposta, e — crucialmente — o que bloquear antes que a resposta do modelo vire uma ação real no mundo.
Fundamento: Por que "intercambiável" é a palavra certa
Um motor de automóvel pode ser substituído sem redesenhar o chassi, os freios ou o volante — desde que a interface (montagem, torque, conexões elétricas) seja respeitada. O mesmo vale para o LLM dentro de um harness bem desenhado: GPT, Claude, Gemini ou um modelo open-weight local devem ser plugáveis atrás da mesma interface de "recebe contexto, retorna texto ou chamada de ferramenta". Se trocar de modelo exige reescrever a lógica de permissões ou de estado, a interface vazou — o harness não estava, de fato, separado do motor.
O teste da separação: "isso sobrevive à troca de modelo?"
Existe um teste simples para saber se sua arquitetura tem separação de preocupações de verdade. Pergunte, para cada regra do seu sistema: "se eu trocar o modelo por outro fornecedor amanhã, essa regra continua valendo sem mudança de código?"
| Regra | Onde deveria viver | Sobrevive à troca de modelo? |
|---|---|---|
| "Nunca escrever fora de /src" | Harness (RBAC/I-O) | Sim, se estiver no harness |
| "Perguntar antes de fazer git push" | Harness (HITL) | Sim, se estiver no harness |
| "Responder em pt-BR" | Contexto/prompt | Depende — ver capítulo 1.2 |
| "Não vazar segredos do .env" | Harness (filtro I/O) | Sim, se estiver no harness |
| "Ser educado com o usuário" | Prompt/instrução | Não é crítico — pode variar |
| "Nunca fazer DROP TABLE sem confirmação" | Harness (permissões) | Sim, se estiver no harness |
Note o padrão: qualquer regra cuja violação tem consequência irreversível ou custosa (apagar dados, vazar segredos, gastar dinheiro, publicar algo errado) precisa estar no harness — fora do alcance de qualquer variação do modelo. Regras de estilo e tom podem, com segurança, viver no prompt, porque uma variação ali tem custo baixo.
Sintomas de acoplamento indevido
Como reconhecer, numa base de código real, que harness e motor estão grudados quando não deveriam?
Sintoma 1: "Prompt de segurança"
→ Instruções como "nunca delete arquivos importantes" dentro
do system prompt, sem nenhuma barreira técnica por trás.
→ Se o modelo ignorar (e modelos ignoram instruções sob
certas condições adversariais ou até por erro comum),
nada impede a ação.
Sintoma 2: troca de modelo quebra o sistema
→ Você troca de Claude para outro fornecedor e as
permissões "somem" porque estavam implícitas no
comportamento aprendido daquele modelo específico,
não codificadas em lógica externa.
Sintoma 3: não existe log de decisão fora do que o
modelo narrou
→ Se a única fonte de verdade sobre "por que o agente fez
X" é o texto que o próprio modelo gerou, você não tem
auditoria — tem uma autobiografia não confiável.
Sintoma 4: aprovação humana é "pedida" pelo modelo,
não "imposta" pelo sistema
→ Se o modelo decide quando parar para perguntar,
ele também pode decidir não perguntar.Em todos os quatro casos, o problema tem a mesma raiz: uma responsabilidade que deveria ser determinística e externa ao modelo foi delegada a um componente probabilístico e interno. O restante deste livro é, em grande parte, um catálogo de como evitar esse erro em cada camada do sistema — contexto (1.2), permissões (1.3), estado (1.4), ferramentas (1.5) e o próprio loop de execução (1.6).
Aprofundamento Técnico
Onde a fronteira realmente é traçada
Na prática, a fronteira entre harness e motor passa por um único ponto de controle: a chamada de API ao LLM. Tudo que acontece antes dessa chamada (montar o contexto, decidir quais ferramentas expor, verificar quem está pedindo) é harness. Tudo que acontece depois da resposta voltar (validar se a ferramenta pedida é permitida, checar se precisa de aprovação humana, decidir se o loop continua) também é harness. O modelo em si só existe no instante entre esses dois momentos — e é exatamente por isso que ele pode ser trocado sem que o resto mude.
function turno_do_agente(estado, mensagem_usuario):
# ---- HARNESS: antes da chamada ----
contexto = montar_contexto(estado, mensagem_usuario) # 1.2
ferramentas_permitidas = resolver_ferramentas(estado) # 1.5
verificar_rbac(estado.usuario, ferramentas_permitidas) # 1.3
# ---- MOTOR: caixa-preta intercambiável ----
resposta = chamar_llm(contexto, ferramentas_permitidas)
# ---- HARNESS: depois da chamada ----
if resposta.pede_ferramenta:
if not permitido(resposta.ferramenta, estado.usuario): # 1.3
return recusar("ferramenta fora do raio de impacto")
if requer_aprovacao_humana(resposta.ferramenta): # 1.3
aguardar_hitl(resposta)
resultado = executar_ferramenta(resposta.ferramenta) # 1.5
persistir_estado(estado, resultado) # 1.4
return continuar_loop(estado) # 1.6
return resposta.textoRepare que chamar_llm é a única função que muda quando você troca de fornecedor de modelo. Todas as outras oito chamadas nesse pseudocódigo são propriedade do harness e não sabem, nem precisam saber, qual modelo está por trás de chamar_llm.
O motor não é só "o LLM" — é qualquer coisa substituível
Uma armadilha comum é pensar que "motor de inferência" significa apenas "a chamada de API do modelo de linguagem". Na prática, a categoria é mais ampla: qualquer componente cuja lógica interna é opaca, evolui por conta própria (novas versões do fornecedor) e cujo comportamento exato não pode ser garantido por contrato determinístico pertence à categoria de "motor" e deveria ser tratado com a mesma desconfiança arquitetural. Isso inclui:
Motor (intercambiável, opaco):
- O LLM principal do agente
- Um modelo de embeddings usado para busca semântica
- Um classificador de intenção baseado em modelo
- Um modelo de re-ranking de resultados
Harness (determinístico, propriedade do arquiteto):
- A lógica que decide QUANDO chamar cada motor
- A lógica que valida o QUE o motor retornou
- A lógica que decide o QUE fazer com o resultado
- Todo o controle de acesso, auditoria e persistênciaEsse reconhecimento importa porque o mesmo princípio de separação que você aplica ao LLM principal precisa se propagar para todo componente probabilístico do sistema — inclusive os que aparecem mais adiante neste livro, como o motor de embeddings da Parte 2.
Trade-off: separação total tem custo de engenharia
Vale nomear o trade-off, não só o benefício. Separar harness e motor com rigor exige mais código de orquestração do que simplesmente "confiar no prompt e deixar o modelo decidir tudo". Um protótipo rápido, de baixo risco, sem dados sensíveis e sem ação irreversível, pode legitimamente optar por acoplamento maior em troca de velocidade de entrega — isso não é preguiça, é dimensionamento correto do investimento em governança para o risco real do sistema.
A decisão de arquiteto não é "sempre separar ao máximo", é: o raio de impacto de uma falha do modelo justifica o custo de uma camada de harness robusta? Um assistente que só sugere texto para revisão humana tem raio de impacto baixo. Um agente que executa git push --force, deleta registros de banco de produção ou movimenta dinheiro tem raio de impacto alto — e é exatamente para esse segundo grupo que a separação rigorosa deixa de ser luxo e vira pré-requisito. O capítulo 1.3 aprofunda como medir e conter esse raio de impacto de forma sistemática.
Por que isso não é "só usar function calling"
Uma confusão frequente entre arquitetos que vêm da parte de engenharia da série é achar que "usar function calling/tool use" já resolve a separação de preocupações. Não resolve — function calling é apenas o protocolo de comunicação entre harness e motor (como o modelo expressa "eu quero chamar esta ferramenta com estes argumentos"). Ele não impõe, por si só, que o harness verifique permissão antes de executar. Um sistema pode usar tool use perfeitamente e ainda assim executar qualquer ferramenta que o modelo pedir, sem checagem alguma — nesse caso, o protocolo está correto e a arquitetura está quebrada. A separação de preocupações vive na disciplina de o que o harness faz com a chamada de ferramenta que o modelo solicitou, não na existência do protocolo em si.