【Agent智能体】39TurnPlanner实现
章节三十九:TurnPlanner实现
1. 概述
TurnPlanner:负责根据用户当前输入和对话状态,生成本轮对话计划 TurnPlan。
整体流程:
第一步:DialogueEngine 收到文本消息,调用 TurnPlanner.predict。
第二步:构建 prompt_inputs(把当前状态整理成提示词变量)。
第三步:渲染 planning/turn_plan_v1 提示词。
第四步:调用 LLM 生成 TurnPlan。
第五步:TurnPlanValidator 校验是否可直接执行。
第六步:如果校验通过,DialogueEngine 分发到对应 Handler;如果校验不通过,ClarifyResponder 生成澄清回复。
重要边界:
- TurnPlanner:负责真实识别用户意图,可以识别出多个轨道
- TurnPlanValidator:负责判断当前执行引擎是否能直接处理
- DialogueEngine:只在校验通过后,分发到一个具体 Handler
当前系统支持三个轨道:
- task:任务型流程,例如查订单、查物流、申请退款
- knowledge:知识问答,例如商品信息、退款政策、配送规则
- chitchat:闲聊,例如打招呼、询问助手身份
2. TurnPlan JSON 格式
LLM 输出的 TurnPlan 是一个 JSON 对象,顶层固定包含三个字段:task、knowledge、chitchat。
如果用户是在办理业务,填写 task:
// 功能说明:Task 类型的 TurnPlan 示例
// task.commands 包含要执行的命令列表,如 start_flow、set_slots 等
如果用户是在咨询知识,填写 knowledge:
// 功能说明:Knowledge 类型的 TurnPlan 示例
// knowledge.intents 包含命中知识意图ID列表
如果用户是在闲聊,填写 chitchat:
// 功能说明:Chitchat 类型的 TurnPlan 示例
// chitchat 为空对象即可
如果用户一句话同时表达多个意图,LLM 也可以同时填写多个轨道。但这种多意图 TurnPlan 会被 TurnPlanValidator 认定为当前引擎不能直接执行,然后引导用户澄清先处理哪一个。
3. TurnPlan 模型
与 JSON 对应的 Python 模型:
| 模型 | 说明 |
|---|---|
| TaskTurnPlan | 对应 task 字段,内部保存 commands |
| KnowledgeTurnPlan | 对应 knowledge 字段,内部保存 intents |
| ChitchatTurnPlan | 对应 chitchat 字段,当前不需要额外参数 |
| TurnPlan | 顶层模型,包含 task、knowledge、chitchat 三个可选字段 |
from_dict() 负责把 LLM 输出的 JSON 字典转换成对应模型。
# 功能说明:TurnPlan 数据模型
# 将 LLM 输出的 JSON 解析为 Python 对象
# 支持 task/knowledge/chitchat 三种轨道的组合
4. TurnPlanner 入口
TurnPlanner.predict() 是本组件的入口方法。
接收三类信息:
- state:当前对话状态
- flows:系统支持的任务流程
- knowledge_intents:系统支持的知识意图
入口方法内部调用两个方法:
- build_prompt_inputs():把当前状态、可用 flow、知识意图整理成提示词变量
- _predict_from_prompt_inputs():使用提示词变量调用 LLM,并把输出转换成 TurnPlan
# 功能说明:TurnPlanner.predict() 入口方法
# 1. 构建提示词输入变量
# 2. 调用 LLM 生成 TurnPlan
# 3. 返回 TurnPlan 对象
5. 提示词设计
提示词的核心要求:
- TurnPlan 顶层只允许 task、knowledge、chitchat 三个字段
- 这三个字段的值必须是 JSON 对象或 null
- 如果用户同时表达多个意图,可以同时填写多个轨道
- 后续执行引擎一次只能处理一个轨道;如果输出多个轨道,系统会向用户澄清先处理哪一个
- 只输出合法 JSON,不要输出 markdown 代码块
提示词中使用的参数:
| 参数 | 说明 |
|---|---|
| available_flows_json | 系统当前支持的任务流程列表。LLM 根据它判断用户是否要启动某个业务流程 |
| knowledge_intents_json | 系统当前支持的知识意图列表。LLM 根据它选择要查询哪类知识 |
| active_task_json | 当前正在执行的任务。如果用户继续补充信息,LLM 可据此生成 set_slots 等命令 |
| interrupted_tasks_json | 当前被暂停的任务列表。如果用户表达"继续之前的任务",LLM 可据此生成 resume_flow |
| focused_object_json | 当前聚焦的业务对象(商品或订单)。帮助 LLM 判断用户是要办理对象相关业务,还是咨询对象相关知识 |
| current_conversation | 最近对话历史。让 LLM 判断当前意图时能参考上下文 |
| user_message | 用户本轮输入的原始文本。TurnPlan 的预测主要围绕这句话展开 |
6. 构造提示词输入
build_prompt_inputs() 负责把当前对话状态转换成提示词需要的变量。
这一步不会调用 LLM,也不会修改状态,只是做数据整理。
返回的变量包括:
- current_conversation:最近对话历史,并追加当前用户消息
- available_flows_json:系统支持哪些任务流程(去掉 steps 细节)
- active_task_json:当前是否有正在执行的任务
- interrupted_tasks_json:当前被暂停的任务列表
- focused_object_json:当前聚焦的商品或订单
- knowledge_intents_json:系统支持哪些知识意图
# 功能说明:build_prompt_inputs() 提示词输入构建
# 将 DialogueState 中的各种状态信息格式化为提示词模板变量
# 使用 json.dumps 将对象序列化为 JSON 字符串
7. 调用 LLM
_predict_from_prompt_inputs() 负责真正调用 LLM。
使用 LangChain 的链式写法:prompt -> llm -> JsonOutputParser。
执行结果是 JSON 字符串,先用 json.loads() 转成字典,再通过 TurnPlan.from_dict() 转成 TurnPlan 对象。
# 功能说明:_predict_from_prompt_inputs() LLM 调用
# 加载 turn_plan 提示词模板(Jinja2 格式)
# 组装 LangChain 调用链:prompt | llm | JsonOutputParser
# 异步调用大模型,解析输出为 TurnPlan 对象
8. TurnPlanValidator
8.1 校验结果定义
TurnPlanValidator 的返回值是 TurnPlanValidationResult,表达当前 TurnPlan 是否可以执行,以及校验失败的原因。
ClarifyReason 枚举定义了各种失败原因:
| 原因 | 说明 |
|---|---|
| MISSING_TRACK | TurnPlan 没有命中任何轨道,系统无法判断本轮应该做什么 |
| MULTIPLE_TRACKS | TurnPlan 同时命中了多个轨道,执行引擎一次只能处理一个 |
| MISSING_TASK_COMMANDS | 命中了 task 轨道,但 commands 为空,不知道具体执行什么命令 |
| MISSING_KNOWLEDGE_INTENT | 命中了 knowledge 轨道,但 intents 为空,不知道查询哪类知识 |
| MISSING_FOCUSED_OBJECT | 知识意图需要聚焦对象,但当前状态中没有合适的 focused_object |
| OBJECT_REQUIRES_INTENT | 用户只发送了对象,但没有说明想做什么 |
8.2 校验逻辑
整体流程:
第一步:获取活跃轨道列表(_active_tracks)。
第二步:如果没有活跃轨道,返回 MISSING_TRACK。
第三步:如果有多个活跃轨道,返回 MULTIPLE_TRACKS。
第四步:取唯一轨道,根据轨道类型分别校验:
- task 轨道:校验 commands 是否为空
- knowledge 轨道:校验 intents 是否为空,以及是否需要聚焦对象
- chitchat 轨道:直接通过
# 功能说明:TurnPlanValidator.validate() 校验入口
# 1. 检查活跃轨道数量
# 2. 根据轨道类型调用对应校验方法
# 3. 返回 TurnPlanValidationResult(valid + reason)
task 校验:检查 commands 是否为空。具体 command 是否能执行,由后续 TaskHandler 和 CommandProcessor 处理。
knowledge 校验:检查两件事:intents 不能为空;如果某个 intent 要求聚焦对象,则当前状态中必须有对应类型的 focused_object。
例如:product_info 需要当前聚焦商品;order_info 需要当前聚焦订单;refund_policy 这类规则咨询不一定需要聚焦对象。
9. ClarifyResponder
9.1 概述
ClarifyResponder 负责把澄清原因转换成最终的 BotMessage。
接收两类信息:state(当前对话状态)和 reason(澄清原因)。
整体处理思路:
第一步:根据 reason 和 state 生成一条基础澄清话术(build_clarify_message)。
第二步:读取当前对话历史和聚焦对象。
第三步:调用 clarify/rewrite 提示词,把基础话术改写成自然的客服回复。
第四步:返回 BotMessage。
职责分离:TurnPlanValidator 只负责判断失败原因,ClarifyResponder 负责生成基础澄清话术并改写成自然回复。
9.2 澄清提示词
提示词要点:
- 角色:中文电商客服助手,语气自然、友好、简洁
- 任务:把系统澄清提示改写成更自然的一句话
- 要求:不要扩写,不要新增信息,不要改变澄清意图
提示词变量:
| 变量 | 说明 |
|---|---|
| reason | 澄清原因枚举值 |
| clarify_message | 基础澄清话术 |
| focused_object | 当前聚焦对象描述 |
| history | 当前会话历史 |
| user_message | 用户本轮输入文本 |
9.3 基础话术生成
build_clarify_message() 根据 reason 生成基础澄清话术:
| 原因 | 基础话术 |
|---|---|
| MULTIPLE_TRACKS | 你这次同时提到了多个方向。我们先处理一个,你想先办业务还是先咨询信息呢? |
| MISSING_FOCUSED_OBJECT | 请先发送你想咨询的商品或订单,我再继续帮你看。 |
| MISSING_KNOWLEDGE_INTENT | 你是想了解商品信息、订单信息,还是售后配送规则呢? |
| MISSING_TRACK | 你是想先处理业务问题,还是先咨询信息呢? |
| MISSING_TASK_COMMANDS | 你这次是想办理什么业务呢?比如查订单、查物流,或者申请退款。 |
| OBJECT_REQUIRES_INTENT | 我已经收到这个订单/商品了。你想查状态、查物流,还是申请退款/了解信息呢? |
# 功能说明:ClarifyResponder 澄清回复生成器
# 1. 根据 reason 生成基础澄清话术
# 2. 加载对话历史和聚焦对象
# 3. 调用 clarify_respond 提示词让 LLM 改写为自然回复
# 4. 返回 BotMessage
更多推荐


所有评论(0)