Coding Quickstart

Familiarize yourself with Zep and the Zep Python SDK, culminating in building a simple chatbot.

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

A Jupyter notebook version of this guide is available here.

In this guide, we’ll walk through a simple example of how to use Zep Cloud to build a chatbot. We’re going to upload a number of datasets to Zep, building a graph of data about a user.

Then we’ll use the Zep Python SDK to retrieve and search the data.

Finally, we’ll build a simple chatbot that uses Zep to retrieve and search data to respond to a user.

Set up your environment

  1. Sign up for a Zep Cloud account.

  2. Ensure you install required dependencies into your Python environment before running this notebook. See Installing Zep SDKs for more information. Optionally create your environment in a virtualenv.

$pip install zep-cloud openai rich python-dotenv
  1. Ensure that you have a .env file in your working directory that includes your ZEP_API_KEY and OPENAI_API_KEY:
ZEP_API_KEY=<key>
OPENAI_API_KEY=<key>

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.

1import os
2import json
3import uuid
4
5from openai import AsyncOpenAI
6import rich
7
8from dotenv import load_dotenv
9from zep_cloud.client import AsyncZep
10from zep_cloud import Message
11
12load_dotenv()
13
14zep = AsyncZep(api_key=os.environ.get("ZEP_API_KEY"))
15
16oai_client = AsyncOpenAI(
17 api_key=os.getenv("OPENAI_API_KEY"),
18)

Create User and add a Session

Users in Zep may have one or more chat sessions. These are threads of messages between the user and an agent.

Include the user’s full name and email address when creating a user. This improves Zep’s ability to associate data, such as emails or documents, with a user.

1bot_name = "SupportBot"
2
3user_name = "Emily"
4user_id = user_name + str(uuid.uuid4())[:4]
5session_id = str(uuid.uuid4())
6
7await zep.user.add(
8 user_id=user_id,
9 email=f"{user_name}@painters.com",
10 first_name=user_name,
11 last_name="Painter",
12)
13
14await zep.memory.add_session(
15 user_id=user_id,
16 session_id=session_id,
17)

Datasets

We’re going to upload an assortment of data to Zep. These include past dialog with the agent, CRM support cases, and billing data.

