# How to Implement GraphRAG with Semantica's Context Graphs: A Complete Guide

> Implement GraphRAG with Semantica's context graphs. Pass a knowledge graph to AgentContext for hybrid semantic-graph retrieval and multi-hop reasoning. Discover how in this complete guide.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-08-16

---

**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`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/agent_context.py):

```python

# 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:

```python

# 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:

```python

# 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):

```python

# -------------------------------------------------

# 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:

```python

# 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`](https://github.com/semantica-agi/semantica/blob/main/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:

```python
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`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/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.