Handling sensitive situations
Making your agent know when to be careful
Most customer conversations are routine, and a cheap, fast agent handles them well. A few turn serious: a legal threat, a dispute, a moment where a wrong word costs your business. This playbook builds an agent that runs lean by default and becomes careful the moment a conversation turns serious. It uses adaptive effort to switch to stronger models, message review to check the reply before it is sent, and a canned response to control the wording.
- How to start an agent on low effort to keep routine turns cheap
- How an observation raises effort and turns on review
- How a canned response controls the wording of a sensitive reply
- How a dependent policy says what to do, and what happens on a serious turn
What makes customer-facing agents hard is that they face real customers. When your agent gets something wrong on behalf of your business, somebody pays the price.
But a large share of customer interactions are routine. They need no special care. Real call centers work the same way: Tier 1 support agents take up the bulk of the work.
Parlant lets you set up this pattern. When an interaction needs more care, you have several mechanisms to make sure the agent is up to the task, without paying for careful handling the rest of the time.
The plan
This playbook builds that agent from three features that each have their own documentation page: adaptive effort, message reviews, and canned responses. Here we show how they combine. This is what we will do:
- Create the agent with a low default effort, the setting that decides how much model work a turn gets, and tell the server which stronger models to use when effort is raised.
- Recognize tricky situations using an observation, a rule that only detects a situation and lets us reconfigure things when it happens. We will use it to raise effort and turn on message review.
- Control the wording with a canned response, an approved example the agent imitates.
- Say what to do with a policy that is only considered when the legal threat observation holds.
Building it
The agent and its models
Every agent turn in Parlant runs at a particular effort level, from MIN to MAX. The turn's effort level controls things like which models run, how deeply they reason, how carefully rules are matched, and whether the reply is reviewed. The agent has a baseline, but a rule can raise it for specific turns.
The models mapping tells the server what runs each kind of work. A key like react[effort>=high] binds a model to one kind of work, here react for generating the reply, only on turns at or above HIGH effort. At MEDIUM those entries are ignored and the * provider's defaults run. See Model routing for more details.
import parlant.sdk as p
async with p.Server(models={"*": "openrouter"}) as server:
agent = await server.create_agent(
id="support",
name="Support Agent",
instructions="Help customers with orders, deliveries, and account questions.",
effort=p.Effort.LOW, # Spend less by default
)
Recognizing the moment
Parlant has two kinds of rules, policies and observations. A policy says what to do in a situation. An observation only detects a situation, with no instruction given to the model. Observations are mostly used to change how the turn runs.
An observation is the right tool here because we just need to change how careful the agent is in tricky situations, not give it new policies.
legal_threat = await agent.create_observation(
condition="the customer explicitly threatens legal action",
trigger_effort=p.Effort.HIGH, # use a stronger model for applicable turns
trigger_message_review=True, # check replies against policies before sending
)
Fixing the wording
When a customer threatens legal action, we want a calm reply that acknowledges their concern and offers a next step without promising an outcome.
A canned response gives the agent an approved example to follow. With message review enabled, Parlant not only considers the canned response when writing its own reply, but also checks its draft against that example.
Let's build on the observation above. Replace its definition with the following code: create the canned response first, then add it to the same observation through canned_responses.
legal_threat_reply = await agent.create_canned_response(
template=(
"I understand you're considering legal action. "
"I can help you contact our support team to discuss your complaint."
),
# The optional note helps the agent understand the context
# and constraints for using this canned response
note=(
"Stay calm and respectful. Don't argue about the legal claim "
"or promise an outcome. Don't say the complaint has been "
"forwarded unless that has actually happened."
),
# Signals are also optional, but they help the agent find the
# appropriate canned response even when the customer's actual
# message doesn't explicitly correlate with the template
signals=[
"I'm going to sue you.",
"You'll be hearing from my lawyer.",
"I'll take you to court over this.",
],
)
# ...
# Add the canned response to the observation
legal_threat = await agent.create_observation(
condition="the customer explicitly threatens legal action",
trigger_effort=p.Effort.HIGH, # use a stronger model for applicable turns
trigger_message_review=True, # check replies against policies before sending
# Add the canned response (you can add many if you want)
canned_responses=[legal_threat_reply],
)
A canned response is used for reference; it is not rigid. The customer still gets natural, contextual wording, so the reply fits the conversation instead of reading like a script.
If you do need a canned response to read like a script, say so clearly in the note parameter.
The observation now raises effort, enables message review, and supplies the agent with approved wording.
Saying what to do
Besides raising the effort level and controlling the wording, it also helps to guide the agent on how to approach the situation. We can do this with simple steering guidelines.
A steering guideline is a short, plain-language instruction for a situation. We make this policy depend on our legal threat observation. A policy that depends on the observation is only considered once the observation has held in the session. This keeps the policy out of unrelated turns, so that the agent is not biased by it out of context.
weight sets how strictly a policy is followed. The default is quite firm already, but we use HIGH here so the agent holds to the rule even if the customer pressures it to offer compensation.
no_settlement = await agent.create_policy(
"Never offer to settle or compensate the customer to avoid a legal dispute. "
"If the customer asks or hints about it, tell them to call our live customer support.",
weight=p.Weight.HIGH, # High attention to this instruction
dependencies=[legal_threat], # Only considered when facing a legal threat
)
The policy says what to do, while the canned response on the observation shows how the reply should sound. Message review checks the draft against both the applicable policy and the approved example.
What happens on a sensitive turn
Reading a turn back, the pieces fire in this order:
- The observation matches. Agent effort becomes
HIGH. - The dependent policy is judged and, if it applies, joins the prompt alongside the observation's canned response.
- The reply is generated on the high-effort model.
- Message review checks the draft against the policy and the approved wording, and tries again if it does not pass.
- The customer sees the reviewed reply.
Note that an unrelated turn, say about a delivery date, does none of this. It runs at LOW effort on a smaller model, with no review, while the observation only costs one cheap matching check per turn.