Google ADK integration
Google’s Agent Development Kit (ADK) agents equipped with Zep’s context layer can maintain context across conversations and access personalized knowledge graphs. The zep-adk package provides real-time message persistence and automatic context injection for ADK agents.
Core benefits
- Zero restructuring: Add Zep to an existing ADK agent without changing your agent architecture
- Shared-agent architecture: One
Agentdefinition serves all users. Per-user identity is resolved at runtime from ADK session state - Real-time persistence: Both user and assistant messages are persisted to Zep on every turn, not batched at session end
- Automatic context injection: Zep’s context block — facts, relationships, and prior knowledge — is injected into the LLM prompt before each response
- Lazy resource creation: Zep users and threads are created automatically on first use
How it works
The integration uses two components that hook into ADK’s agent lifecycle:
ZepContextTool — A BaseTool subclass that overrides process_llm_request() (the same hook ADK’s own PreloadMemoryTool uses). On every LLM turn, it resolves the user’s Zep identity from session state, persists the user’s message, retrieves relevant context, and injects it into the LLM’s system instruction. The tool is never called by the model directly.
create_after_model_callback — A factory that returns an after_model_callback for persisting assistant responses to Zep after each model call.
What gets persisted
Only the user’s message and the model’s final response are persisted to Zep on each turn. Intermediate model outputs — such as “thinking” text emitted alongside a tool call (e.g. “Let me look that up for you.”) — are not persisted. Tool calls and tool results are also excluded. This keeps the Zep thread clean: one user message and one assistant message per turn, reflecting the actual conversation rather than internal agent mechanics.
If the user message contains multiple text parts (e.g. text alongside an image), all text parts are joined. Non-text parts (images, files) are ignored — only text is sent to Zep.
This approach does not use ADK’s BaseMemoryService abstraction. Zep’s real-time, per-message memory model doesn’t fit ADK’s batch-at-session-end pattern. See Why not BaseMemoryService? for details.
Installation
Requires Python 3.10+, google-adk>=1.0.0, and a Zep Cloud API key. Get your API key from app.getzep.com. If google-adk is not installed, importing zep_adk raises a ZepDependencyError (an ImportError subclass) with installation instructions.
Adding Zep to an agent
Whether you’re building a new agent or adding Zep to an existing one, the setup is the same. Add ZepContextTool to your tools list and wire up the after-model callback:
That’s it. Every user message is persisted to Zep, relevant context is injected into the LLM prompt, and assistant responses are captured — all automatically.
The ignore_roles parameter shown above excludes specific message roles from graph ingestion while still storing them in the thread history. This is useful when assistant messages don’t add meaningful knowledge to the graph — they’re preserved for conversation context but don’t create nodes or edges. Both ZepContextTool and create_after_model_callback accept ignore_roles. See Ignore assistant messages in the Zep docs for more detail.
Identity and session state
The integration maps ADK session metadata to Zep automatically: user_id becomes the Zep user ID, and session_id becomes the Zep thread ID. Zep’s knowledge graph is per-user, not per-thread — it accumulates knowledge across all of a user’s conversations, so when they start a new session they get context from everything Zep has learned about them.
The following session state keys are recognized (all optional):
Advanced usage
Per-user setup
When the integration creates a new Zep user for the first time, you can run a setup hook to configure per-user resources — such as a custom ontology, custom extraction instructions, or user summary instructions. Pass an on_user_created callback to ZepContextTool:
The hook fires only when the user is genuinely new — not for users that already exist. If the hook raises an exception, a warning is logged but the agent turn continues normally.
See custom ontology, custom instructions, and user summary instructions for details on each API.
Custom context builder
By default, the integration uses thread.add_messages(return_context=True) — a single API call that persists the message and retrieves context. This works well for most use cases.
For advanced scenarios — multi-graph searches, custom context templates, or combining multiple Zep API calls — you can provide a context_builder. When set, message persistence and context building run in parallel for lower latency.
The ContextBuilder and UserSetupHook type signatures (both importable from zep_adk):
See advanced context block construction and context templates for more on assembling custom context.
Graph search tool
ZepContextTool injects context automatically on every turn. For cases where the model needs to actively search the knowledge graph — e.g. looking up specific facts, entities, or prior messages — you can add ZepGraphSearchTool. This is a model-callable tool: the model sees it in its tool list and decides when to invoke it.
The tool automatically resolves user_id from session state, so the model only needs to provide a search query. The model can also optionally choose the scope (edges, nodes, episodes), reranker, limit, and other search parameters.
Pinning parameters
Any search parameter can be locked at construction time. Pinned parameters are hidden from the model’s schema — it can’t override them.
Shared documentation graph
To search a fixed graph that all users share (e.g. a documentation knowledge base), pass graph_id. The tool will search that graph instead of the current user’s personal graph. Use distinct name and description values when combining multiple instances:
The model sees two distinct tools and chooses which to call based on the user’s query.
Backfill strategy for existing users
If you have existing users with conversation history, you can backfill their data into Zep so they get rich context from day one.
ID matching
Use the same user IDs and thread IDs. The backfill script must create Zep users and threads with the exact same IDs used in ADK:
- User IDs must match what you pass as
user_idto ADK’screate_session(). This links live sessions to the correct knowledge graph. Mismatched user IDs mean backfilled history is orphaned. - Thread IDs must match the ADK
session_idfor each conversation. If a user continues an existing session after cutover, the integration uses that session ID as the Zep thread ID. If the backfill used a different thread ID, the conversation history is split — the continued thread won’t see the backfilled messages in its thread context.
Example backfill script
This runs outside of ADK as a standalone script using the Zep Python SDK directly:
After backfilling, allow time for Zep to process the messages and build knowledge graphs. Zep processes messages asynchronously — the graph won’t be available instantly. For large backfills, add delays between users to avoid rate limits.
Transition gap
There is a window between when the backfill runs and when the Zep-integrated agent goes live. Any messages sent to existing threads during this window won’t be in Zep. For most use cases this is acceptable — the knowledge graph catches up quickly once the agent is live. But if thread-level continuity is critical, consider a dual-write period: after the backfill completes but before full cutover, have your application write new messages to Zep (via the SDK directly) alongside the existing system. This ensures no messages are missed in the transition.
Cutover checklist
- Run the backfill script — Zep now has knowledge graphs for existing users
- Update your agent — Add
ZepContextTooland the after-model callback - Add session state keys — Include
zep_first_nameandzep_last_nameincreate_session()calls - Deploy — Existing users get rich context from their first message; new users build context over time
Why not BaseMemoryService?
ADK provides a BaseMemoryService abstraction with two methods: add_session_to_memory() (called at session end) and search_memory() (called before each turn). This is a poor fit for Zep:
- Real-time, not batch: Zep persists messages immediately on every turn. Batching at session end would delay knowledge graph updates and prevent the agent from using newly extracted facts mid-conversation.
- Thread-based context, not keyword search: ADK’s
search_memory()passes a query string. Zep’s context retrieval takes a thread ID and returns a pre-assembled context block built from conversation history, extracted facts, and the user’s knowledge graph.
Next steps
- Explore customizing graph structure for advanced knowledge organization
- Learn about searching the graph for direct graph queries
- See the Zep Python SDK reference for all available API methods