Introduction
"Graph RAG typically pre-builds a global graph offline, then uses PageRank for query-time scoring and expansion — but PageRank has decay: the longer the chain, the lower the score. SAG uses SQL JOINs to expand at query time instead. No decay, no pre-built global graph."
This is article #116 in the Open Source Project of the Day series. Today's project is SAG (Structured Agentic Graph) — Zleap-AI's open-source next-generation multi-hop RAG framework, backed by an arXiv paper (2606.15971).
Multi-hop retrieval's core challenge: some questions need to chain information from multiple separate document passages. Standard vector retrieval finds semantically similar chunks — but "semantically similar" doesn't mean "can answer questions requiring multi-step reasoning." GraphRAG and HippoRAG solve this with knowledge graphs, but at two costs: expensive offline global graph construction, and PageRank score decay over longer chains.
SAG takes a different path: no global graph pre-built, SQL JOINs for graph-structure expansion at query time. Each chunk produces one "event" (semantic summary) and a set of entities. Relationships between events and entities are expressed through relational database foreign keys. Multi-hop expansion is just a JOIN operation — deterministic, traceable, no decay.
What You'll Learn
- SAG's core data model: the design logic of chunk → event + entities
- The three-step query process: seed retrieval → SQL expansion → dual-path final selection
- Why SQL JOINs outperform PageRank on long-chain multi-hop
- Comparison with HippoRAG 2 and GraphRAG: strengths and weaknesses
- MCP integration: exposing each SAG project as an agent-callable tool
- Full-stack implementation: TypeScript + PostgreSQL + pgvector + React
Prerequisites
- Familiarity with RAG and multi-hop retrieval basics
- Basic understanding of knowledge graphs (nodes, edges, multi-hop reasoning)
- Familiarity with SQL JOIN concepts
Project Background
What Is SAG?
SAG (Structured Agentic Graph) is a document retrieval system that organizes knowledge in an event-entity graph structure, achieves multi-hop retrieval through SQL JOINs, and is designed specifically for agent workflows.
"Structured" means converting unstructured documents into structured event + entity representations. "Agentic" means each SAG project has a built-in MCP server, exposable as an agent tool endpoint. "Graph" refers to query-time graph traversal via SQL JOINs.
Author / Team
- Organization: Zleap-AI
- Website: zleap.com
- arXiv: 2606.15971
- License: MIT
- Benchmark repo: Zleap-AI/SAG-Benchmark
Project Stats
- ⭐ GitHub Stars: 1,900+
- 🍴 Forks: 87+
- 📄 License: MIT
Core Design: chunk → event + entities
SAG's base data model has three elements:
One document chunk
↓
One Event (semantic event)
↑↕↓
Multiple Entities
Event: A semantic summary of the chunk. Each chunk maps to exactly one event. The event preserves complete semantics.
Entity: Named entities extracted from the chunk, serving as anchors for graph traversal. 11 types: time, location, person, organization, group, topic, work, product, action, metric, label. Entities carry no standalone semantics — they exist only as "index and expansion points for connecting different events."
Implicit hyperedge: One event plus all its entities forms an implicit hyperedge. This is conceptually similar to HyperGraphRAG, but SAG doesn't explicitly build a hypergraph — it achieves equivalent effect through relational database foreign key associations.
Why events instead of triples?
Triple approach:
chunk → (Alice, works_at, Google)
(Alice, attended, Meeting_001)
(Bob, attended, Meeting_001)
Relationship fragmented; reconstructing full context requires multiple hops
Event approach:
chunk → Event: "Alice and Bob discussed the product roadmap at Meeting_001"
Entity: Alice, Bob, Meeting_001
Complete semantics preserved in event; entities serve as connection points
The paper's ablation confirms: on MuSiQue, the hyperedge (event) approach scores Recall@5 = 80.0%, while the triple approach scores 77.1%.
Two-Phase Architecture
Offline Phase (Document Ingestion)
Document (Markdown / TXT)
↓
Text chunking
↓
LLM extraction (parallel, configurable concurrency):
Each chunk → 1 event + N entities
↓
Written to two backends (synchronous):
PostgreSQL → Structured storage (events table, entities table, join table)
pgvector → Vector index (event vectors, entity vectors)
Full-text index → BM25 entity matching
Key property: append-only writes, no global graph rebuild. New document ingestion doesn't affect existing data — no need to re-run PageRank or rebuild graph structures.
Online Phase (Three-Step Retrieval)
Step 1: Seed Retrieval (dual-path parallel)
Path A: Entity-guided structured recall
1. LLM extracts entities from query → seed entity set U_q
2. Vector similarity search over entity index (threshold 0.9) → expanded set Û_q
3. SQL JOIN: find all events containing these entities
ℰR_entity = {e | ∃u ∈ Û_q : SQL-Join(e, u)}
Path B: Direct event recall
Query vector → event vector similarity search (threshold 0.4)
Merge: ℰR = ℰR_entity ∪ ℰR_direct
Step 2: Query-Time Expansion (SQL multi-hop)
This is SAG's core mechanism:
Starting from seed event set ℰR:
↓
Reverse JOIN: extract all entities from seed events (entity frontier)
↓
Forward JOIN: find all new events containing frontier entities (cross-document expansion)
↓
Repeat for H hops (default H=1)
Result: ℰ_cand = ℰR ∪ ℰE
This is the "multi-hop" implementation. If Document A mentions Entity X and Document B also mentions Entity X, one JOIN from Document A's events finds Document B's related events — even if the two documents are far apart in vector space.
Step 3: Final Selection (dual-path fusion)
Candidate set ℰ_cand (top 100 candidates)
↓
Structural path: LLM reranks chain candidates → top 5 events → mapped to chunks
Semantic path: query vector directly retrieves chunks → top 5
↓
Merge, deduplicate → final 10 chunks
SQL JOIN vs. PageRank: Why SAG Is Better on Long-Chain Multi-Hop
HippoRAG 2's approach: build a global knowledge graph offline, then use Personalized PageRank (PPR) at query time, propagating scores from seed nodes along graph edges.
The problem is PPR's damping factor: at each hop, the score multiplies by (1-d) (d is typically 0.85), retaining only 15% probability. After 2 hops, a node's score is multiplied by 0.15² = 0.0225; after 3 hops, it's near zero.
HippoRAG 2 long-chain multi-hop problem:
Answer requires path: A → B → C → D → E (4 hops)
After PPR: E's score ≈ seed_score × 0.15⁴ ≈ 0.0005 × seed_score
Distant node scores too low to compete with directly related near nodes
SAG's SQL JOINs don't propagate scores — they propagate reachability: all events connected to Entity X through a JOIN are treated equally, regardless of how many hops they are from the seed.
MuSiQue concentrates this difference: it specifically constructs 4-step reasoning chain questions. HippoRAG 2 significantly underperforms SAG on this dataset (65.1% vs 80.0%).
SAG's weakness is on 2WikiMultiHop: SAG has a fixed entity frontier pruning budget (50 entities). Low-frequency bridging entities can get truncated during pruning, causing SAG to slightly underperform HippoRAG 2 there (88.0% vs 90.4%).
Benchmark Results
Using bge-large-en-v1.5 embeddings and qwen3.6-flash as LLM:
Recall@5 comparison:
| Dataset | SAG | HippoRAG 2 | Gap |
|---|---|---|---|
| MuSiQue | 80.0% | 65.1% | +14.9pp |
| HotpotQA | 96.5% | 94.4% | +2.1pp |
| 2WikiMultiHop | 88.0% | 90.4% | -2.4pp |
| Average Recall@2 | 79.30% | 68.14% | +11.16pp |
Switching to the stronger NV-Embed-v2 embedding raises MuSiQue Recall@5 to 81.71%, confirming the gains come from structural design rather than just embedding quality.
Ablation results:
| Configuration | MuSiQue R@5 |
|---|---|
| Full SAG | 80.0% |
| Remove multi-hop expansion (H=0) | 69.4% |
| Remove structural path | 56.2% |
| Replace LLM reranker with lightweight reranker | 62.2% |
Multi-hop expansion contributes ~10.6pp improvement. LLM reranking is not skippable (17.8pp gap).
Quick Start
git clone https://github.com/Zleap-AI/SAG.git
cd SAG
cp .env.example .env
# Edit .env: add LLM API key, Embedding API key
docker compose up -d # Start PostgreSQL with pgvector
npm install
npm run db:setup
npm run dev
# WebUI: http://localhost:5173
# API: http://localhost:4173
Key .env configuration:
# LLM (OpenAI-compatible API)
LLM_BASE_URL=https://api.openai.com/v1
LLM_API_KEY=your_key
LLM_MODEL=qwen3.6-flash # or gpt-4o-mini
# Embedding
EMBEDDING_BASE_URL=https://api.openai.com/v1
EMBEDDING_API_KEY=your_key
EMBEDDING_MODEL=text-embedding-3-large
# Optional: Rerank model
RERANK_MODEL=qwen3-rerank
# Search mode
DEFAULT_SEARCH_MODE=fast # fast / standard
INGEST_CONCURRENCY=5 # parallel ingestion workers
Two Search Modes
Fast mode (no LLM query parsing):
Query → BM25 full-text entity matching → SQL multi-hop expansion → reranking
Advantage: Low latency, no LLM query parsing cost
Best for: Queries with explicit entity names
Standard mode (LLM entity extraction):
Query → LLM extracts entities → vector + SQL multi-hop expansion → LLM reranking
Advantage: More robust for ambiguous and natural language questions
Best for: Queries requiring complex reasoning
MCP Integration
Each SAG project automatically exposes an MCP server endpoint, usable directly from Claude Code and other agents:
{
"mcpServers": {
"sag": {
"command": "npm",
"args": ["run", "mcp"],
"env": {
"SAG_MCP_SOURCE_ID": "your_project_id"
}
}
}
}
Available MCP tools:
| Tool | Function |
|---|---|
sag_search |
Search the project knowledge base |
sag_ingest_document |
Upload a new document |
sag_explain_search |
Explain the retrieval path for a specific query |
sag_get_event |
Get detailed information for a specific event |
Web UI Features
- Knowledge graph explorer: Visualize event-entity nodes with drag, zoom, and expand
- Search trace visualization: Live display of each retrieval step and stage latency
- Raw model logs: Inspect complete LLM / Embedding / Rerank requests and responses
- Project isolation: Each project has independent document library, conversation history, graph, and MCP configuration
Links and Resources
- 🌟 GitHub: Zleap-AI/SAG
- 📄 arXiv: 2606.15971
- 🔬 Benchmarks: Zleap-AI/SAG-Benchmark
- 🌐 Website: zleap.com
Conclusion
SAG's core contribution is a lightweight multi-hop retrieval implementation: no global knowledge graph pre-built, no PageRank scoring, relational database JOINs doing dynamic graph-structure expansion at query time. Two consequences follow from that choice: document updates are append-only and don't require rebuilds, and SQL JOIN reachability is unaffected by hop count and has no decay.
The "event as semantic unit" design (rather than triples) is also worth attention: each chunk's complete semantics are preserved in one event node, with entities serving only as connection points. This beats the triple approach by nearly 3 percentage points on MuSiQue, validating the design decision.
The weakness is transparent: the fixed pruning budget slightly underperforms HippoRAG 2 on 2WikiMultiHop, missing some critical paths when bridging entities are low-frequency. Knowing where the weakness is makes it possible to judge whether it fits your scenario.
Explore PrimeSkills — A marketplace for handpicked AI Agents and skills. Each is validated in real enterprise workflows, stripping away hype and keeping only what truly works.
Welcome to my Homepage for more useful insights and interesting products.
Top comments (0)