4

LLM propõe, código determinístico dispõe: como deixo um agente rodar em produção sem medo

TL;DR — Nunca dê ao LLM a ferramenta que causa o efeito colateral. Ele propõe um artefato estruturado; o código determinístico valida e executa. Foi assim que coloquei um agente pra rodar ~200 propostas/mês em produção sem perder o sono.

Todo mundo quer o agente autônomo que faz tudo sozinho. Aí ele posta a resposta errada pro cliente, aprova o reembolso que não devia, ou dispara o e-mail com o valor alucinado — e a confiança evapora. Existe um jeito de ter a inteligência do LLM sem entregar a chave do cofre pra ele.

🎯 O problema real de agente em produção

Um LLM é probabilístico. Isso é ótimo pra gerar e péssimo pra garantir. Se o mesmo componente que decide o que fazer é o que executa a ação, cada alucinação vira um efeito colateral real: um dado gravado, um e-mail enviado, um valor cobrado.

Em ambiente interno, tudo bem experimentar. Em produção, com cliente do outro lado, você precisa de garantia — não de "quase sempre certo".

🔑 O princípio: separar quem propõe de quem executa

A regra que uso é uma frase só:

💡 LLM propõe, código determinístico dispõe.

Na prática: o agente não recebe a tool que causa o efeito colateral. Ele só devolve um artefato estruturado (um JSON validável). O código então valida esse artefato contra regras rígidas e, só se passar, executa.

sequenceDiagram
    participant U as Ticket/Input
    participant L as LLM (propõe)
    participant V as Código determinístico (dispõe)
    participant S as Sistema real (Zendesk/DB)
    U->>L: contexto
    L->>V: artefato estruturado (JSON)
    Note over V: hard-rules +<br>salvaguardas anti-alucinação
    alt passou na validação
        V->>S: executa a ação
    else falhou
        V-->>U: barra / manda pra revisão humana
    end

Repara onde está a seta que toca o sistema real: ela sai do código, nunca do LLM. O LLM sugere; o código é o único com permissão de agir.

🪝 O que isso te dá na prática

Sem separaçãoCom "propõe/dispõe"
Alucinação vira ação realAlucinação é barrada antes de executar
Difícil de testar (saída é ação)Fácil de testar (saída é um JSON)
Autonomia é tudo-ou-nadaAutonomia sobe em degraus controlados
Auditoria = ler logs soltosAuditoria = o artefato + a regra que passou

O ganho escondido é o de avaliação: como o LLM só produz um JSON, eu consigo congelar esse JSON e testar o código determinístico de forma repetível — coisa impossível se a "saída" fosse uma ação no mundo.

📚 O que a teoria diz

Michael Albada (Building Applications with AI Agents) trata isso como resiliência e modularidade: um agente sério precisa de tratamento de erro, fallback e componentes plugáveis com interfaces claras — não um LLM cabeado direto no efeito colateral.

E conecta com a ideia de escada de autonomia: você começa em "humano obrigatório", e só promove um fluxo pra rodar sozinho quando a taxa de aceitação das propostas justifica. A separação propõe/dispõe é o que torna essa promoção gradual e reversível — você libera degrau por degrau, não de uma vez.

Chip Huyen (AI Engineering) reforça pelo lado do risco: saída aberta é difícil de avaliar. Ao forçar o LLM a devolver estrutura (o JSON) em vez de ação, você transforma um problema aberto num problema fechado, verificável.

⚠️ O ponto cego honesto

⚠️ Isso reduz a autonomia do agente de propósito — e nem todo caso quer isso. Se o seu problema é aberto, criativo e de baixo risco (brainstorm, rascunho pra humano revisar), amarrar tudo em hard-rules é over-engineering. O padrão brilha quando a ação tem consequência real (grava, cobra, envia, aprova). Escolha a dose pelo risco.

E tem um custo: escrever e manter as regras determinísticas dá trabalho. Você troca "esforço de engenharia" por "garantia". Em produção com cliente, esse trade quase sempre compensa. Num protótipo de fim de semana, talvez não.

🏁 O que fica

Antes de dar uma tool ao seu agente, pergunte: "se ele alucinar bem na hora de usar isso, o que acontece no mundo real?" Se a resposta assusta, tire a tool das mãos dele e ponha o código no meio. O LLM propõe; o código dispõe.


Como você segura seus agentes em produção — dá a tool direto e confia, ou põe uma camada determinística no meio? Conta o teu caso.

Carregando publicação patrocinada...
1

Eu tenho a seguinte visão de agentes de IA: São a interface probabilística de interação com a camada determinística. Em outras palavras: é o novo "teclado", ou novo "navegador", ou novo "touchscreen". É só uma interface. Poderosa, mas só interface.

Se delegarmos regras de negócio para a interface decidir, o resultado pode ser caótico.

Agora, o ponto que vc abordou, da amarração das regras de forma rígida, é onde o desenvolvedor (no sentido mais amplo da palavra, quem está concebendo) deverá ajustar a régua. Não é um determinístico VS probabilístico. É pra qual lado a balança pesa mais (falei igual IA agora kkkkk)

Vou dar um exemplo concreto para não ficar abstrato:

Ao desenvolver um agente de agendamentos o mesmo alucinava com a agenda correta (qual id?), com o horário correto (qual horário?), com o profissional correto (qual profissional?).

Minha solução: amarrei no backend, com base em interações do usuário, um novo ID que representava diversos outros IDs por baixo dos panos.

Ex.: ID "s_124" representava {agenda: 'ac5697eb-d692-4835-8dac-c84d14105b7b', horario: '2026-07-21T14:00:00.000Z', profissional: 'c152bbd4-f1d8-481e-8ca4-08c4b1c2b661', servicos:['c2fba37e-42ba-4931-b4f5-fdc1ed301b1c']}

Agora imagina uma lista de 40 slots de horário por dia, na janela de 1 semana para o usuário escolher! Alucinação garantida, pelo excesso de dados.

E de quebra economizei muito token.

Aqui a decisão probabilística foi resumida a um único id, que deterministicamente foi mapeado para diversas decisões internas.

Parabéns pelo artigo!

1

Gostei do jeito como você colocou a fronteira entre o LLM e o código que realmente executa a ação. Para mim, esse é o ponto que separa demo de produção.

Uma coisa que eu adicionaria nesse desenho é versionar o contrato do JSON junto com as regras determinísticas. Quando o prompt muda, às vezes a saída continua válida no schema, mas muda a intenção em detalhes pequenos.

Ter schema_version, motivo de rejeição e alguns exemplos reais congelados ajuda a descobrir se o agente melhorou de verdade ou só aprendeu a “passar no validador”.

Você chegou a montar alguma suite de casos reais, incluindo casos rejeitados, para evoluir essas regras?