Avançado 12 minAvançado

Agentic RAG local: quando vale a peine

O agentic RAG entrega a um modelo o controle da busca: ele decide o que procurar, lê o que encontrou e faz uma nova consulta se faltar alguma coisa. Esse loop tem um preço, principalmente em uma máquina local, onde cada rodada é paga em tempo de geração. Este guia explica o que muda em relação a um RAG clássico e em quais casos esse custo adicional se justifica, além de mostrar um exemplo completo com um modelo servido por Ollama e LangGraph.

Por Samir K.·Atualização 2026-11-02·Testado no Windows, macOS e Linux

#O agentic RAG em resumo

Um RAG clássico segue um caminho fixo: a pergunta dispara uma busca, os trechos encontrados vão para o prompt e o modelo responde. O agentic RAG substitui esse caminho por um loop. O modelo tem ferramentas de busca à disposição e decide sozinho se vai chamá-las, com qual consulta e quantas vezes, até avaliar que pode responder ou que deve desistir.

O curso AI Agents for Beginners, da Microsoft, descreve isso como um funcionamento em que o modelo planeja as próximas etapas enquanto busca informações em fontes externas, com um loop do tipo “maker-checker”: produzir, verificar, corrigir. Esse mesmo curso lembra o limite dessa autonomia: ela é exercida dentro da tarefa e das ferramentas que você forneceu.

A conclusão prática cabe em uma frase. Se o seu RAG falha porque uma única busca não consegue reunir toda a resposta, um loop pode ajudar. Se ele falha porque a ingestão ou o chunking estão ruins, o loop só vai repetir o problema, e mais devagar.

i
O que este guia não afirma
Nenhum ganho de precisão é anunciado aqui, por falta de medição nos seus dados. Nenhum benchmark foi realizado para este guia: as ordens de grandeza são cálculos ilustrativos, sinalizados como tal.

#Agentic RAG ou RAG de uma só passagem: a diferença

O kit completo para criar o seu próprio RAG local.

Aproveite a nossa experiência e um percurso guiado para construir o seu RAG local e trabalhar com os seus próprios documentos.

  • Espaço online vitalício
  • PDF + arquivos
  • Reembolsado em 30 dias

Os componentes básicos continuam os mesmos: embeddings, banco de dados vetorial, modelo de geração. Se eles não forem familiares para você, comece pela introdução ao RAG local. O que muda é quem decide a sequência de etapas. Em um RAG clássico, é o seu código; em um RAG agêntico, é o modelo, dentro dos limites que o código impõe a ele.

Consulta
RAG clássico: a pergunta do usuário, às vezes reescrita uma vez. Agêntico: o modelo formula as próprias consultas e pode decompor uma pergunta em várias.
Número de buscas
RAG clássico: uma, conhecida de antemão. Agêntico: variável de uma pergunta para outra, restrita por um limite que você define.
Fontes
RAG clássico: em geral, um único índice. Agêntico: várias ferramentas possíveis (índice vetorial, busca por palavras-chave, banco SQL), entre as quais o modelo escolhe.
Verificação do resultado
RAG clássico: nenhum, o modelo redige com o que recebeu. Agêntico: o modelo pode julgar os trechos insuficientes e buscar de novo, o que não é uma garantia: ele também pode errar nesse julgamento.
Exigência para o modelo
RAG clássico: qualquer modelo capaz de redigir a partir de trechos. Agêntico: um modelo que lide corretamente com chamadas de ferramentas.
Previsibilidade
RAG clássico: tempo de resposta bastante regular. Agêntico: tempo variável e caminho a ser verificado nos traces.

Três mecanismos compõem o loop. O planejamento: decompor a pergunta em subperguntas. O uso de ferramentas: traduzir cada subpergunta em uma chamada. A nova tentativa: ler o resultado e decidir se é preciso reformular ou concluir. Para a arquitetura geral de um agente (memória, proteções, supervisão), consulte o guia dedicado: aqui, só o loop de busca nos interessa.

Existe também um meio-termo muitas vezes esquecido: o pipeline de etapas fixas. Uma reescrita de consulta, uma busca híbrida e depois um reranker são executados sempre na mesma ordem, sem decisão do modelo. Isso não é agêntico, e costuma ser a primeira coisa a experimentar.

#Quando o agentic RAG vale a pena

O critério certo está na forma das suas perguntas, não no nível de sofisticação desejado. Observe as falhas reais do seu RAG atual e depois classifique-as.

