Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
ConceitoIniciantecódigo testado

O que é um LLM e como ele realmente funciona

Token, contexto, temperatura e alucinação explicados com um modelo de linguagem minúsculo escrito em JavaScript, rodando e imprimindo de verdade.

Rodolfo Mori11 min de leitura

LLM é a sigla de large language model, modelo de linguagem grande. Por baixo de toda a conversa que você tem com um assistente de IA existe uma máquina que faz uma única coisa: dado um texto, prever qual é o próximo pedaço de texto mais provável. Repete isso algumas centenas de vezes e sai um parágrafo.

Não há intenção, memória nem verificação nesse processo. Isso soa reducionista, e é — mas é o modelo mental correto, e é ele que explica todos os comportamentos estranhos que você já viu.

A melhor forma de entender é escrever um. O modelo abaixo é ridiculamente pequeno, roda em JavaScript puro e não tem rede neural nenhuma. Ainda assim, ele exibe três dos quatro comportamentos que importam: probabilidade, temperatura e alucinação. Se objeto, array e função ainda não são território conhecido, leia o código pelo comportamento e volte a ele depois — a ideia sobrevive sem a sintaxe.

Um autocomplete gigantesco, uma previsão por vez

Imagine o autocomplete do celular depois de ler uma biblioteca inteira. Você escreve um começo, ele compara aquele começo com padrões que aprendeu e aposta no próximo pedaço. Assim que escolhe, o texto ficou um pouco maior e ele faz uma nova aposta. Repetir esse ciclo muitas vezes produz uma resposta que parece ter sido planejada do começo ao fim.

Num LLM, cada pedaço é um token e cada aposta é uma distribuição de probabilidades calculada pelo modelo. A analogia não transforma o modelo num teclado: ela só isola o mecanismo central, a previsão do próximo token. Na microprática abaixo, dê o mesmo começo ao modelo pequeno mais de uma vez e compare os finais; a variação observada mostra a escolha probabilística em ação.

Um modelo de linguagem é treinado lendo texto e contando o que costuma vir depois do quê. Vamos treinar um com cinco frases de um atendimento de loja:

js
const corpus = `
o cliente pediu reembolso do pedido
o cliente pediu troca do produto
o cliente pediu segunda via do boleto
o cliente cancelou o pedido
o cliente elogiou o atendimento
`;

const palavras = corpus.trim().split(/\s+/);

const seguintes = {};
for (let i = 0; i < palavras.length - 1; i++) {
  const atual = palavras[i];
  seguintes[atual] ??= {};
  seguintes[atual][palavras[i + 1]] = (seguintes[atual][palavras[i + 1]] ?? 0) + 1;
}

const depoisDeCliente = seguintes['cliente'];
const total = Object.values(depoisDeCliente).reduce((a, b) => a + b, 0);

for (const [palavra, vezes] of Object.entries(depoisDeCliente)) {
  console.log(palavra.padEnd(10), (vezes / total).toFixed(2));
}
pediu 0.60 cancelou 0.20 elogiou 0.20

Isso é um modelo de linguagem. Depois da palavra “cliente”, ele atribui 60% a “pediu” e 20% a cada uma das outras duas. Um LLM de verdade faz exatamente a mesma coisa, com três diferenças de escala: olha para milhares de palavras anteriores em vez de uma, distribui a probabilidade entre cem mil possibilidades em vez de três, e aprendeu essas probabilidades ajustando bilhões de parâmetros em vez de contando ocorrências.

A operação, porém, é essa: uma distribuição de probabilidade sobre o próximo pedaço. E o parágrafo inteiro sai de repetir esse passo, uma vez por token, realimentando o resultado na entrada:

texto até aqui(o contexto)fatiadoem tokensprobabilidade decada token seguintesorteio(temperatura)o token sorteado entra no contexto — e o ciclo recomeça

Não existe uma etapa de “decidir o que dizer” antes dessa alça. O texto inteiro é o subproduto de repeti-la.

Token: o pedaço não é a palavra

O modelo não trabalha com palavras nem com letras, e sim com tokens — fragmentos de texto de tamanho variável, decididos por um algoritmo de compressão durante o treino.

Palavras comuns viram um token só. Palavras raras, nomes próprios e termos em português são quebrados em pedaços: “inteligência” pode virar algo como intel + ig + ência. Números costumam ser fatiados de formas contraintuitivas, o que é parte da razão de os modelos errarem aritmética.

