Pular para o conteúdo
Aguiar Labs

RAG em produção: o que muda quando existe SLA

Orçamento de latência, custo por token e qualidade de contexto. O que separa um RAG de demonstração de um que aguenta produção — com números de um assistente real.

Publicado
Leitura
6 min
Render 3D escuro de um campo de placas finas deitadas em grade, com exatamente três placas de pé entre elas, pegando um pouco mais de luz.

Montar um RAG hoje é uma tarde de trabalho: LangChain, um banco Postgres com pgvector, um modelo de embedding e pronto, o chat responde citando os seus documentos. A demo funciona. Ela sempre funciona.

O que separa essa demo de um sistema em produção são três números que a demo nunca te obriga a olhar: a latência p95, o custo por consulta e o quanto da resposta veio mesmo do contexto recuperado.

Os números abaixo são de um assistente interno que responde com base nas regras de produto de uma plataforma em produção. Não cito nomes nem valores de cliente — o que interessa aqui são as ordens de grandeza e as decisões.

Latência é orçamento, não sorte

Quando alguém promete "resposta em até 2 segundos", isso deixa de ser uma métrica e vira um orçamento a ser dividido entre as etapas:

EtapaOrçamento p95
Embedar a pergunta40 ms
Buscar no índice vetorial120 ms
Reordenar os trechos80 ms
Gerar a resposta1.400 ms

Se a soma estourar o SLA, não adianta trocar o modelo: a arquitetura é que está errada. E a etapa que quase todo mundo subestima é a busca.

No pgvector, a escolha do índice é a primeira alavanca. O HNSW entrega melhor relação entre velocidade e recall, mas demora mais para construir e ocupa mais memória. O IVFFlat constrói rápido e ocupa pouco, com recall pior para o mesmo tempo de busca. Em produção, na prática, HNSW ganha quase sempre — o custo é a construção do índice, que você paga uma vez.

O botão que controla o trade-off fica no tempo de consulta: hnsw.ef_search (padrão 40) no HNSW e ivfflat.probes (padrão 1) no IVFFlat. Subir esses valores melhora o recall e custa latência. É aí, e não no modelo, que se compra qualidade de busca.

-- índice HNSW por similaridade de cosseno
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);

-- recall x latência: ajuste por consulta, não no banco inteiro
SET LOCAL hnsw.ef_search = 100;

SELECT id, conteudo
FROM chunks
WHERE tenant_id = $1 AND doc_type = 'regra'
ORDER BY embedding <=> $2
LIMIT 3;

Repare no WHERE daquela consulta, porque ele guarda a armadilha mais cara do pgvector: com índice aproximado, o filtro é aplicado depois da varredura do índice. Você pede 3 resultados, o índice devolve os vizinhos mais próximos, o filtro derruba a maior parte e sobra 1 — ou nenhum. A resposta vem vazia e parece bug de modelo. A saída é o iterative scan (hnsw.iterative_scan), que faz o banco buscar mais candidatos até completar o LIMIT. Descobrir isso em produção, com um cliente perguntando por que o assistente "esqueceu" a regra, é caro.

Token é contexto, e contexto é escolha

O tutorial padrão manda os 10 trechos mais próximos para o modelo. É o maior desperdício silencioso de um RAG: você paga entrada por 10 trechos, o modelo lê 10 trechos e a resposta sai de 2.

No assistente que medi, o corpus é pequeno e bem delimitado: 16 documentos de regras viram 384 chunks, cerca de 530 mil caracteres, algo perto de 133 mil tokens. Cada pergunta leva 3 trechos, por volta de 1.400 tokens de contexto, mais a pergunta embedada. A indexação inteira, num modelo de embedding de US$ 0,02 por milhão de tokens, custa menos de um centavo de dólar. E reindexar toca só o que mudou, porque o hash do conteúdo decide o que é novo.

Três decisões fazem esse número ficar pequeno sem perder resposta:

  • Chunk com fronteira semântica. Cortar a cada mil caracteres é simples e quebra tabela, lista e regra no meio. Cortar por seção custa um dia de trabalho e melhora recall e resposta ao mesmo tempo.
  • Rerank antes de mandar. Trazer 20 candidatos da busca e mandar 3 para o modelo é mais barato e mais preciso do que mandar 10 direto.
  • Metadado como filtro, não como texto. Tenant, tipo de documento e versão entram no WHERE, não no prompt.