Perguntas com vários saltos
A resposta a uma primeira busca determina a segunda: encontrar o fornecedor de um contrato e, depois, a cláusula que se aplica a esse fornecedor.
Comparações entre documentos
« Compare o aviso prévio dos contratos A e B » exige duas buscas distintas. Uma única consulta pode trazer cinco trechos do mesmo contrato.
Várias fontes de naturezas diferentes
Um número em um banco SQL e uma explicação em PDFs. O modelo escolhe a ferramenta de acordo com a pergunta, como descreve o curso da Microsoft para interações complexas com um banco de dados.
Tolerância à espera
Pesquisa documental, preparação de um dossiê, processamento em segundo plano: algumas dezenas de segundos a mais não incomodam ninguém se o resultado for revisado.
Exatidão com prioridade sobre a velocidade
Quando uma resposta incompleta sai caro, uma etapa de verificação se justifica, desde que se mantenha uma revisão humana nas decisões que geram compromissos.

Por outro lado, fique com um RAG simples nestas situações:

FAQ e perguntas de uma única fonte
A resposta está em um trecho: uma busca basta, e um loop só acrescenta espera.
Assistente conversacional em hardware modesto
O usuário espera uma resposta rápida e o modelo já roda perto dos próprios limites.
Busca que não encontra os trechos certos
Corrija primeiro a divisão, os embeddings e a busca híbrida. Repetir uma busca mal ajustada só traz outros resultados ruins.
Cálculo exato sobre dados estruturados
Uma consulta SQL escrita e testada é mais confiável do que um agente que improvisa uma.
Múltiplas relações entre entidades em todo o corpus
Se a necessidade é percorrer relações em grande escala, uma abordagem baseada em grafos responde a outro problema: veja o guia GraphRAG.

#O custo em latência e em modelo

Na nuvem, cada rodada do loop aparece na fatura. No ambiente local, ela aparece no relógio e na memória. Três itens pesam.

#A latência se multiplica

Para N buscas, o modelo gera N + 1 vezes: uma vez antes de cada busca e uma última para a resposta. Um RAG de uma só passada gera apenas uma vez. Como o prompt fica mais longo a cada rodada, cada geração relê mais texto, exceto o que o cache de contexto do runtime permite reutilizar. O tempo total depende do modelo, da quantização e da máquina; meça no seu ambiente em vez de confiar em um número genérico.

#O contexto enche rápido

Cálculo ilustrativo: 4 trechos de 1 200 caracteres representam cerca de 1 400 tokens, à razão de 3 a 4 caracteres por token. Cinco buscas acrescentam, portanto, cerca de 7 000 tokens, sem contar a pergunta, as instruções e os raciocínios do modelo. Com num_ctx em 8192, a margem quase desapareceu. Ollama então trunca o contexto, e os primeiros resultados, às vezes as instruções, podem sair da janela sem que o aplicativo avise claramente.

Aumentar num_ctx consome mais memória e deixa as rodadas seguintes mais lentas. Muitas vezes é melhor retornar menos trechos ou resumir o conteúdo deles antes de reinjetá-lo.

#O modelo precisa dar conta do loop

O modelo precisa produzir chamadas de ferramentas bem formadas e depois avaliar se o que leu é suficiente. Verifique o suporte com ollama show: a seção Capabilities deve mencionar tools. Essa verificação indica que o formato é suportado, não que o modelo toma boas decisões.

RTX 3060 12 GB ou RTX 4070 12 GB
Um modelo de 7 a 9B em Q4_K_M (referência do site: 7B ≈ 5 GB) deixa espaço para o contexto e o embedding. É o ponto de partida do exemplo abaixo, com qwen3.5:9b.
RTX 4080 16 GB
Um 14B em Q4_K_M (≈ 9 GB) cabe com uma margem mais confortável para um contexto ampliado.
RTX 4090 24 GB ou M4 Pro de 24 a 48 GB
Um modelo maior passa a ser viável, como qwen3.8:27b (cerca de 18 GB). Com 24 GB, fique de olho no que sobra depois de ampliar o contexto.
!
O vaivém entre dois modelos
O loop alterna embedding e geração. Se os dois modelos não couberem juntos na memória, o Ollama pode descarregar um para carregar o outro a cada rodada, e esse tempo se soma a todos os outros. Verifique com ollama ps durante uma execução e ajuste OLLAMA_MAX_LOADED_MODELS se necessário.

#Escolher um orquestrador

O orquestrador executa o loop: ele repassa as chamadas de ferramentas, devolve os resultados ao modelo e aplica os limites. Existem três caminhos, todos compatíveis com um modelo local.

Loop escrito à mão
Cerca de vinte linhas em torno da API de chat do Ollama e do parâmetro tools dela. Serve para entender o mecanismo ou para um caso muito simples. Você mesmo escreverá os limites e os traces.
LangGraph
O loop é um grafo explícito de nós e arestas, com estado, limite de recursão e streaming das etapas. Boa escolha se você quer controlar cada transição. É o que usamos no nosso exemplo.
LlamaIndex
Interessante se sua ingestão e seus índices já estiverem lá: os agentes dele reutilizam seus mecanismos de consulta como ferramentas.