1support_cases = [
2 {
3 "subject": "Bug: Magic Pen Tool Drawing Goats Instead of Boats",
4 "messages": [
5 {
6 "role": "user",
7 "content": "Whenever I use the magic pen tool to draw boats, it ends up drawing goats instead.",
8 "timestamp": "2024-03-16T14:20:00Z",
9 },
10 {
11 "role": "support_agent",
12 "content": f"Hi {user_name}, that sounds like a bug! Thanks for reporting it. Could you let me know exactly how you're using the tool when this happens?",
13 "timestamp": "2024-03-16T14:22:00Z",
14 },
15 {
16 "role": "user",
17 "content": "Sure, I select the magic pen, draw a boat shape, and it just replaces the shape with goats.",
18 "timestamp": "2024-03-16T14:25:00Z",
19 },
20 {
21 "role": "support_agent",
22 "content": "Got it! We'll escalate this to our engineering team. In the meantime, you can manually select the boat shape from the options rather than drawing it with the pen.",
23 "timestamp": "2024-03-16T14:27:00Z",
24 },
25 {
26 "role": "user",
27 "content": "Okay, thanks. I hope it gets fixed soon!",
28 "timestamp": "2024-03-16T14:30:00Z",
29 },
30 ],
31 "status": "escalated",
32 },
33]
34
35chat_history = [
36 {
37 "role": "assistant",
38 "name": bot_name,
39 "content": f"Hello {user_name}, welcome to PaintWiz support. How can I assist you today?",
40 "timestamp": "2024-03-15T10:00:00Z",
41 },
42 {
43 "role": "user",
44 "name": user_name,
45 "content": "I'm absolutely furious! Your AI art generation is completely broken!",
46 "timestamp": "2024-03-15T10:02:00Z",
47 },
48 {
49 "role": "assistant",
50 "name": bot_name,
51 "content": f"I'm sorry to hear that you're experiencing issues, {user_name}. Can you please provide more details about what's going wrong?",
52 "timestamp": "2024-03-15T10:03:00Z",
53 },
54 {
55 "role": "user",
56 "name": user_name,
57 "content": "Every time I try to draw mountains, your stupid app keeps turning them into fountains! And what's worse, all the people in my drawings have six fingers! It's ridiculous!",
58 "timestamp": "2024-03-15T10:05:00Z",
59 },
60 {
61 "role": "assistant",
62 "name": bot_name,
63 "content": f"I sincerely apologize for the frustration this is causing you, {user_name}. That certainly sounds like a significant glitch in our system. I understand how disruptive this can be to your artistic process. Can you tell me which specific tool or feature you're using when this occurs?",
64 "timestamp": "2024-03-15T10:06:00Z",
65 },
66 {
67 "role": "user",
68 "name": user_name,
69 "content": "I'm using the landscape generator and the character creator. Both are completely messed up. How could you let this happen?",
70 "timestamp": "2024-03-15T10:08:00Z",
71 },
72]
73
74transactions = [
75 {
76 "date": "2024-07-30",
77 "amount": 99.99,
78 "status": "Success",
79 "account_id": user_id,
80 "card_last_four": "1234",
81 },
82 {
83 "date": "2024-08-30",
84 "amount": 99.99,
85 "status": "Failed",
86 "account_id": user_id,
87 "card_last_four": "1234",
88 "failure_reason": "Card expired",
89 },
90 {
91 "date": "2024-09-15",
92 "amount": 99.99,
93 "status": "Failed",
94 "account_id": user_id,
95 "card_last_four": "1234",
96 "failure_reason": "Card expired",
97 },
98]
99
100account_status = {
101 "user_id": user_id,
102 "account": {
103 "account_id": user_id,
104 "account_status": {
105 "status": "suspended",
106 "reason": "payment failure",
107 },
108 },
109}
110
111def convert_to_zep_messages(chat_history: list[dict[str, str | None]]) -> list[Message]:
112 """
113 Convert chat history to Zep messages.
114
115 Args:
116 chat_history (list): List of dictionaries containing chat messages.
117
118 Returns:
119 list: List of Zep Message objects.
120 """
121 return [
122 Message(
123 role_type=msg["role"],
124 role=msg.get("name", None),
125 content=msg["content"],
126 )
127 for msg in chat_history
128 ]
129
130# Zep's high-level API allows us to add a list of messages to a session.
131await zep.memory.add(
132 session_id=session_id, messages=convert_to_zep_messages(chat_history)
133)
134
135# The lower-level data API allows us to add arbitrary data to a user's Knowledge Graph.
136for tx in transactions:
137 await zep.graph.add(user_id=user_id, data=json.dumps(tx), type="json")
138
139 await zep.graph.add(
140 user_id=user_id, data=json.dumps(account_status), type="json"
141 )
142
143for case in support_cases:
144 await zep.graph.add(user_id=user_id, data=json.dumps(case), type="json")

Wait a minute or two!

We’ve batch uploaded a number of datasets that need to be ingested into Zep’s graph before they can be queried. In ordinary operation, this data would stream into Zep and ingestion latency would be negligible.

Retrieve data from Zep

We’ll start with getting a list of facts. We’ll see the temporal data associated with facts as well as the graph nodes the fact is related to.

This data is also viewable in the Zep Web application.
1fact_response = await zep.user.get_facts(user_id=user_id)
2
3rich.print(fact_response.facts[:3])
[
Fact(
created_at='2024-10-18T17:07:24.518227Z',
expired_at=None,
fact='user has the id of Emily5e58',
invalid_at=None,
name='HAS_USER',
rating=None,
source_node_name='Emily5e58',
target_node_name='User',
uuid_='3106874a-b7dd-492a-9df9-2ca6dc9acadd',
valid_at=None
),
Fact(
created_at='2024-10-18T17:07:35.283028Z',
expired_at=None,
fact='SupportBot is providing assistance to Emily.',
invalid_at=None,
name='ASSISTS',
rating=None,
source_node_name='SupportBot',
target_node_name='Emily Painter',
uuid_='e13041be-5313-4553-a4c1-3796abc1fe99',
valid_at='2024-10-18T17:07:29.284607Z'
),
Fact(
created_at='2024-10-18T17:07:40.758345Z',
expired_at=None,
fact='Emily is expressing frustration with the AI art generation system, claiming it is completely
broken.',
invalid_at=None,
name='FRUSTRATED_WITH',
rating=None,
source_node_name='Emily5e58',
target_node_name='AI art generation',
uuid_='7f954e5c-2cb2-48c8-9992-5018d229f994',
valid_at='2024-10-18T17:07:29.284607Z'
)
]

