← Voltar para o Blog

RAG na prática: o que a sua infraestrutura precisa ter

A demonstração roda em um notebook em uma tarde. O que quebra na produção é a reindexação, o custo de embeddings e a busca que devolve o trecho errado com muita confiança.

Equipe EasyOps Cloud · · 8 min de leitura

RAG — retrieval-augmented generation — é a técnica de buscar trechos relevantes na sua base antes de perguntar ao modelo, para que ele responda com o seu conteúdo em vez de com o que memorizou. O protótipo é famoso por ser fácil: cem páginas de PDF, um banco vetorial em memória e uma tarde de trabalho.

O que separa esse protótipo de um sistema em produção não é o modelo. É encanamento: ingestão, reindexação, custo por documento e uma forma de saber se a busca está trazendo o trecho certo.

As quatro peças

Vale separar o sistema antes de escolher ferramenta:

  1. Ingestão — ler o documento, extrair texto, dividir em pedaços.
  2. Embeddings — transformar cada pedaço em um vetor.
  3. Armazenamento e busca — guardar os vetores e achar os mais próximos.
  4. Montagem e geração — juntar os trechos no prompt e chamar o modelo.

A qualidade da resposta é decidida quase inteiramente nas etapas 1 e 3. A etapa 4 é a mais visível e a que menos costuma ser o problema — quando o sistema "alucina", na grande maioria dos casos ele recebeu o trecho errado e respondeu bem a partir dele.

O passo que mais afeta o resultado: como você divide o texto

Dividir por número fixo de caracteres é o padrão de todo tutorial e a causa de boa parte dos resultados ruins. Um corte no meio de uma frase produz um pedaço que não significa nada sozinho — e a busca compara justamente o significado.

O que funciona melhor, em ordem:

  • Dividir por estrutura, não por tamanho: seção, subtítulo, item de FAQ, artigo de contrato. O documento já traz a fronteira semântica; use-a.
  • Manter sobreposição entre pedaços vizinhos (uns 10% a 20%), para que uma informação que caia na fronteira apareça inteira em pelo menos um deles.
  • Guardar contexto junto do pedaço: título do documento, seção, data, identificador. Serve para filtrar na busca e para citar a origem na resposta.
  • Não misturar tipos de conteúdo no mesmo índice sem um campo que distinga documentação, contrato e ticket. São registros com precisões diferentes.

Um pedaço na faixa de 300 a 800 tokens costuma ser um bom ponto de partida — mas teste com o seu material, porque a resposta certa depende do formato dele.

Banco vetorial: comece pelo que você já opera

A escolha aqui é menos importante do que parece, e o custo de errar para mais é alto: um banco vetorial dedicado é mais um serviço para manter de pé, monitorar, atualizar e fazer backup.

