Steering observations

Guide how Zep generates observations with a custom instruction and observation types
Experimental API

Observation steering is an experimental feature. The API may change in future releases.

Available to Flex Plus and Enterprise customers — the same plans that generate observations.

Why use observation steering

Zep automatically derives observations — durable, evidence-backed patterns — from a graph. By default, Zep decides how each observation is worded and labels every observation with the type generic. Observation steering lets you guide that generation without changing the underlying evidence.

Steering influences generation along two axes. You can set either one on its own, or both together:

  • Instruction: free-text guidance that shapes the wording and relevance of the observations Zep writes. The instruction cannot introduce facts, choose which evidence is used, or change how many observations are produced — evidence always comes from the graph.
  • Observation types: up to ten named categories Zep may assign to an observation. Zep writes the selected type to the observation_type property on the observation node, which you can filter on during graph search. When none of your types fit, Zep falls back to generic.

Steering applies only to observations generated after you configure it. It does not enqueue a job or regenerate existing observations; those update on their own as new evidence arrives.

Use cases

  • Domain vocabulary: Label observations with categories that match your product — commitment, risk, preference, churn_signal — then filter graph search by type.
  • Relevance tuning: Steer wording and emphasis toward what your agent needs, without post-processing.
  • Per-user or per-graph control: Apply distinct guidance to a specific user or graph while keeping a project-wide default.

Basic usage

Use set_observation_steering to replace the configuration at a scope, and get_observation_steering to read it back. Both return the resulting configuration. With no user_id or graph_id, the request addresses the project-wide default.

1from zep_cloud import Zep, ObservationType
2
3client = Zep(
4 api_key=API_KEY,
5)
6
7# Set the project-wide default.
8config = client.project.set_observation_steering(
9 instruction="Prioritize durable commitments and stated preferences. Keep observations concise.",
10 types=[
11 ObservationType(name="commitment", description="A promise or planned action the user has committed to."),
12 ObservationType(name="preference", description="A durable preference the user has expressed."),
13 ],
14)
15
16# Read the current project configuration.
17config = client.project.get_observation_steering()
18print(config.instruction)
19for t in config.types or []:
20 print(f"{t.name}: {t.description}")

Scoping to a user or graph

Steering resolves at one of three scopes:

  • Project: the default configuration, applied to every user and graph in the project. Addressed when you pass neither user_id nor graph_id.
  • User: configuration for a single user’s graph, addressed with user_id.
  • Graph: configuration for a single named graph, addressed with graph_id.

Pass at most one of user_id or graph_id; passing both returns a 400. A user or graph configuration is a complete override, not a merge — when a user or graph has its own configuration, Zep uses it in full and ignores the project default. Reading a user or graph scope returns its effective configuration, falling back to the project default when that scope has none of its own.

1# Steer observations for one user only.
2client.project.set_observation_steering(
3 user_id="alice",
4 instruction="Focus on support escalations and unresolved issues.",
5 types=[
6 ObservationType(name="escalation", description="An issue the user escalated to support."),
7 ],
8)
9
10# Read the effective configuration for the user (falls back to the project default).
11config = client.project.get_observation_steering(user_id="alice")

Observation types

Each entry in types defines a category Zep may assign to an observation. When Zep generates an observation, it selects the best-fitting type and writes the name to the observation_type property on the observation node. If none of your configured types fit — or you configure no types — Zep uses generic.

FieldRules
nameMust match ^[a-z][a-z0-9_]*$ (start with a lowercase letter, then lowercase letters, digits, or underscores); up to 50 characters; unique within the list. generic is reserved and cannot be configured.
descriptionRequired; 1–500 characters. Describes when the type applies, which guides Zep’s selection.

You can configure up to 10 types.

Because the selected type is stored as the observation_type node property, you can retrieve observations of a given type with graph search property filters:

1from zep_cloud.types import SearchFilters, PropertyFilter
2
3results = client.graph.search(
4 user_id="alice",
5 query="commitments to the customer",
6 scope="observations",
7 search_filters=SearchFilters(
8 property_filters=[
9 PropertyFilter(
10 comparison_operator="=",
11 property_name="observation_type",
12 property_value="commitment",
13 )
14 ]
15 ),
16)
17
18for obs in results.observations or []:
19 print(obs.name, obs.score)

Clearing steering

Sending an empty configuration — a null instruction and an empty types list — clears steering at the addressed scope. Clearing the project scope removes the default; clearing a user or graph scope removes the override, so that scope falls back to the project default.

1# Remove the override for a user (falls back to the project default).
2client.project.set_observation_steering(
3 user_id="alice",
4 instruction=None,
5 types=[],
6)

Configurable parameters

ParameterTypeDescriptionDefaultRequired
user_idstringAddress the steering configuration for a single user’s graph.-No*
graph_idstringAddress the steering configuration for a named graph.-No*
instructionstring | nullGuidance for the wording and relevance of generated observations. Up to 2000 characters. An empty or omitted instruction clears it.nullNo
typesarrayUp to 10 custom observation types, each with a name and description.[]No

*Pass at most one of user_id or graph_id. Passing both returns a 400; passing neither addresses the project scope. In the TypeScript and Go SDKs, instruction and types are set on the request’s body field.

Observation type fields

FieldTypeDescription
namestringCategory name. Must match ^[a-z][a-z0-9_]*$, up to 50 characters, unique within the list. generic is reserved.
descriptionstringWhen the type applies. Required, 1–500 characters.

Response

Both get_observation_steering and set_observation_steering return the resulting configuration at the addressed scope:

FieldTypeDescription
instructionstring | nullThe configured instruction, or null if none is set.
typesarrayThe configured observation types, each with a name and description.

Reading a user or graph scope returns its effective configuration, falling back to the project default when that scope has no configuration of its own.