The high-level memory API provides an easy way to retrieve memory relevant to the current conversation by using the last 4 messages and their proximity to the User node.

The memory.get method is a good starting point for retrieving relevant conversation context. It shortcuts passing recent messages to the graph.search API and returns a context string, raw facts, and historical chat messages, providing everything needed for your agent’s prompts.

1# pass in the session ID of the conversation thread
2memory = zep_client.memory.get(session_id="session_id")
3print(memory.context)
FACTS and ENTITIES represent relevant context to the current conversation.
# These are the most relevant facts and their valid date ranges
# format: FACT (Date range: from - to)
<FACTS>
- Emily is experiencing issues with logging in. (2024-11-14 02:13:19+00:00 -
present)
- User account Emily0e62 has a suspended status due to payment failure.
(2024-11-14 02:03:58+00:00 - present)
- user has the id of Emily0e62 (2024-11-14 02:03:54 - present)
- The failed transaction used a card with last four digits 1234. (2024-09-15
00:00:00+00:00 - present)
- The reason for the transaction failure was 'Card expired'. (2024-09-15
00:00:00+00:00 - present)
- user has the name of Emily Painter (2024-11-14 02:03:54 - present)
- Account Emily0e62 made a failed transaction of 99.99. (2024-07-30
00:00:00+00:00 - 2024-08-30 00:00:00+00:00)
</FACTS>
# These are the most relevant entities
# ENTITY_NAME: entity summary
<ENTITIES>
- Emily0e62: Emily0e62 is a user account associated with a transaction,
currently suspended due to payment failure, and is also experiencing issues
with logging in.
- Card expired: The node represents the reason for the transaction failure,
which is indicated as 'Card expired'.
- Magic Pen Tool: The tool being used by the user that is malfunctioning.
- User: user
- Support Agent: Support agent responding to the user's bug report.
- SupportBot: SupportBot is the virtual assistant providing support to the user,
Emily, identified as SupportBot.
- Emily Painter: Emily is a user reporting a bug with the magic pen tool,
similar to Emily Painter, who is expressing frustration with the AI art
generation tool and seeking assistance regarding issues with the PaintWiz app.
</ENTITIES>
1rich.print(m.messages)
[
Message(
content='Hello Emily, welcome to PaintWiz support. How can I assist you today?',
created_at='2024-10-18T17:07:29.284607Z',
metadata=None,
role='SupportBot',
role_type='assistant',
token_count=0,
updated_at='0001-01-01T00:00:00Z',
uuid_='4d706f47-5024-42fc-bc20-de18502ce4a7'
),
Message(
content="I'm absolutely furious! Your AI art generation is completely broken!",
created_at='2024-10-18T17:07:29.284607Z',
metadata=None,
role='Emily',
role_type='user',
token_count=0,
updated_at='0001-01-01T00:00:00Z',
uuid_='0f588fe9-2be1-439c-b661-921f2ce1c1a5'
)
]

We can also use the graph.search method to search facts for arbitrary text. This API offers more options, including the ability to search node summaries and various re-rankers.

1r = await zep.graph.search(user_id=user_id, query="Why are there so many goats?", limit=4, scope="edges")
2rich.print([r.fact for r in r.edges])
[
Fact(
created_at='2024-10-18T17:07:40.758345Z',
expired_at=None,
fact='Emily is expressing frustration with the AI art generation system, claiming it is completely
broken.',
invalid_at=None,
name='FRUSTRATED_WITH',
rating=None,
source_node_name='',
target_node_name='',
uuid_='7f954e5c-2cb2-48c8-9992-5018d229f994',
valid_at='2024-10-18T17:07:29.284607Z'
),
Fact(
created_at='2024-10-18T17:07:35.283028Z',
expired_at=None,
fact='SupportBot is providing assistance to Emily.',
invalid_at=None,
name='ASSISTS',
rating=None,
source_node_name='',
target_node_name='',
uuid_='e13041be-5313-4553-a4c1-3796abc1fe99',
valid_at='2024-10-18T17:07:29.284607Z'
),
Fact(
created_at='2024-10-18T17:07:58.290198Z',
expired_at=None,
fact='The PaintWiz app generates fountains instead of the intended mountains.',
invalid_at=None,
name='GENERATES_INSTEAD',
rating=None,
source_node_name='',
target_node_name='',
uuid_='42c1f997-e98a-4477-949a-040ddc3940d2',
valid_at='2024-10-18T17:07:29.284607Z'
)
]

