Engenharia

Determinismo é uma feature: as partes chatas são código, não prompts

Qualquer coisa que precisa ser exata, auth, contas de dinheiro, roteamento, pertence ao código; só o julgamento pertence a um prompt. Um agent confiável é um núcleo de linguagem fino dentro de uma casca determinística.

ASR

Apollo Space Research

Apollo Space

· 11 min de leitura

Peça a um language model para somar duas colunas de moeda mil vezes e ele vai errar uma delas. Não porque o modelo é ruim, porque não é para isso que um language model serve. Ele prevê o próximo token; ele não transporta o “vai um” através de uma casa decimal do jeito que uma função de quatro linhas faz, toda vez, para sempre. A função é chata. A parte chata é exatamente a parte que você não pode se dar ao luxo de errar.

Então aqui está a pergunta que decide se um agent é uma demo ou um colega de trabalho: quais partes do trabalho dele têm permissão de ser um prompt, e quais partes têm que ser código?

Qualquer coisa que precisa ser exata, auth, contas de dinheiro, roteamento, pertence ao código; só o julgamento pertence a um prompt.

Essa única linha é o post inteiro. O resto é o mecanismo: por que a abordagem óbvia (prompt em tudo) parece ótima por uma semana e depois silenciosamente te trai, onde a costura de fato vai, e como um sistema fica quando você para de pedir a uma coisa probabilística para ser determinística.

A versão ingênua: prompt em tudo, torça para aguentar

A primeira versão que todo mundo constrói, incluindo nós, incluindo as demos que você viu, é a maximalista. Um modelo capaz, um prompt grande, e você deixa ele fazer tudo. Ler a requisição. Decidir quem tem permissão. Escolher a ferramenta. Fazer a aritmética. Formatar o resultado. Enviar.

É genuinamente empolgante por uma tarde. O modelo lê um e-mail bagunçado, descobre que o cliente quer dizer a fatura do mês passado, totaliza os itens de linha e rascunha uma resposta, tudo numa passada, sem código de cola, sem schema. Você pensa: por que software algum dia foi mais difícil que isso?

Então você roda mil vezes.

A falha não é dramática. Não há crash, nem stack trace, nem vermelho. O modelo apenas deriva. O total está certo novecentas e noventa vezes e errado por um erro de arredondamento dez vezes, e essas dez caem na frente de um cliente. A mesma requisição que roteou para “billing” ontem roteia para “suporte” hoje, porque você trocou duas frases no prompt e o humor do modelo se moveu com elas. Uma vez, numa formulação que ninguém antecipou, ele decide que uma requisição somente-leitura é uma permissão para agir e faz a coisa que deveria ter recusado.

O modelo não quebrou. Ele nunca foi determinístico para começar, você só pediu que ele fingisse.

Essa é a armadilha. Um prompt é uma distribuição de probabilidade vestindo a fantasia de uma função. Na maioria das vezes o output mais provável também é o correto, então ele parece uma função. A lacuna só aparece em escala, nos inputs que você não testou, nas dimensões que você não consegue ver, e esses são precisamente os inputs de que a produção é feita. O gargalo nunca desaparece. Ele se move de “o modelo consegue fazer isto uma vez na demo” para “ele faz isto toda vez na frente de uma pessoa real”, e a segunda pergunta tem uma resposta muito pior.

Você sente a dor como instabilidade. Mesmo input, output diferente. Um teste que está verde na terça e vermelho na sexta sem mudança de código. Uma auditoria que você não consegue rodar porque não há lógica para apontar, apenas um prompt e um dar de ombros.

A costura: exatidão é código, julgamento é prompt

A correção não é um prompt melhor. É uma linha traçada através do próprio trabalho.

Olhe para qualquer tarefa de agent e você vai achar que ela é, na verdade, dois tipos de trabalho trançados juntos. Um tipo tem uma resposta certa que não depende da formulação: este usuário ou tem permissão ou não tem, estes números ou somam este total ou não somam, esta requisição ou pertence a esta fila ou àquela. O outro tipo não tem uma única resposta certa e vive inteiramente na interpretação: o que esta pessoa de fato quis dizer, qual de três respostas razoáveis cabe na situação, este e-mail vale a pena ser sinalizado afinal.