Não escolha pela popularidade. Se o seu pipeline já roda com um framework, continue nele. Em todo caso, fixe suas versões: essas bibliotecas evoluem rápido e suas funções pré-construídas mudam. Por isso, nosso exemplo escreve o grafo explicitamente, o que também torna o loop legível.

#Pré-requisitos

Ollama
Instalado e escutando em http://localhost:11434.
Python
Um ambiente virtual recente. Verifique a versão exigida pelos pacotes no momento da instalação.
Documentos
Alguns arquivos Markdown ou de texto em uma pasta mes_documents. Para PDFs, retome a ingestão do tutorial do ChromaDB.
Memória
Cerca de 6 GB livres para um modelo de 9B e seu contexto, mais se você aumentar o num_ctx.

#Exemplo de agentic RAG com LangGraph e Ollama

O exemplo constrói um agente que dispõe de uma única ferramenta de busca, apoiada em um índice ChromaDB local. Ele é propositalmente mínimo para que o loop fique visível.

!
Código não executado para este guia
Este código segue as APIs documentadas dessas bibliotecas, mas não foi executado durante a redação, e nenhuma saída é reproduzida aqui. Teste-o em um corpus pequeno e consulte a documentação da versão que você instalar.

#Etapa 1: instalar os modelos e os pacotes

Terminal
ollama pull qwen3.5:9b
ollama pull nomic-embed-text
ollama show qwen3.5:9b

python -m venv .venv
source .venv/bin/activate
pip install langgraph langchain-ollama chromadb ollama
pip freeze > requirements.txt

#Etapa 2: indexar os documentos

A divisão por caracteres serve apenas para manter o exemplo curto. Em um corpus real, use uma divisão que respeite a estrutura e um modelo de embedding validado com seus textos em francês.

index.py
from pathlib import Path

import chromadb
import ollama

EMBED_MODEL = "nomic-embed-text"

client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection(
    "docs", metadata={"hnsw:space": "cosine"}
)


def decouper(texte, taille=1200, recouvrement=150):
    pas = taille - recouvrement
    return [texte[i:i + taille] for i in range(0, len(texte), pas)]


for fichier in Path("mes_documents").glob("*.md"):
    morceaux = decouper(fichier.read_text(encoding="utf-8"))
    if not morceaux:
        continue
    vecteurs = ollama.embed(model=EMBED_MODEL, input=morceaux)["embeddings"]
    collection.upsert(
        ids=[f"{fichier.name}-{i}" for i in range(len(morceaux))],
        documents=morceaux,
        embeddings=vecteurs,
        metadatas=[{"source": fichier.name} for _ in morceaux],
    )

print(collection.count(), "passages indexés")

#Etapa 3: escrever a ferramenta e o loop

A descrição da ferramenta importa: é ela que o modelo lê para decidir se vai chamá-la. A instrução de sistema exige buscar antes de responder, separar as subperguntas e admitir a ausência de informação.

agent.py
import chromadb
import ollama
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
from langgraph.graph import START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode, tools_condition

EMBED_MODEL = "nomic-embed-text"
collection = chromadb.PersistentClient(path="./chroma_db").get_collection("docs")


@tool
def chercher_documents(requete: str) -> str:
    """Cherche dans les documents internes. Utiliser une requête courte
    portant sur un seul sujet. Renvoie des passages précédés de leur source."""
    vecteur = ollama.embed(model=EMBED_MODEL, input=requete)["embeddings"][0]
    res = collection.query(query_embeddings=[vecteur], n_results=4)
    passages = zip(res["documents"][0], res["metadatas"][0])
    return "\n\n".join(f"[{m['source']}] {d}" for d, m in passages) or "Aucun passage."


outils = [chercher_documents]
llm = ChatOllama(model="qwen3.5:9b", temperature=0, num_ctx=8192).bind_tools(outils)

CONSIGNE = SystemMessage(content=(
    "Tu réponds uniquement à partir des résultats de chercher_documents. "
    "Si la question porte sur plusieurs sujets, fais une recherche par sujet. "
    "Si les passages ne suffisent pas, reformule une fois puis dis clairement "
    "ce que tu n'as pas trouvé. Cite la source entre crochets."
))


def agent(state: MessagesState):
    return {"messages": [llm.invoke([CONSIGNE] + state["messages"])]}


graphe = StateGraph(MessagesState)
graphe.add_node("agent", agent)
graphe.add_node("tools", ToolNode(outils))
graphe.add_edge(START, "agent")
graphe.add_conditional_edges("agent", tools_condition)
graphe.add_edge("tools", "agent")
app = graphe.compile()

