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:
- Ingestão — ler o documento, extrair texto, dividir em pedaços.
- Embeddings — transformar cada pedaço em um vetor.
- Armazenamento e busca — guardar os vetores e achar os mais próximos.
- 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.
| Vetores | 768 dimensões | 1536 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_idmais índice do pedaço — comON 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
kprimeiros. 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 INDEXem 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.