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

  • AgentContext auto-detects GraphRAG when knowledge_graph is provided, routing retrieval to ContextRetriever instead of AgentMemory
  • Hybrid retrieval merges vector similarity with graph expansion and proximity weighting in semantica/context/context_retriever.py
  • query_with_reasoning enables 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →