An advanced Autonomous GraphRAG Agent that unifies vector similarity and relational reasoning into a single Pure Neo4j architecture. The system intelligently decides whether to answer directly, search its long-term memory, or browse the live internetβcontinuously learning from every interaction.
API v2.0 β All features are now exposed as production-ready REST endpoints. Build FAQ bots, legal record systems, research assistants, and more.
- Pure GraphRAG: ChromaDB has been replaced by Neo4j's native vector index. Text chunks, their embeddings, and structured entities/relationships all live in a single, unified database.
- Autonomous Agent (ReAct): Uses an Agentic Orchestrator that dynamically chooses from a suite of tools (
web_browser,query_memory,graph_query,calculator) to answer complex queries. - Continuous Learning Loop:
- From Web: Scraped content is automatically chunked, indexed, and enriched with extracted entities and relationships.
- From Chat: Every user query and assistant answer is automatically indexed into memory for future recall.
- Multi-Hop Reasoning: Capable of traversing the knowledge graph to "connect the dots" across multiple entities and relationships.
- Full REST API: 20+ endpoints covering queries, ingestion, knowledge graph, NLP, reasoning, evaluation, and system management.
- Beautiful Terminal UI: Powered by
Richfor a polished, interactive experience with streaming tokens and status indicators.
graph TD
User([User Query]) --> Agent[Agentic Orchestrator\nReAct Reasoning Loop]
subgraph Tools [Dynamic Toolset]
Agent <--> Web[Web Browser\nDDG + Playwright]
Agent <--> VectorTool[query_memory\nSimilarity Search]
Agent <--> GraphTool[graph_query\nMulti-hop Logic]
Agent --> Store[store_memory\nFact Injection]
Agent --> Calc[calculator\nMath Engine]
end
subgraph Learning [Continuous Learning Loop]
Web -- 1. Scrape --> Content[Raw Text]
Content -- 2. Index --> Neo4jVector
Content -- 3. NLP Entity Extraction --> Entities[Nodes and Relations]
Entities -- 4. Upsert --> Neo4jGraph
end
subgraph Unified [Neo4j Graph Database]
Neo4jVector[(Vector Index)]
Neo4jGraph[(Knowledge Graph)]
end
subgraph API [REST API Layer]
QueryAPI[/api/v1/query]
GraphAPI[/api/v1/graph]
NLPAPI[/api/v1/nlp]
ReasonAPI[/api/v1/reasoning]
end
VectorTool <--> Neo4jVector
GraphTool <--> Neo4jGraph
Store --> Neo4jVector
Agent --> Answer[Final Answer + Citations]
Answer --> User
API --> Agent
API --> Neo4jVector
API --> Neo4jGraph
active_rag/
βββ api.py # FastAPI app factory (mounts all routers)
βββ dependencies.py # Shared DI (sessions, resources, auth)
βββ routers/ # API endpoint modules
β βββ query.py # Query pipelines (agent/hybrid/ultimate)
β βββ ingestion.py # File upload, text, batch, URL ingestion
β βββ knowledge_base.py # KB stats, search, export, reset
β βββ graph.py # Knowledge graph operations
β βββ nlp.py # NLP pipeline (entities, relations, classify)
β βββ reasoning.py # Multi-hop reasoning & analytics
β βββ evaluation.py # Answer quality evaluation
β βββ system.py # Health, sessions, performance, cache
βββ agent.py # Agentic Orchestrator (ReAct loop)
βββ vector_store.py # Neo4j-backed Vector Store
βββ knowledge_graph/ # Neo4j Client & Graph Operations
βββ reasoning/ # Reasoning engine, community detection, cross-domain
βββ nlp_pipeline/ # Entity & Relation Extraction
βββ tools/ # ReAct Agent Toolset
βββ web_search.py # Playwright-based Scraper
βββ config.py # Centralized Configuration
main.py # CLI Interface
- Python 3.10+
- Docker (for Neo4j)
- An LLM backend (Ollama, OpenAI, or GitHub Copilot API)
pip install -r requirements.txt
python -m spacy download en_core_web_sm
playwright install chromiumdocker-compose -f docker-compose.neo4j.yml up -dSettings are managed via a .env file:
| Variable | Default | Description |
|---|---|---|
MODEL_NAME |
gpt-4o |
LLM model to use |
OLLAMA_BASE_URL |
http://localhost:4141/v1 |
API endpoint (e.g., local proxy or Ollama) |
NEO4J_URI |
bolt://localhost:7687 |
Neo4j Bolt connection string |
VECTOR_INDEX_NAME |
active_rag |
Name of the vector index in Neo4j |
HEADLESS |
true |
Set to false to see the browser while scraping |
ACTIVE_RAG_API_KEY |
(none) | Optional API key for auth (set to enable) |
python main.pypython main.py "How is A connected to C in my family tree?"/stats: View knowledge base size (nodes, relations, chunks)./health: Run full system diagnostics./reset: Wipe the entire knowledge base and start fresh./dump: See every raw text chunk learned by the agent./clear: Clear current conversation context.
Start the API server:
python main.py --serve
# Server runs on http://localhost:8000
# Swagger docs: http://localhost:8000/docsAll endpoints are under /api/v1/. Optional API key auth via X-API-Key header (set ACTIVE_RAG_API_KEY env var to enable).
# Health check
curl http://localhost:8000/api/v1/system/health
# Ask a question
curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{"query": "What is quantum computing?", "session_id": "user-1"}'Execute queries against any of the 4 RAG pipelines.
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string | required | The question to ask |
session_id |
string | "default" |
Session ID for conversation memory |
pipeline_type |
string | "agent" |
Pipeline: agent, hybrid, ultimate, legacy |
curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"query": "Who founded OpenAI?",
"session_id": "user-42",
"pipeline_type": "agent"
}'Response:
{
"answer": "OpenAI was founded by Sam Altman, Elon Musk, ...",
"citations": ["https://en.wikipedia.org/wiki/OpenAI"],
"path": "agent",
"confidence": 0.92,
"reasoning": "Known fact with high web evidence",
"session_id": "user-42"
}Same parameters as above. Returns an NDJSON stream for real-time token-by-token responses.
curl -X POST http://localhost:8000/api/v1/query/stream \
-H "Content-Type: application/json" \
-d '{"query": "Explain transformers in ML"}'Load documents into the knowledge base.
Upload a file (PDF, TXT, MD, DOCX) using multipart form data.
curl -X POST http://localhost:8000/api/v1/ingest/upload \
-F "file=@/path/to/document.pdf"Ingest raw text content.
curl -X POST http://localhost:8000/api/v1/ingest/text \
-H "Content-Type: application/json" \
-d '{"content": "Active RAG is a GraphRAG system...", "source": "manual"}'Bulk-ingest multiple documents at once. Perfect for loading FAQ databases, legal records, or knowledge articles.
curl -X POST http://localhost:8000/api/v1/ingest/batch \
-H "Content-Type: application/json" \
-d '{
"documents": [
{"content": "Q: How to reset my password? A: Go to Settings > Security...", "source": "faq"},
{"content": "Q: What are your business hours? A: Mon-Fri, 9am-5pm.", "source": "faq"},
{"content": "Q: How to contact support? A: Email support@company.com", "source": "faq"}
]
}'Response:
{
"status": "success",
"total_documents": 3,
"chunks_created": 3,
"ids": ["chunk-abc123-1f2e3d4c", "chunk-def456-5a6b7c8d", "chunk-ghi789-9e0f1a2b"]
}Scrape a URL and ingest its content automatically.
curl -X POST http://localhost:8000/api/v1/ingest/url \
-H "Content-Type: application/json" \
-d '{"url": "https://en.wikipedia.org/wiki/Knowledge_graph", "max_pages": 1}'Direct access to the Neo4j knowledge graph for entity exploration and path discovery.
Search for entities by name pattern, optionally filtered by type.
curl -X POST http://localhost:8000/api/v1/graph/entities/search \
-H "Content-Type: application/json" \
-d '{"name_pattern": "Einstein", "entity_types": ["Person"]}'Response:
{
"count": 2,
"entities": [
{"id": "person_abc", "name": "Albert Einstein", "labels": ["Person"]},
{"id": "person_def", "name": "Einstein (disambiguation)", "labels": ["Person"]}
]
}Explore all entities within a given radius of hops.
curl "http://localhost:8000/api/v1/graph/entities/person_abc/neighborhood?radius=2"Get directly related entities with relationship types.
curl "http://localhost:8000/api/v1/graph/entities/person_abc/related?depth=1"Find paths connecting two entities β essential for legal case analysis, citation chains, and organizational mapping.
curl -X POST http://localhost:8000/api/v1/graph/paths \
-H "Content-Type: application/json" \
-d '{"start_id": "person_abc", "end_id": "org_xyz", "max_depth": 3}'NLP-powered multi-hop reasoning over the graph.
curl -X POST http://localhost:8000/api/v1/graph/multi-hop \
-H "Content-Type: application/json" \
-d '{"query": "Which researchers at MIT work on transformers?", "max_hops": 2}'Get graph statistics: total nodes, relationships, type breakdowns.
curl http://localhost:8000/api/v1/graph/statsExtract structured information from unstructured text.
Extract named entities with domain-specific strategies.
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
string | required | Text to analyze |
domain |
string | auto-detect | research, technical, business, or mixed_web |
curl -X POST http://localhost:8000/api/v1/nlp/entities/extract \
-H "Content-Type: application/json" \
-d '{
"text": "Dr. Sarah Chen at Stanford published a paper on transformer architectures using PyTorch.",
"domain": "research"
}'Response:
{
"domain": "research",
"count": 3,
"entities": [
{"label": "Person", "properties": {"id": "person_sarah_chen", "name": "Sarah Chen"}},
{"label": "Organization", "properties": {"id": "org_stanford", "name": "Stanford"}},
{"label": "Concept", "properties": {"id": "concept_transformer", "name": "transformer architectures"}}
]
}Extract subject-predicate-object relationships between entities.
curl -X POST http://localhost:8000/api/v1/nlp/relations/extract \
-H "Content-Type: application/json" \
-d '{"text": "John manages the engineering team at Google."}'Classify text into content domains: research, technical, business, or mixed_web.
curl -X POST http://localhost:8000/api/v1/nlp/classify \
-H "Content-Type: application/json" \
-d '{"text": "Abstract: We present a novel approach to reinforcement learning..."}'Response:
{"domain": "research", "text_length": 64}Analyze text sentiment.
curl -X POST http://localhost:8000/api/v1/nlp/sentiment \
-H "Content-Type: application/json" \
-d '{"text": "This product is absolutely fantastic and exceeded all expectations!"}'Advanced graph analysis with multi-hop reasoning, community detection, and cross-domain discovery.
Execute the full multi-hop reasoning pipeline: extract entities β expand neighborhoods β find paths β rank by relevance β return confidence.
curl -X POST http://localhost:8000/api/v1/reasoning/reason \
-H "Content-Type: application/json" \
-d '{"query": "How is Dr. Smith connected to the Stanford AI Lab?", "max_hops": 3}'Response:
{
"query": "How is Dr. Smith connected to the Stanford AI Lab?",
"confidence": 0.78,
"reasoning_summary": "Identified entities: Dr. Smith, Stanford AI Lab. Found 3 reasoning path(s). Top path: Dr. Smith β[AFFILIATED_WITH]β Stanford β[CONTAINS]β AI Lab",
"has_results": true,
"ranked_paths": [
{
"reasoning_text": "Dr. Smith β[AFFILIATED_WITH]β Stanford β[CONTAINS]β AI Lab",
"score": 0.85,
"length": 2,
"start_entity": "Dr. Smith",
"end_entity": "AI Lab"
}
],
"subgraph": {"node_count": 12, "edge_count": 8}
}Detect entity communities using label propagation clustering.
curl -X POST http://localhost:8000/api/v1/reasoning/communities \
-H "Content-Type: application/json" \
-d '{"entity_type": "Person", "max_entities": 100}'Response:
{
"count": 3,
"communities": [
{"community_id": 0, "size": 8, "dominant_label": "Person", "entity_names": ["Alice", "Bob", "Carol"]},
{"community_id": 1, "size": 5, "dominant_label": "Organization", "entity_names": ["MIT", "Stanford"]}
]
}Find how an entity connects across different content domains.
curl -X POST http://localhost:8000/api/v1/reasoning/cross-domain \
-H "Content-Type: application/json" \
-d '{"entity_id": "person_abc", "max_depth": 2}'Discover bridge entities that connect multiple domains.
curl "http://localhost:8000/api/v1/reasoning/bridges?max_entities=50"Score answer quality using the LLM as a judge.
curl -X POST http://localhost:8000/api/v1/evaluate \
-H "Content-Type: application/json" \
-d '{
"query": "What is the capital of France?",
"answer": "The capital of France is Paris."
}'Response:
{
"quality": 0.95,
"is_acceptable": true,
"issues": [],
"suggestion": ""
}Manage the vector knowledge base.
| Endpoint | Method | Description |
|---|---|---|
/api/v1/kb/stats |
GET | Vector chunk count + graph node/relation counts |
/api/v1/kb/search |
POST | Semantic search ({"query": "...", "limit": 5}) |
/api/v1/kb/export |
GET | Export all stored documents |
/api/v1/kb/reset |
DELETE | Wipe the entire knowledge base |
Health checks, monitoring, and management.
| Endpoint | Method | Description |
|---|---|---|
/api/v1/system/health |
GET | Check LLM, Neo4j, and graph connectivity |
/api/v1/system/sessions |
GET | List all active conversation sessions |
/api/v1/system/memory/{session_id} |
GET | Dump memory for a session |
/api/v1/system/memory/{session_id} |
DELETE | Clear a session's memory |
/api/v1/system/performance |
GET | Query execution time stats and cache hit rates |
/api/v1/system/cache/stats |
GET | Graph cache metrics (hits, misses, evictions) |
/api/v1/system/cache/invalidate |
POST | Clear cache ({"query_type": null} for all) |
/api/v1/config |
GET | View current system configuration |
/api/v1/config |
PATCH | Update config (top_k, thresholds, etc.) |
import requests
API = "http://localhost:8000/api/v1"
# Step 1: Bulk-load FAQ entries
faqs = [
{"content": "Q: How to reset password? A: Go to Settings > Security > Reset", "source": "faq"},
{"content": "Q: What are business hours? A: Mon-Fri, 9am-5pm EST", "source": "faq"},
{"content": "Q: How to contact support? A: Email support@company.com", "source": "faq"},
]
requests.post(f"{API}/ingest/batch", json={"documents": faqs})
# Step 2: Query with session memory for follow-up questions
response = requests.post(f"{API}/query", json={
"query": "How do I reset my password?",
"session_id": "customer-123",
})
print(response.json()["answer"])
# Step 3: Evaluate answer quality
answer = response.json()["answer"]
eval_result = requests.post(f"{API}/evaluate", json={
"query": "How do I reset my password?",
"answer": answer,
})
print(f"Quality: {eval_result.json()['quality']}")import requests
API = "http://localhost:8000/api/v1"
# Step 1: Ingest case documents
requests.post(f"{API}/ingest/upload", files={"file": open("case_file.pdf", "rb")})
# Step 2: Extract entities from text
entities = requests.post(f"{API}/nlp/entities/extract", json={
"text": "Defendant John Doe was represented by Acme Legal Corp in Case #2024-001.",
"domain": "business",
}).json()
# Step 3: Find how two entities are connected
paths = requests.post(f"{API}/graph/paths", json={
"start_id": "person_john_doe",
"end_id": "org_acme_legal",
"max_depth": 3,
}).json()
# Step 4: Full reasoning query
reasoning = requests.post(f"{API}/reasoning/reason", json={
"query": "How is John Doe connected to Case #2024-001?",
"max_hops": 3,
}).json()
print(reasoning["reasoning_summary"])import requests
API = "http://localhost:8000/api/v1"
# Step 1: Ingest research papers via URL
requests.post(f"{API}/ingest/url", json={"url": "https://arxiv.org/abs/2301.00001"})
# Step 2: Classify document domains
result = requests.post(f"{API}/nlp/classify", json={
"text": "We propose a novel attention mechanism for language models..."
}).json()
print(f"Domain: {result['domain']}") # β "research"
# Step 3: Discover research communities
communities = requests.post(f"{API}/reasoning/communities", json={
"entity_type": "Person",
"max_entities": 200,
}).json()
for c in communities["communities"][:3]:
print(f"Community {c['community_id']}: {', '.join(c['entity_names'][:5])}")
# Step 4: Find cross-domain bridges
bridges = requests.get(f"{API}/reasoning/bridges?max_entities=50").json()
for b in bridges["bridges"][:5]:
print(f"Bridge: {b['entity']['name']} β Domains: {b['connected_domains']}")# All tests
python -m pytest tests/ -v
# API tests only
python -m pytest tests/test_api_v1.py -vInteractive Swagger UI is available at http://localhost:8000/docs when the server is running. All endpoints are grouped by category with full request/response schemas.