项目地址: github.com/emcie-co/pa…
项目定位与核心价值
项目定位
Parlant 是一个开源的 Agentic Behavior Modeling (ABM) 引擎,专门用于构建面向客户的对话式 AI 代理。与传统的基于提示工程的框架不同,Parlant 通过结构化的行为建模方法,确保 AI 代理能够可靠地遵循业务规则和预期行为。
核心价值主张
解决的核心问题
- 问题 1:LLM 不遵循指令 - 传统方法依赖系统提示词,但 LLM 经常忽略或误解这些指令
- 问题 2:行为不一致 - 相同输入可能产生不同输出,难以保证生产环境下的可靠性
- 问题 3:难以控制 - 缺乏有效机制确保代理在关键时刻遵循业务规则
- 问题 4:调试困难 - 无法理解代理为何做出特定决策
Parlant 的解决方案
- ✅ 确保规则遵循 - 通过动态指南匹配和上下文应用,确保代理遵循业务规则
- ✅ 行为可预测 - 结构化的行为建模方法提供一致、可预测的行为
- ✅ 生产就绪 - 从第一天起就具备企业级功能,支持大规模部署
- ✅ 完全可解释 - 提供详细的决策过程追踪和可解释性
与传统方法的对比
| 传统 AI 框架 | Parlant |
|---|---|
| 编写复杂的系统提示词 | 用自然语言定义规则 |
| 希望 LLM 遵循提示 | 确保规则遵循 |
| 调试不可预测的行为 | 可预测、一致的行为 |
| 通过提示工程扩展 | 通过添加指南扩展 |
| 可靠性靠运气 | 从第一天起就生产就绪 |
第一章:Guidelines(行为准则)
1.1 什么是 Guidelines?
Guidelines 是 Parlant 中用于以上下文和目标方式调整代理行为的主要方法。它们允许我们指示代理在特定情况下如何响应,覆盖其默认行为,从而确保行为符合我们的期望和业务需求。
核心定义
Guideline:用自然语言定义的上下文规则,指导代理在特定情况下的行为。
每个 Guideline 由两部分组成:
- Condition(条件):指定何时应该应用该指南
- Action(动作):描述应该做什么
基本结构
await agent.create_guideline(
condition="客户询问产品库存",
action="先检查库存状态,然后提供准确信息"
)
当条件满足时,代理会执行动作。在非正式讨论中,我们通常用"当...时,则..."的形式描述:当客户询问产品库存时,则先检查库存状态,然后提供准确信息。
1.2 Guidelines 的核心特性
1.2.1 条件-动作结构
每个 Guideline 都遵循清晰的条件-动作模式:
# 基本指南
await agent.create_guideline(
condition="客户要求退款",
action="验证订单状态,然后处理退款请求"
)
# 观察性指南(只有条件,没有动作)
await agent.create_guideline(
condition="客户是 VIP 会员",
action=None # 仅用于上下文理解,不执行动作
)
1.2.2 动态匹配
系统自动评估对话上下文,只加载相关的 Guidelines。这确保了:
- 最大化 LLM 注意力:只关注相关的指南
- 降低认知负担:避免信息过载
- 提高准确性:专注于最相关的规则
1.2.3 工具关联
Guidelines 可以与工具(函数)关联,确保工具在正确时机被调用:
@p.tool
async def check_inventory(
context: p.ToolContext,
product_name: str
) -> p.ToolResult:
stock = await db.get_stock(product_name)
return p.ToolResult(data=stock)
await agent.create_guideline(
condition="客户询问特定产品的库存",
action="查询该产品的实时库存信息",
tools=[check_inventory] # 关联工具
)
1.2.4 应用追踪
系统跟踪 Guideline 是否已被应用,避免重复:
- 默认行为:一旦应用就不再重复应用
- 持续型指南:可以重复应用
- 上下文变化:如果上下文发生变化,可能重新应用
1.3 Guidelines 的类型
1.3.1 类型确定方式
重要说明:Guidelines 的类型可以通过两种方式确定:
- 手动指定(推荐):创建者在创建 Guideline 时明确指定类型
- 自动检测(可选):系统可以使用 LLM 自动检测某些类型(主要用于评估和索引阶段)
运行时行为:
- 在运行时匹配阶段,系统使用 metadata 中的显式标记来确定类型
- 如果创建者没有指定,系统会使用默认行为
1.3.2 Observational Guidelines(观察性指南)
特点:只有条件,没有动作
确定方式:
- 手动指定:创建 Guideline 时设置
action=None - 自动判断:系统通过检查
g.content.action是否为None来判断
用途:
- 理解对话上下文
- 影响其他指南的匹配
- 不触发任何行为
示例:
await agent.create_guideline(
condition="客户是 VIP 会员",
action=None # 系统会自动识别为观察性指南
)
1.3.3 Actionable Guidelines(可操作指南)
特点:有条件和动作
确定方式:
- 手动指定:创建 Guideline 时提供
action参数 - 自动判断:系统通过检查
g.content.action是否存在来判断
用途:
- 当条件满足时,代理执行动作
- 默认情况下,一旦应用就不再重复应用
示例:
await agent.create_guideline(
condition="客户要求退款",
action="验证订单状态,然后处理退款请求"
)
1.3.4 Continuous Guidelines(持续型指南)
特点:可以重复应用
确定方式:
- 手动指定(推荐):在 metadata 中明确设置
{"continuous": True} - 自动检测(可选):系统可以使用 LLM 自动检测(主要用于评估和索引阶段)
用途:
- 适用于需要持续关注的情况
- 每次条件满足时都会应用
示例:
await agent.create_guideline(
condition="对话中出现技术问题",
action="提供技术支持",
metadata={"continuous": True} # 明确标记为持续型
)
1.3.5 Customer-Dependent Guidelines(客户依赖型指南)
特点:动作需要客户提供信息才能完成
确定方式:
- 手动指定(推荐):在 metadata 中明确设置
customer_dependent_action_data - 自动检测(可选):系统可以使用 LLM 自动检测(主要用于评估和索引阶段)
用途:
- 系统会追踪客户是否已提供所需信息
- 只有在客户提供信息后才认为动作完成
示例:
await agent.create_guideline(
condition="需要验证客户身份",
action="获取客户的账户号码",
metadata={"customer_dependent_action_data": {
"is_customer_dependent": True,
"customer_action": "客户提供了账户号码",
"agent_action": "代理询问了客户的账户号码"
}}
)
1.3.6 类型确定总结
| 类型 | 手动指定方式 | 自动检测 | 运行时判断依据 |
|---|---|---|---|
| Observational | action=None | 不需要(直接判断) | g.content.action 是否为 None |
| Actionable | 提供 action | 不需要(直接判断) | g.content.action 是否存在 |
| Continuous | metadata={"continuous": True} | ✅ LLM 自动检测 | g.metadata.get("continuous", False) |
| Customer-Dependent | metadata={"customer_dependent_action_data": {...}} | ✅ LLM 自动检测 | g.metadata.get("customer_dependent_action_data", {}).get("is_customer_dependent", False) |
最佳实践:
- ✅ 推荐手动指定:明确指定类型可以确保行为符合预期
- ✅ 使用自动检测作为辅助:在评估阶段使用自动检测来验证和补充
- ⚠️ 运行时优先使用显式标记:运行时匹配阶段优先使用 metadata 中的显式标记
1.4 Guidelines 的优先级和关系
1.4.1 优先级关系
Guidelines 可以建立优先级关系,确保重要规则优先执行:
guideline1 = await agent.create_guideline(
condition="紧急情况",
action="立即处理"
)
guideline2 = await agent.create_guideline(
condition="一般请求",
action="按正常流程处理"
)
# guideline1 优先于 guideline2
await guideline1.prioritize_over(guideline2)
1.4.2 依赖关系
Guidelines 可以建立依赖关系:
# guideline2 依赖 guideline1
await guideline2.depend_on(guideline1)
注意:Guidelines 还可以与 Journeys 建立关系(优先级和依赖关系),这部分内容将在第二章"Journeys"中详细介绍。
1.5 Guidelines 的作用域
1.5.1 Agent-Scoped Guidelines(代理作用域)
代理级别的指南,适用于该代理的所有对话:
await agent.create_guideline(
condition="客户询问产品信息",
action="提供准确的产品信息"
)
1.5.2 Journey-Scoped Guidelines(Journey 作用域)
只在特定 Journey 激活时才生效的指南:
journey = await agent.create_journey(
title="订单处理",
conditions=["客户有订单相关问题"]
)
# 这个指南只在"订单处理"Journey 激活时才会被评估
await journey.create_guideline(
condition="客户想要取消订单",
action="确认订单状态,然后处理取消请求",
tools=[cancel_order]
)
1.5.3 Global Guidelines(全局指南)
没有特定作用域的指南,适用于所有代理:
await agent.create_guideline(
condition="客户表达了不满",
action="表示歉意并提供帮助"
)
1.6 Guidelines 的实现架构
1.6.1 数据模型
Guideline(指南):
id:唯一标识符content:包含条件和动作enabled:是否启用tags:标签列表(用于作用域控制)metadata:元数据(存储指南类型、依赖关系等)criticality:重要性级别composition_mode:组合模式(可选)
GuidelineContent(指南内容):
condition:条件字符串action:动作字符串(可选)description:描述(可选)
GuidelineMatch(指南匹配结果):
guideline:匹配的指南score:匹配分数(0-10)rationale:匹配理由metadata:匹配元数据
1.6.2 存储架构
文档数据库存储:
guidelines集合:存储指南基本信息guideline_tags集合:存储标签关联guideline_tool_associations集合:存储工具关联
向量数据库存储:
- 用于语义搜索相关指南
- 支持快速查找匹配的指南
第二章:Journeys(对话流程)
2.1 什么是 Journeys?
Journeys 是 Parlant 中用于定义结构化、多步骤对话流程的功能。它们允许代理引导客户完成特定目标,如预订行程、故障排除或其他需要多轮交互的过程。 Journeys 是一组 Guidelines 的逻辑组合,通过一个状态图维护进度。
核心定义
Journey:结构化的多步骤对话流程,引导客户完成特定目标。
Journey 有 4 个重要组成部分:
- Title(标题):简短、描述性的名称,用于区分不同的 Journey
- Conditions(条件):上下文查询,确定何时应该激活 Journey
- Description(描述):描述 Journey 的性质,包括动机或指导说明
- States & Transitions(状态和转换):状态图,传达理想的流程
核心特性
- 状态图模型:基于状态图定义对话流程
- 灵活导航:代理可以跳过状态、回溯或提前跳转,保持自然对话
- 条件激活:通过上下文查询确定何时激活 Journey
- 平衡灵活性与控制:在灵活性和协议遵循之间取得平衡
2.2 Journey 的状态类型
2.2.1 Chat States(对话状态)
代理与客户交流的状态:
journey = await agent.create_journey(
title="预订航班",
conditions=["客户想要预订航班"]
)
# 创建对话状态
initial_state = journey.initial_state
state1 = await initial_state.transition_to(
chat_state="询问目的地和出发日期"
)
2.2.2 Tool States(工具状态)
调用外部工具执行操作的状态:
@p.tool
async def search_flights(
context: p.ToolContext,
origin: str,
destination: str,
date: str
) -> p.ToolResult:
flights = await flight_api.search(origin, destination, date)
return p.ToolResult(data=flights)
# 创建工具状态
state2 = await state1.transition_to(
tool_state=search_flights
)
2.2.3 Fork States(分支状态)
根据条件分支对话流程的状态:
# 创建分支状态
fork_state = await state2.transition_to(
fork_state="根据搜索结果决定下一步"
)
# 分支条件
await fork_state.fork(
condition="找到可用航班",
target=state3 # 继续预订流程
)
await fork_state.fork(
condition="未找到可用航班",
target=state4 # 提供替代方案
)
2.3 Journey 的灵活性与控制
2.3.1 灵活性特性
Parlant 的 Journey 设计在灵活性和控制之间取得平衡:
灵活性:
- 代理可以跳过已完成的状态
- 支持回溯到之前的状态
- 允许客户提供信息顺序与流程不同
- 支持多轮对话停留在同一状态
2.3.2 控制性特性
控制性:
- 确保关键步骤不被跳过
- 验证必要信息已收集
- 强制执行工具调用顺序
- 确保协议遵循
2.4 Journey 的激活条件
2.4.1 激活条件定义
Journey 的激活条件实际上是观察性 Guidelines:
journey = await agent.create_journey(
title="预订航班",
conditions=["客户想要预订航班"] # 转换为观察性指南
)
系统内部会创建:
Guideline(condition="客户想要预订航班", action=None)
2.4.2 激活机制
当 Journey 的激活条件 Guideline 匹配成功时,Journey 被激活:
1. 用户消息:"我想预订航班"
↓
2. 系统评估 Guidelines(包括 Journey 的激活条件)
→ 匹配到"客户想要预订航班"Guideline
↓
3. 激活"预订航班"Journey
2.4.3 Journey 激活的详细机制
激活过程:
-
检查匹配的 Guidelines:
# 获取所有匹配成功的 Guideline ID matched_guideline_ids = {g.id for g in matched_guidelines} # 检查哪些 Journey 的激活条件在匹配的 Guidelines 中 activated_journeys = [ journey for journey in all_journeys if set(journey.conditions).intersection(matched_guideline_ids) ] -
激活 Journey:
- 如果 Journey 的激活条件 Guideline 匹配成功,Journey 被激活
- 重要:所有匹配条件的 Journey 都会被激活,不限制数量
- 激活后,Journey 的状态会被投影为 Guidelines 供后续使用
-
保持已激活的 Journey:
- 如果 Journey 在之前的交互中已经激活,且仍在路径中,保持激活状态
- 这确保了 Journey 的连续性
-
多个 Journey 同时激活:
- 多个 Journey 可以同时激活(如果它们的激活条件都匹配)
- 每个激活的 Journey 都会独立处理其状态选择
- 所有激活的 Journey 的状态都会被投影为 Guidelines
- 这些 Guidelines 会一起参与响应生成
- LLM 会根据所有激活的 Journey 状态和匹配的 Guidelines 生成响应
示例:
场景:用户说"我想预订航班和酒店"
匹配结果:
→ "客户想要预订航班"Guideline 匹配 ✓
→ "客户想要预订酒店"Guideline 匹配 ✓
激活结果:
→ JourneyA(预订航班)被激活 ✓
→ JourneyB(预订酒店)被激活 ✓
→ 两个 Journey 同时激活
状态选择:
→ JourneyA 选择状态:"询问目的地"
→ JourneyB 选择状态:"询问入住日期"
响应生成:
→ 使用两个 Journey 的状态 Guidelines + 其他匹配的 Guidelines
→ 生成:"好的,我来帮您预订航班和酒店。请问您想去哪里?入住日期是什么时候?"
2.5 Journey 状态投影为 Guidelines
2.5.1 投影机制
Journey 的每个节点(Node)和转换(Edge)会被自动投影成 Guidelines:
- 节点动作 → Guideline 的动作
- 边条件 → Guideline 的条件
投影过程:JourneyGuidelineProjection.project_journey_to_guidelines()
2.5.2 投影示例
# Journey 定义
journey = await agent.create_journey(...)
t1 = await journey.initial_state.transition_to(
chat_state="询问目的地"
)
# 系统内部会自动创建 Guideline:
# Guideline(
# condition="", # 从边条件
# action="询问目的地", # 从节点动作
# metadata={"journey_node": {...}} # 包含 Journey 信息
# )
2.5.3 状态图 Guidelines 的逻辑关系
重要:Journey 状态图投影生成的 Guidelines 是有逻辑关系的,这些关系反映了状态图的结构:
-
状态图的连接关系:
- 每个节点对应一个 Guideline
- 节点之间的转换(Edge)关系通过
follow_ups字段保存在 Guideline 的 metadata 中 follow_ups记录了从当前节点可以到达的下一个节点的 Guideline ID
-
逻辑关系示例:
# Journey 状态图: # 节点1 → 节点2 → 节点3 # 投影后的 Guidelines: # Guideline1 (节点1): # - action: "询问目的地" # - metadata.journey_node.follow_ups: [Guideline2的ID] # # Guideline2 (节点2): # - condition: "客户提供了目的地" # - action: "询问出发日期" # - metadata.journey_node.follow_ups: [Guideline3的ID] # # Guideline3 (节点3): # - condition: "客户提供了出发日期" # - action: "搜索航班" -
关系的作用:
- 系统使用
follow_ups来确定 Journey 的下一步状态 - 这些关系确保了 Journey 的状态转换逻辑被正确执行
- 代理可以根据这些关系选择下一个要执行的状态
- 系统使用
-
与 Journey-Scoped Guidelines 的区别:
- 状态图投影的 Guidelines:有逻辑关系(通过
follow_ups和状态图结构) - Journey-Scoped Guidelines(通过
journey.create_guideline()创建):- 不一定有逻辑关系
- 只是作用域绑定到 Journey
- 用于处理 Journey 中的特殊情况,不一定与状态图有直接关系
- 状态图投影的 Guidelines:有逻辑关系(通过
2.6 Journey 状态选择机制
重要:每个 Journey 在每次交互中只会选择一个状态转化为 Guidelines 给 agent。
执行时机:Journey 状态选择是在 Guideline 匹配过程中进行的,作为 Guideline 匹配批次的一部分。
完整流程:
1. 匹配 Guidelines(包括 Journey 的激活条件)
↓
2. 激活 Journey(基于匹配的激活条件)
↓
3. 对于每个激活的 Journey,在 Guideline 匹配批次中:
a. 调用 LLM 评估当前状态完成度
b. 调用 LLM 选择下一个状态(如果需要)
c. 更新 Journey 路径状态
d. 将选中的状态投影为 Guideline
↓
4. 所有匹配的 Guidelines(包括 Journey 状态 Guidelines)一起给 agent 参考
状态选择过程:
-
评估当前状态完成度:
- 对于每个激活的 Journey,调用 LLM 评估当前状态是否完成
- 对于客户依赖型状态,检查客户是否已提供所需信息
- 对于工具状态,检查工具是否已执行
-
评估转换条件:
- 如果当前状态已完成,评估所有可能的转换条件
- 使用 LLM 判断哪个转换条件最匹配当前上下文
- 重要:LLM 只会选择一个最匹配的转换条件(
applied_condition_id)
-
选择下一个状态:
- 情况 A:当前状态未完成 → 保持当前状态(
applied_condition_id = "0") - 情况 B:Journey 应该结束 → 选择根节点(
applied_condition_id = "None") - 情况 C:当前状态已完成 → 选择匹配度最高的转换条件对应的目标状态
- 结果:每个 Journey 只会选择一个状态(当前状态或下一个状态)
- 情况 A:当前状态未完成 → 保持当前状态(
-
更新 Journey 路径状态:
- 将选中的状态添加到
journey_paths[JourneyId]中 - 记录 Journey 的状态转换历史
- 将选中的状态添加到
-
生成状态 Guidelines:
- 将选中的状态投影为 Guidelines
- 每个 Journey 只会生成一个状态对应的 Guideline
- 这些 Guidelines 会和其他匹配的 Guidelines 一起参与响应生成
示例:
场景:JourneyA(预订航班)已激活,当前在"询问目的地"状态
情况 1:客户还未提供目的地
→ 当前状态未完成
→ 保持当前状态:"询问目的地"
→ 生成 1 个 Guideline(询问目的地)
情况 2:客户提供了目的地
→ 当前状态已完成
→ 评估转换条件:
- 条件1:"客户提供了目的地" → 状态:"询问出发日期"
- 条件2:"客户提供了目的地和出发日期" → 状态:"搜索航班"
→ LLM 选择最匹配的条件(假设是条件1)
→ 选择下一个状态:"询问出发日期"
→ 生成 1 个 Guideline(询问出发日期)
情况 3:客户说"我不想预订了"
→ Journey 应该结束
→ 选择根节点(退出 Journey)
→ 生成 1 个 Guideline(根节点,表示退出)
关键理解:
- ✅ 每个 Journey 每次交互只选择一个状态:要么保持当前状态,要么选择下一个状态,要么退出 Journey
- ✅ 状态选择是互斥的:不会同时选择多个状态
- ✅ Journey 路径是线性的:
journey_paths[JourneyId]是一个列表,记录 Journey 的状态路径 - ✅ 多个 Journey 可以并行:不同 Journey 可以同时激活,每个 Journey 独立选择自己的状态
2.7 Journey-Scoped Guidelines
2.7.1 定义
可以创建只在特定 Journey 激活时才生效的 Guidelines:
journey = await agent.create_journey(
title="预订航班",
conditions=["客户想要预订航班"]
)
# 这个 Guideline 只在"预订航班"Journey 激活时才会被评估
await journey.create_guideline(
condition="客户想要取消预订",
action="提供取消选项并确认"
)
2.7.2 使用场景
- 处理 Journey 中的特殊情况
- 处理偏离或异常情况
- 在 Journey 中提供额外的行为指导
2.8 Guidelines 与 Journey 的关系
2.8.1 核心关系
Guidelines 和 Journey 在 Parlant 中紧密相关,但服务于不同的目的:
| 关系类型 | 说明 | 示例 |
|---|---|---|
| 激活条件 | Journey 的条件是观察性 Guideline | conditions=["客户想要预订"] → 观察性 Guideline |
| 状态投影 | Journey 状态自动转换为 Guidelines | 节点动作 → Guideline 动作 |
| 作用域绑定 | Guideline 绑定到特定 Journey | journey.create_guideline() |
| 优先级 | Guideline 可以优先于 Journey 状态 | guideline.prioritize_over(journey) |
| 依赖关系 | Guideline 可以依赖 Journey | guideline.depend_on(journey) |
2.8.2 Guidelines 与 Journey 的优先级和依赖关系
Guidelines 可以优先于 Journey 状态:
journey = await agent.create_journey(...)
# Guideline 优先于 Journey 状态
await guideline.prioritize_over(journey)
# Guideline 依赖 Journey(只有在 Journey 激活时才生效)
await guideline.depend_on(journey)
使用场景:
- 优先级关系:当 Guideline 和 Journey 状态冲突时,Guideline 优先执行
- 依赖关系:Guideline 只在特定 Journey 激活时才生效,用于 Journey 中的特殊情况处理
示例:
# 即使 Journey 状态说"询问目的地"
# 但如果这个 Guideline 匹配,会优先执行 Guideline 的动作
await journey.create_guideline(
condition="客户表达了紧急需求",
action="先处理紧急情况,然后再继续预订流程"
)
2.8.3 使用场景对比
| 场景 | 使用 Guideline | 使用 Journey |
|---|---|---|
| 简单的条件-动作规则 | ✅ | ❌ |
| 多步骤流程 | ❌ | ✅ |
| 处理特殊情况 | ✅ | ❌ |
| 结构化对话流程 | ❌ | ✅ |
| 工具调用触发 | ✅ | ❌ |
| 需要状态管理 | ❌ | ✅ |
2.9 Journey 的实现架构
2.9.1 数据模型
Journey(旅程):
id:唯一标识符title:标题description:描述conditions:激活条件(Guideline ID 列表)root_id:根节点 IDtags:标签列表composition_mode:组合模式(可选)
JourneyNode(节点):
id:节点 IDaction:节点动作(Chat State 的指令或 Tool State 的工具)tools:关联的工具列表description:节点描述metadata:元数据composition_mode:节点级别的组合模式(覆盖 Journey 级别)
JourneyEdge(边/转换):
id:边 IDsource:源节点 IDtarget:目标节点 IDcondition:转换条件(可选)metadata:元数据
2.9.2 存储架构
文档数据库存储:
journeys集合:存储 Journey 基本信息journey_nodes集合:存储节点信息journey_edges集合:存储边信息journey_conditions集合:存储条件关联journey_tags集合:存储标签关联
向量数据库存储:
- 用于语义搜索相关 Journey
- 内容包含标题、描述、节点动作和边条件
- 支持快速查找匹配的 Journey
2.10 Journey 的最佳实践
2.10.1 设计原则
-
从简单开始:
- ✅ 从简单流程开始,逐步增加复杂性
- ✅ 每个状态应该有明确的完成标准
-
状态设计:
- ✅ Chat States 应该清晰、具体
- ✅ Tool States 应该专注于单一操作
- ✅ 使用 Fork States 处理明确的分支场景
-
转换设计:
- ✅ 条件应该明确、可评估
- ✅ 避免过于复杂的嵌套结构
2.10.2 常见陷阱
-
过度复杂化:
- ❌ 创建过于复杂的嵌套结构
- ✅ 保持流程简单、清晰
-
忽略灵活性:
- ❌ 假设客户会严格按照流程
- ✅ 允许客户以不同顺序提供信息
第三章:Recall and Matching Logic(召回与匹配逻辑)
3.1 概述
当用户发送消息时,Parlant 需要确定使用哪些 Guidelines 和 Journeys。这个过程涉及多个阶段的过滤和匹配,以确保只评估相关的规则,同时优化性能和成本。
3.1.1 核心原则
重要澄清:不是"先匹配 Journey 再匹配 Guideline",而是:
- 预测高概率 Journey(用于过滤 Guidelines,不是匹配)
- 匹配 Guidelines(LLM 评估)
- 激活 Journey(基于匹配结果)
关键区别:
- 预测 Journey:使用向量搜索或已有路径,快速找到可能相关的 Journey(用于优化)
- 匹配 Guidelines:使用 LLM 评估 Guideline 条件是否匹配(核心步骤)
- 激活 Journey:检查匹配的 Guideline ID 中是否有 Journey 的激活条件 ID
重要澄清:向量搜索不会导致不准确:
向量搜索只是用于性能优化,不会影响最终结果的准确性,原因如下:
-
向量搜索只是过滤,不是最终判断:
- 向量搜索只用于预测"可能相关"的 Journey,用于减少需要评估的 Guidelines 数量
- 真正的匹配判断还是通过 LLM 评估 Guidelines 来完成的
- Journey 的激活由其激活条件 Guideline 的匹配结果决定,而不是向量搜索的结果
-
有补充匹配机制:
- 如果向量搜索预测错误(低概率 Journey 实际上被激活),系统会在阶段 8:补充匹配中自动处理
- 当低概率 Journey 的激活条件 Guideline 匹配成功时,系统会:
- 检测到该 Journey 被激活
- 加载该 Journey 相关的 Guidelines
- 进行额外的 LLM 匹配
- 确保不遗漏相关行为
-
准确性保障:
- 向量搜索的准确性不影响最终结果,因为:
- 如果预测正确:正常流程,性能优化
- 如果预测错误:补充匹配机制会自动纠正,确保准确性
- 最终激活的 Journey 都是基于 LLM 精确评估的结果,而不是向量搜索的相似度
- 向量搜索的准确性不影响最终结果,因为:
示例:
场景:向量搜索预测错误的情况
阶段 4:概率过滤
→ 向量搜索找到 JourneyA(预订航班)作为高概率 Journey
→ JourneyB(预订酒店)被标记为低概率
阶段 5:过滤 Guidelines
→ 保留 JourneyA 的 Guidelines
→ 过滤掉 JourneyB 的 Guidelines
阶段 6:LLM 语义匹配
→ 评估所有保留的 Guidelines(包括 JourneyA 的激活条件)
→ 同时评估全局 Guidelines(包括 JourneyB 的激活条件)
阶段 7:激活 Journey
→ JourneyA 的激活条件匹配 ✓ → 激活 JourneyA
→ JourneyB 的激活条件也匹配 ✓ → 激活 JourneyB(虽然被标记为低概率)
阶段 8:补充匹配(关键步骤)
→ 检测到 JourneyB 被激活(虽然之前被过滤)
→ 加载 JourneyB 相关的 Guidelines
→ 进行额外的 LLM 匹配
→ 确保 JourneyB 的行为被正确执行
结果:即使向量搜索预测错误,系统仍然能够正确激活所有相关的 Journey
3.2 完整处理流程
当用户发送消息时,系统按照以下步骤处理:
用户消息
↓
[阶段 1] 加载上下文
- 加载代理、会话、客户信息
- 检查是否有激活的 Journey 路径
↓
[阶段 2] 获取可用 Journey
- 查询该代理的所有可用 Journey
↓
[阶段 3] 标签过滤 - 加载相关 Guidelines
- 代理特定 Guidelines
- 全局 Guidelines
- Journey 关联的 Guidelines
- Journey 投影生成的 Guidelines
↓
[阶段 4] 概率过滤 - 确定高概率 Journey
├─ 情况A:有激活的 Journey 路径 → 使用这些 Journey
└─ 情况B:无激活路径 → 向量搜索找到最相关的 Journey(top_k=1)
↓
[阶段 5] 过滤 Guidelines
- 保留:高概率 Journey 相关的 Guidelines + 全局 Guidelines
- 过滤掉:低概率 Journey 相关的 Guidelines
↓
[阶段 6] LLM 语义匹配 - 评估 Guidelines
- 对过滤后的 Guidelines 进行分类和批次处理
- 使用 LLM 评估每个 Guideline 的条件是否匹配
- 生成匹配结果(分数、理由)
↓
[阶段 7] 激活 Journey
- 检查匹配的 Guidelines 中是否有 Journey 的激活条件
- 如果有,激活对应 Journey
↓
[阶段 8] 补充匹配(如果需要)
- 如果低概率 Journey 被激活,加载其 Guidelines 并重新匹配
↓
[阶段 9] 关系解析
- 加载依赖和优先级相关的 Guidelines
↓
[阶段 10] Journey 状态选择(在 Guideline 匹配过程中进行)
- 对于每个激活的 Journey,调用 LLM 评估当前状态完成度并选择下一个状态
- 更新 Journey 路径状态
- 将选中的状态投影为 Guidelines
- 这些 Guidelines 会和其他匹配的 Guidelines 一起参与响应生成
↓
[阶段 11] 工具调用(如果有工具关联的 Guidelines)
- 提取参数 → 调用工具 → 获取结果
- 如果需要,返回阶段 6 重新评估
↓
[阶段 12] 生成响应
- 使用所有匹配的 Guidelines 和 Journey 状态
- 生成最终响应
3.3 多阶段过滤机制详解
3.3.1 阶段 1:标签过滤(Tag-based Filtering)
目的:只加载与当前上下文相关的 Guidelines
加载的 Guidelines:
- 代理特定的 Guidelines(通过
Tag.for_agent_id()) - 全局 Guidelines(无标签)
- 代理标签关联的 Guidelines
- 这些 Journey 关联的 Guidelines
- Journey 投影生成的 Guidelines(从 Journey 状态转换而来)
代码实现:
# find_guidelines_for_context
agent_guidelines = await guideline_store.list_guidelines(
tags=[Tag.for_agent_id(agent_id)]
)
global_guidelines = await guideline_store.list_guidelines(tags=[])
guidelines_for_journeys = await guideline_store.list_guidelines(
tags=[Tag.for_journey_id(journey.id) for journey in journeys]
)
效果:从所有 Guidelines 减少到代理相关的 Guidelines(例如:从 1000 个减少到 200 个)
3.3.2 阶段 2:概率过滤(Probability-based Pruning)
目的:基于 Journey 激活概率进一步过滤 Guidelines
3.3.2.1 判断高概率 Journey
情况 A:已有激活的 Journey 路径
- 如果对话中已经有激活的 Journey(
journey_paths不为空) - 这些 Journey 被认为是"高概率"的
- 不需要使用向量搜索,直接使用这些 Journey
- 重要:如果激活的 Journey 数量超过
top_k,会保留所有激活的 Journey(不限制数量)
情况 B:没有激活的 Journey
- 如果对话中没有任何激活的 Journey
- 使用向量数据库语义搜索找到与当前对话上下文最相关的 Journey
- 向量搜索的对象是Journey,不是 Guidelines
- 默认只选择最相关的
top_k=1个 Journey 作为"高概率"候选 - 如果激活的 Journey 数量少于
top_k,会补充最相关的其他 Journey 直到达到top_k
向量搜索查询构建:
# 构建查询文本
query = ""
query += 对话历史
query += 上下文变量
query += 已匹配的 Guidelines
query += 术语表
# 向量搜索
高概率 Journey = 向量搜索(query, top_k=1)
多个 Journey 的处理逻辑:
当有多个 Journey 被召回或激活时,系统采用以下策略:
-
概率过滤阶段(用于过滤 Guidelines):
- 默认
top_k=1,只选择最相关的 1 个 Journey 用于过滤 Guidelines - 但如果已经有激活的 Journey 路径,会保留所有激活的 Journey(不限制数量)
- 如果激活的 Journey 数量少于
top_k,会补充最相关的其他 Journey
- 默认
-
激活阶段(实际激活 Journey):
- 所有匹配条件的 Journey 都会被激活,不限制数量
- 激活条件:
- Journey 的激活条件 Guideline 匹配成功
- 或者 Journey 在之前的交互中已经激活(保持连续性)
- 多个 Journey 可以同时激活
-
并行处理多个激活的 Journey:
- 每个激活的 Journey 都会独立处理其状态选择
- 所有激活的 Journey 的状态都会被投影为 Guidelines
- 这些 Guidelines 会一起参与响应生成
- LLM 会根据所有激活的 Journey 状态和匹配的 Guidelines 生成响应
示例:
场景:用户说"我想预订航班和酒店"
概率过滤阶段:
→ 向量搜索找到最相关的 Journey(top_k=1)
→ 假设找到 JourneyA(预订航班)
激活阶段:
→ 评估所有 Journey 的激活条件
→ JourneyA(预订航班)的激活条件匹配 ✓
→ JourneyB(预订酒店)的激活条件也匹配 ✓
→ 两个 Journey 都被激活
并行处理:
→ JourneyA 选择状态:"询问目的地"
→ JourneyB 选择状态:"询问入住日期"
→ 两个状态都被投影为 Guidelines
→ LLM 根据所有 Guidelines 生成响应:"好的,我来帮您预订航班和酒店。请问您想去哪里?入住日期是什么时候?"
关键理解:
- 概率过滤:用于优化性能,减少需要评估的 Guidelines 数量(默认 top_k=1)
- 激活阶段:基于匹配结果,所有匹配条件的 Journey 都会被激活(不限制数量)
- 并行处理:多个 Journey 可以同时激活,它们的状态会一起影响响应生成
3.3.2.2 过滤 Guidelines
过滤逻辑:
# 伪代码
if 有激活的 Journey 路径:
高概率 Journey = 所有激活的 Journey
else:
高概率 Journey = 向量搜索找到的最相关的 top_k 个 Journey
# 只保留高概率 Journey 相关的 Guidelines
过滤后的 Guidelines = [
Guideline for Guideline in 所有 Guidelines
if (Guideline 属于高概率 Journey) or (Guideline 不依赖任何 Journey)
]
关键理解:
-
通过向量选择 Journey,就默认选择了挂载在 Journey 上的 Guidelines:
- 当向量搜索找到高概率 Journey 后,系统会自动包含这些 Journey 相关的所有 Guidelines
- 包括:
- Journey 的激活条件 Guidelines
- Journey-Scoped Guidelines(通过
journey.create_guideline()创建的) - Journey 状态投影生成的 Guidelines(从 Journey 节点和转换自动生成)
-
不挂在 Journey 上的 Guidelines 会全量通过 LLM 匹配:
- 全局 Guidelines(不依赖任何 Journey)会全部保留
- 这些 Guidelines 会全部通过 LLM 进行匹配评估
- 因为它们是全局的,不依赖 Journey,所以不能通过 Journey 过滤
-
挂载在低概率 Journey 上的 Guidelines 会被过滤掉:
- 如果某个 Journey 不是高概率的,它相关的 Guidelines 会被过滤掉
- 这样可以大幅减少需要评估的 Guidelines 数量
- 如果低概率 Journey 后来被激活,会在补充匹配阶段重新加载其 Guidelines
实际例子:
假设有:
- JourneyA(预订航班):高概率,有 50 个相关 Guidelines
- JourneyB(预订酒店):低概率,有 40 个相关 Guidelines
- JourneyC(查询天气):低概率,有 30 个相关 Guidelines
- 全局 Guidelines:30 个
过滤后:
- ✅ JourneyA 的 50 个 Guidelines(保留)
- ❌ JourneyB 的 40 个 Guidelines(过滤掉)
- ❌ JourneyC 的 30 个 Guidelines(过滤掉)
- ✅ 全局 Guidelines 30 个(保留)
结果:只对 80 个 Guidelines 进行 LLM 匹配,而不是 150 个
3.3.2.3 为什么 Journey 使用向量搜索,而 Guidelines 不使用?
核心原因:
-
数量差异:
- Journey 数量少:通常只有几十个到几百个
- Guidelines 数量多:可能有成千上万个
- 对少量 Journey 进行向量搜索成本低,对大量 Guidelines 进行向量搜索成本高
-
用途不同:
- Journey 向量搜索 = 粗筛选(性能优化):
- 目的是快速找到"可能相关"的 Journey
- 用于过滤 Guidelines,减少需要评估的 Guidelines 数量
- 不需要精确匹配,只需要找到最相关的几个
- 重要:向量搜索的准确性不影响最终结果,因为有补充匹配机制保障
- Guidelines LLM 匹配 = 精筛选(准确性保障):
- 目的是精确判断"是否真的匹配"当前上下文
- 需要理解复杂的语义和上下文关系
- 必须给出准确的匹配结果(匹配/不匹配、分数、理由)
- Journey 向量搜索 = 粗筛选(性能优化):
-
成本优化:
- 向量搜索成本低:只是计算向量相似度,不需要调用 LLM
- LLM 评估成本高:需要调用 LLM 进行语义理解
- 策略:先用便宜的向量搜索过滤 Journey,再用 LLM 评估少量过滤后的 Guidelines
- 效果:从评估 1000 个 Guidelines 减少到评估 80 个 Guidelines,大幅降低成本
-
设计逻辑:
- Journey 的激活条件本身就是 Guidelines
- 最终还是要通过 LLM 评估 Guidelines 来判断 Journey 是否激活
- 向量搜索只是用来预测哪些 Journey 可能相关,用于过滤 Guidelines
- 真正的匹配判断还是通过 LLM 评估 Guidelines 来完成
- 即使向量搜索预测错误,补充匹配机制也会自动纠正
-
为什么 Guidelines 不使用向量搜索:
- Guidelines 数量太多,向量搜索成本仍然较高
- Guidelines 的匹配需要精确的语义理解,向量搜索的相似度匹配不够精确
- 标签过滤已经能够有效减少需要评估的 Guidelines 数量
- 通过 Journey 过滤进一步减少后,剩余的 Guidelines 数量已经足够少,可以直接用 LLM 评估
-
准确性保障机制:
- 补充匹配:如果低概率 Journey 被激活,系统会自动加载其 Guidelines 并重新匹配
- 全局 Guidelines 不受影响:全局 Guidelines 不会被 Journey 过滤,始终参与匹配
- 激活条件匹配:所有 Journey 的激活条件都会参与 LLM 匹配,不受向量搜索影响
- 结果:即使向量搜索预测错误,系统仍然能够正确激活所有相关的 Journey
总结:
- ✅ Journey 使用向量搜索:数量少 + 粗筛选 + 成本低 + 有补充匹配机制保障准确性
- ✅ Guidelines 使用 LLM 匹配:数量多 + 精筛选 + 已经通过标签和 Journey 过滤
- ✅ 组合策略:向量搜索(Journey)→ 过滤 Guidelines → LLM 匹配(Guidelines)→ 激活 Journey → 补充匹配(如果需要)
- ✅ 准确性保障:即使向量搜索预测错误,补充匹配机制也会自动纠正,确保最终结果的准确性
3.3.3 阶段 3:初始匹配(Initial Matching)
目的:对过滤后的 Guidelines 进行匹配评估
过程:
-
Guidelines 分类:
- 观察性 Guidelines 批次
- 可操作 Guidelines 批次
- 已应用 Guidelines 批次
- 客户依赖型 Guidelines 批次
- 消歧批次(处理冲突的 Guidelines)
-
批次处理:
- 使用批次处理优化 LLM 调用
- 每个批次包含多个 Guidelines,一起评估
-
LLM 评估:
- 对每个 Guideline 的条件进行评估
- 判断是否匹配当前上下文
- 生成匹配结果(分数 0-10、理由)
-
生成匹配结果:
- 返回匹配成功的 Guidelines
- 包括匹配分数和理由
3.3.4 阶段 4:补充匹配(Supplemental Matching)
目的:如果低概率 Journey 被激活,进行额外的匹配
触发条件:
- 在阶段 7 中,如果低概率 Journey 被激活(其激活条件 Guideline 匹配成功)
- 需要加载该 Journey 相关的 Guidelines 并重新匹配
过程:
- 加载新激活 Journey 相关的 Guidelines
- 进行额外的 LLM 匹配
- 确保不遗漏相关行为
- 合并到主匹配结果中
为什么需要:
- 初始过滤时,低概率 Journey 的 Guidelines 被过滤掉了
- 但如果这些 Journey 的激活条件匹配成功,说明它们实际上是相关的
- 需要补充匹配这些 Journey 的 Guidelines,确保完整的行为覆盖
3.4 匹配与激活机制
3.4 匹配与激活机制
3.4.1 Guidelines 匹配机制
匹配过程:
-
批次分类:
# 系统自动将 Guidelines 分类为不同批次 observational_guidelines = [g for g in guidelines if not g.content.action] actionable_guidelines = [g for g in guidelines if g.content.action] previously_applied_guidelines = [g for g in guidelines if g.id in applied_ids] customer_dependent_guidelines = [g for g in guidelines if g.metadata.get("customer_dependent")] -
LLM 评估:
# 对每个批次进行评估 for batch in batches: 匹配结果 = LLM评估(batch, 当前对话上下文) # 返回每个 Guideline 的匹配结果(匹配/不匹配、分数、理由) -
匹配结果:
- 每个 Guideline 的匹配状态(匹配/不匹配)
- 匹配分数(0-10)
- 匹配理由(为什么匹配或不匹配)
3.5 优化策略与效果
3.5.1 优化策略
核心策略:先过滤,后匹配
-
标签过滤:
- 只加载代理相关的 Guidelines
- 减少需要处理的 Guidelines 数量
-
概率过滤:
- 使用向量搜索预测高概率 Journey
- 过滤掉低概率 Journey 相关的 Guidelines
- 大幅减少需要评估的 Guidelines 数量
-
批次处理:
- 将 Guidelines 分类为不同批次
- 每个批次一起评估,减少 LLM 调用次数
-
智能回退:
- 如果低概率 Journey 被激活,补充匹配其 Guidelines
- 确保不遗漏相关行为
3.5.2 优化效果
性能优化示例:
假设有 1000 个 Guidelines:
阶段 1:标签过滤
→ 只加载当前代理相关的 Guidelines(例如:200 个)
阶段 2:概率过滤
→ 基于 Journey 概率进一步过滤(例如:50 个高概率 Guidelines)
阶段 3:初始匹配
→ 只对这 50 个 Guidelines 进行 LLM 评估
阶段 4:补充匹配(如果需要)
→ 如果低概率 Journey 被激活,再评估相关 Guidelines(例如:额外 20 个)
总计:只评估了 70/1000 = 7% 的 Guidelines
优化效果总结:
- 减少 LLM 调用:只评估相关 Guidelines,大幅减少成本(从 1000 个减少到 70 个)
- 降低延迟:减少需要处理的 Guidelines 数量,提高响应速度
- 提高准确性:专注于最相关的 Guidelines,减少噪音
- 智能回退:如果低概率 Journey 被激活,自动补充匹配,确保完整性
3.6 迭代处理机制
3.6.1 多轮迭代
如果工具调用后需要重新评估,系统会进行多轮迭代:
第一次迭代:
→ 匹配 Guidelines → 调用工具 → 获取结果
第二次迭代(如果需要):
→ 基于工具结果重新评估 Guidelines
→ 可能激活新的 Journey
→ 可能匹配新的 Guidelines
→ 继续处理直到准备好响应
3.6.2 迭代条件
系统会在以下情况进行迭代:
- 工具调用返回了新信息
- 需要重新评估客户依赖型 Guidelines
- Journey 状态发生变化
- 需要获取更多信息才能生成响应
3.7 完整示例
3.7.1 场景:用户说"我想预订航班"
完整流程追踪:
[阶段 1] 加载上下文
→ 会话历史:[](新会话)
→ 激活 Journey:无
[阶段 2] 获取可用 Journey
→ ["预订航班", "预订酒店", "查询天气"]
[阶段 3] 标签过滤
→ 加载 200 个 Guidelines(包括所有 Journey 的 Guidelines)
[阶段 4] 概率过滤
→ 无激活 Journey → 向量搜索
→ 查询:"我想预订航班"
→ 结果:JourneyA(预订航班)最相关
→ 高概率 Journey = [JourneyA]
[阶段 5] 过滤 Guidelines
→ 保留:JourneyA 的 Guidelines(50个)+ 全局 Guidelines(30个)
→ 过滤:JourneyB 和 JourneyC 的 Guidelines(120个)
→ 结果:80 个 Guidelines
[阶段 6] LLM 语义匹配
→ 评估 80 个 Guidelines
→ 匹配成功:
- "客户想要预订航班"(JourneyA 的激活条件)✓
- "询问客户偏好"(全局 Guideline)✓
- ...(其他匹配的 Guidelines)
→ 结果:10 个 Guidelines 匹配
[阶段 7] 激活 Journey
→ "客户想要预订航班"Guideline 匹配 → 激活 JourneyA
[阶段 8] 补充匹配
→ JourneyA 被激活,加载 JourneyA 作用域的 Guidelines
→ 评估这些 Guidelines
[阶段 9] 关系解析
→ 加载依赖和优先级相关的 Guidelines
[阶段 10] Journey 状态选择
→ JourneyA 激活 → 选择初始状态
→ 状态:"询问目的地"
→ 生成状态 Guidelines
[阶段 11] 工具调用
→ 检查是否有工具关联的 Guidelines 需要调用
→ 无工具调用
[阶段 12] 生成响应
→ 使用所有匹配的 Guidelines 和 Journey 状态
→ 生成:"好的,我来帮您预订航班。请问您想去哪里?"
3.8 核心原则总结
3.8.1 原则 1:先过滤,后匹配
- 不是评估所有 Guidelines,而是先过滤出相关的 Guidelines
- 通过标签系统和概率过滤大幅减少需要评估的 Guidelines 数量
3.8.2 原则 2:先预测 Journey,再匹配 Guidelines,最后激活 Journey
不是先匹配 Journey 再匹配 Guidelines,实际流程是:
- 预测高概率 Journey(用于过滤 Guidelines,不是匹配 Journey)
- 过滤 Guidelines(基于高概率 Journey)
- 匹配 Guidelines(LLM 评估)
- 激活 Journey(基于匹配结果)
3.8.3 原则 3:匹配决定激活
- Journey 的激活由其条件 Guidelines 的匹配结果决定
- 如果 Journey 的激活条件 Guideline 匹配成功,Journey 被激活
- 激活后,Journey 的状态会被投影为 Guidelines 供后续使用
3.8.4 原则 4:Guidelines 优先于 Journey 状态
- Guidelines 被视为更具体的行为覆盖
- 如果 Guideline 匹配,通常会优先于 Journey 状态
- 允许在 Journey 中处理特殊情况
3.8.5 原则 5:迭代优化
- 工具调用后可能触发重新评估
- 确保基于最新信息做出决策
总结
本文档详细介绍了 Parlant 的三个核心概念:
- Guidelines(行为准则):用自然语言定义的上下文规则,指导代理在特定情况下的行为
- Journeys(对话流程):结构化的多步骤对话流程,引导客户完成特定目标
- Recall and Matching Logic(召回与匹配逻辑):确定使用哪些 Guidelines 和 Journeys 的完整流程
这三个概念共同构成了 Parlant 的行为建模框架,确保了 AI 代理能够可靠地遵循业务规则和预期行为。