Duas consequências práticas:

  • Preço e limite são contados em tokens, não em caracteres. Como regra de bolso para português, algo entre 3 e 4 caracteres por token. Textos em inglês rendem mais tokens por real gasto, porque os tokenizadores foram treinados majoritariamente em inglês.
  • Pedir para “contar as letras de uma palavra” é pedir para o modelo enxergar algo que ele não recebe. Ele viu tokens, não letras.

Contexto: a janela, e a memória que não existe

A janela de contexto é o número máximo de tokens que entram numa chamada: instruções, histórico da conversa, documentos anexados e a resposta que está sendo gerada, tudo somado.

Fora dessa janela, não existe memória. Um chat parece lembrar do que você disse porque a aplicação reenvia o histórico inteiro a cada mensagem. Quando o histórico passa do limite, alguém precisa cortar — e é aí que o assistente “esquece” o que foi combinado no começo.

js
const historico = [
  { papel: 'sistema', texto: 'Você é o suporte da Club Store.' },
  { papel: 'usuario', texto: 'Meu pedido 1042 não chegou.' },
  { papel: 'assistente', texto: 'Vou verificar o rastreio do pedido 1042.' },
  { papel: 'usuario', texto: 'Consigo cancelar?' },
];

const estimarTokens = (texto) => Math.ceil(texto.length / 3.6);

const cabemNaJanela = (mensagens, limite) => {
  const mantidas = [];
  let usados = 0;
  for (const m of [...mensagens].reverse()) {
    const custo = estimarTokens(m.texto);
    if (usados + custo > limite) break;
    usados += custo;
    mantidas.unshift(m);
  }
  return { mantidas, usados };
};

const { mantidas, usados } = cabemNaJanela(historico, 20);
console.log('tokens usados:', usados);
console.log('mensagens que sobreviveram:', mantidas.map((m) => m.papel));
tokens usados: 17 mensagens que sobreviveram: [ 'assistente', 'usuario' ]

Repare no que se perdeu: a instrução de sistema. Uma janela apertada e uma estratégia ingênua de corte descartaram justamente a mensagem que definia o comportamento do assistente. É por isso que aplicações sérias fixam o prompt de sistema e cortam só o meio da conversa.

Temperatura: o quanto ele se permite arriscar

Tendo a distribuição de probabilidades, falta decidir como escolher. Temperatura é o parâmetro que achata ou afia essa distribuição antes do sorteio.

js
const contagens = { pediu: 3, cancelou: 1, elogiou: 1 };

function comTemperatura(contagens, temperatura) {
  const nomes = Object.keys(contagens);
  const logits = nomes.map((n) => Math.log(contagens[n]));
  const escalados = logits.map((l) => l / temperatura);
  const maior = Math.max(...escalados);
  const exp = escalados.map((l) => Math.exp(l - maior));
  const soma = exp.reduce((a, b) => a + b, 0);
  return Object.fromEntries(nomes.map((n, i) => [n, exp[i] / soma]));
}

for (const t of [0.2, 1, 2]) {
  const p = comTemperatura(contagens, t);
  const linha = Object.entries(p).map(([n, v]) => `${n} ${v.toFixed(3)}`);
  console.log(`T=${t}`.padEnd(7), linha.join('   '));
}
T=0.2 pediu 0.992 cancelou 0.004 elogiou 0.004 T=1 pediu 0.600 cancelou 0.200 elogiou 0.200 T=2 pediu 0.464 cancelou 0.268 elogiou 0.268

Com temperatura 0,2 o favorito abocanha 99,2% da probabilidade: a saída fica quase determinística. Com temperatura 2 as três opções ficam próximas: o modelo passa a sortear alternativas improváveis com frequência.

Na prática: temperatura baixa para extrair dados, classificar e gerar código; temperatura alta para variação criativa. E note o que a tabela deixa claro — temperatura não mexe em qual token é o mais provável. Ela mexe só na chance de você receber outro.

Alucinação: fluência sem verificação

Aqui está a parte que mais confunde. Vamos treinar o mesmo modelo minúsculo com fatos de rastreio e deixá-lo gerar uma frase:

js
const corpus = `
o pedido 1042 foi entregue em Sorocaba
o pedido 1042 foi cancelado pelo cliente
o pedido 2318 foi entregue em Curitiba
o pedido 2318 foi extraviado pela transportadora
`;

const palavras = corpus.trim().split(/\s+/);
const seguintes = {};
for (let i = 0; i < palavras.length - 1; i++) {
  (seguintes[palavras[i]] ??= []).push(palavras[i + 1]);
}

let semente = 7;
const aleatorio = () => ((semente = (semente * 1103515245 + 12345) % 2147483648) / 2147483648);

let atual = 'o';
const frase = [atual];
for (let i = 0; i < 7; i++) {
  const opcoes = seguintes[atual];
  if (!opcoes) break;
  atual = opcoes[Math.floor(aleatorio() * opcoes.length)];
  frase.push(atual);
}

console.log(frase.join(' '));
o pedido 1042 foi extraviado pela transportadora

Leia o corpus de novo. O pedido 1042 foi entregue ou cancelado. Quem foi extraviado foi o 2318. A frase que o modelo produziu é gramaticalmente perfeita, tem o formato exato de um fato de rastreio, e é falsa.

Ninguém mentiu. O modelo emendou trechos prováveis: depois de “1042 foi” cabe “extraviado”, porque “foi extraviado” apareceu no treino. A verificação de que a combinação corresponde a algo real simplesmente não faz parte da operação.

Alucinação não é um defeito que será consertado com um modelo maior. É o mesmo mecanismo que gera as respostas certas, aplicado onde os padrões prováveis não coincidem com os fatos. Modelos maiores erram menos porque viram mais; erram igual quando o dado não estava lá.

De onde vêm essas probabilidades

Contar ocorrências, como fizemos acima, só funciona em cinco frases. Com a internet inteira, o número de sequências possíveis é maior que o número de átomos disponíveis para guardá-las. Um LLM resolve isso comprimindo: em vez de uma tabela, uma função com bilhões de parâmetros ajustáveis — a diferença entre guardar todas as respostas e guardar uma regra capaz de produzi-las.

O treino acontece em três etapas, e vale conhecer os nomes porque eles explicam comportamentos diferentes.

Pré-treino. O modelo recebe quantidades enormes de texto com um pedaço escondido e tenta adivinhar o que vem a seguir. Errou, os parâmetros são corrigidos um pouquinho; repita bilhões de vezes. É aqui que ele absorve gramática, fatos, estilos e também os vieses do material. É a etapa cara — meses de máquina — e é por isso que o conhecimento tem data de corte.

Ajuste por instrução. Um modelo recém-pré-treinado não responde perguntas: ele completa texto. Perguntando “qual a capital da França?”, ele pode devolver mais perguntas, porque listas de perguntas são padrões prováveis. A segunda etapa treina em pares de pedido e resposta bem-feita, ensinando o formato de assistente.

Alinhamento com preferência humana. Pessoas comparam respostas duas a duas e dizem qual é melhor; essas comparações treinam o modelo a preferir respostas úteis, seguras e no tom certo. É daqui que vem boa parte da personalidade que você percebe — e também a tendência a concordar demais com quem pergunta.

A arquitetura por trás de tudo isso é o Transformer, apresentado em 2017. A ideia central, o mecanismo de atenção, é o que permite ao modelo pesar quais palavras anteriores importam para prever a próxima — em vez de tratar o texto como uma fila em que só o vizinho conta, como o nosso modelinho de bigrama faz.

O que o prompt realmente muda

Se o modelo é fixo depois do treino, o único ponto de controle que sobra é o texto que entra. Isso não é pouco: mudar o contexto muda a distribuição de probabilidade sobre a resposta inteira.

Três coisas mudam resultado de forma mensurável, e nenhuma delas é fórmula mágica:

  • Contexto específico. Colar o dado real (o pedido, o log, o trecho de código) em vez de descrevê-lo. O modelo não pode consultar o que você não mandou.
  • Formato pedido explicitamente. “Responda em JSON com as chaves causa e correcao” produz saída processável; “me explica o erro” produz um ensaio.
  • Exemplos. Duas ou três amostras de entrada e saída no formato desejado guiam melhor do que um parágrafo de instrução. É o que se chama de few-shot.

O que não muda muito: implorar, ameaçar, prometer gorjeta, ou repetir “importante” em maiúsculas. Se funcionou uma vez, foi ruído de amostragem — teste dez vezes antes de virar superstição.

Chamando um de verdade

A interface de todos os provedores é a mesma ideia: você manda a lista de mensagens e os parâmetros de amostragem, e recebe o texto gerado mais a contagem de tokens usados.

js
const resposta = await fetch('https://api.anthropic.com/v1/messages', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'x-api-key': process.env.ANTHROPIC_API_KEY,
    'anthropic-version': '2023-06-01',
  },
  body: JSON.stringify({
    model: 'claude-opus-5',
    max_tokens: 2048,
    output_config: { effort: 'low' },
    system: 'Você é o suporte da Club Store. Responda em no máximo três frases.',
    messages: [{ role: 'user', content: 'Meu pedido 1042 não chegou. O que faço?' }],
  }),
});

