How to Integrate Knowledge Graphs for Structured Agent Memory
You can integrate knowledge graphs into agent memory by extending the KnowledgeBase class in 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 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:
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:
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:
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:
# 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 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.
# 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 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:
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
KnowledgeBasefromchapter8/gaia-experience/knowledge_base.pyto add triple storage while preserving existing persistence viadocuments.pklandfaiss.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
searchmethod to call bothsuper().search()for embeddings and_graph_match()for structured retrieval. - Update the graph dynamically through
add_triple, which appends facts toself.documentsand refreshes the vector index without manual persistence calls. - Integrate seamlessly with
ExperienceAgentinchapter8/gaia-experience/experience_agent.pyby substituting the base class withGraphKnowledgeBasein 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 or your main entry point, then pass it to ExperienceAgent. Alternatively, modify 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.
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 →