O ganho do RAG não é economia, é acerto com fonte

Existe um argumento de venda comum: "RAG economiza tokens porque você não precisa mandar o manual inteiro no prompt". A conta parece boa — mandar 133 mil tokens a cada pergunta, a um preço típico de US$ 3 por milhão de tokens de entrada, daria uns US$ 0,40 por pergunta.

Só que essa não é a alternativa real. Ninguém ia mandar o manual inteiro a cada pergunta. Sem RAG, a alternativa é o assistente não saber responder — ou pior, inventar uma regra que soa plausível.

O ganho do RAG é outro: acerto com fonte citada. Uma resposta que aponta de qual documento e de qual trecho ela saiu pode ser conferida por quem recebeu. Isso é o que permite usar o assistente em cima de regra de negócio, preço e política. Economia de token é consequência de um contexto bem escolhido, não o objetivo.

O dinheiro quase nunca está onde você procura

Ao medir o custo dessa plataforma, o RAG não era o problema. A indexação custa centavos, e o contexto por pergunta é pequeno.

O que apareceu foi outra coisa: em dezenas de milhares de chamadas ao modelo, o cache de prompt estava desligado — o contador de tokens lidos do cache estava zerado em todas elas. A feature mais cara, responsável pela maior parte da conta, manda cerca de 8,5 mil tokens de entrada por chamada, e boa parte disso é prefixo estável: regras de segurança, instruções de sistema, dados da oferta.

Leitura de cache custa cerca de 10% do preço da entrada normal (gravar custa por volta de 25% a mais que uma entrada comum, uma vez). Num item que domina a conta e repete o mesmo prefixo milhares de vezes por dia, a ordem de grandeza da economia é de centenas de dólares por mês.

Três detalhes decidem se isso funciona:

  • O cache é por prefixo. Um byte que muda no começo invalida tudo o que vem depois. Timestamp no system prompt, JSON com chave em ordem aleatória e lista de ferramentas que muda de ordem derrubam o cache inteiro.
  • Existe um tamanho mínimo. O prefixo precisa ter entre 512 e 4.096 tokens, dependendo do modelo. Abaixo disso ele simplesmente não é cacheado, em silêncio.
  • Dá para verificar. O campo de tokens lidos do cache na resposta responde em um minuto o que uma discussão de arquitetura leva uma semana para especular.

A lição que eu levo: antes de prometer economia, meça qual fatia do prompt é realmente fixa. O número honesto vem da medição, não da estimativa.

Há ainda uma armadilha de observabilidade que vale registrar. O gasto com embedding pode não aparecer no seu painel de custo de IA, porque o registro costuma ser um middleware que embrulha o modelo de linguagem — e o provedor de embedding não passa por ali. O custo é pequeno, mas o painel fica mentindo, e painel que mente é pior que painel que não existe — o mesmo padrão dos controles que ninguém testou.

O que eu meço antes de dizer que está pronto

  1. Orçamento de latência por etapa, com p95 medido em produção, não em média local.
  2. Recall da busca num conjunto de perguntas reais, antes de culpar o modelo pela resposta ruim.
  3. Tokens por resposta, separando prefixo fixo de contexto recuperado.
  4. Taxa de leitura do cache, que precisa ser maior que zero.
  5. Quanto da resposta é sustentado pelo contexto, com a citação do trecho de origem visível para quem lê.
  6. Um caminho de fallback determinístico para quando o modelo estiver fora do ar — mesmo que seja uma busca por padrões explícitos, respondendo menos e errando menos.

Nada disso aparece na demo. Todos aparecem na primeira semana de produção.

Leitura complementar

Fontes

Newsletter mensal da Aguiar Labs.

Uma ideia técnica por mês. Curta, sem enrolação.

Ao inscrever, você concorda em receber nossa newsletter e com nossa Política de Privacidade. Cancele a qualquer momento.

Continue lendo