Entity Types

Zep classifies newly created nodes as one of your defined entity types or leaves them unclassified. For example, a node representing a preference is classified as a Preference node, and attributes specific to that type are automatically populated. You may restrict graph queries to nodes of a specific type, such as Preference.

There are default entity types applied to all nodes by default, but you may define custom types as needed.

Each node is classified as a single entity type only. Multiple classifications are not supported.

Default Entity Types

The default entity types are:

  • User: A human that is part of the current chat thread.
  • Preference: One of the User’s preferences.
  • Procedure: A request informing the agent how to behave (e.g. ‘Always respond in Haikus’)

Default entity types only apply to user graphs (not group graphs). All nodes in any user graph will be classified into one of these types or none.

When searching nodes in the graph, you can provide a list of types to filter the search by. The provided types are ORed together. Search results will only include nodes that satisfy one of the provided types:

1from zep_cloud.types import SearchFilters
2
3search_results = client.graph.search(
4 user_id=user_id,
5 query="what foods the user likes and dislikes",
6 scope="nodes",
7 search_filters=SearchFilters(
8 node_labels=["Preference"]
9 )
10)

Custom Entity Types

In addition to the default entity types, you can specify your own custom entity types. You need to provide a description of the type and a description for each of the fields. Note that the syntax for this is different for each language:

1from pydantic import Field
2from zep_cloud.external_clients.ontology import EntityModel, EntityText, EntityInt
3
4class ApartmentComplex(EntityModel):
5 """
6 Represents an apartment complex.
7 """
8 complex_name: EntityText = Field(
9 description="The name of the apartment complex",
10 default=None
11 )
12 price_of_rent: EntityInt = Field(
13 description="The price of rent for the apartment complex",
14 default=None
15 )
16
17class Restaurant(EntityModel):
18 """
19 Represents a restaurant.
20 """
21 restaurant_name: EntityText = Field(
22 description="The name of the restaurant",
23 default=None
24 )

You can then set these as the custom entity types for your current Zep project:

1client.graph.set_entity_types(
2 entities={
3 "ApartmentComplex": ApartmentComplex,
4 "Restaurant": Restaurant
5 }
6)

Now, when we add data to the graph, new nodes are classified into exactly one of the overall set of entity types or none:

1from zep_cloud.types import Message
2import json
3
4messages = [
5 {"role": "John Doe", "role_type": "user", "content": "The last apartment complex I lived in was Oasis"},
6 {"role": "John Doe", "role_type": "user", "content": "There were really great restaurants near Oasis, such as The Biscuit"}
7]
8
9apartment_complexes = [
10 {"name": "Oasis", "description": "An apartment complex", "price_of_rent": 1050},
11 {"name": "Sanctuary", "description": "An apartment complex", "price_of_rent": 1100},
12 {"name": "Harbor View", "description": "An apartment complex", "price_of_rent": 1250},
13 {"name": "Greenwood", "description": "An apartment complex", "price_of_rent": 950},
14 {"name": "Skyline", "description": "An apartment complex", "price_of_rent": 1350}
15]
16
17for apartment_complex in apartment_complexes:
18 client.graph.add(
19 user_id=user_id,
20 type="json",
21 data=json.dumps(apartment_complex)
22 )
23
24client.memory.add(session_id=session_id, messages=[Message(**m) for m in messages])

Now that we have created a graph with custom entity types, we can filter node search results by entity type. In this case, we are able to get a structured answer (an ApartmentComplex object) to an open ended query (the apartment complex the user previously resided in) where the answer required fusing together the chat history and the JSON data:

1from zep_cloud.types import SearchFilters
2
3search_results = client.graph.search(
4 user_id=user_id,
5 query="The apartment complex the user previously resided in",
6 scope="nodes",
7 limit=1,
8 search_filters=SearchFilters(
9 node_labels=["ApartmentComplex"]
10 )
11)
12previous_apartment_complex = ApartmentComplex(**search_results.nodes[0].attributes)
13print(f"{previous_apartment_complex}")
complex_name='Oasis' price_of_rent=1050

The search filter ORs together the provided types, so search results will only include nodes that satisfy one of the provided types.

You can also retrieve all nodes of a specific type:

1nodes = client.graph.node.get_by_user_id(user_id)
2for node in nodes:
3 if "ApartmentComplex" in node.labels:
4 apartment_complex = ApartmentComplex(**node.attributes)
5 print(f"{apartment_complex}")
complex_name='Oasis' price_of_rent=1050
complex_name='Sanctuary' price_of_rent=1100
complex_name='Greenwood' price_of_rent=950
complex_name='Skyline' price_of_rent=1350
complex_name='Harbor View' price_of_rent=1250

Important Notes/Tips

Some notes regarding custom entity types:

  • The set_entity_types method overwrites any previously defined custom entity types, so the set of custom entity types is always the list of types provided in the last set_entity_types method call
  • The overall set of entity types for a project includes both the custom entity types you set and the default entity types
  • You can overwrite the default entity types by providing custom entity types with the same names
  • Changing the custom entity types will not update previously created nodes. The classification and attributes of existing nodes will stay the same. The only thing that can change existing classifications or attributes is adding data that provides new information.
  • You must avoid the following attribute names when creating custom entity types, because the name collides with default node attributes: ‘uuid’, ‘name’, ‘group_id’, ‘name_embedding’, ‘summary’, or ‘created_at’
  • Tip: Design custom entity types to represent entities/nouns as opposed to relationships/verbs. Your type might be represented in the graph as an edge more often than as a node
  • Tip: If you have overlapping entity types (e.g. ‘Hobby’ and ‘Hiking’), you can prioritize one type over another by mentioning which to prioritize in the entity type descriptions