How to Implement Persistent Agent Memory Using ContextGraph in Semantica
Persistent agent memory in Semantica is achieved by combining AgentMemory for conversational fragments with ContextGraph for entity relationships and decisions, using JSON serialization methods save()/load() and save_to_file()/load_from_file() to restore complete agent state across restarts.
Semantica's architecture deliberately separates short-term RAG memory from persistent knowledge storage. This design lets agents retain learned entities, relationship patterns, and decision history even after process termination. The ContextGraph class in semantica/context/context_graph.py serves as the backbone for this persistence layer, working alongside AgentMemory to create a complete, reloadable cognitive state.
Core Components of Persistent Memory
Three integrated classes handle persistence in Semantica:
| Component | Source File | Persistence Role |
|---|---|---|
| AgentMemory | semantica/context/agent_memory.py |
Stores conversational fragments, vector embeddings, and entity links with save()/load() methods |
| ContextGraph | semantica/context/context_graph.py |
Maintains entity/relationship graph and decision nodes with save_to_file()/load_from_file() methods |
| AgentContext | semantica/context/agent_context.py |
High-level façade that wires memory and graph together; persistence flows through its composed components |
Both AgentMemory and ContextGraph use JSON serialization exclusively—no pickles for security. This makes persisted states version-controllable, portable across machines, and cloud-cacheable.
Initializing ContextGraph for Persistent Memory
To enable persistence, instantiate ContextGraph with analytics capabilities and pass it to AgentContext:
from semantica.context import AgentContext, ContextGraph
from semantica.vector_store import SimpleInMemoryStore
# Create the vector store backend
vector_store = SimpleInMemoryStore()
# Initialize ContextGraph with advanced analytics
kg = ContextGraph(advanced_analytics=True) # Enables centrality, community detection
# Create the agent context with decision tracking
ctx = AgentContext(
vector_store=vector_store,
knowledge_graph=kg,
decision_tracking=True, # Required to use ContextGraph decision APIs
retention_days=60, # Automatic memory expiration
)
Setting advanced_analytics=True in ContextGraph.__init__() enables graph algorithms (degree centrality, community detection) that help the agent rank entity importance and identify knowledge clusters.
Storing Memories with Entity Extraction
The AgentContext.store() method forwards to AgentMemory.store(), which performs three operations: buffering in short-term memory, indexing in the vector store, and updating the ContextGraph with extracted entities:
# Store a conversational memory with linked entities
mem_id = ctx.store(
content="User asked how to encrypt data with AES-256",
metadata={"type": "conversation", "conversation_id": "conv-42"},
entities=[
{"id": "aes_256", "type": "algorithm", "text": "AES-256"},
{"id": "encryption", "type": "concept", "text": "encryption"},
],
)
The internal _update_knowledge_graph() call in AgentMemory creates nodes for each entity and links them to the memory item. These entities become addressable in the persistent graph for future retrieval and decision-making.
Recording Decisions in ContextGraph
When decision_tracking=True, AgentContext exposes record_decision() to create causal links between memories and agent actions:
dec_id = ctx.record_decision(
category="security_policy",
scenario="data_at_rest",
reasoning="User wants strong encryption",
outcome="enable_aes_256",
confidence=0.97,
entities=["aes_256"], # Links decision to existing graph node
)
This creates a decision node in ContextGraph connected to the same entities that appear in memory items. The resulting structure forms a causal view of why specific agent actions were taken, queryable via trace_decision_causality().
Persisting Agent State to Disk
To implement true persistence, serialize both components before shutdown:
# Persist AgentMemory (includes items, buffer, vector-ID mappings, statistics)
ctx.memory.save("./persisted_memory") # Creates agent_memory.json
# Persist ContextGraph (includes nodes, edges, sub-graphs, decision nodes)
ctx.knowledge_graph.save_to_file("./graph.json")
Both calls produce self-contained JSON files:
AgentMemory.save()insemantica/context/agent_memory.pywrites: items dictionary, short-term deque, vector-ID map, and runtime statisticsContextGraph.save_to_file()insemantica/context/context_graph.pywrites: nodes, edges, linked sub-graphs, and analytics cache
Restoring Persistent Memory After Restart
The reload sequence recreates the identical cognitive state:
from semantica.context import AgentContext, ContextGraph
from semantica.vector_store import SimpleInMemoryStore
# Reinitialize with the same vector store backend
vector_store = SimpleInMemoryStore()
# Restore the ContextGraph first
kg = ContextGraph()
kg.load_from_file("./graph.json") # Rebuilds entity/decision graph
# Create AgentContext with restored graph
ctx = AgentContext(
vector_store=vector_store,
knowledge_graph=kg,
decision_tracking=True,
)
# Restore AgentMemory (must happen after AgentContext creation)
ctx.memory.load("./persisted_memory") # Restores all memories and mappings
# Agent now retains full prior state: conversations, entities, and decisions
Critical restoration order: ContextGraph must be loaded before AgentContext construction, but AgentMemory.load() must occur after AgentContext exists since AgentContext creates and holds the AgentMemory instance.
Querying Persisted Knowledge Graph Data
Once restored, combine semantic retrieval with graph analytics:
# Hybrid RAG + graph context retrieval
results = ctx.retrieve(
"What encryption method should I use?",
max_results=5,
min_score=0.2,
type="conversation",
)
# Rank results by entity centrality in the knowledge graph
for r in results:
for entity in r.get("entities", []):
centrality = ctx.knowledge_graph.get_node_centrality(entity["id"])
print(f"{entity['text']}: degree={centrality['degree']}")
The get_node_centrality() method—available when advanced_analytics=True—returns degree, betweenness, and eigenvector centrality scores that help the agent prioritize more "important" entities in reasoning.
Tracing Decision Causality
Leverage ContextGraph to explain why specific decisions were made:
# Trace the causal chain for a recorded decision
causal_chain = ctx.knowledge_graph.trace_decision_causality(dec_id)
for hop in causal_chain:
print(f"Node: {hop['node_id']}, Reason: {hop['reason']}")
This traversal follows edges from decision nodes through supporting entities and prerequisite memories, enabling explainable agent behavior audits.
Summary
- Persistent agent memory requires both
AgentMemory(conversational data) andContextGraph(entity/decision graph) working together - JSON serialization via
save()/load()andsave_to_file()/load_from_file()provides secure, portable, version-controllable persistence - Entity linking during
store()operations creates the bridge between raw memory and structured graph knowledge - Decision tracking with
record_decision()builds causal, explainable agent action histories - Restoration order matters: load
ContextGraphbeforeAgentContext, thenAgentMemoryafter
Frequently Asked Questions
What file formats does Semantica use for persistent memory?
Semantica uses JSON exclusively for all persistence. Both AgentMemory.save() and ContextGraph.save_to_file() produce JSON outputs. This design avoids pickle serialization for security (preventing arbitrary code execution) and enables human inspection, version control, and cross-platform portability.
Can I use a different vector store with persisted ContextGraph?
Yes. The vector store and ContextGraph are loosely coupled. You can persist AgentMemory and ContextGraph independently, then restore them with any vector store implementation that matches your original schema. However, AgentMemory maintains an internal vector_id_map that must remain consistent with your vector store's indexing—use the same backend type (e.g., SimpleInMemoryStore, Chroma, Pinecone) for reliable retrieval.
How do I migrate persisted memory between Semantica versions?
Since persistence uses self-contained JSON, migrate by: (1) loading with the original version, (2) optionally reprocessing with AgentContext methods to update schemas, and (3) saving with the new version. The ContextGraph structure in semantica/context/context_graph.py uses standard node/edge dictionaries that remain backward-compatible across minor versions.
Does ContextGraph persistence include vector embeddings?
No—embeddings are not stored in ContextGraph. Vector embeddings reside in the configured vector_store (passed to AgentContext). Persist the vector store separately using its own mechanism (e.g., Chroma's persist() or Pinecone's native storage). AgentMemory saves only the mapping between memory items and vector IDs, not the embeddings themselves.
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 →