Skip to main content

Scaling complexity

Keeping a large catalog sharp​

As your agent's rules grow from a handful to dozens or hundreds, related instructions start to drift apart. Observations describe a situation once so that many policies can share it. Terms define your business vocabulary once so that every rule means the same thing by it. Together with a shallow two-level hierarchy, they keep a large catalog consistent and make it clear where each new policy belongs.

What you'll learn
  • How an observation anchors a family of policies
  • What else an observation can change when it matches
  • How terms keep your business vocabulary consistent across rules
  • How to give a large catalog a shallow two-level shape
Talk this page through with your coding agent

Three problems tend to show up as a catalog grows. First, policies about the same topic drift apart in how they draw its boundary. Second, the same business word gets explained differently in each rule. Third, it stops being obvious where a new policy belongs.

Parlant gives you three tools to solve them: observations that anchor a family of policies, terms that define your vocabulary once, and a shallow hierarchy that makes the catalog read like a table of contents. Let's take each in turn.

Writing a single policy

Designing policies covers writing and tuning an individual policy. This page is about how your policies work together.

Observations: anchoring a family of policies​

An observation lets you describe a situation once, so that the policies about it do not each have to describe it again.

Suppose several of your policies cover account security. Rather than having each policy define the topic separately, you describe it once in an observation, a rule that recognizes a situation without telling the agent what to do. Related policies can then depend on it, so Parlant only considers them once that situation has come up in the session:

account_security = await agent.create_observation(
"the conversation involves account security: login issues, suspicious activity, or credential changes",
)

verify_identity = await agent.create_policy(
"When the customer needs an account change, direct them to Account settings "
"in the signed-in app, where they can make the change after identity verification",
)
no_alert_details = await agent.create_policy(
"When discussing suspicious activity, never reveal which signals triggered the alert",
)
await verify_identity.depend_on(account_security)
await no_alert_details.depend_on(account_security)

Whether the conversation is "about account security" is now judged once, by the observation's wording. Each member policy's content can focus on what to do within that topic, and when those instructions apply.

Once the observation has applied, its dependent policies stay available for the rest of the session.

A policy can depend on several rules at once. Pass them all to depend_on to require every one of them, or use depend_on_any when any one is enough. A dependency can also target a group of rules, which requires all of its members; wrap the group in p.AnyOf to require just one.

Letting an observation change how the turn runs​

An observation also carries the same runtime settings a policy does. That means matching it can change how the turn runs, without adding a word to your agent's instructions. It can raise effort, request a review, label the session, or carry tools and retrievers:

await agent.create_observation(
"the customer threatens legal action",
trigger_effort=p.Effort.HIGH, # effort: how much model work the turn gets
trigger_message_review=True, # the reply is checked before delivery
labels=["legal-risk"], # a marker that makes the session findable; see Session analytics
)

Adding a note when the condition could be misread​

Sometimes the condition alone could be misread. In that case, give the observation a note. Parlant carries the note along with the observation, both when it judges the condition and when the agent acts on the match:

service_outage = await agent.create_observation(
"the customer reports a service outage",
note="An outage means the service is unreachable. A bug in one feature is not an outage.",
)

Note that most observations do not need one. Policies have no separate note either; a policy's content is its full text, so any interpretation guidance goes there.

Deciding membership with code​

Observations can also decide membership with code rather than with the model. Give one an evaluation_func that checks the customer's groups, and every policy that depends on it is scoped to that group by exact logic, never by the model's guess.

tip

Customers shows the pattern in full.

Defining the terms rules rely on​

Once your policies are anchored to observations, there is still one more source of drift: the words themselves.

When several rules use a word your business defines its own way, define it once as a term rather than explaining it in each rule. Parlant recalls the terms relevant to a turn and shows them alongside the rules that use them, so that "outage", "VIP", or "the Pro plan" mean the same thing everywhere:

await agent.create_term(
name="outage",
description="The service is unreachable for the customer. A bug in one feature is not an outage.",
synonyms=["downtime", "the site is down"],
)

Synonyms help Parlant recall a term when customers do not use your word for it, say, "the site is down" for outage.

Note that a note on a single observation is enough when only that rule needs the definition. A term is for vocabulary the whole catalog shares.

How a catalog scales​

Now that you can anchor policies and share vocabulary, here is what actually happens as the catalog grows large.

A real agent carries dozens or hundreds of policies. Per-turn selection keeps only the relevant ones in front of the agent, so an unrelated policy costs nothing while it is inactive. Size alone is not the problem.

What does hurt is near-duplication: two policies that half-cover the same task drift apart and compete. If you find yourself writing a policy that mostly overlaps an existing one, extend the existing one instead, or split by task, not by phrasing.

Giving the catalog a two-level shape​

As the catalog grows, give it a shallow, two-level shape: a small set of topical observations, one per domain your agent handles, with each policy depending on its topic. For example, a support agent might have one observation for billing, one for shipping, and one for account security, with every policy hanging off one of them.

The catalog then reads like a table of contents, and you can tell at a glance where a new policy belongs.

Note that dependency checks cost a little latency on the turns where they apply. We recommend introducing the hierarchy around 25 to 30 policies; smaller catalogs do not need it.

Where to go next​

Observations decide more than topics, and the playbooks show a few of the ways you can put them to work.

Learn more

Customer personalization scopes policies to a customer group with an observation judged by code, and Handling sensitive situations uses one to raise effort and review on serious turns.

For long procedures that carry the business, the Pro engine's policy distiller judges them more precisely on every turn.