
Você já jogou pinball?
Você lança a bola, acompanha o percurso e tenta acertar o momento de usar os flippers, aquelas pequenas alavancas na parte de baixo do tabuleiro. Às vezes, consegue fazer exatamente o que pretendia. Em outras, um toque um pouco antes ou depois leva a bola para um lugar completamente diferente.
O tabuleiro continua igual. As regras também. Mesmo assim, conhecer o jogo não significa saber por onde a bola vai passar.
O pinball obedece à física. A comparação que me interessa não é entre o funcionamento da máquina e o de uma IA, mas entre as sensações de quem tenta lidar com eles: existe uma estrutura conhecida, existem formas de intervir, mas o controle não é completo.
Construir software com IA generativa me provoca uma estranheza parecida. Passei anos aprendendo a escrever sistemas em que, dadas as mesmas entradas e condições, o resultado deveria ser o mesmo. Se algo mudava sem explicação, havia uma investigação pela frente. Algum estado diferente, uma dependência instável, uma regra que eu não tinha entendido direito.
Agora, coloco no meio da aplicação um componente que pode responder à mesma pergunta de maneiras diferentes. E o mais desconfortável é que isso não significa, necessariamente, que alguma coisa deu errado.
Meu primeiro impulso é tentar trazer esse comportamento de volta para um terreno familiar, ajustar a instrução, restringir a resposta, encontrar uma configuração que faça tudo se repetir. Essas medidas podem ajudar, mas não resolvem a pergunta que começou a me acompanhar:
O que precisa continuar certo quando a resposta pode mudar?
O primeiro choque
Imagine que estamos construindo um assistente para explicar como recuperar uma senha.
A regra é simples: a pessoa recebe um link no e-mail cadastrado. Se não tiver mais acesso a esse e-mail, precisa procurar o atendimento para confirmar sua identidade.
A integração funciona. A pergunta chega ao modelo, a resposta aparece na tela. Tudo parece encaminhado, até chegar a hora de escrever o teste e preencher aquela parte tão familiar: o resultado esperado.
Em uma execução, o assistente responde:
“Solicite um link de redefinição no e-mail cadastrado. Caso não tenha mais acesso a ele, procure o atendimento para confirmar sua identidade.”
Em outra, recebemos:
“Se você ainda acessa o e-mail cadastrado, use o link de redefinição de senha. Se perdeu o acesso, será necessário confirmar sua identidade com o atendimento.”
As palavras mudaram. A ordem também. A orientação, não. Eu aceitaria as duas respostas. Reprovar uma delas porque não corresponde exatamente à frase que escrevi no teste seria confundir uma diferença de redação com um defeito.
Então vem uma terceira:
“Para recuperar sua senha, solicite um link no e-mail cadastrado.”
A frase é clara e descreve o caminho mais comum. Mas, para a explicação completa que esperamos nesse exemplo, falta uma parte importante: o que fazer quando a pessoa não acessa mais o e-mail. Essa resposta não inventou uma regra. Ela deixou uma regra para trás.
É aí que aparece o choque. Uma comparação literal pode rejeitar uma resposta boa. Uma busca por palavras como “senha”, “link” e “e-mail” pode aceitar uma resposta incompleta. O velho assertEquals continua fazendo seu trabalho. Só não responde, sozinho, à pergunta que temos agora.
Lendo os exemplos, a diferença parece evidente. Transformar essa percepção em um critério de avaliação exige mais cuidado. Precisamos dizer o que pode variar, o que não pode desaparecer e por que aquela ausência importa. Não basta escrever “a resposta deve estar correta”. Correta em relação a quê? Para qual situação? Preservando quais condições?
O incômodo não está apenas em receber uma resposta diferente. Está em perceber que uma parte do julgamento que parecia resolvida pelo teste ainda estava na minha cabeça.
Talvez esse seja o primeiro ajuste de expectativa. Conseguir uma resposta convincente é mais fácil do que explicar por que deveríamos confiar nela.
O que eu esperava do mundo
Existe uma razão para esse apego à previsibilidade. Ele foi útil durante muito tempo e continua sendo. Quando calculamos um desconto, queremos chegar ao resultado pelas regras e pelos valores usados. Quando uma operação é rejeitada, esperamos conseguir explicar o motivo. Quando corrigimos um defeito, escrevemos um teste para que ele não volte sem ser percebido.
Há conforto nisso. Não porque tudo seja fácil, mas porque temos uma forma conhecida de investigar, verificar e conversar sobre o que aconteceu. O software tradicional também convive com incerteza. Redes falham, requisições chegam fora de ordem, estados mudam entre duas consultas. Quem já passou horas tentando reproduzir um problema de concorrência sabe que o mundo nunca foi tão comportado quanto gostaríamos.
Ainda assim, em muitas partes do sistema, minha expectativa era reduzir a variação até conseguir explicar cada resultado. Com a linguagem gerada por um modelo, preciso admitir outra possibilidade, duas saídas diferentes podem cumprir igualmente bem o mesmo papel. É um ajuste pequeno de explicar e estranho de incorporar.
O hábito de procurar uma única resposta esperada não desaparece só porque entendi a teoria. No pinball, seria como considerar uma partida defeituosa porque a bola não repetiu a trajetória anterior. O percurso mudou, mas isso não diz, por si só, se jogamos bem ou mal. No assistente, ajuda separar três perguntas que antes poderiam acabar misturadas em um único “funcionou”.
A integração funcionou? A chamada terminou, o retorno pôde ser interpretado, os campos vieram preenchidos e o tempo de resposta foi aceitável. Esse continua sendo um terreno conhecido. Uma orientação excelente que nunca chega à pessoa não resolve o problema.
O conteúdo preservou a regra? O link vai para o e-mail cadastrado? Quem perdeu o acesso é orientado a procurar o atendimento? A confirmação de identidade continua sendo necessária? A resposta pode ter o formato certo e, ainda assim, trazer uma orientação errada ou incompleta.
A explicação ajuda aquela pessoa a agir? Aqui entra o contexto. Se alguém já disse que perdeu o acesso ao e-mail, repetir todos os caminhos possíveis transfere para ela o trabalho de descobrir qual se aplica.
Eu esperaria algo mais direto: “Como você não tem mais acesso ao e-mail cadastrado, procure o atendimento para confirmar sua identidade.”
Perceber essas diferenças muda o que significa testar a funcionalidade. Um campo preenchido mostra que houve uma resposta. Não mostra, sozinho, que a pessoa recebeu a orientação de que precisava. A engenharia que eu conhecia continua ali. Só que agora preciso tornar explícitas algumas coisas que a linguagem permite deixar implícitas.
A mudança de perspectiva
Parte dessa adaptação passa por entender o que estamos colocando dentro do sistema. Um modelo de linguagem trabalha com probabilidades para construir uma resposta. Quando a geração usa amostragem, há uma seleção entre possibilidades orientada por essas probabilidades. É daí que vem a estocasticidade.
Isso não significa que qualquer resposta seja igualmente possível ou adequada. Existem instruções e contexto orientando a geração. Também existem estratégias que tornam a saída mais repetível. Mas repetir uma resposta não garante que ela esteja certa. É possível repetir o mesmo erro com bastante consistência.
Por isso, eu começaria por uma mudança de pergunta. Em vez de pensar apenas em “qual frase espero receber?”, pensaria em “o que essa resposta precisa preservar?”.
No exemplo da senha, a redação pode mudar. O caminho para quem perdeu o acesso ao e-mail, não. A necessidade de confirmar a identidade também não pode desaparecer. E o assistente não deve prometer uma solução que a política não oferece.
Parece óbvio quando escrito assim. Mas escrever é justamente a parte importante. Enquanto esses critérios ficam apenas na cabeça de quem desenvolve, cada pessoa pode avaliar a resposta de um jeito.
O passo seguinte seria variar as situações. Uma pessoa esqueceu a senha. Outra perdeu o acesso ao e-mail. Uma terceira ainda acessa a caixa de entrada, mas não recebeu o link. Alguém escreve apenas “não consigo entrar”, e talvez o próximo passo adequado seja perguntar mais, não adivinhar o problema.
Esses casos, acompanhados de critérios para julgar as respostas, formam um conjunto de avaliações, ou evals. Eles ajudam a observar se o assistente continua preservando o que importa, mesmo quando a pergunta ou a redação muda.
Parte dessa verificação pode ser automática. Parte pode precisar de revisão humana. Outro modelo também pode ajudar a avaliar as respostas, mas ele não vira uma autoridade infalível só porque recebeu a tarefa de avaliar. Precisamos conferir se seus julgamentos reconhecem os erros que nos preocupam.
Uma boa média também não encerra a conversa. O assistente pode ir bem no caminho mais comum e falhar justamente quando alguém perdeu o acesso ao e-mail. Eu gostaria de enxergar essa falha separadamente, não diluída no resultado geral.
Ao mesmo tempo, há decisões que eu não deixaria depender apenas da interpretação do modelo.
Se o assistente puder executar ações, como alterar o e-mail cadastrado, a confirmação de identidade e as permissões precisam ser verificadas pelos mecanismos responsáveis por isso. O modelo pode entender o pedido e ajudar a conduzir a conversa. Não deveria conseguir liberar a alteração apenas porque produziu um texto convincente.
É aqui que os flippers voltam à imagem. Eles não determinam todo o percurso da bola, mas oferecem pontos de intervenção. Não preciso transformar a conversa inteira em uma sequência fixa para manter sob controle as ações que exigem regras claras.
Também precisamos decidir o que acontece quando falta informação. Sem encontrar a política de recuperação, o assistente deve reconhecer a limitação e encaminhar a dúvida, não improvisar um procedimento.
Escrever tudo isso no prompt, a instrução enviada ao modelo, pode orientar o comportamento. Mas “siga as regras” não substitui a verificação de que elas foram seguidas. Uma intenção bem escrita ainda precisa ser acompanhada por testes e limites na aplicação.
Depois da entrega, o aprendizado continua. Uma falha relevante pode virar um novo caso de avaliação. Uma mudança no modelo, na instrução ou na política pede uma nova comparação com os casos conhecidos. Registrar o contexto necessário para investigar, com cuidado em relação a dados sensíveis, continua fazendo parte do trabalho.
Não é abandonar o controle. É entender onde precisamos exercê-lo de outra maneira.
O aprendizado
Essa mudança também mexe com a forma como reconheço que alguma coisa está pronta. Uma demonstração bem-sucedida é animadora. Você faz uma pergunta, recebe uma boa resposta e consegue imaginar o produto funcionando. É fácil sentir que a parte difícil ficou para trás.
Mas uma boa resposta mostra que o sistema deu conta daquele caso, naquelas condições. É uma evidência útil, não uma conclusão sobre todas as situações que ainda vão aparecer.
No pinball, acertar uma jogada difícil não significa que já conhecemos o tabuleiro inteiro. Repetir a mesma pergunta ajuda a perceber variações. Não substitui testar perguntas diferentes. Dez respostas boas sobre o caminho comum não mostram como o assistente vai tratar quem perdeu o acesso ao e-mail.
Começo, então, a olhar para a revisão de uma funcionalidade com outras perguntas. Quais situações examinamos? Que erros apareceram? Quais condições não podem se perder? O que acontece quando o assistente não consegue ajudar? Isso também aproxima a conversa das decisões de produto. O assistente só explica como recuperar a senha ou inicia o procedimento? Pode alterar algum dado? Precisa pedir uma confirmação antes de agir?
Essas definições mudam a responsabilidade do sistema. Deixá-las implícitas não evita a decisão; apenas permite que ela apareça durante o uso, talvez de uma maneira que ninguém pretendia. O peso dos erros também é diferente. Uma frase pouco elegante não tem a mesma consequência de orientar alguém a usar um e-mail ao qual já não tem acesso. E explicar mal um procedimento não envolve o mesmo risco de executar uma alteração sem a verificação necessária.
Por isso, não espero que uma única nota de qualidade resolva tudo. Importa saber quais erros acontecem, com que frequência e o que eles podem causar.
Continuam existindo perguntas sem respostas confortáveis. Nosso conjunto de testes representa bem as pessoas que vão usar o produto? Há situações importantes que ainda não imaginamos? O que consideramos suficiente para começar a oferecer essa funcionalidade?
A diferença é que agora essas dúvidas precisam fazer parte da conversa, em vez de ficarem escondidas atrás de uma demonstração que funcionou.
Quando volto às três respostas do começo, o critério fica mais claro. As duas primeiras preservam a orientação. A terceira deixa de fora uma condição necessária. Não preciso exigir palavras idênticas, nem aceitar qualquer texto que pareça razoável.
Existe um espaço entre esses extremos. É nele que estou aprendendo a trabalhar.
Aprender a jogar
Talvez a parte mais estranha dessa transição seja perceber que a experiência ajuda, mas também cria expectativas que precisamos revisar.
Depois de anos resolvendo problemas de uma determinada maneira, é natural tentar reconhecer o novo pelas ferramentas que já conhecemos. Às vezes, elas continuam servindo exatamente como antes. Em outras, precisam de um ajuste. E há momentos em que ainda não sabemos direito o que fazer.
Isso não apaga o que aprendemos. Contratos, validações, testes, observabilidade e revisão continuam sustentando o sistema. Aprender a lidar com componentes estocásticos não exige jogar fora o determinismo. Exige distinguir onde a variação é aceitável e onde uma regra precisa continuar sendo aplicada sem depender dela.
O desconforto diminui quando deixo de tratar essa mudança como uma cobrança para já saber tudo. Posso começar por um caso pequeno, observar uma falha, melhorar um critério e entender um pouco mais do comportamento que estou tentando construir.
Adaptar-se não é aceitar qualquer resultado em nome da novidade. Também não é rejeitar tudo o que não cabe imediatamente nos nossos hábitos. É continuar fazendo perguntas, usando o que já sabemos e reconhecendo o que ainda precisamos aprender.
No pinball, aprendemos o tabuleiro aos poucos. Descobrimos onde prestar atenção, quando intervir e quais movimentos costumam nos colocar em dificuldade. Não ganhamos controle completo sobre a trajetória. Ganhamos repertório para lidar melhor com ela.
Com IA generativa, começo a reconhecer um aprendizado parecido. A confiança não precisa vir da promessa de que nada vai variar, mas dos critérios, dos limites e da capacidade de perceber quando o sistema sai deles.
Aprender algo novo também é permitir que a experiência mude a nossa forma de trabalhar, sem perder o cuidado que nos trouxe até aqui.
A próxima bola pode seguir outro caminho. Ainda assim, podemos aprender a jogar melhor.