Creating a simple Chatbot

In the next cells, Emily starts a new chat session with a support agent and complains that she can’t log in. Our simple chatbot will, given relevant facts retrieved from Zep’s graph, respond accordingly.

Here, the support agent is provided with Emily’s billing information and account status, which Zep retrieves as most relevant to Emily’s login issue.

1new_session_id = str(uuid.uuid4())
2
3emily_message = "Hi, I can't log in!"
4
5# We start a new session indicating that Emily has started a new chat with the support agent.
6await zep.memory.add_session(user_id=user_id, session_id=new_session_id)
7
8# we need to add the Emily's message to the session in order for memory.get to return
9# relevant facts related to the message
10await zep.memory.add(
11 session_id=new_session_id,
12 messages=[Message(role_type="user", role=user_name, content=emily_message)],
13)
1system_message = """
2You are a customer support agent. Carefully review the facts about the user below and respond to the user's question.
3Be helpful and friendly.
4"""
5
6memory = await zep.memory.get(session_id=new_session_id)
7
8messages = [
9 {
10 "role": "system",
11 "content": system_message,
12 },
13 {
14 "role": "assistant",
15 # The context field is an opinionated string that contains facts and entities relevant to the current conversation.
16 "content": memory.context,
17 },
18 {
19 "role": "user",
20 "content": emily_message,
21 },
22]
23
24response = await oai_client.chat.completions.create(
25 model="gpt-4o-mini",
26 messages=messages,
27 temperature=0,
28)
29
30print(response.choices[0].message.content)
Hi Emily! I'm sorry to hear that you're having trouble logging in. It looks like your account is currently suspended as a result of several failed payments.
You can update your payment information by visiting your account page.
Please let me know if you have any other questions or difficulty accessing your account.

Let’s look at the raw facts Zep retrieved for the above memory.get call.

1rich.print(memory.relevant_facts[:4])
[
Fact(
created_at='2024-10-27T02:39:40.299221Z',
expired_at=None,
fact='User account Emily4a4f has a suspended status due to payment failure.',
invalid_at=None,
name='HAS_ACCOUNT_STATUS',
rating=None,
source_node_name='',
target_node_name='',
uuid_='a55be4ad-e336-4833-8978-c3ba27a9a310',
valid_at='2024-10-27T02:38:56.198275Z'
),
Fact(
created_at='2024-10-27T02:39:47.62593Z',
expired_at=None,
fact="The reason for the failed transaction was 'Card expired'.",
invalid_at=None,
name='FAILURE_REASON',
rating=None,
source_node_name='',
target_node_name='',
uuid_='c1c4e42e-2681-4616-9421-29e3a317f842',
valid_at='2024-09-15T00:00:00Z'
),
Fact(
created_at='2024-10-27T02:39:36.368034Z',
expired_at='2024-10-27T02:39:49.950056Z',
fact='Account Emily4a4f used card ending in 1234 for the transaction.',
invalid_at='2024-08-30T00:00:00Z',
name='USED_CARD',
rating=None,
source_node_name='',
target_node_name='',
uuid_='f59bac52-f5fa-4027-8765-b5c06634252c',
valid_at='2024-09-15T00:00:00Z'
),
Fact(
created_at='2024-10-27T02:39:47.625872Z',
expired_at=None,
fact='The account Emily4a4f had a transaction that failed.',
invalid_at=None,
name='TRANSACTION_STATUS',
rating=None,
source_node_name='',
target_node_name='',
uuid_='d81190d2-b354-4fbe-bbf9-a70cc990553e',
valid_at='2024-09-15T00:00:00Z'
)
]