How to Implement GraphRAG with Semantica's Context Graphs: A Complete Guide
Pass a knowledge graph instance to AgentContext along with a vector store, and Semantica automatically switches from standard RAG to GraphRAG—enabling hybrid semantic-graph retrieval with multi-hop reasoning.
Semantica's AgentContext class in semantica-agi/semantica provides a unified API for building GraphRAG applications. When you supply both a vector store and a knowledge graph, the context manager auto-detects GraphRAG mode and delegates retrieval to a specialized hybrid retriever. This article walks through the implementation, from backend setup to LLM-powered reasoning over knowledge graphs.
What Is GraphRAG in Semantica?
GraphRAG (Graph Retrieval-Augmented Generation) combines vector similarity search with graph-structured traversal to retrieve more contextually relevant information than either approach alone. In Semantica, this means:
- Semantic lookup: Find documents by embedding similarity
- Graph expansion: Traverse entity relationships to discover connected information
- Hybrid scoring: Blend vector and graph relevance signals
The architecture is designed so you don't manually switch between retrieval modes. The presence of a knowledge graph triggers automatic behavior changes in the retrieval pipeline.
Auto-Detection Logic in AgentContext
The GraphRAG decision happens in AgentContext.retrieve at lines 49-52 of semantica/context/agent_context.py:
# From semantica/context/agent_context.py#L49-L52
def retrieve(self, query: str, **kwargs):
use_graph = self.knowledge_graph is not None and self._retriever is not None
if use_graph:
return self._retriever.retrieve(query, **kwargs)
# Fallback to vector-only retrieval...
When use_graph evaluates to True, the request routes to ContextRetriever.retrieve. Otherwise, execution falls through to AgentMemory.retrieve for pure vector search (lines 81-85).
This auto-detection design means zero configuration changes between RAG and GraphRAG modes—you simply pass or omit the knowledge_graph parameter during AgentContext initialization.
The Hybrid Retrieval Pipeline
Semantic Vector Lookup
ContextRetriever.retrieve performs the initial retrieval using vector similarity, then enriches results with graph context. The method signature and first phase appear at lines 58-66:
# From semantica/context/agent_context.py#L58-L66
def retrieve(self, query: str, max_results: int = 10, expand_graph: bool = True):
# Phase 1: Semantic vector search
vector_results = self.vector_store.search(query, k=max_results * 2)
# Phase 2: Optional graph expansion
if expand_graph and self.knowledge_graph:
graph_results = self._expand_via_graph(query, vector_results)
# Merge and re-rank...
Graph Expansion and Proximity Weighting
The retriever applies graph-based proximity weighting through _apply_proximity_metadata (lines 85-90 and 105-112). This boosts items closer to user-specified anchor nodes:
# Conceptual flow from semantica/context/agent_context.py#L85-L112
def _apply_proximity_metadata(self, results, anchor_node=None):
if anchor_node and self.knowledge_graph:
distances = self.knowledge_graph.node_distances(anchor_node)
for result in results:
entity_id = result.get("entity_id")
if entity_id in distances:
# Reduce score proportional to graph distance
proximity_boost = 1.0 / (1.0 + distances[entity_id])
result["score"] *= (1 + self.proximity_weight * proximity_boost)
return results
Multi-hop traversal depth is configurable via max_hops parameters in both retrieval and reasoning methods.
Complete Implementation Example
This end-to-end example demonstrates GraphRAG setup with PGVector and AgnoKnowledgeGraph (Neo4j backend):
# -------------------------------------------------
# 1️⃣ Set up a vector store (PGVector used here)
# -------------------------------------------------
from semantica.vector_store.pgvector import PGVectorStore
vector_store = PGVectorStore(
connection_string="postgresql://user:pwd@localhost/semantica",
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
)
# -------------------------------------------------
# 2️⃣ Set up a knowledge-graph backend
# -------------------------------------------------
from semantica.integrations.agno.knowledge_graph import AgnoKnowledgeGraph
kg = AgnoKnowledgeGraph(
uri="bolt://localhost:7687",
auth=("neo4j", "password"),
embedder=vector_store.embedding_model,
)
# -------------------------------------------------
# 3️⃣ Build the AgentContext (GraphRAG enabled)
# -------------------------------------------------
from semantica.context import AgentContext
ctx = AgentContext(
vector_store=vector_store,
knowledge_graph=kg, # <-- presence triggers GraphRAG
graph_expansion=True, # enable multi-hop expansion
hybrid_alpha=0.6, # 60% graph weight, 40% vector weight
decision_tracking=True, # optional decision-tracking features
)
# -------------------------------------------------
# 4️⃣ Store documents with auto graph-building
# -------------------------------------------------
docs = [
{"content": "Patient John has hypertension.", "metadata": {"type": "clinical_note"}},
{"content": "Hypertension increases stroke risk.", "metadata": {"type": "knowledge_base"}},
]
ctx.store(docs, extract_entities=True, extract_relationships=True)
# -------------------------------------------------
# 5️⃣ Retrieve with GraphRAG (hybrid search)
# -------------------------------------------------
results = ctx.retrieve(
query="What are the complications of hypertension?",
max_results=5,
expand_graph=True, # uses graph expansion
)
for r in results:
print("- Score:", round(r["score"], 3), "Content:", r["content"])
# -------------------------------------------------
# 6️⃣ LLM-driven reasoning over the graph
# -------------------------------------------------
from semantica.llms import Groq
llm = Groq(model="llama-3.1-8b-instant")
answer = ctx.query_with_reasoning(
query="How does hypertension relate to stroke risk?",
llm_provider=llm,
max_hops=2,
)
print("\n🔎 Answer:", answer["response"])
print("🧭 Reasoning path:", answer["reasoning_path"])
Multi-Hop Reasoning with LLM Integration
The query_with_reasoning method (lines 96-104) extends retrieval with structured reasoning. It builds multi-hop paths through the graph and prompts an LLM to generate grounded answers:
# From semantica/context/agent_context.py#L96-L104
def query_with_reasoning(self, query: str, llm_provider, max_hops: int = 2, **kwargs):
# Build reasoning paths via graph traversal
paths = self._build_reasoning_paths(query, max_hops=max_hops)
# Construct prompt with retrieved context and path structure
prompt = self._format_reasoning_prompt(query, paths)
# Generate answer with traceability
response = llm_provider.generate(prompt)
return {
"response": response,
"reasoning_path": paths,
"source_nodes": self._extract_sources(paths)
}
Key parameters for reasoning control:
| Parameter | Purpose | Default |
|---|---|---|
max_hops |
Maximum traversal depth for path building | 2 |
path_strategy |
Path selection: shortest, diverse, or scored |
scored |
include_intermediates |
Return subgraph of traversed nodes | False |
Knowledge Graph Backend: AgnoKnowledgeGraph
Semantica ships with AgnoKnowledgeGraph in integrations/agno/knowledge_graph.py, implementing the required graph API:
- Vector-augmented search: Combine embedding similarity with graph topology
- Multi-hop traversal: BFS or DFS with relationship-type filtering
- Decision tracking: Annotate retrieval decisions for explainability
Alternative backends (Neo4j native, NetworkX, etc.) can be integrated by implementing the same interface:
class CustomKnowledgeGraph:
def search(self, embedding: list, k: int = 10) -> list: ...
def traverse(self, start_node: str, max_depth: int, filters: dict) -> list: ...
def node_distances(self, anchor: str) -> dict: ...
Key Configuration Parameters
When initializing AgentContext for GraphRAG, these parameters control hybrid behavior:
| Parameter | Effect | Typical Value |
|---|---|---|
hybrid_alpha |
Weight for graph vs. vector scores (0=vector-only, 1=graph-only) | 0.5–0.7 |
graph_expansion |
Enable multi-hop expansion beyond initial vector results | True |
proximity_weight |
Strength of distance-based_boosting for anchor nodes | 0.3–0.5 |
max_expansion_nodes |
Limit graph traversal breadth for latency control | 20–50 |
Summary
AgentContextauto-detects GraphRAG whenknowledge_graphis provided, routing retrieval toContextRetrieverinstead ofAgentMemory- Hybrid retrieval merges vector similarity with graph expansion and proximity weighting in
semantica/context/context_retriever.py query_with_reasoningenables LLM-powered answers with explicit reasoning paths through the knowledge graph- AgnoKnowledgeGraph provides a production-ready Neo4j backend with vector-augmented search and decision tracking
- Minimal code changes are required to upgrade from RAG to GraphRAG—swap the context initialization and enable entity extraction
Frequently Asked Questions
What triggers GraphRAG mode versus standard RAG in Semantica?
GraphRAG activates when you pass a knowledge_graph instance to AgentContext and a retriever is initialized. The check self.knowledge_graph is not None and self._retriever is not None at line 49 of agent_context.py determines the retrieval path. Without a knowledge graph, the system transparently falls back to vector-only search through AgentMemory.retrieve.
Can I use GraphRAG without entity extraction during document storage?
Yes, but with limited connectivity. The store() method accepts extract_entities=False and extract_relationships=False, which skips automatic graph building. You can subsequently populate the graph manually via knowledge_graph.add_node() and knowledge_graph.add_edge() calls, or use pre-existing graph data. Graph expansion during retrieval still works if the underlying graph contains relevant nodes.
How does the hybrid_alpha parameter affect retrieval quality?
hybrid_alpha controls the interpolation between vector and graph relevance scores in the final ranking. A value of 0.6 applies 60% weight to graph-based signals (proximity, connectivity, path strength) and 40% to vector similarity. Higher values prioritize relational structure—useful for domain-specific queries where explicit relationships matter more than semantic similarity. Lower values suit open-domain questions where embedding match quality dominates.
What LLM providers work with query_with_reasoning?
Any provider implementing Semantica's LLM interface in semantica/llms/__init__.py. The built-in Groq wrapper is shown in the example; additional providers (OpenAI, Anthropic, local models via vLLM/ollama) can be integrated by subclassing the base LLM class and implementing generate() and embed() methods.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →