Como eu fiz o RAG ficar 100x mais rápido sem perder nada importante
Resumo rápido
RAG normal é burro: toda vez que você pergunta, ele olha pra TODOS os documentos do teu corpus. Custa O(n), ou seja, quanto mais documentos, mais explode a conta. Eu fiz o Lazy RAG: primeiro acha uns candidatos baratinho com busca aproximada (FAISS, O(log n) ou quase), depois só olha direitinho pros k melhores.
Testei 20 vezes num corpus de 1001 documentos (com uma “agulha” escondida). Resultado: recall perfeito (1.0000) em tudo, mas com k=10 o custo caiu 99% e ficou 100x mais rápido que o RAG guloso. Todas as configs que testei (k=10,20,50,100) batem o baseline em tudo: mesma precisão, custo bem menor.
O pulo do gato: o caro não é achar candidato — é calcular score exato em 384 dimensões pra todo mundo. Lazy RAG só faz o caro onde vale a pena. Simples assim.
Por que isso importa
RAG virou padrão pra bot responder com conhecimento externo, mas todo mundo aceita que o retrieval é o gargalo. O jeito clássico (olha tudo) é preguiçoso no sentido ruim — gasta recurso à toa.
Eu pensei: e se a gente for preguiçoso no sentido bom? Só calcula o que realmente precisa. Lazy evaluation clássica: não faz nada até alguém pedir. Apliquei isso no retrieval.
Como funciona (sem firula)
RAG guloso (o normal)
Query → codifica → compara com TODOS os docs → pega top-k.
Custo: O(n) comparações caras toda vez.
Lazy RAG (o meu)
Fase barata: FAISS acha k candidatos rápidos (aproximado ou exato com IndexFlatIP).
Fase cara: só nesses k você calcula score exato.
Resultado: custo total ~ O(log n + k). Se k pequeno, explode menos que O(n).
O experimento (bem simples)
Corpus fake de 1001 docs (1000 normais + 1 agulha randômica).
Embeddings: all-MiniLM-L6-v2 (o padrãozinho).
20 runs independentes.
Métricas: recall@1 (se achou a agulha), custo (quantas comparações caras), speedup.
Tabela final (média das 20 rodadas):
Eager RAG → recall 1.0 | custo 1001 | speedup 1x
Lazy k=10 → recall 1.0 | custo 10 | speedup 100x (99% menos) ✓
Lazy k=20 → recall 1.0 | custo 20 | speedup 50x ✓
Lazy k=50 → recall 1.0 | custo 50 | speedup 20x ✓
Lazy k=100 → recall 1.0 | custo 100 | speedup 10x ✓
Todas batem o guloso em tudo. Sem perda de recall, só economia bruta.
Por que isso funciona mesmo
Embedding space é estruturado — documentos parecidos ficam perto. A busca barata já acha o caminho certo 100% das vezes nesse teste. O caro (score exato em 384 dims) só precisa rodar em 10–100 docs, não em 1000+.
É o mesmo truque que o universo usa: não calcula tudo, só colapsa onde olha.
Limitações (pra não enrolar)
Corpus pequeno (1k docs). Em milhões pode mudar.
Usei IndexFlatIP (exato). Com IVF/HNSW o recall pode cair um pouquinho.
Índice offline (custa pra construir, mas amortiza).
Teste controlado (sintético). Precisa rodar em NQ, BEIR, etc.
Próximos passos que eu quero fazer
Testar em benchmarks reais (BEIR, Natural Questions).
k adaptativo (olha a confiança da fase 1 e decide k).
Juntar com memória persistente (reforçar docs que são úteis sempre).
Ver se P(t) (a métrica de persistência do meu outro projeto) prevê quanto o sistema aguenta carga.
Conclusão curta
Lazy RAG ganha do RAG guloso em tudo que testei: mesma qualidade, custo muito menor.
O segredo é simples: não faça trabalho caro onde não precisa.
Isso vale pra retrieval, vale pra LLM, vale pra quase qualquer sistema que tem recurso finito.
O universo faz isso há bilhões de anos. A gente só tá copiando o truque.
Código público: https://github.com/ThiagoSilm/Universe-simulator
Pergunta, crítica, fork, whatever — tô aqui.
Thiago Maciel
2026