Skip to navigation

Custom instructions

Describe your domain so Zep can better understand your data

Available to Flex Plus and Enterprise customers.

Why use custom instructions

Zep’s graph extraction uses general-purpose logic by default. Custom instructions let you describe the domain your application operates in, including specialized terminology and concepts that Zep might not otherwise understand. This domain context helps Zep interpret data more accurately during extraction.

Custom instructions describe your domain — the terminology, concepts, and context Zep needs to understand your data — and can limit the scope of the facts that Zep extracts (see Scope instructions). If you need to define specific entity types or relationship types for your graph, use custom ontology instead.

How custom instructions work

Custom instructions are applied automatically in the background whenever data is added to a graph. There is no parameter on thread.add_messages, graph.episode.add, or any other ingestion method to select which instructions to use — Zep fetches and applies the relevant instructions based on the target graph.

Resolution order

When data is ingested into a graph, Zep determines which instructions to use in the following order:

  1. Graph-specific instructions — If the target graph has its own instructions, set with graph.set_instructions, those are used.
  2. Project-wide defaults — If no graph-specific instructions exist, Zep falls back to project-wide default instructions.
  3. Built-in extraction logic — If no custom instructions are defined at all, Zep uses its general-purpose extraction logic.

This means you can set broad project-wide instructions as a baseline and override them for specific graphs when needed.

Defining custom instructions

Project-wide instructions

Use project.set_instructions to set the project-wide defaults. These apply to all graphs that don’t have their own graph-specific instructions. Each set call replaces the full set of instructions at that scope.

from zep_cloud import Zep, CustomInstruction
client = Zep(api_key="YOUR_API_KEY")
# Set the project-wide custom instructions
client.project.set_instructions(
instructions=[
CustomInstruction(
name="legal_domain",
text=(
"This application operates in the legal domain. "
"Common legal terminology includes: consideration, "
"estoppel, tort, indemnification, force majeure, "
"severability, arbitration clause, non-compete, "
"and confidentiality. A 'party' refers to a person "
"or organization involved in a legal agreement. "
"'Clauses' are specific provisions within a contract."
)
)
]
)

When you add data to any graph, Zep automatically applies these project-wide instructions. No extra parameters are needed. The examples use the uuid that graph.create returns, which you store in your application database:

# Add data to a graph — the legal_domain instructions apply automatically
client.graph.episode.add(
zep_graph_uuid,
type="text",
data=(
"The licensing agreement between Acme Corp and GlobalTech Inc "
"includes a non-compete clause effective for 24 months and an "
"arbitration clause requiring disputes be resolved in New York."
)
)

Graph-specific instructions

To set instructions for one graph, use graph.set_instructions with the UUID of the graph. For a user graph, use the user UUID that user.create returns. These instructions override any project-wide defaults for that graph. To apply the same instructions to more than one graph, send the call once for each graph.

from zep_cloud import Zep, CustomInstruction
client = Zep(api_key="YOUR_API_KEY")
# Set instructions for one user's graph.
# zep_user_uuid is the uuid of the user, from your application database.
client.graph.set_instructions(
zep_user_uuid,
instructions=[
CustomInstruction(
name="healthcare_domain",
text=(
"This application operates in the healthcare domain. "
"Common medical terminology includes: prognosis (expected "
"outcome), etiology (cause of a condition), contraindication "
"(reason to avoid a treatment), comorbidity (co-occurring "
"conditions), and differential diagnosis (distinguishing "
"between conditions with similar symptoms). A 'prescription' "
"refers to a specific medication, dosage, and schedule."
)
)
]
)

When you add messages to a thread of this user, Zep automatically applies the healthcare_domain instructions. No extra parameters are needed. The examples use the uuid that thread.create returns:

from zep_cloud import AddMessage
# Add messages — the healthcare_domain instructions apply automatically
response = client.thread.add_messages(
zep_thread_uuid,
messages=[
AddMessage(
name="Dr. Patel",
role="user",
content="Patient shows signs of acute bronchitis with a secondary comorbidity of asthma. Prescribing azithromycin 500mg for 3 days.",
),
AddMessage(
name="Assistant",
role="assistant",
content="Noted. Should I flag any contraindications with the patient's existing medications?",
),
AddMessage(
name="Dr. Patel",
role="user",
content="Good point — check against the current prednisone prescription. The prognosis is good if we manage both conditions.",
),
]
)

Scope instructions

A custom instruction can also limit which facts Zep extracts. The extraction model is trained on three scope patterns. Write a scope instruction in one of these patterns, so that the model applies it as you intend.

PatternWhat the model doesExample
ExclusionLeaves out each fact about the named topicDo not extract facts about health, for example diagnoses or medications.
InclusionKeeps only the facts about the named topic and leaves out all other factsKeep only facts about orders and deliveries, for example order dates and shipping status.
HybridKeeps only the facts about one topic and leaves out the facts about a second topicKeep only facts about work and career, for example job titles and employers, but leave out facts about salary, for example pay and bonuses.

In a hybrid instruction, the leave-out rule wins. The model leaves out a fact that is about both topics.

Follow these rules when you write a scope instruction:

  • Name each topic in plain words, and give one or two general examples of what the topic covers. Do not use an ID or a category code as the topic.
  • Put the word only in each keep rule. Keep facts about orders does not tell the model what to do with the other facts. Keep only facts about orders does.
  • Write a rule that two careful readers apply the same way. Do not use a vague scope, such as relevant information.
  • Write about topics, not about one conversation. Do not quote a specific fact, name, or event.
  • Do not use a double negative, such as Do not ignore facts about orders.

A longer instruction can hold the same patterns. The model is trained on these longer forms:

  • A rule with one sentence that gives the reason for the rule.
  • A short bullet list with one Keep only rule and one Leave out rule.
  • A scope section or a numbered policy with three to five rules.

In a longer form, each rule must name only the topics that the instruction covers.

An exclusion instruction about a topic that an episode does not contain changes nothing. The model extracts the facts of that episode as it does without the instruction. An inclusion instruction is different: when an episode has no facts about the kept topic, the model keeps no facts from that episode.

Important behaviors

Whole-set writes

A set call replaces the full set of instructions at its scope. An instruction that is not in the request is removed from that scope. To add or change one instruction, read the current set, change the list, and write the full list back. To remove all instructions at a scope, write an empty list.

graph.get_instructions returns the effective instructions of a graph. When the graph has no instructions of its own, the response contains the project-wide defaults and inherited is true.

# Change one project-wide instruction and keep the others.
current = client.project.get_instructions()
instructions = [i for i in current.instructions or [] if i.name != "legal_domain"]
instructions.append(CustomInstruction(name="legal_domain", text="This application operates in the legal domain."))
client.project.set_instructions(instructions=instructions)

Limits

LimitValue
Instructions per request5
Instruction name length100 characters
Instruction text length1-5,000 characters