O primeiro tipo é exatidão. O segundo tipo é julgamento. E a confiabilidade inteira de um agent se resume a recusar confundi-los.

Qualquer coisa que precisa ser exata, auth, contas de dinheiro, roteamento, pertence ao código; só o julgamento pertence a um prompt.

À esquerda, um modelo é pedido para fazer tudo num único prompt, ler intenção, checar permissão, somar o dinheiro, escolher a rota, enviar, e as partes exatas derivam e ocasionalmente agem sem permissão. À direita, a mesma tarefa é dividida: um núcleo de linguagem fino lida apenas com intenção e tom, enquanto código determinístico numa casca ao redor é dono da checagem de permissão, da aritmética, do roteamento e do envio.

Pegue os três do título, porque são os três que mais doem quando derivam.

Auth. Se alguém pode fazer uma coisa nunca é uma questão de julgamento. É uma busca contra uma regra que ou bate ou não bate. Se um modelo é a coisa decidindo acesso, então sua fronteira de segurança tem um ajuste de temperatura, e uma formulação que ninguém testou pode falar até abri-la. O modelo pode ler a requisição e te dizer o que o usuário está tentando fazer. Se ele tem permissão de fazer isso é uma função com uma resposta booleana, rodada antes de a intenção do modelo sequer ser executada. Mesmo input, mesma resposta, toda vez, e uma linha de log que diz por quê.

Contas de dinheiro. Totais, impostos, rateio, o saldo corrente, esses têm exatamente um valor correto e um auditor que vai checá-lo. Um modelo que está certo 99,9% das vezes está, em dinheiro, errado. O trabalho do modelo é entender que o cliente está perguntando sobre a fatura do mês passado. Computar quanto a fatura do mês passado de fato deu é aritmética, e aritmética é código que não pode arredondar diferente num dia ruim.

Roteamento. Para onde o trabalho vai a seguir, qual fila, qual agent, qual passo de aprovação, é o esqueleto do sistema inteiro. Se roteamento é um vibe, o sistema não tem forma; o mesmo caso vagueia para um lugar diferente a cada rodada e ninguém consegue raciocinar sobre o fluxo. O modelo pode classificar, “isto soa como um pedido de reembolso” é um julgamento, e um bom julgamento para um modelo fazer. Mas transformar essa classificação em “portanto entra no workflow de reembolso, que requer esta aprovação” é um mapeamento determinístico. Classificação é mole; a consequência é dura.

Note o padrão. Em cada um, o modelo ainda faz trabalho real, ele lê, interpreta, classifica. O que ele nunca faz é decidir a coisa exata. Ele entrega sua interpretação ao código, e o código faz a parte que tem que ser a mesma na sexta que foi na terça.

A forma: um núcleo de linguagem fino numa casca determinística

Uma vez que você traçou a costura, a arquitetura se desenha sozinha, e é o inverso da ingênua.

A versão ingênua é um modelo grosso embrulhado em cola fina, o modelo faz tudo, o código só passa strings de um lado para o outro. A versão confiável é o oposto: um núcleo de linguagem fino fazendo apenas a parte que genuinamente precisa de linguagem, embrulhado numa casca determinística grossa que é dona de cada decisão exata ao redor dele.

A casca é o código chato em que você confia. Ela checa a permissão antes de a intenção do modelo ter permissão de importar. Ela roda a aritmética em números reais, não em tokens. Ela valida que o que o modelo retornou está na forma que o resto do sistema espera, e se não está, ela rejeita em vez de passar julgamento malformado adiante. Ela mapeia a classificação mole do modelo numa rota dura. Ela escreve a linha de auditoria. Nada disso jamais varia, porque nada disso é um prompt.

O núcleo é o modelo, perguntado uma coisa estreita de cada vez: o que esta pessoa quer dizer, qual destas opções cabe, escreva isto numa voz humana. Perguntas sem uma única resposta certa, aquelas onde uma coisa probabilística, fluente, que lê contexto é genuinamente a melhor ferramenta do mundo. Você dá a ela o julgamento e nada mais. Você não dá a ela o talão de cheques, as chaves, ou a tabela de roteamento.

