Building Multi-Agent Systems with CrewAI and Zep

Learn how to create CrewAI agents with persistent memory powered by Zep's context engineering platform

For an introduction to Zep’s memory layer, Knowledge Graph, and other key concepts, see the Concepts Guide.

In this guide, we’ll walk through building a multi-agent system using CrewAI with Zep’s persistent memory capabilities. We’ll create specialized agents that can retain context and knowledge across conversations, enabling more sophisticated collaborative workflows.

CrewAI is a powerful framework for orchestrating multi-agent systems, and when combined with Zep’s memory layer, your agents can maintain persistent context, learn from past interactions, and provide more personalized responses.

Set Up Your Environment

  1. Sign up for a Zep Cloud account.

  2. Install the required dependencies for CrewAI and Zep integration:

$pip install zep-crewai
  1. Ensure you have a .env file in your working directory with your API keys:

Zep API keys are specific to a project. You can create multiple keys for a single project. Visit Project Settings in the Zep dashboard to manage your API keys.

ZEP_API_KEY=<your_zep_api_key>
OPENAI_API_KEY=<your_openai_api_key>
Python
1import os
2import sys
3import time
4import uuid
5
6from crewai import Agent, Crew, Task, Process
7from crewai.memory.external.external_memory import ExternalMemory
8from zep_cloud.client import Zep
9from zep_crewai import ZepStorage
10
11def main():
12 # Load environment variables
13 api_key = os.environ.get("ZEP_API_KEY")
14 if not api_key:
15 print("Error: Please set your ZEP_API_KEY environment variable")
16 sys.exit(1)
17
18 openai_key = os.environ.get("OPENAI_API_KEY")
19 if not openai_key:
20 print("Error: Please set your OPENAI_API_KEY environment variable")
21 sys.exit(1)
22
23 # Initialize Zep client
24 zep_client = Zep(api_key=api_key)

Create User and Thread for Agent Memory

Before our agents can store and retrieve memories, we need to establish a user and thread context in Zep. This allows agents to maintain persistent memory across different conversation sessions.

Python
1 # Generate unique identifiers for this session
2 user_id = "business_user_" + str(uuid.uuid4())
3 thread_id = "planning_thread_" + str(uuid.uuid4())
4
5 # Create user in Zep
6 try:
7 zep_client.user.add(
8 user_id=user_id,
9 first_name="Sarah",
10 last_name="Johnson",
11 email="[email protected]"
12 )
13 except Exception:
14 # User may already exist
15 pass
16
17 # Create thread for this conversation
18 try:
19 zep_client.thread.create(user_id=user_id, thread_id=thread_id)
20 except Exception:
21 # Thread may already exist
22 pass

Configure Zep Memory for CrewAI

Now we’ll set up the Zep memory integration for CrewAI. The ZepStorage class bridges CrewAI’s external memory system with Zep’s persistent storage.

Python
1 # Initialize Zep storage for CrewAI
2 zep_storage = ZepStorage(
3 client=zep_client,
4 user_id=user_id,
5 thread_id=thread_id
6 )
7
8 # Create external memory instance
9 external_memory = ExternalMemory(storage=zep_storage)

The ZepStorage adapter automatically handles converting CrewAI memory operations to Zep’s memory format, enabling seamless integration between the two systems.

Pre-populate Context Data

Before our agents start working, let’s add some initial context data to help them understand the user’s preferences and requirements. This demonstrates how you can seed agent memory with relevant information.

Python
1 # Add structured user preferences
2 external_memory.save(
3 '{"trip_type": "business", "destination": "New York", "duration": "3 days", "budget": 2000, "accommodation_preference": "mid-range hotels", "dietary_restrictions": "vegetarian"}',
4 metadata={"type": "json"}
5 )
6
7 # Add conversation history
8 external_memory.save(
9 "Hi, I need help planning a business trip to New York. I'll be there for 3 days and prefer mid-range hotels with good vegetarian dining options nearby.",
10 metadata={"type": "message", "role": "user", "name": "Sarah Johnson"}
11 )
12
13 external_memory.save(
14 "I'd be happy to help you plan your New York business trip! Let me provide some excellent recommendations based on your preferences.",
15 metadata={"type": "message", "role": "assistant", "name": "Travel Planning Assistant"}
16 )
17
18 # Add behavioral insights
19 external_memory.save(
20 "Sarah Johnson prefers sustainable travel options, values convenience for business meetings, and requires vegetarian meal options",
21 metadata={"type": "text"}
22 )
23
24 external_memory.save(
25 "Budget constraint: Total budget is around $2000 for the entire trip. Looking for good value mid-range accommodations with business amenities.",
26 metadata={"type": "text"}
27 )
28
29 # Wait for Zep to process and index the data
30 time.sleep(20)

