Agentic GraphRAG is a modular, schema-driven system for building knowledge graphs from unstructured and structured data, retrieving evidence across graph and vector indexes, and answering questions with agentic reasoning.
- One ingestion API for raw text, files, directories, globs, and prebuilt documents.
- Structure-aware loading and chunking with core text readers, Docling for rich documents, and Chonkie for text chunking.
- Schema-driven extraction with runtime-defined entity types, relation types, and valid graph patterns.
- Local-first extraction cascade using GLiNER 2.5 with type-safe BAML/LLM fallback for weak or ambiguous chunks.
- Tiered entity resolution combining exact, fuzzy, embedding, and LLM-verified matching with fail-safe merge rules.
- Auditable graph merges with field-level conflict handling, relation repointing, provenance union, and soft tombstones.
- Pluggable storage with Neo4j for graph data and native vectors, plus Qdrant, Weaviate, and Milvus/Zilliz for dedicated vector search.
- Layered retrieval across entities, relations, chunks, graph neighborhoods, and community reports, with hybrid fusion and reranking.
- Agentic plan–research–verify loop that decomposes questions, gathers evidence in parallel, checks coverage, and produces cited answers.
- OpenTelemetry-native observability across loading, chunking, extraction, resolution, and storage.
The system is built using:
- Docling and Chonkie for document parsing and chunking.
- GLiNER 2.5 for local schema-guided entity and relation extraction.
- BAML for typed LLM functions and provider-independent client routing.
- Neo4j for the property graph and optional native vector search.
- Qdrant, Weaviate, and Milvus for dense and hybrid retrieval.
- Sentence Transformers and FastEmbed for dense and sparse embeddings.
- OpenTelemetry for vendor-neutral traces and metrics.
Agentic GraphRAG stores source material, extracted knowledge, and graph summaries in one typed property graph:
(:Document)<-[:PART_OF]-(:Chunk)-[:MENTIONS]->(:Entity:<Type>)
(:Chunk)-[:NEXT_CHUNK]->(:Chunk)
(:Entity)-[:<RELATION_TYPE>]->(:Entity)
(:Entity)-[:IN_COMMUNITY]->(:Community)
(:Community)-[:PARENT_COMMUNITY]->(:Community)
(:Community)-[:HAS_REPORT]->(:CommunityReport)
Documents keep their source URI, format, loader, content hash, and record identity. Text formats use content-based identities; binary Docling formats use raw-byte hashes. Chunks keep stable document links and source provenance:
- Text chunks record character and line spans plus their heading path.
- Layout-aware chunks record page numbers and bounding boxes.
- Record formats such as CSV, TSV, JSON, and JSON Lines preserve row identity.
Extraction produces mentions first, not graph nodes. Each mention keeps its source chunk, label, text span, confidence, and extractor provenance. Resolution then assigns canonical identities and merges aliases before storage.
Relations are directed subject–predicate–object triples. The active schema constrains valid source type, relation type, and target type combinations, so invalid triples are removed before they reach the graph.
Hierarchical community detection groups related entities and relations into nested topics. Each community can receive an LLM-generated report with a title, summary, findings, and importance score. Community reports provide broad context without forcing retrieval to return every low-level edge.
GraphSchema is a first-class runtime value. It defines:
- entity types and their descriptions;
- relation types and their descriptions;
- valid
(source, relation, target)patterns; - the vocabulary injected into local and LLM extractors.
Use the generic preset for open-domain data or provide a schema for a specific domain. The same schema guides extraction, validation, resolution, storage, and query generation.
Agentic GraphRAG has two main data flows:
Ingestion: source -> document -> chunk -> mentions -> resolved graph -> indexes
Query: question -> plan -> parallel retrieval -> verify -> cited answer
Graph.add() is the single entry point for adding content. The complete pipeline is organized into these stages:
- Load: Select a loader by format, decode or parse the source, preserve source metadata, and apply
RAISE,SKIP, orQUARANTINEper-source error handling. - Chunk: Use Docling's layout-aware chunking before flattening rich documents; use Chonkie for text and record documents.
- Extract: Run GLiNER locally against the active schema. Escalate weak results to a typed BAML extraction function when configured.
- Validate: Drop entities and triples that do not conform to the schema.
- Resolve: Apply exact, fuzzy, embedding, and LLM-verified comparison tiers. Ambiguous or failed comparisons do not merge.
- Merge: Resolve properties field by field, combine provenance, deduplicate repointed relations, and retain an audit trail.
- Store: Upsert canonical nodes and relations, then populate graph-native or dedicated vector indexes.
The extraction cascade replaces a weak local result with the LLM result instead of combining two conflicting outputs. Exact matches use global store-backed lookup; more expensive fuzzy and LLM comparisons are blocked to a smaller candidate set.
Graph.consolidate() provides a separate whole-graph reconciliation pass for duplicates found across ingestion runs. It is dry-run by default so applications can inspect proposed merges before applying them.
The async Embedder, GraphStore, and VectorStore interfaces keep model and database choices outside graph-construction logic.
- Dense embeddings through Sentence Transformers.
- Sparse BM25 embeddings through FastEmbed.
- Batch-first async APIs with optional content-addressed caching by text and model.
- Dimension checks before collections or indexes accept vectors.
The Neo4j backend supports local Neo4j and Aura over Bolt, managed read/write transactions, node and relation upserts, constraints, indexes, and native dense vector search. Dynamic labels and relation types are validated before Cypher interpolation.
| Backend | Dense search | Hybrid search | Deployment |
|---|---|---|---|
| Neo4j | Yes | No | Local or Aura |
| Qdrant | Yes | Dense + sparse fusion | Local or Cloud |
| Weaviate | Yes | Native BM25/vector weighting | Custom or Cloud |
| Milvus / Zilliz | Yes | Dense + BM25 fusion | Local or Cloud |
All dedicated vector stores share collection lifecycle, batch upsert, retrieval, scrolling, counting, deletion, filtering, dense search, and hybrid search. Filters use exact scalar matches, OR within a list value, and AND across keys.
Retrieval composes small search methods into retrievers, runs them concurrently, and fuses their results through data-only recipes.
- Entity retrieval finds canonical entities by dense or hybrid search and can expand matched seeds with bounded graph traversal.
- Relation retrieval searches relation representations and hydrates full subject–predicate–object edges from the graph.
- Chunk retrieval returns source passages with document and span provenance.
- Community retrieval searches community reports for thematic and corpus-wide questions.
- Text-to-Cypher retrieval generates a schema-aware, read-only query with bounded retries.
- Graph traversal uses bounded, degree-aware breadth-first search to collect connected evidence.
| Recipe | Search methods | Fusion |
|---|---|---|
entity, relation, chunk, community |
One focused retriever | Reciprocal Rank Fusion |
hybrid_rrf |
Entity + relation + chunk + community | Reciprocal Rank Fusion |
hybrid_cross_encoder |
All semantic retrievers + graph expansion | Cross-encoder |
bfs_expand |
Entity seeds + bounded graph traversal | Reciprocal Rank Fusion |
text2cypher |
Schema-aware Cypher | Reciprocal Rank Fusion |
Reciprocal Rank Fusion, cross-encoder, maximal marginal relevance, and graph-distance rerankers cover different query needs. A recipe can ignore an empty search branch and still return evidence from the remaining methods.
The agent coordinates three roles around the retrieval layer:
- Planner: decomposes a question into focused sub-questions and selects a retrieval recipe for each.
- Researcher: runs sub-questions in parallel across entity, relation, chunk, community, graph, and Cypher tools; every evidence item keeps its citation.
- Verifier: scores coverage and evidence depth, lists unsupported claims, and proposes targeted follow-up searches.
If the evidence gate fails, the missing items seed another research round. When the gate passes, or the iteration limit is reached, the orchestrator produces a structured answer with citations, confidence, caveats, and an answerability flag.
BAML defines typed extraction, entity-comparison, community-summary, planning, verification, and answer contracts. Runtime client registries support a single provider, fallback chains, or round-robin routing across OpenAI, Anthropic, AWS Bedrock, Google AI, Vertex AI, Azure OpenAI, and OpenAI-compatible endpoints.
OpenTelemetry API support is part of the core package; exporters and the SDK are optional. Applications can send traces to any OTLP-compatible backend.
Long-running graph builds report bounded, structured stage statistics for ingestion, extraction, resolution, merging, and storage. Failures include the affected item, error type, message, and trace/span IDs. Full detail remains in the trace backend so result objects stay bounded on large corpora.
Agentic GraphRAG requires Python 3.11 or newer.
uv pip install agentic-graphragInstall only the integrations you use:
# Rich documents and local extraction
uv pip install "agentic-graphrag[docling,extract]"
# LLM extraction and local dense embeddings
uv pip install "agentic-graphrag[llm,embed-local]"
# Neo4j with a dedicated Qdrant vector store and OTLP tracing
uv pip install "agentic-graphrag[neo4j,qdrant,observability]"| Extra | Adds |
|---|---|
docling |
PDF, DOCX, PPTX, image, XML, and layout-aware parsing |
extract |
Local GLiNER 2.5 extraction |
llm |
BAML-powered extraction and verification |
embed-local |
Sentence Transformers dense embeddings |
neo4j |
Neo4j graph storage and native vector search |
qdrant |
Qdrant dense and hybrid search |
weaviate |
Weaviate dense and hybrid search |
milvus |
Milvus/Zilliz dense and hybrid search |
observability |
OpenTelemetry SDK and OTLP export |
import asyncio
from agrag.ingestion import Graph
async def main() -> None:
graph = await Graph.open()
files = await graph.add(source="./corpus/**/*.md")
text = await graph.add(text="Agentic GraphRAG turns evidence into a graph.")
print(files.documents, len(files.chunks))
print(text.documents, len(text.chunks))
asyncio.run(main())Graph.add() accepts exactly one of:
source=— a file, directory, glob, or list of paths;text=— raw text as one document;documents=— prebuiltDocumentobjects.
from agrag.loaders.corpus.types import ErrorPolicy
result = await graph.add(
source="./corpus",
error_policy=ErrorPolicy.QUARANTINE,
)
for uri, reason in result.quarantined_items:
print(uri, reason)See the documentation for guides and the generated API reference.
| Format | Extension(s) | Loader |
|---|---|---|
| Plain text and logs | .txt, .log |
Core |
| Markdown | .md, .markdown |
Core |
| AsciiDoc | .adoc, .asciidoc |
Docling, with core fallback |
| HTML | .html, .htm |
Core |
| CSV / TSV | .csv, .tsv |
Core, one document per row |
| JSON | .json |
Core, record-aware |
| JSON Lines | .jsonl, .ndjson |
Core, one document per row |
.pdf |
Docling | |
| Word | .docx |
Docling |
| PowerPoint | .pptx |
Docling |
| Images | .png, .jpg, .jpeg, .tif, .tiff, .bmp |
Docling |
| XML | .xml |
Docling or the core XML reader |
Core loaders remain the default for Markdown, HTML, CSV, TSV, and JSON records. Docling takes precedence for layout-rich documents and AsciiDoc when installed.
agrag/
├── common/data_models/ # documents, chunks, schemas, extraction and storage records
├── chunking/ # Chonkie and Docling chunk adapters
├── loaders/ # core corpus readers and optional Docling loader
├── ingestion/ # Graph API, extraction, resolution, merge and pipeline stages
├── embedding/ # dense and sparse embedding interfaces
├── graphdb/ # graph-store interface and Neo4j backend
├── vectordb/ # vector-store interface and Qdrant/Weaviate/Milvus backends
├── cypher/ # validated Cypher builders
├── retrieval/ # search methods, retrievers, recipes and rerankers
├── agents/ # planner, researcher, verifier and answer synthesis
├── communities/ # hierarchical detection and report generation
├── llm/ # BAML sources, generated client and provider routing
└── observability.py # OpenTelemetry helpers
tests/
├── unit/ # isolated tests with external services mocked
└── integration/ # live backend tests against Docker services
git clone https://github.com/ontogr/agentic-graphrag.git
cd agentic-graphrag
make sync
make lint-check
make lint-typing
make testIntegration tests run against local Neo4j, Qdrant, Weaviate, and Milvus services:
make dev-services-up
make test-integration
make dev-services-downSee CONTRIBUTING.md for the development workflow, test conventions, and pull request guidelines.
- Microsoft GraphRAG — hierarchical communities and community reports
- Graphiti — layered graph search and entity-aware retrieval
- Cognee — data pipelines, graph memory, and consolidation
- KG-Gen — knowledge-graph extraction and alias deduplication
- FalkorDB GraphRAG SDK — graph-native retrieval and entity resolution
- Neo4j GraphRAG — Neo4j retrieval and vector integration
- LightRAG — graph and vector retrieval
- PathRAG — relational-path retrieval
- GLiNER — generalist zero-shot information extraction
- BAML, Docling, and Chonkie
This project is licensed under the Apache License 2.0.