Dois layouts do mesmo agent. O layout ingênuo é um modelo grosso que é dono da intenção, permissão, aritmética, roteamento e do envio, com cola fina ao redor, então as decisões exatas herdam a deriva do modelo. O layout confiável inverte isso: um núcleo de modelo fino lida apenas com significado, escolha e tom, cercado por uma casca determinística que é dona do portão de permissão, da matemática, da checagem de schema e do roteamento, as partes exatas não podem mais derivar porque nunca foram um prompt.

Por que essa inversão compra confiabilidade é quase aritmética. Cada lugar onde você deixa o modelo tomar uma decisão exata é um lugar que pode derivar. Encolha a superfície do modelo para apenas as perguntas que não têm resposta exata, e você encolheu a deriva exatamente para os lugares onde a deriva não importa, porque não havia uma única resposta certa da qual derivar. Uma interpretação diferente-mas-razoável de um e-mail vago está ok; isso é julgamento fazendo seu trabalho. Um total diferente na mesma fatura é um bug; isso é exatidão vazando para um prompt.

Há um teste que você pode aplicar a qualquer linha no sistema. Pergunte: se você rodar isto duas vezes no mesmo input, precisa da mesma resposta? Se sim, é código. Se uma pessoa razoável poderia dar duas respostas diferentes e ambas serem aceitáveis, é candidato a prompt. Auth, dinheiro, roteamento, mesma resposta exigida, toda vez. Tom, intenção, qual-dos-três, variação é permitida, até bem-vinda. A costura não é uma questão de gosto. É uma propriedade do trabalho.

E a fronteira é também de onde a confiança vem. Uma casca determinística é auditável, você pode ler a função que decidiu o acesso, refazer a matemática, apontar a regra que roteou o caso. Um prompt não é auditável da mesma forma; você pode lê-lo, mas não pode provar o que ele vai fazer no input que você não viu. Colocar as decisões exatas em código não é só sobre correção. É a única forma de algum dia responder “por que o sistema fez aquilo” com uma linha de lógica em vez de um dar de ombros.

A virada: as partes chatas são onde a confiança mora

Aqui está a parte que não é sobre arquitetura.

Há um romance na ideia de que o modelo faz tudo, que você descreve a empresa em português e a inteligência cuida do resto. É uma imagem sedutora, e é por isso que a versão maximalista continua sendo construída. Mas um colega de trabalho em quem você de fato pode confiar não é o que é brilhante na demo e imprevisível em produção. É aquele cujas partes chatas são chatas toda vez. O colega que sempre checa se você tem permissão antes de entregar as chaves. Que nunca erra o total, mesmo no fim de um longo dia. Que manda o trabalho para o lugar certo sem ser lembrado.

Essa confiabilidade nunca ia vir de um modelo mais inteligente, porque a coisa de que você precisa de auth e dinheiro e roteamento não é inteligência, é igualdade. A mesma resposta na sexta que na terça. A coisa de que você precisa de intenção e tom e julgamento é o oposto, fluência, contexto, uma leitura do que uma pessoa de fato quis dizer. O erro é pedir a um componente que seja ambos. Determinismo é uma feature, e você o obtém dando o trabalho exato à parte do sistema que não pode ter um dia ruim, e dando apenas o julgamento à parte que pode.

O modelo vai continuar ficando mais inteligente. Isso é bom, e muda a metade do julgamento, interpretação mais rica, rascunhos melhores, classificação mais afiada. Não muda a outra metade. Dinheiro ainda vai ter um total correto. Permissão ainda vai ser um booleano. O lugar certo para um caso ainda vai ser um fato, não um sentimento. Os agents em que as empresas de fato confiarem trabalho real serão aqueles cujos construtores souberam qual metade era qual.


É assim que construímos agents na Apollo, um núcleo de linguagem fino para o julgamento, uma casca determinística para tudo que tem que ser exato, para que as partes chatas continuem chatas sob carga. Se você já assistiu a uma demo brilhante desmoronar no momento em que encontrou mil requisições reais, você já sabe que o modelo nunca foi a parte que precisava ser confiável. A aritmética era.

A Apollo cuida da operação repetitiva da sua empresa pro seu time não precisar.

Entre na lista de espera: acesso antecipado, preço de usuário fundador e um lugar na primeira fila enquanto a gente constrói.

Entrar na lista de espera