Observations and policies
The rules an agent runs on
A rule is how you control what your agent does. There are two kinds. An observation notices a situation in the conversation, such as a customer asking for a refund, so your agent or your code can react. A policy also tells the agent what to do in that situation. You write rules in plain language, and Parlant decides each turn which ones apply.
- What an observation catches, and what you can hook into it
- How a policy adds instructions the agent actually reads
- How dependency and priority relate one rule to another
- When to change a rule's weight, and in which direction
Observations are mostly for you and your code. Policies are for the agent. Let's break it down.
Observations
An observation is a way to catch a situation as it arises in the conversation, and hook into it in some way. For example, you can observe that "the customer wants a refund" and trigger some behavior when that happens. Here are a few common examples of what you can hook into it, for as long as the observation holds:
- Raise the agent's effort level so that it uses a larger model, or more reasoning
- Add a label to the conversation for later reference and analytics
- Bring specific tools into the agent's awareness
- Trigger custom logic or side effects in your application
- Request careful review of any tool calls before they're issued
- Request careful review of messages, so that they're in line with policy and tone of voice
Here is what all of this together looks like in code:
await agent.create_observation(
condition="the customer wants a refund",
# Note: you can also use a code-based evaluation, instead of a natural language one
trigger_effort=p.Effort.HIGH, # You can configure and customize 5 different effort levels
labels=["refund_request"],
tools=[process_refund], # List of tools to be made available to the agent
on_matched=my_custom_callback, # Run this every time the observation is matched
trigger_tool_review=True,
trigger_message_review=True,
)
Policies
Policies extend observations with instructions that your agent actually sees.
A policy can do everything an observation can, but it also comes with two properties that find their way into the agent's prompts, and therefore guide its behavior.
These properties are content and title (and Parlant will generate the title for you if you don't specify it).
Here is how you create a policy:
await agent.create_policy(
title="Handling refunds", # Optional: you don't have to specify it if you don't want
content="""\
When the customer asks for a refund, follow this procedure:
1. Ask for the order number and look the order up with `get_order`.
2. A refund is only possible within 30 days of delivery. If the order is
older than that, or not yet delivered, explain why a refund isn't
possible and offer to open a support ticket instead.
3. Ask for the reason. If the item arrived damaged or defective, do not
ask the customer to ship it back.
4. Ask whether the refund should go to the original payment method or to
store credit; store credit is issued immediately, the original payment
method takes 5 to 7 business days.
5. Summarize the refund details and get the customer's explicit
confirmation, then process it with `process_refund`.
Never promise a refund will be issued before step 5 is complete.
""",
tools=[get_order, process_refund],
)
Rule relationships
Relationships let you say how the presence (or absence) of one rule affects another one.
Policies and observations support several kinds of relationships. The most common one is dependency. Its classic use is a rule hierarchy, where certain rules only become relevant in the right context:
discussing_refunds = await agent.create_observation("currently discussing a potential refund")
refund_policy_1 = await agent.create_policy(..., dependencies=[discussing_refunds])
refund_policy_2 = await agent.create_policy(..., dependencies=[discussing_refunds])
The other one you will reach for is priority, for turns where two rules both apply but give conflicting instructions. The prioritized rule is followed. The other rule stays in the agent's instructions, with a note that says it is set aside for this turn:
freeze = await agent.create_policy("When fraud is suspected on the account, freeze all transactions and say why")
refunds = await agent.create_policy("When the customer requests a refund on a delivered order, process it")
await freeze.prioritize_over(refunds)
To learn more, Rule relationships covers all four types and how they combine.
Weight: how firmly the agent holds to a rule
A rule's weight decides how strongly the agent sticks to it during a conversation. The default weight is quite steadfast, but sometimes you will find that less rigidity, or even more strictness, is appropriate.
Leave weight unset when creating a rule: the default, MEDIUM, is usually well-tuned. To give particular turns more model work, use adaptive effort. Tune weight when a conversation shows one of these problems:
-
If the agent keeps forcing a rule into conversations that have moved past it, set its weight to
p.Weight.LOW. This turns it into softer guidance rather than a hard requirement. -
If the agent applies a rule too little, say it falls for a clever argument for an exception or does not hold to it consistently, set it to
p.Weight.HIGH. Parlant will then issue structured reminders when appropriate.
Where to go next
How the engine works follows these rules through a turn, starting with how they are matched and how they are kept in focus. Designing policies is the practical guide to writing them, and Rule relationships has the full semantics of dependency, entailment, priority and reevaluation.