A tese desta página: dá para integrar um LLM sem entender um único peso desde que se respeite meia dúzia de invariantes. Elas não são opinião nem boa prática: são propriedades do mecanismo, e valem para qualquer provedor e qualquer modelo. As outras páginas da série explicam como o modelo funciona por dentro. Esta explica o que dá para assumir de fora, que é a pergunta de quem tem código em produção. Cada etapa é um axioma, o bug que ele explica, e a conta que prova.
Os seis, e o sintoma de cada um
Explore cada etapa →
As contas, num só lugar
As 4 contas desta página. Clique em qualquer uma para pular direto para a etapa que a explica.
Honestidade, antes de começar: esta é a única página da série que não roda inferência nenhuma. Ela não chama API, não carrega modelo e não gera resposta de LLM mostra a requisição, que é o objeto sobre o qual você tem controle, e as consequências de cada axioma sobre ela. O que roda de verdade: a serialização da requisição, a conta quadrática da conversa, o prefixo comum caractere a caractere, o relógio do seu navegador, a amostragem repetida e a aritmética da janela. Na etapa 3 roda um gerador de trigramas de verdade, treinado no corpus que está na própria página ele é ridiculamente mais burro que um LLM, e é exatamente por isso que serve: ele tem o mesmo mecanismo de "escolher a próxima palavra" e nenhum mecanismo de verificação, que é o ponto do axioma. A contagem de tokens é aproximada (~4 caracteres por token); token de verdade depende do tokenizador do modelo, e onde isso importa a página avisa.
Do lado de lá não existe sessão. Não há um objeto conversa, não há memória entre chamadas, não há nada que sobreviva ao fim da requisição. O que existe é uma função sem estado: entra um texto, sai um texto. A continuidade que o usuário sente é inteiramente construída pelo seu código, reenviando tudo de novo a cada vez.
Fórmula · a conta da conversa
total = n·S + t · n(n+1)/2
Leia assim: cada turno reenvia o system (S) mais tudo que veio antes. Somar isso ao longo de n turnos dá aquele n(n+1)/2, que é a soma dos primeiros n números ou seja, o custo cresce com o quadrado do tamanho da conversa, não com o tamanho dela. Dobrar o número de turnos não dobra a fatura: multiplica por quatro.
O bug que este axioma explica: "o assistente esqueceu o que eu falei". Ele nunca soube alguém no caminho parou de reenviar, ou truncou o histórico para caber, ou reordenou as mensagens. O modelo não tem como sinalizar isso: ele responde com o que recebeu, e o que recebeu parecia completo. A correção não é do lado do modelo: trate o histórico como estado seu, com o mesmo cuidado que você daria a qualquer estado de aplicação guardado, versionado e com política explícita de descarte, que é o assunto da etapa 6.
Se toda chamada é isolada, nada persiste com uma exceção. Quando duas requisições começam com exatamente os mesmos bytes, o trabalho feito sobre esse trecho pode ser reaproveitado. É a única memória real que existe entre chamadas, ela é sua para desenhar, e ela morre no primeiro byte que muda de lugar.
Ordem de montagem (mova os blocos)
rosa: muda a cada chamada · verde: estável entre chamadas
verde: sobrevive · rosa: reenviado do zero
Fronteira com a página de cache: aqui o prefixo aparece só como consequência do axioma 1 se nada persiste, o prefixo idêntico é a única coisa que pode persistir. A mecânica completa mora em Cache de prompt: a ordem de renderização que o provedor usa, os invalidadores silenciosos, os multiplicadores de escrita e leitura e o ponto de equilíbrio em número de chamadas. Se você chegou aqui atrás da conta, é para lá que deve ir.
Não existe um passo de verificação no meio da geração. O modelo escolhe a próxima palavra a partir das anteriores, e repete. Fluência e veracidade são mecanismos separados, e só o primeiro está dentro do modelo o que explica a coisa mais desconcertante da área: a resposta errada vem tão bem escrita quanto a certa.
O gerador acima é um trigrama, não um LLM: ele escolhe a próxima palavra olhando só as duas anteriores. É absurdamente mais burro, e é de propósito o que ele tem em comum com um modelo de verdade é justamente o que importa aqui: escolhe pelo que veio antes, e não tem nenhum mecanismo de conferência. A diferença de escala muda a qualidade das frases e não muda essa ausência. Um LLM erra muito menos e erra do mesmo jeito: com a mesma gramática impecável e a mesma ausência de dúvida.
O bug, e a correção: o sintoma é a resposta impecável com um número inventado, um artigo que não existe, uma cláusula que ninguém escreveu. Pedir "não invente" no prompt reduz e não resolve, porque não existe o órgão que obedeceria a esse pedido. A verificação é uma camada sua, e ela tem formas conhecidas: recuperação com citação obrigatória e trecho conferível, saída estruturada com esquema estrito, e conferência programática contra a fonte que é literalmente o que a classificação acima faz. Repare que a conferência não veio do gerador: veio de código escrito por fora, com uma tabela de fatos explícita. Num sistema de verdade, essa tabela é o seu banco de dados.
Não há relógio dentro dos pesos. O modelo não sabe que dia é hoje, quanto tempo passou desde a mensagem anterior, nem que existe um mundo depois do corte de treino. E o mais traiçoeiro: ele não sabe que não sabe para ele, o mundo simplesmente termina ali, sem aviso.
Agora, pelo seu navegador
O que o modelo sabe sobre agora
O carimbo, e o preço dele
Este axioma esbarra no axioma 2, e é aí que fica interessante: a correção óbvia é injetar a data no prompt. Mas o carimbo muda a cada chamada, então onde você o coloca decide se ele custa quase nada ou destrói o prefixo inteiro. No início do system: tudo depois dele é reenviado do zero, para sempre. No fim do prompt: o estrago é o tamanho do próprio carimbo. É a mesma informação, no mesmo prompt, com ordens de grandeza de diferença na fatura e é o invalidador de cache mais comum que existe, exatamente porque a correção parece inofensiva.
E o corolário prático: qualquer cálculo que envolva tempo é trabalho do seu código, não do modelo. "Quantos dias faltam", "isso ainda está no prazo", "qual a versão mais recente" nada disso tem resposta confiável saindo dos pesos, mesmo com a data injetada, porque o modelo faz aritmética de data do mesmo jeito que faz o resto: prevendo o próximo token. Se a resposta precisa estar certa, a conta é sua e o modelo só apresenta o resultado.
A saída é amostrada de uma distribuição de probabilidade. Rodar a mesma pergunta de novo e receber outra coisa não é bug, instabilidade nem falha do provedor é o mecanismo funcionando. O que isso quebra não é a demonstração: é o seu teste automatizado.
Fronteira com "Dentro de um LLM":como a temperatura reformata a distribuição é assunto da etapa 4 de lá, com o softmax e as probabilidades mudando de forma ao vivo. Aqui a pergunta é outra e é operacional: dado que a saída é sorteada, o que isso faz com o seu teste? A distribuição acima é declarada, não medida a página não roda modelo nenhum. O que roda de verdade é o sorteio sobre ela, e é ele que produz a dispersão da tabela.
O bug: o teste passou ontem e falhou hoje, sem ninguém ter feito deploy. A causa quase nunca é o modelo ter mudado é o teste afirmar sobre uma string, quando a saída é uma amostra. A correção tem três partes. Afirme sobre propriedade, não sobre texto: "contém 24 meses", "valida contra o esquema", "não cita fonte inexistente". Rode N vezes e afirme sobre a taxa, com um limite que você escolheu de propósito. E use saída estruturada onde puder, porque um esquema estrito reduz o espaço de variação a algo sobre o qual dá para afirmar.
E a pegadinha de quem já sabe disso: "então eu ponho temperatura zero e resolvo". Temperatura zero torna a escolha gulosa, o que remove o sorteio mas não entrega determinismo garantido. O resultado ainda pode variar com o tamanho do lote, com a versão do modelo por baixo, com o hardware que atendeu a chamada e com a ordem de soma em ponto flutuante. Temperatura zero reduz muito a variação e não é um contrato. Se o seu sistema depende de bit a bit igual, o lugar de garantir isso é um cache do seu lado, não um parâmetro de amostragem.
System, ferramentas, documentos recuperados, histórico e a reserva para a resposta disputam o mesmo orçamento. Quando a soma passa da janela, alguma coisa é cortada e quem escolhe o quê é você, inclusive quando você não escolheu nada e deixou o corte acontecer por acidente.
Honestidade · o meio da janela: existe um resultado bem estabelecido de que a informação colocada no meio de um contexto longo é recuperada com menos confiabilidade que a do começo ou do fim é o efeito que ficou conhecido como lost in the middle, publicado em 2023 e reproduzido várias vezes desde então, com magnitude que varia bastante por modelo. Esta página não mede isso: medir exigiria rodar um modelo, e ela não roda nenhum. Fica como resultado citado, não como número desta página e a consequência prática é a que interessa: o que importa vai no começo ou no fim, nunca enterrado no meio.
O bug: a qualidade cai só nas conversas longas, e ninguém consegue reproduzir. É o corte acontecendo em silêncio: a biblioteca truncou o histórico, ou a recuperação trouxe mais documento do que cabia, ou a resposta ficou sem espaço e saiu pela metade. Nenhuma dessas três vira erro todas devolvem 200. A correção é escrever o orçamento por seção, em código, com uma política de descarte explícita: quantos turnos ficam, quantos documentos entram, quanto se reserva para a resposta. A janela grande não elimina a decisão: ela só adia o momento em que você vai precisar tê-la tomado.
Os seis, de um relance
No fim: o que as seis têm em comum é que nenhuma delas aparece na mensagem de erro. A API devolve 200 e um texto plausível em todos os casos o histórico truncado, a data errada, o número inventado, a resposta que mudou entre execuções. É por isso que estas seis valem mais que qualquer stack trace na hora de depurar uma integração com LLM: o sistema não está quebrado, ele está fazendo exatamente o que a mecânica dele prevê, e o que estava errado era a suposição. Depurar aqui é menos ler log e mais perguntar qual das seis foi violada.