const dados = await resposta.json();
const texto = dados.content.find((bloco) => bloco.type === 'text');
console.log(texto.text);
console.log(dados.usage);

Os campos que decidem o resultado estão aí: system (as instruções fixas), messages (o contexto) e o controle de esforço. O usage que volta é o que você vai pagar — entrada e saída são cobradas em tokens, com preços diferentes.

Duas armadilhas nesse trecho, e as duas custam caro em produção:

  • content é uma lista de blocos de tipos diferentes, não um texto. Nos modelos que raciocinam antes de responder, o primeiro item pode ser um bloco de raciocínio; content[0].text pega o bloco errado. Procure pelo bloco de tipo text, como no exemplo.
  • max_tokens é o teto da resposta inteira, raciocínio incluído. Apertar esse número para economizar corta a resposta no meio, e você paga pelo pedaço truncado do mesmo jeito.

Onde os alunos se confundem

Depois de muita turma passando por este assunto, três confusões se repetem, e vale nomeá-las.

A primeira é achar que o modelo consulta a internet. Por padrão ele não consulta nada: responde a partir dos pesos, que foram congelados no fim do treino. Quando um produto de IA cita uma fonte, é porque alguém programou uma busca e colou o resultado no contexto antes de chamar o modelo. Isso é engenharia ao redor, não capacidade do modelo.

A segunda é confundir contexto com memória. Aluno pede ao assistente para “lembrar” de uma preferência e se frustra quando ele esquece. Não há onde guardar: se a informação não estiver no texto enviado nesta chamada, ela não existe. Persistência é um banco de dados que você escreve.

A terceira, e a mais cara, é tratar temperatura como controle de qualidade. Vejo gente baixando a temperatura para zero esperando eliminar erro factual. Não elimina — deixa o erro consistente. Se a resposta mais provável está errada, você passa a recebê-la todas as vezes, com firmeza.

O modelo mental que resolve as três: um LLM é um completador de texto muito bom, sem acesso ao mundo e sem estado. Tudo que ele sabe sobre a sua situação está no que você mandou nesta chamada. Todo produto de IA que funciona é, em grande parte, o trabalho de escolher bem o que colocar ali dentro.

Vale um aviso sobre usar LLM para aprender a programar, que é o uso mais comum entre quem está começando. Pedir explicação de um conceito funciona muito bem — o modelo é excelente em reformular. Pedir código pronto para um exercício funciona contra você: o código costuma rodar, e é exatamente por isso que engana. Quando ele erra, erra com a mesma segurança de quando acerta, e você ainda não tem repertório para diferenciar os dois casos. Um erro clássico dessa fase é receber um trecho que assume um dado sempre presente e cair no TypeError: Cannot read properties of undefined na primeira execução com dado real — a linha estava plausível, a suposição é que era falsa.

  • llm
  • inteligencia artificial
  • token
  • temperatura
  • alucinacao

Perguntas frequentes

LLM é a mesma coisa que inteligência artificial?
Não. Inteligência artificial é o campo inteiro; LLM é um tipo específico de modelo, treinado para prever a próxima parte de um texto. Reconhecimento de imagem, recomendação e detecção de fraude também são IA e não são LLMs.
O modelo aprende com as minhas conversas?
Por padrão, não durante a conversa. Os pesos do modelo são fixos depois do treino. O que parece aprendizado dentro do chat é apenas o histórico sendo reenviado a cada mensagem, dentro da janela de contexto. Se o provedor usa as conversas em treinos futuros é uma questão de política de dados, não de arquitetura.
Por que o modelo erra conta simples?
Porque ele não calcula: ele prevê a sequência de caracteres mais provável para aquela conta. Em contas vistas muitas vezes no treino, acerta. Em números grandes ou incomuns, escreve algo plausível e errado. Por isso as ferramentas modernas chamam uma calculadora de verdade por baixo.
Temperatura zero garante resposta correta?
Garante resposta mais previsível, não mais correta. Com temperatura zero o modelo sempre escolhe o token mais provável — se a informação mais provável no treino estiver errada, ele vai repetir o erro com firmeza.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. Attention Is All You Need (Vaswani et al., 2017) — arxiv.org
  2. Language Models are Few-Shot Learners (Brown et al., 2020) — arxiv.org
  3. The Curious Case of Neural Text Degeneration (Holtzman et al., 2019) — arxiv.org

Continue por aqui