Create Specialized Agents

Now we’ll create specialized agents with distinct roles and capabilities. Each agent can access the shared Zep memory, allowing them to collaborate effectively while maintaining context.

Python
1 # Create travel planning specialist
2 travel_planner = Agent(
3 role="Travel Planning Specialist",
4 goal="Plan efficient and cost-effective business trips based on user preferences and constraints",
5 backstory="You are an experienced travel planner who specializes in business travel and considers user preferences and budget constraints.",
6 verbose=True,
7 llm="gpt-4.1-mini" # or your preferred model
8 )
9
10 # Create dining recommendation specialist
11 dining_specialist = Agent(
12 role="Dining Recommendation Specialist",
13 goal="Recommend restaurants that match user dietary preferences and business needs",
14 backstory="You are a culinary expert who specializes in business dining recommendations with knowledge of dietary accommodations.",
15 verbose=True,
16 llm="gpt-4.1-mini" # or your preferred model
17 )

Each agent has a specific role and expertise, allowing for specialized task handling while sharing access to the same memory context through Zep.

Define Agent Tasks

Create specific tasks for each agent that leverage the shared memory context. The agents will automatically access relevant information from Zep when executing these tasks.

Python
1 # Define hotel recommendation task
2 hotel_task = Task(
3 description="Based on the user's saved preferences, provide 3 hotel recommendations in New York. Include hotel name, location, price range, and why it fits user preferences.",
4 expected_output="A list of 3 hotel recommendations with explanations",
5 agent=travel_planner
6 )
7
8 # Define dining recommendation task
9 dining_task = Task(
10 description="Recommend 5 vegetarian-friendly restaurants in New York suitable for business dining. Include restaurant name, location, cuisine type, and price range.",
11 expected_output="A list of 5 vegetarian-friendly restaurants with descriptions",
12 agent=dining_specialist
13 )

Create and Execute the Crew

Now we’ll assemble our agents into a crew with shared Zep memory and execute the tasks collaboratively.

Python
1 # Create the crew with shared external memory
2 planning_crew = Crew(
3 agents=[travel_planner, dining_specialist],
4 tasks=[hotel_task, dining_task],
5 process=Process.sequential,
6 external_memory=external_memory, # Shared Zep memory
7 verbose=True
8 )
9
10 # Execute the crew tasks
11 result = planning_crew.kickoff()
12
13 # Save the final results back to memory for future reference
14 external_memory.save(
15 str(result),
16 metadata={"type": "message", "role": "assistant", "name": "Travel Planning Crew"}
17 )
18
19 print("RESULTS:")
20 print(result)

Understanding the Memory Integration

When you run this example, several important things happen:

  1. Context Awareness: Each agent automatically accesses relevant information from Zep’s memory when executing their tasks, including user preferences, budget constraints, and dietary restrictions.

  2. Persistent Storage: All interactions, decisions, and results are stored in Zep’s knowledge graph, creating a permanent record of the collaborative planning session.

  3. Cross-Agent Learning: Future conversations can build upon this stored knowledge, enabling more sophisticated and personalized recommendations over time.

  4. Memory Retrieval: The agents don’t need explicit instructions about user preferences - they retrieve this information automatically from Zep’s context-aware memory system.

Complete Example