Se você já usa PostgreSQL, comece com pgvector. Ele resolve confortavelmente até a casa dos milhões de vetores, e traz uma vantagem que os dedicados nem sempre têm: filtro relacional e busca vetorial na mesma consulta, dentro da mesma transação, no mesmo backup.

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE chunk (
  id          bigserial PRIMARY KEY,
  doc_id      text NOT NULL,
  secao       text,
  conteudo    text NOT NULL,
  embedding   vector(768) NOT NULL,
  atualizado  timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX ON chunk USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON chunk (doc_id);

A consulta junta as duas naturezas sem esforço:

SELECT conteudo, secao, 1 - (embedding <=> $1) AS score
FROM chunk
WHERE doc_id LIKE 'manual/%'
ORDER BY embedding <=> $1
LIMIT 8;

Duas notas práticas sobre o índice: ele é aproximado, então a busca pode não devolver o vizinho mais próximo real — é a troca que a torna rápida. E construir um índice HNSW consome bastante memória; em base grande, faça isso em janela de manutenção e acompanhe o maintenance_work_mem.

Migre para um banco dedicado quando tiver uma razão medida: dezenas de milhões de vetores, exigência de latência muito baixa com alta concorrência, ou necessidade de escalar a busca separada do banco transacional. Antes disso, é complexidade adiantada.

Dimensionamento: memória de novo

O tamanho bruto dos vetores é fácil de estimar: dimensões × 4 bytes por vetor.

Vetores768 dimensões1536 dimensões
100 mil~300 MB~600 MB
1 milhão~3 GB~6 GB
10 milhões~30 GB~60 GB

Some o índice (que costuma ocupar de metade a uma vez o tamanho dos vetores), o texto original e o restante do banco. O número que importa é o quanto disso cabe em memória: busca vetorial com índice fora do cache vira leitura de disco a cada consulta, e a latência sai de milissegundos para centenas deles.

Duas consequências de projeto:

  • Menos dimensões é mais barato para sempre. Um modelo de embedding de 768 dimensões custa metade da memória de um de 1536 para o resto da vida do sistema. Se a qualidade for equivalente no seu material, a escolha é óbvia.
  • Guarde o documento original fora do banco. O PDF, o DOCX e o anexo vão para Object Storage; o banco guarda o texto extraído, o vetor e a referência. Isso mantém o banco pequeno o suficiente para caber em memória e para restaurar rápido.

O método de dimensionamento é o mesmo de sempre, com a memória mandando: como escolher CPU, memória e disco.

Ingestão é um pipeline, não um script

No protótipo, a ingestão é um for que processa uma pasta. Em produção ela precisa de propriedades que esse for não tem:

  • Idempotência. Reprocessar o mesmo documento não pode duplicar pedaços. Use uma chave estável — doc_id mais índice do pedaço — com ON CONFLICT DO UPDATE.
  • Detecção de mudança. Guarde o hash do conteúdo. Se não mudou, não gere embedding de novo. É a otimização de maior retorno do sistema inteiro, porque embedding é o custo recorrente.
  • Remoção. Documento apagado na origem precisa sumir do índice. É o defeito mais constrangedor de um RAG: responder com base em um documento que foi revogado.
  • Fila e retentativa. Extração de PDF falha, API de embedding devolve 429. Precisa retomar do ponto em que parou, não do começo.
  • Lote. Gere embeddings em lotes; uma chamada por pedaço multiplica latência e, em API paga, custo por requisição.

O pipeline roda em fila ou em janela agendada — e, se for agendada, vale ler antes por que o seu cron não rodou, porque uma ingestão que falha em silêncio produz exatamente o sintoma mais difícil de perceber: o sistema continua respondendo, só que com a base de duas semanas atrás.

Registre a data da última indexação bem-sucedida em algum lugar visível. "Desde quando o índice está velho?" precisa ter resposta.

O que fazer quando o modelo de embedding mudar

Este é o custo que surpreende. Vetores gerados por modelos diferentes não são comparáveis. Trocar o modelo de embedding significa reprocessar a base inteira.

Trate isso como migração de esquema, porque é:

  • Guarde na tabela qual modelo e qual versão gerou cada vetor.
  • Ao migrar, escreva os vetores novos em uma coluna ou tabela nova, indexe, valide, e só então troque a leitura. Reindexar por cima deixa o sistema devolvendo lixo durante a janela.
  • Estime o custo antes: número de pedaços × tokens médios. Em base grande, uma troca de modelo é uma decisão orçamentária, não técnica.

É mais um argumento a favor de rodar o modelo de embedding na sua infraestrutura: embeddings são baratos de gerar em CPU comparados a geração de texto, e uma reindexação total deixa de ter custo por token.

Você precisa de um jeito de medir a busca

Sem isso, todo ajuste vira opinião. O mínimo viável é um conjunto de perguntas reais com o trecho que deveria ser recuperado para cada uma. Cinquenta pares já mudam a conversa.

Com esse conjunto, duas métricas bastam para começar:

  • Recall@k — em que fração das perguntas o trecho correto aparece entre os k primeiros. Se estiver baixo, o problema é a divisão do texto ou o embedding; mexer no prompt não resolve.
  • Precisão do topo — quanto do que veio nas primeiras posições é realmente relevante. Ruim aqui significa contexto poluído, que aumenta custo e piora a resposta.

E rode esse conjunto como teste, no CI, a cada mudança de divisão, de modelo ou de parâmetro de busca. É a diferença entre "ficou melhor" e "melhorou 12% no recall".

Dois ajustes costumam dar o maior salto de qualidade, nesta ordem: busca híbrida — combinar a vetorial com busca textual clássica, porque termos exatos como código de erro e número de contrato são justamente o ponto fraco da semântica — e reordenação dos candidatos por um modelo mais preciso antes de montar o prompt.

Operação: o de sempre, que continua valendo

RAG não inventa uma disciplina nova de operação; ele só adiciona um banco a mais na lista do que precisa sobreviver a um acidente.

  • Backup do banco vetorial. Reindexar do zero pode custar horas e dinheiro real em API. Restaurar de backup custa minutos. O script de dump e envio para bucket serve tal como está.
  • Snapshot antes de migração de índice ou de extensão. Um CREATE INDEX em tabela grande e uma atualização de extensão são exatamente o tipo de mudança que vale reverter em um clique.
  • Segredos e prompts. O que vai no prompt sai da sua rede, se você usa API. Os controles estão em colocar IA no produto sem vazar dado do cliente.
  • Métrica de latência por etapa. Meça busca e geração separadamente. Quando o usuário reclamar de lentidão, você precisa saber qual das duas cresceu.

Comece pequeno: um índice, um modelo de embedding, pgvector, cinquenta perguntas de avaliação. Quase todo sistema de RAG que dá certo em produção é mais simples do que a arquitetura desenhada na primeira reunião — e tem mais cuidado com a ingestão do que a primeira reunião imaginou.

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta