RAG estático recupera de uma vez. RAG agêntico decide: busca? o quê? quantas vezes? Você ganha em qualidade (multi-hop, query refinement) e perde em custo/latência. Este módulo é beta — padrões ainda evoluem rapidamente.
⚖️ Trade-off explícito: custo vs qualidade
RAG agêntico é uma promoção condicional do RAG estático — só compensa quando a pergunta REALMENTE exige.
- •Pergunta single-hop, fonte clara → RAG estático.
- •Pergunta multi-hop, fontes múltiplas → RAG agêntico (com cap).
- •Verificação crítica → + critic loop.
- •Sempre: max_iterations + budget cap.
💡 Comece estático, escale para agêntico
Antes de adotar RAG agêntico, esgote RAG estático com reranker e contextual retrieval. Ganho de 3.2 frequentemente fecha a lacuna sem custo agêntico.
🔄 Multi-hop: encadear buscas
Quando uma busca não basta
Multi-hop é quando a resposta exige encadeamento de buscas. Ex.: 'compare a janela de contexto do Claude 3 com a do GPT-4 em 2024' — 2 buscas (uma por modelo) + 1 comparação. RAG estático despeja tudo em 1 query; agêntico faz busca dirigida por etapa.
perguntas que multi-hop resolve melhor
- ▸Comparação ('A vs B em métrica X')
- ▸Ranking ('quais os 3 maiores X em 2024')
- ▸Encadeamento causal ('por que isso aconteceu, dado este contexto')
- ▸Verificação cruzada ('isso bate com o que disse Y?')
📑 Resumo navegável
🤔 Self-RAG: decidir se buscar
Asai et al. 2023
Self-RAG (Asai et al. 2023): o modelo emite token especial decidindo se precisa buscar. Reduz custo em queries triviais ('o que é 2+2') e mantém qualidade em queries factuais. Versão simplificada para produção: classificar a query antes do retrieval.
def decidir_busca(query: str) -> bool:
decisor = llm.generate(
f'Para responder esta query, preciso de busca em base externa? Responda só sim ou não.\n'
f'Query: {query}'
)
return decisor.strip().lower().startswith('sim')
if decidir_busca(query):
docs = retriever.search(query)
resposta = llm_responder_com_contexto(query, docs)
else:
resposta = llm_responder_direto(query)
📑 Resumo navegável
🧭 Query decomposition
Quebrar pergunta complexa
Para perguntas compostas, decompor em sub-perguntas melhora recall. LLM faz a decomposição; cada sub-pergunta vira busca; respostas são combinadas. Cuidado: cada sub-busca custa; cap em 3-5 sub-perguntas é sensato.
exemplo de decomposição
- ▸Query: 'compare janela do Claude 3 e GPT-4 em 2024'
- ▸Sub-1: 'qual a janela do Claude 3 em 2024?'
- ▸Sub-2: 'qual a janela do GPT-4 em 2024?'
- ▸Combinação: LLM recebe ambas respostas e gera comparação final.
📑 Resumo navegável
🛡️ Guards: critic step e verificação
Checar antes de entregar
Critic step é um segundo passo: outro LLM (ou o mesmo com prompt diferente) verifica se a resposta está grounded. Se não, refaz a busca. Custo: 2× tokens; ganho: redução de alucinação em casos críticos. Usar com critério — não em todas as queries.
def rag_com_critic(query, max_tries=2):
for _ in range(max_tries):
docs = retriever.search(query)
resp = gerar(query, docs)
crit = llm.generate(
f'A resposta abaixo está grounded no contexto?\n'
f'<ctx>{docs}</ctx>\n<resp>{resp}</resp>\n'
'Sim/Não + 1 frase.'
)
if crit.startswith('Sim'):
return resp
return 'Não foi possível responder com confiança.'
📑 Resumo navegável
🚦 Stopping criteria
Quando o agente para de buscar
Sem critério de parada explícito, agente loopa em produção e queima orçamento. Defina: max_iterations (3-5 típico), confiança mínima da resposta, OU custo máximo em tokens. O primeiro que disparar para o loop. Isto é pré-requisito de qualquer rollout.
def agentic_rag(query, max_iter=3, max_tokens=20_000):
tokens_usados = 0
for i in range(max_iter):
if tokens_usados > max_tokens:
return 'budget exceeded', tokens_usados
resp = um_passo(query, ...)
tokens_usados += resp.tokens
if resp.confianca > 0.85:
return resp, tokens_usados
return 'max_iter sem convergência', tokens_usados
📑 Resumo navegável
💸 Quando NÃO usar RAG agêntico
O custo é real
RAG agêntico é tentador mas frequentemente injustificado. Em 80% dos casos, RAG estático com reranker e contextual retrieval resolve a custo 3-10× menor. Antes de adotar agêntico, esgote o estático e meça o gap real com seu golden set.
| Sinal | Estático | Agêntico |
|---|---|---|
| Pergunta single-hop | ✓ default | ✗ overhead |
| Multi-hop confirmado em eval | ✗ recall baixo | ✓ vale custo |
| Latência crítica (UX live) | ✓ | ✗ múltiplos roundtrips |
| Volume 1k+/dia | ✓ econômico | depende — meça |
📑 Resumo navegável
📑 Resumo navegável dos tópicos
1 🔄 Multi-hop: encadear buscas — Quando uma busca não basta
2 🤔 Self-RAG: decidir se buscar — Asai et al. 2023
3 🧭 Query decomposition — Quebrar pergunta complexa
4 🛡️ Guards: critic step e verificação — Checar antes de entregar
5 🚦 Stopping criteria — Quando o agente para de buscar
6 💸 Quando NÃO usar RAG agêntico — O custo é real
✓ O que FAZER
- ✓max_iterations explícito (ex.: 3)
- ✓Budget de tokens por chamada agêntica
- ✓Logs de cada hop com query e resultado
- ✓RAG agêntico só onde estático falha
✗ O que NÃO fazer
- ✗Loop indefinido
- ✗Custos fora de controle
- ✗Debug impossível em produção
- ✗Adotar por padrão
🚫 Quando NÃO usar
- •Latência baixa exigida: cada hop é uma roundtrip.
- •Volume alto: custo escala linearmente.
- •Quando RAG estático já passa em eval: complexidade extra é dívida técnica.
💻 Exemplo de código
# Pseudo-código de loop agêntico simplificado
def agentic_rag(query: str, max_hops: int = 3) -> dict:
historico = []
for hop in range(max_hops):
decisao = llm_decide(query, historico) # buscar? parar? refinar?
if decisao == "parar":
return llm_responder_final(query, historico)
elif decisao == "buscar":
sub_query = llm_refinar_query(query, historico)
chunks = retriever.search(sub_query, k=5)
historico.append({"hop": hop, "query": sub_query, "chunks": chunks})
return llm_responder_final(query, historico) # fallback
🏋️ Exercício hands-on
Implemente RAG agêntico com max 3 hops contra um conjunto multi-hop de 10 perguntas. Compare com RAG estático: medir custo e acurácia.
📚 Bibliografia
- Asai et al. (2023) — Self-RAG: Learning to Retrieve, Generate, and Critique
- Yao et al. (2022) — ReAct: Synergizing Reasoning and Acting
- Trivedi et al. (2022) — Multi-Hop QA via Iterative Retrieval
- Anthropic (2024) — Contextual Retrieval
🎯 Resumo do Módulo
- ✓Multi-hop resolve perguntas que single-hop falha.
- ✓Self-RAG: decidir se buscar reduz custo em casos triviais.
- ✓Decomposition: quebrar pergunta complexa em sub-perguntas.
- ✓Stopping criteria obrigatório (max_iterations, budget).
- ✓Default ao simples: estático com reranker resolve 80% dos casos.
Próximo Módulo:
T4 — Tools, Agentes e Multi-Agente