# How to Integrate Knowledge Graphs for Structured Agent Memory

> Learn to integrate knowledge graphs for structured agent memory. Extend the KnowledgeBase class to store RDF triples and enable semantic search and graph queries for enhanced AI agent capabilities.

- Repository: [Bojie Li/ai-agent-book](https://github.com/bojieli/ai-agent-book)
- Tags: how-to-guide
- Published: 2026-07-31

---

**You can integrate knowledge graphs into agent memory by extending the `KnowledgeBase` class in [`chapter8/gaia-experience/knowledge_base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter8/gaia-experience/knowledge_base.py) to store RDF-style triples (subject, predicate, object) alongside text documents, enabling both semantic search and structured graph queries.**

The `bojieli/ai-agent-book` repository provides a generic experience storage system that stores documents and enables semantic search through FAISS indexing. To add structured reasoning capabilities, you can layer a lightweight knowledge graph on top of this existing infrastructure without modifying the underlying persistence logic, allowing agents to retrieve precise factual relationships while maintaining fuzzy semantic retrieval.

## Why Knowledge Graphs Matter for Agent Memory

Knowledge graphs provide deterministic, interpretable relationships between entities that complement the fuzzy matching of vector embeddings. While **semantic search** retrieves relevant context based on similarity scores, **graph traversal** retrieves precise facts (e.g., "Paris → capital_of → France") that follow logical rules and support explainable reasoning.

The base implementation stores experiences as unstructured text documents. By adding a triple layer, you enable the agent to answer questions requiring exact entity relationships that might be semantically distant in embedding space but logically adjacent in the graph.

## Extending the KnowledgeBase Class with Triple Storage

The base `KnowledgeBase` class in [`chapter8/gaia-experience/knowledge_base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter8/gaia-experience/knowledge_base.py) manages documents, embeddings, and FAISS indexing through the `documents` and `metadata` lists. To support graph structures, subclass `KnowledgeBase` and add triple handling while preserving the existing persistence mechanisms.

### Representing Facts as RDF-Style Triples

Each piece of structured knowledge follows the *(subject, predicate, object)* format. Store these triples within document dictionaries that remain compatible with the existing `documents` list:

```python
container = {
    "triples": [("Python", "created_by", "Guido van Rossum")],
    "metadata": {"source": "graph"},
    "source": "graph"
}

```

This approach ensures that `documents.pkl` automatically persists the graph data alongside regular text documents.

### Implementing the GraphKnowledgeBase Subclass

Create a subclass that adds graph-specific methods while inheriting persistence and indexing behavior from the base implementation:

```python
from chapter8.gaia_experience.knowledge_base import KnowledgeBase
import logging

logger = logging.getLogger(__name__)

class GraphKnowledgeBase(KnowledgeBase):
    """KnowledgeBase with an embedded RDF-style graph."""
    
    def add_triple(self, subject: str, predicate: str, obj: str,
                   metadata: dict | None = None):
        """Append a new triple to the documents list and update the index."""
        triple = (subject, predicate, obj)
        container = {
            "triples": [triple],
            "metadata": metadata or {},
            "source": "graph",
        }
        # Store the container as a normal document

        self.documents.append(container)
        self.metadata.append({"query": f"{subject} {predicate} {obj}"})
        
        # Re-index the new entry if an encoder is available

        if self.encoder and self.index:
            try:
                emb = self.encoder.encode([f"{subject} {predicate} {obj}"])
                self.index.add(emb)
            except Exception as e:
                logger.error(f"Failed to index triple: {e}")

```

The `add_triple` method appends new facts to the `documents` list and updates the FAISS index, ensuring triples remain searchable via semantic similarity while preserving their structured format.

## Querying and Updating the Graph

Agents interact with the knowledge graph through the `search` method, which combines vector similarity with structured triple matching to provide comprehensive context.

### Structured Retrieval with Triple Matching

Implement a token-based matcher that retrieves triples where subjects or objects match query terms:

```python
    def _graph_match(self, query: str):
        """Simple triple matcher – returns triples whose subject or object contains any query token."""
        tokens = set(query.lower().split())
        matches = []
        for doc in self.documents:
            for subj, pred, obj in doc.get("triples", []):
                if tokens & set(subj.lower().split()) or tokens & set(obj.lower().split()):
                    matches.append({"subject": subj, "predicate": pred, "object": obj})
        return matches

    def search(self, query: str, top_k: int = 3):
        """First use semantic search, then augment with graph matches."""
        results = super().search(query, top_k)           # existing docs

        graph_hits = self._graph_match(query)            # structured hits

        # Combine and de-duplicate

        return results + [{"graph": hit} for hit in graph_hits][:top_k]

```

The overridden `search` method first calls `super().search()` for semantic retrieval, then enriches results with matching triples from `_graph_match()`, giving the agent both contextual embeddings and structured facts.

### Agent-Side Graph Updates

Agents add knowledge dynamically by calling `add_triple`, which automatically handles persistence through the existing `_save_index` method:

```python

# Example usage from an agent

kb = GraphKnowledgeBase(index_path="./kb_graph")
kb.add_triple("Paris", "capital_of", "France")
kb.add_triple("OpenAI", "produces", "GPT-4")

# Query combines semantic and graph search

results = kb.search("Who created Python?")

```

## Integration with ExperienceAgent

The `ExperienceAgent` class in [`chapter8/gaia-experience/experience_agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter8/gaia-experience/experience_agent.py) calls `KnowledgeBase.search` to retrieve context for decision-making. By instantiating `GraphKnowledgeBase` instead of the base class, the agent automatically receives both semantic search results and structured triples without modifying the agent's core logic.

```python

# In experience_agent.py or your initialization script

from chapter8.gaia_experience.knowledge_base import GraphKnowledgeBase

class ExperienceAgent:
    def __init__(self, index_path: str):
        self.kb = GraphKnowledgeBase(index_path=index_path)
    
    def retrieve_context(self, query: str):
        """Retrieve combined semantic and graph context."""
        return self.kb.search(query, top_k=5)

```

The [`run_with_experience.py`](https://github.com/bojieli/ai-agent-book/blob/main/run_with_experience.py) script demonstrates end-to-end usage and can be modified to instantiate `GraphKnowledgeBase` instead of the base `KnowledgeBase`.

## Persistence and Storage Details

The base `KnowledgeBase` persists data via `documents.pkl`, `metadata.pkl`, and `faiss.index` through the `_save_index` and `_load_index` methods. Because triples are stored as dictionaries within the `documents` list, they are automatically pickled alongside other documents. No changes to storage logic are required to persist the graph.

To access the raw graph for debugging or export:

```python
def get_all_triples(kb: GraphKnowledgeBase):
    """Utility to fetch the whole graph for inspection or external export."""
    all_triples = []
    for doc in kb.documents:
        all_triples.extend(doc.get("triples", []))
    return all_triples

# Extract complete graph

print("Full graph:", get_all_triples(kb))

```

## Summary

- **Subclass `KnowledgeBase`** from [`chapter8/gaia-experience/knowledge_base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter8/gaia-experience/knowledge_base.py) to add triple storage while preserving existing persistence via `documents.pkl` and `faiss.index`.
- **Store triples as (subject, predicate, object)** tuples within document dictionaries to leverage automatic pickle-based storage and FAISS indexing.
- **Combine semantic and graph search** by overriding the `search` method to call both `super().search()` for embeddings and `_graph_match()` for structured retrieval.
- **Update the graph dynamically** through `add_triple`, which appends facts to `self.documents` and refreshes the vector index without manual persistence calls.
- **Integrate seamlessly** with `ExperienceAgent` in [`chapter8/gaia-experience/experience_agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter8/gaia-experience/experience_agent.py) by substituting the base class with `GraphKnowledgeBase` in your initialization code.

## Frequently Asked Questions

### Can I export the knowledge graph to standard RDF formats like Turtle or JSON-LD?

Yes. The `get_all_triples` utility extracts all *(subject, predicate, object)* tuples from the `documents` list. You can then serialize these using libraries like `rdflib` to generate Turtle, JSON-LD, or other RDF formats while preserving the original FAISS index for semantic search capabilities.

### How does the graph layer affect the existing FAISS vector search performance?

The graph layer adds minimal overhead. Triples are indexed as text embeddings when added via `add_triple`, and `_graph_match` performs simple token-based filtering on retrieved candidates. The FAISS approximate nearest neighbor search performance remains unchanged for semantic queries.

### Where should I initialize the GraphKnowledgeBase in the agent lifecycle?

Initialize it in [`run_with_experience.py`](https://github.com/bojieli/ai-agent-book/blob/main/run_with_experience.py) or your main entry point, then pass it to `ExperienceAgent`. Alternatively, modify [`experience_agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/experience_agent.py) to instantiate `GraphKnowledgeBase` instead of the base `KnowledgeBase` class. The persistence files (`documents.pkl`, `faiss.index`) will store the graph data automatically through the inherited `_save_index` method.

### Can the agent update the knowledge graph dynamically during task execution?

Yes. Expose the `add_triple` method through the agent's interface, allowing it to capture new relationships discovered during tool use or reasoning. Because `add_triple` appends to `self.documents` and triggers re-indexing, the graph persists across sessions without manual intervention, automatically saving when the process exits or when `_save_index` is called.