Python
1import os
2import sys
3import time
4import uuid
5
6from crewai import Agent, Crew, Task, Process
7from crewai.memory.external.external_memory import ExternalMemory
8from zep_cloud.client import Zep
9from zep_crewai import ZepStorage
10
11
12def main():
13 api_key = os.environ.get("ZEP_API_KEY")
14 if not api_key:
15 print("Error: Please set your ZEP_API_KEY environment variable")
16 sys.exit(1)
17
18 openai_key = os.environ.get("OPENAI_API_KEY")
19 if not openai_key:
20 print("Error: Please set your OPENAI_API_KEY environment variable")
21 sys.exit(1)
22
23 zep_client = Zep(api_key=api_key)
24 user_id = "business_user_" + str(uuid.uuid4())
25 thread_id = "planning_thread_" + str(uuid.uuid4())
26
27 try:
28 zep_client.user.add(
29 user_id=user_id,
30 first_name="Sarah",
31 last_name="Johnson",
32 email="[email protected]"
33 )
34 except Exception:
35 pass
36
37 try:
38 zep_client.thread.create(user_id=user_id, thread_id=thread_id)
39 except Exception:
40 pass
41
42 zep_storage = ZepStorage(
43 client=zep_client,
44 user_id=user_id,
45 thread_id=thread_id
46 )
47 external_memory = ExternalMemory(storage=zep_storage)
48
49 # Pre-populate context
50 external_memory.save(
51 '{"trip_type": "business", "destination": "New York", "duration": "3 days", "budget": 2000, "accommodation_preference": "mid-range hotels", "dietary_restrictions": "vegetarian"}',
52 metadata={"type": "json"}
53 )
54
55 external_memory.save(
56 "Hi, I need help planning a business trip to New York. I'll be there for 3 days and prefer mid-range hotels with good vegetarian dining options nearby.",
57 metadata={"type": "message", "role": "user", "name": "Sarah Johnson"}
58 )
59
60 external_memory.save(
61 "Sarah Johnson prefers sustainable travel options, values convenience for business meetings, and requires vegetarian meal options",
62 metadata={"type": "text"}
63 )
64
65 # Wait for Zep to process and index the data
66 time.sleep(20)
67
68 # Create agents
69 travel_planner = Agent(
70 role="Travel Planning Specialist",
71 goal="Plan efficient and cost-effective business trips based on user preferences and constraints",
72 backstory="You are an experienced travel planner who specializes in business travel and considers user preferences and budget constraints.",
73 verbose=True,
74 llm="gpt-4.1-mini"
75 )
76
77 dining_specialist = Agent(
78 role="Dining Recommendation Specialist",
79 goal="Recommend restaurants that match user dietary preferences and business needs",
80 backstory="You are a culinary expert who specializes in business dining recommendations with knowledge of dietary accommodations.",
81 verbose=True,
82 llm="gpt-4.1-mini"
83 )
84
85 # Define tasks
86 hotel_task = Task(
87 description="Based on the user's saved preferences, provide 3 hotel recommendations in New York. Include hotel name, location, price range, and why it fits user preferences.",
88 expected_output="A list of 3 hotel recommendations with explanations",
89 agent=travel_planner
90 )
91
92 dining_task = Task(
93 description="Recommend 5 vegetarian-friendly restaurants in New York suitable for business dining. Include restaurant name, location, cuisine type, and price range.",
94 expected_output="A list of 5 vegetarian-friendly restaurants with descriptions",
95 agent=dining_specialist
96 )
97
98 # Create and execute crew
99 planning_crew = Crew(
100 agents=[travel_planner, dining_specialist],
101 tasks=[hotel_task, dining_task],
102 process=Process.sequential,
103 external_memory=external_memory,
104 verbose=True
105 )
106
107 result = planning_crew.kickoff()
108
109 # Save results to memory
110 external_memory.save(
111 str(result),
112 metadata={"type": "message", "role": "assistant", "name": "Travel Planning Crew"}
113 )
114
115 print("RESULTS:")
116 print(result)
117
118
119if __name__ == "__main__":
120 main()

Next Steps

This example demonstrates the foundation for building sophisticated multi-agent systems with persistent memory. You can extend this pattern by:

  • Adding more specialized agents (research, booking, itinerary management)
  • Implementing custom memory retrieval strategies
  • Creating agent hierarchies with different access levels to memory
  • Building conversational interfaces that leverage the stored context
  • Integrating with external APIs and data sources

Monitor your agents’ memory usage in the Zep dashboard to understand how they’re storing and retrieving contextual information across conversations.

The combination of CrewAI’s multi-agent orchestration with Zep’s persistent memory creates a powerful foundation for building intelligent, context-aware agent systems that can learn and improve over time.