if __name__ == "__main__":
    question = "Compare la durée de préavis du contrat A et du contrat B."
    entree = {"messages": [HumanMessage(content=question)]}
    for etape in app.stream(entree, {"recursion_limit": 12}, stream_mode="values"):
        etape["messages"][-1].pretty_print()

#Etapa 4: ler o trace

A vantagem de stream_mode="values" é mostrar cada mensagem. Leia o trace antes da resposta final, com a ajuda desta grade:

  1. 01
    O modelo chama a ferramenta?
    Se ele responde diretamente, não está buscando: reforce a instrução ou troque de modelo.
  2. 02
    As consultas fazem sentido?
    Para a comparação, o ideal é esperar uma consulta por contrato. Uma única consulta repetindo a pergunta inteira indica que a decomposição não está acontecendo.
  3. 03
    Os trechos respondem à pergunta?
    Se os trechos estiverem fora do assunto, o problema está no índice, não no agente.
  4. 04
    A resposta se baseia nos trechos?
    Confira cada citação entre colchetes no trecho correspondente.

#Etapa 5: limitar o loop

Cada busca consome duas etapas do grafo (agente e depois ferramenta). Um limite de 12 permite, portanto, cinco buscas e depois a resposta final. Além disso, o LangGraph lança um erro GraphRecursionError (módulo langgraph.errors): capture-o na sua aplicação e retorne uma mensagem clara, em vez de deixar o usuário diante de um stack trace.

#Armadilhas e solução de problemas

O modelo nunca chama a ferramenta
Verifique tools em ollama show, reformule a descrição da ferramenta e experimente outro modelo. Não tente compensar com uma instrução cada vez mais longa.
Ele repete a mesma busca
O modelo está andando em círculos. Reduza o limite e, na ferramenta, retorne uma mensagem clara quando a consulta já tiver sido feita.
A resposta esquece os primeiros resultados
Sinal provável de contexto truncado. Reduza n_results, divida em partes menores ou aumente num_ctx se a memória permitir.
As respostas ficam muito lentas
Confira o ollama ps: talvez parte do modelo esteja no processador, ou os modelos estejam se revezando na memória. Conte também o número de turnos no trace.
Ele inventa mesmo sem ter encontrado nada
O loop não impede a invenção de informações. Verifique as citações por programa: cada fonte citada deve constar nos resultados de ferramenta da conversa.
Uma ferramenta poderosa demais
Um agente que lê documentos também recebe o conteúdo deles, possivelmente hostil. Dê a ele ferramentas somente leitura e uma validação humana para qualquer ação que modifique algo.
→
Experimente primeiro sem agente
Antes de adicionar um loop, teste uma decomposição fixa: uma geração que divide a pergunta em subperguntas, uma busca por subpergunta e depois uma resposta. Se isso resolver suas comparações, você mantém um tempo de resposta previsível e um código mais simples.

#Decidir com base nas suas próprias perguntas

Os números publicados em outros lugares se referem a outros corpora, outros modelos e outras configurações. Só uma comparação com os seus dados permite decidir, e ela não exige muito hardware.

  1. 01
    Montar um conjunto de perguntas
    Escolha perguntas reais cuja resposta e cujos trechos de origem você conhece, misturando perguntas simples e perguntas de múltiplos saltos. Registre o tipo de cada pergunta.
  2. 02
    Definir uma referência
    Passe essas perguntas pelo seu RAG atual, sem agente. Anote se o trecho certo foi recuperado, se a resposta está correta e o tempo total.
  3. 03
    Mudar uma única coisa
    Execute o mesmo conjunto com o agente, no mesmo índice e com o mesmo modelo, na mesma máquina.
  4. 04
    Ler por tipo de pergunta
    Observe o resultado separadamente para as perguntas simples e as complexas, e anote o número de buscas por pergunta. Uma média global pode esconder um ganho em umas e uma perda de tempo em outras.
  5. 05
    Manter o que se justifica
    Se apenas algumas perguntas se beneficiarem, um roteamento pode bastar: RAG direto por padrão e loop para as perguntas detectadas como complexas.

Para automatizar a parte de qualidade dessa comparação, o guia dedicado ao Ragas apresenta métricas adequadas. Anote também a versão dos pacotes, o modelo, a quantização e o num_ctx: sem isso, seu resultado não será comparável no mês seguinte.


#Para se aprofundar

O agentic RAG se apoia em um RAG que já funciona. Estes guias abordam a base que deve ser estabilizada primeiro, as abordagens próximas e a arquitetura de agente.

Este guia ajudou você?

Um comentário, um erro ou uma observação? Avise-nos; isso ajuda a melhorar o guia para todos.