GraphRAG Mão na Massa: Do Zero à Consulta Multi-hop
Lede: O artigo anterior explicou por que GraphRAG. Este é o guia de campo: instalar, indexar, escolher o método de busca e depurar quando a resposta sai ruim. Dois caminhos — o CLI da Microsoft, que resolve em três comandos, e o Python do Neo4j, que te dá controle total. Com os custos reais, os
--dry-runque você deveria usar e os erros que só aparecem em produção.
🧰 O que você leva daqui:
Microsoft GraphRAG do zero:
init→index→query, com o que cada método exigeNeo4j +
neo4j-graphragem código: índice vetorial, retrievers e pipelineTabela de decisão: qual método de busca para qual pergunta
Custo real de indexação e os 6 erros mais comuns
1. Antes de começar: o que essa coisa custa
GraphRAG não é "RAG com mais poder". O preço vem na indexação: um LLM é chamado para extrair entidades, relações e claims de cada chunk, e depois chamado de novo para escrever um relatório por comunidade. O corpus não é consultado uma vez — é processado com custo de geração.
| Etapa | Chamadas de LLM | Escala com |
|---|---|---|
| Chunking e embedding | 0 (embeddings são baratos) | Nº de chunks |
| Extração de grafo | ~1 por chunk | Nº de chunks |
| Relatórios de comunidade | 1 por comunidade | Nº de comunidades |
| Busca local | 1 por pergunta | — |
| Busca global | N por pergunta (map-reduce) | Nº de relatórios relevantes |
💸 A causa nº 1 de surpresa na fatura: indexar 50.000 documentos não é uma tarefa de background, é uma despesa. Rode o
--dry-runantes, comece com 200 documentos e só escale quando a qualidade do grafo estiver aceitável. Índice mal feito é mais caro que refazer.
Requisitos: Python 3.10, 3.11 ou 3.12 (o Microsoft GraphRAG não suporta 3.13+), um provedor de LLM com completion e embeddings, e um lugar para guardar o grafo.
2. Caminho 1 — Microsoft GraphRAG pelo CLI
É o caminho mais rápido: três comandos e você tem um sistema funcional.
2.1 Instalação e inicialização
pip install graphrag graphrag init --root ./meu-projeto
O init é interativo: pergunta o modelo de completion e o de embeddings. Ele gera a estrutura:
meu-projeto/ ├── settings.yaml # configuração do pipeline ├── .env # chaves de API └── input/ # coloque seus documentos aqui
🧩 Reexecute o
inita cada upgrade de versão. O formato dosettings.yamlevoluiu entre minors e o init é o que te dá o template novo. Rodargraphrag init --root ./meu-projeto --forcedepois de um bump de versão é o passo que quase todo mundo pula.
Coloque os documentos em input/. O padrão do loader aceita texto, CSV e JSON, e você configura o padrão de arquivo.
2.2 O settings.yaml — só o que importa
O arquivo gerado tem dezenas de campos. Estes são os que você realmente mexe:
# models models: completion: type: openai_chat model: gpt-4o api_key: ${OPENAI_API_KEY} max_tokens: 4000 temperature: 0.0 embeddings: type: openai_embeddings model: text-embedding-3-large api_key: ${OPENAI_API_KEY} dimensions: 1536 # chunking — o parâmetro que mais afeta a qualidade do grafo chunks: size: 1200 overlap: 100 # detecção de comunidades community_detection: max_cluster_size: 10 use_lcc: true seed: 12345 # saída output_storage: type: file base_dir: ./output
O chunks.size é a alavanca mais subestimada: chunk pequeno demais quebra entidades ao meio e fragmenta o grafo; chunk grande demais junta contextos diferentes e cria arestas falsas. Comece em 1200 com overlap de 100.
2.3 Indexar — e testar antes de gastar
# valida a configuração sem executar nada graphrag index --root ./meu-projeto --dry-run # executa de verdade, com log verboso graphrag index --root ./meu-projeto -m standard -v
Métodos de indexação:
| Método | Quando usar |
|---|---|
standard | Indexação completa. Padrão. Use na primeira vez |
fast | Sem extração de claims nem embeddings de comunidade. ~metade do custo, menos qualidade |
standard-update | Reindexa incrementalmente documentos novos |
fast-update | Variante incremental enxuta |
Ao terminar, ./output/ fica cheio de arquivos Parquet — é isso que as buscas leem.
2.4 Consultar
graphrag query "Quais são os principais riscos operacionais?" \ --root ./meu-projeto \ --method global
2.5 Os quatro métodos, e o que cada um exige
| Método | Para que pergunta | Tabelas Parquet exigidas |
|---|---|---|
basic | Baseline de similaridade vetorial, sem grafo | text_units |
local | Foco em entidade e vizinhança: "Quem são os dependentes do serviço X?" | entities, communities, community_reports, text_units, relationships (+ covariates se existir) |
global | Síntese do corpus inteiro: "Quais são os temas recorrentes?" | entities, communities, community_reports |
drift | Começa na entidade, sobe para a comunidade: "Por que o componente Y falha?" | entities, communities, community_reports, text_units, relationships |
2.6 Ajustes que mudam a resposta
# nível da hierarquia Leiden — padrão 2. MAIOR = comunidades MENORES = mais específico graphrag query "..." --method global --community-level 1 # panorâmico graphrag query "..." --method global --community-level 3 # detalhado # seleção dinâmica de comunidades: só carrega os relatórios relevantes graphrag query "..." --method global --dynamic-community-selection # formato da resposta graphrag query "..." --method local --response-type "List of 3-5 Points" # streaming graphrag query "..." --method local --streaming
🎛️
--community-levelé o botão de dial mais útil que existe no GraphRAG. Padrão2. Valor menor = comunidades maiores = síntese mais panorâmica e barata. Valor maior = comunidades menores = mais detalhe, mais custo. Se a resposta está rasa demais, suba o nível antes de culpar o modelo.
2.7 Ajustar os prompts ao seu domínio
O prompt de extração de entidades é genérico e erra em jargão da sua área.
graphrag prompt-tune --root ./meu-projeto
Isso usa uma amostra dos seus documentos para reescrever os prompts de extração. Em domínio técnico, é o passo que mais melhora a qualidade do grafo por hora de trabalho investida.
3. Caminho 2 — Neo4j com neo4j-graphrag
Quando você quer o grafo consultável com Cypher, versionado, e integrado ao resto da sua stack.
3.1 Instalação
pip install "neo4j-graphrag[openai]"
O pacote suporta OpenAI, Azure OpenAI, Anthropic, Google Vertex, Cohere, Mistral e Ollama. Python >= 3.10.
3.2 Índice vetorial e carga
from neo4j import GraphDatabase from neo4j_graphrag.indexes import create_vector_index, upsert_vectors from neo4j_graphrag.types import EntityType URI = "neo4j://localhost:7687" AUTH = ("neo4j", "sua-senha") driver = GraphDatabase.driver(URI, auth=AUTH) create_vector_index( driver, "artigo-embedding", label="Artigo", embedding_property="vetor", dimensions=1536, # tem que bater com o modelo de embedding similarity_fn="cosine", ) upsert_vectors( driver, ids=["art-001", "art-002"], embedding_property="vetor", embeddings=[v1, v2], entity_type=EntityType.NODE, )
🔢 O erro mais silencioso dessa biblioteca:
dimensionsdivergente do modelo. O índice aceita, a consulta retorna resultado errado, e não avisa nada. Confira antes:text-embedding-3-smalle3-largesão 1536 dimensões,text-embedding-3-largecomdimensions=256é outra configuração válida — mas tem que ser a mesma na criação e na consulta.
3.3 Pipeline de geração
from neo4j_graphrag.retrievers import VectorRetriever from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings from neo4j_graphrag.llm.openai_llm import OpenAILLM from neo4j_graphrag.generation import GraphRAG embedder = OpenAIEmbeddings(model="text-embedding-3-large") llm = OpenAILLM(model_name="gpt-4o", model_params={"temperature": 0}) retriever = VectorRetriever( driver, index_name="artigo-embedding", embedder=embedder, return_properties=["titulo", "texto"], ) rag = GraphRAG(retriever=retriever, llm=llm) resposta = rag.search(query_text="Como indexar no PostgreSQL?", retriever_config={"top_k": 5}) print(resposta.answer)
3.4 O que faz ser GraphRAG: o retriever com Cypher
Aqui é a virada. Você recupera os nós por similaridade e depois percorre o grafo:
from neo4j_graphrag.retrievers import VectorCypherRetriever retrieval_query = """ MATCH (artigo:Artigo)<-[:ESCRITO_POR]-(autor:Pessoa) WHERE artigo.suporte >= 0.8 RETURN autor.nome, autor.afiliacao, artigo.titulo ORDER BY artigo.suporte DESC """ retriever = VectorCypherRetriever( driver, index_name="artigo-embedding", retrieval_query=retrieval_query, embedder=embedder, )
Esse é o padrão real: a busca vetorial acha o documento, o Cypher traz o contexto relacional que o texto sozinho não carrega.
3.5 Busca híbrida (vetor + full-text)
from neo4j_graphrag.retrievers import HybridRetriever retriever = HybridRetriever( driver, vector_index_name="artigo-embedding", fulltext_index_name="artigo-fulltext", embedder=embedder, ) resultado = retriever.search(query_text="índice invertido", top_k=5)
É o ponto de partida mais barato: você tem busca semântica e textual sem custo de LLM na indexação.
3.6 Construir o grafo a partir de texto solto
from neo4j_graphrag.kg_builder import KGBuilder kg_builder = KGBuilder( driver=driver, llm=llm, embedder=embedder, ) kg_builder.add_entity_types( entity_types=[ ("Pessoa", ["nome", "cargo"]), ("Organizacao", ["nome", "setor"]), ], possible_relations=[ ("Pessoa", "TRABALHA_NA", "Organizacao"), ("Pessoa", "RELACIONADA_COM", "Pessoa"), ], ) await kg_builder.run_async(text=texto_do_documento)
⚠️ O
KGBuilderexige a biblioteca APOC core instalada no seu Neo4j. Sem ela o build falha com erro de plugin. É o erro mais comum de quem vem do RAG vetorial e não sabe que existe essa dependência.
4. Escolhendo o método: tabela de decisão
| A pergunta é… | Método | Por quê |
|---|---|---|
| "O que a doc do módulo 3 diz sobre cache?" | basic | Resposta está em um trecho. Grafo é desperdício |
| "Quem é o responsável pelo serviço de pagamento?" | local | Entidade específica, vizinhança pequena |
| "Quais são os temas dominantes da base?" | global | Não há entidade-âncora; é síntese |
| "Por que a autenticação falha em produção?" | drift | Começa na entidade, sobe para o contexto da comunidade |
5. Os 6 erros que só aparecem em produção
1. Índice vetorial com dimensão errada. Aceita na criação, retorna lixo na consulta. Confira dimensions contra o modelo.
2. APOC ausente. KGBuilder e várias funções de community falham sem a biblioteca instalada.
3. graphrag init não re-executado após upgrade. O settings.yaml antigo não tem os campos novos e o pipeline falha em silêncio, usando defaults.
4. Esquecer o --dry-run****. Descobre config inválida só depois de pagar metade do indexamento.
5. community_reports ausente. Se você pula a etapa 8-9 do pipeline ou indexa com um método que não a gera, a busca global retorna vazio sem erro. O CLI chega a reclamar das tabelas faltantes, mas a API Python não.
6. Grafo ruidoso. Entidades duplicadas, arestas espúrias, entidades que são na verdade a mesma. A resposta fica pior que RAG vetorial. A cure é revisar uma amostra de arestas manualmente antes de indexar o corpus inteiro.
6. Checklist de implantação
- Python 3.10–3.12 em ambiente isolado
- Rodar
graphrag init --roote editarsettings.yaml(chunk size, modelo, embeddings) - Testar o pipeline com 100–200 documentos e
--dry-runantes - Revisar manualmente ~50 arestas extraídas: qualidade do grafo antes de escalar
-
graphrag prompt-tunepara adaptar os prompts ao domínio - Indexar o corpus completo só depois de validar qualidade
- Definir o
--community-levelpadrão por tipo de pergunta - Guardar o cache do LLM: reindexar sem cache custa o mesmo preço
- No Neo4j: instalar APOC antes de usar
KGBuilder - No Neo4j: validar
dimensionsdo índice vetorial contra o modelo
Referências
- 📚 Microsoft GraphRAG — Getting Started — init, index, query
- 📚 Microsoft GraphRAG — CLI — todas as flags de
indexequery - 📚 Microsoft GraphRAG — Query Overview — os 4 métodos
- 📚 Microsoft GraphRAG — DRIFT Search — busca híbrida
- 🔧 neo4j-graphrag-python (GitHub) — pacote oficial, exemplos
- 🔧 Neo4j GraphRAG — Documentação Python — retrievers, índices, KGBuilder
- 🔧 Neo4j GraphRAG — API Reference — assinatura de cada classe
- 🔧 Getting started with the Neo4j GraphRAG package — tutorial com banco de demonstração