AutoGen integration
Add long-term agent memory to AutoGen agents
The zep-autogen package integrates Zep with Microsoft AutoGen agents, backing them with long-term memory and a temporal knowledge graph. It provides memory classes that plug into AutoGen’s native Memory interface for automatic context injection, plus function tools the agent can call to search and add data on demand. Choose between user-specific conversation memory or structured knowledge graph memory.
Core benefits
- Native
Memoryinterface:ZepUserMemoryandZepGraphMemoryimplement AutoGen’sMemoryinterface, so they drop straight into an agent’smemorylist - Automatic context injection: Relevant memory is retrieved and prepended to the model context before each turn via
update_context() - User and knowledge graphs: Persist a user’s conversation history or maintain a shared knowledge graph with custom entity models
- On-demand function tools: Pre-built tools let the agent explicitly search and add graph data when it chooses
- Graceful degradation: A Zep failure is logged but does not crash the agent run
How it works
The integration exposes two complementary retrieval paths:
- Memory classes (
ZepUserMemory,ZepGraphMemory) attach to an agent’smemorylist. AutoGen callsupdate_context()before each turn, and the class retrieves memory from Zep and injects it as a system message — transparent, automatic context on every interaction. - Function tools (
create_search_graph_tool,create_add_graph_data_tool) attach to an agent’stoolslist. The model decides when to call them, giving explicit, observable search and add operations that work with AutoGen’s tool reflection.
Both approaches can be combined on the same agent: memory for consistent background context, tools for targeted lookups.
Context injection is automatic, but persistence is not: AutoGen’s Memory protocol has no hook that fires after the model responds, so your application calls memory.add() explicitly — typically once per user turn and once per assistant turn. This is AutoGen’s design, not a limitation of the integration.
Installation
Requires Python 3.11+, zep-cloud>=3.23.0, autogen-agentchat>=0.7.0, and a Zep Cloud API key. Get your API key from app.getzep.com.
Set up your environment variables:
Upgrading from zep-autogen 1.1.x
Two changes affect existing code.
ZepUserMemory now creates the Zep user and thread lazily on first use instead of requiring pre-provisioning. If your code relied on a 404 from update_context() to detect an unprovisioned user, that signal is gone — call ensure_user/ensure_thread explicitly instead and check their return value.
Search tools also expose scope, reranker, limit, mmr_lambda, and center_node_uuid to the model by default — pass pinned_params (or the legacy scope/limit arguments, which pin) to restore fixed values. See the changelog for the full release history.
Memory types
- User memory: Stores conversation history in user threads with automatic context injection
- Knowledge graph memory: Maintains structured knowledge with custom entity models
User memory
ZepUserMemory persists messages to a user’s thread and injects the context block into the agent before each turn. Set up the imports, initialize the memory, attach it to an agent, then store messages as the conversation proceeds.
Initialize the client and memory
ZepUserMemory binds the client, user, and thread into a memory object that AutoGen can attach to an agent. The Zep user and thread are created lazily on first use by whichever of add() or update_context() runs first — no pre-creation step is required. Creation is idempotent and cached per instance.
The lazy path never raises into add() or update_context(): a provisioning failure (including an on_created failure) is logged and swallowed. To surface provisioning failures loudly — for example during account onboarding, before the first turn — call ensure_user and ensure_thread out-of-band:
Both helpers are idempotent and return True only when the resource is newly created.
Attach the memory to an agent
Pass the memory in the agent’s memory list so context is injected before each turn.
Store messages and run
Persistence is manual: AutoGen never calls memory.add() for you, so persist each turn explicitly — once for the user message and once for the assistant reply. The agent automatically retrieves context via update_context() before responding; skipping the add() calls means the agent still sees Zep’s existing context, but that turn’s messages are never written to Zep and cannot be recalled later.
Automatic context injection: ZepUserMemory injects relevant memory via the update_context() method before each turn. On the default retrieval path it injects the context block and, when one is available, also appends up to 10 recent thread messages. When a context_builder is set, only the builder’s output is injected.
Allow time for indexing — Zep extracts knowledge asynchronously, so facts from a turn are not instantly searchable. Allow time for indexing before querying for newly added content.
Custom context retrieval
By default, update_context() retrieves context via thread.get_user_context(...). Pass context_builder to replace this with custom logic — for example a filtered graph search, or a different graph entirely:
The builder receives a single frozen ContextInput:
If the builder raises, a warning is logged and context injection is skipped for that turn — update_context() never raises. The builder is retrieval-only and never runs concurrently with message persistence: AutoGen’s Memory protocol calls update_context() (injection) and add() (persistence) as two separate, caller-controlled steps, so persist turns explicitly via add().
Customizing the injected context template
Retrieved context (from the default retrieval or a context_builder) is wrapped in context_template before being added to the model context as a system message. The default DEFAULT_CONTEXT_TEMPLATE wraps the context in <ZEP_CONTEXT> tags with a short preamble. Override it with your own wording, as long as it contains a literal {context} placeholder:
The template is rendered via plain string replacement (template.replace("{context}", ...)), never str.format, so context text containing {, }, or % is always safe to inject.
Knowledge graph memory
ZepGraphMemory maintains a standalone knowledge graph with custom entity models. Define an ontology, create the graph, initialize the memory with search filters, add data, then attach the memory to an agent.
ZepGraphMemory is scoped to a standalone graph_id, not a Zep user, so it has no on_created hook and no lazy user provisioning — create the graph out-of-band via graph.create as shown below.
Define entity models
Custom entity models shape how Zep extracts structured knowledge from the data you add.
Set the ontology and create the graph
Register the entity models as the graph’s ontology, then create the graph that will hold the extracted knowledge.
Initialize the graph memory
Configure search filters and context limits to control what ZepGraphMemory injects on each turn.
Graph memory context injection: ZepGraphMemory automatically retrieves the last 2 episodes from the graph and uses their content to query for relevant facts (up to facts_limit) and entities (up to entity_limit). This context is injected as a system message during agent interactions.
Tools integration
Zep tools let agents search and add data directly to memory storage with manual control and structured responses.
Important: Tools must be bound to either graph_id OR user_id, not both. This determines whether they operate on knowledge graphs or user graphs.
Search tool parameters
create_search_graph_tool follows a pin-or-expose pattern: every graph.search parameter is exposed to the model by default, each with a typed schema and documented default. Letting the model choose the scope and reranker per query produces better retrieval than a single fixed configuration; pin parameters when you need deterministic behavior instead. query is always exposed and required.
Use pinned_params to fix a parameter to a constant (hidden from the model), or hidden_params to remove it from the schema without pinning (Zep’s server-side default applies):
The legacy scope and limit arguments pin (and hide) the corresponding parameter — equivalent to passing them via pinned_params. search_filters and bfs_origin_node_uuids are constructor-only and never exposed to the model.
AutoGen’s FunctionTool derives its JSON schema strictly from the wrapped function’s typed signature. create_search_graph_tool implements pin-or-expose by building that signature dynamically: exposed parameters become real, typed parameters of the function AutoGen introspects, while pinned and hidden parameters are never part of the signature at all.
Add tool parameters
create_add_graph_data_tool exposes:
data: str (required) - Content to storedata_type: str (optional, default “text”) - Data type: “text”, “json”, “message”
User graph tools
Knowledge graph tools
Size limits
Zep rejects over-long direct SDK payloads with an HTTP 400. The AutoGen integration truncates before calling Zep, logging only the before and after lengths (never the content):
- Thread messages (
ZepUserMemory.addwithtype="message"): truncated to 4,000 characters, a safety margin under Zep’s 4,096-character thread-message limit - Graph data (
ZepGraphMemory.add,ZepUserMemory.addwithtype="data", andcreate_add_graph_data_tool): truncated to 9,900 characters, a safety margin under Zep’s 10,000-charactergraph.addlimit
Query memory
Both memory types support direct querying with different scope parameters.
User memory queries
Graph memory queries
Search result structure
Edge results (facts)
Node results (entities)
Episode results (messages)
Memory vs tools comparison
Memory objects (ZepUserMemory / ZepGraphMemory):
- Automatic context injection via
update_context(); persistence stays manual viaadd() - Attached to the agent’s
memorylist - Transparent operation — happens automatically
- Better for consistent memory across interactions
Function tools (search/add tools):
- Manual control — the agent decides when to use them
- More explicit and observable operations
- Better for specific search/add operations
- Works with AutoGen’s tool reflection features
- Provides structured return values
Note: Both approaches can be combined — use memory for automatic context and tools for explicit operations.
Best practices
- Pick the right memory type — use
ZepUserMemoryfor per-user conversation history andZepGraphMemoryfor a shared knowledge graph - Persist every turn explicitly — call
memory.add()once per user turn and once per assistant turn; injection is the only automatic half of the loop - Bind tools to exactly one scope — a search or add tool targets either a
graph_idor auser_id, never both - Combine memory and tools — attach a memory class for automatic context and add function tools for targeted lookups
- Allow time for indexing — Zep extracts knowledge asynchronously, so facts from a turn are not instantly searchable
Next steps
- Explore customizing graph structure for advanced knowledge organization
- Learn about searching the graph and how to tune search
- See code examples for additional patterns