39 KiB
当前项目完整流程说明
1. 文档目标
本文档描述当前项目在代码层面的真实运行流程,不是目标态蓝图,而是“现在这个仓库实际如何工作”。
覆盖范围包括:
- 服务启动与运行时装配
- API 请求入口与返回结构
- 会话状态管理
- 输入改写
- 本地路由与多阶段融合
- 社交闲聊分流
- planner 触发与多步骤 workflow 生成
- 单步执行、多步执行、条件执行、确认执行
- 配置驱动加载方式
- 当前使用的技术、模型、阈值、分支条件
- 主要风险点与当前边界
2. 系统定位
当前项目是一个面向“智能座舱 + 客服”的执行型 Agent 服务,后端基于 FastAPI,核心特点如下:
- 配置驱动:意图、动作、响应模板、表单、规则、workflow 模板都来自
config/ - 本地优先:优先走
rewrite -> keyword/classifier/retrieval -> fusion - planner 不是默认入口:只有复杂句、多意图、条件句、低置信句才触发 planner
- 会话显式维护:多轮状态不依赖 LLM 记忆,而依赖
SessionState - 社交闲聊单独分流:问候、感谢、能力问答、开放闲聊走
SocialRouter - 插件执行统一抽象:所有意图最终映射到
plugin_id
3. 总体架构图
flowchart TD
A[HTTP 请求 /api/v1/agent/chat] --> B[AgentService.handle_chat]
B --> C[SessionStore get_or_create]
C --> D[Dialog Act 更新]
D --> E{是否停止当前任务}
E -->|是| F[停止任务并返回 stopped]
E -->|否| G{是否社交闲聊}
G -->|是| H[SocialRouter + SocialResponder]
G -->|否| I[ContextRewriteEngine 改写]
I --> J[Router.route]
J --> J1[keyword matcher]
J --> J2[classifier matcher]
J --> J3[retrieval matcher]
J1 --> J4[fusion 决策]
J2 --> J4
J3 --> J4
J4 --> K{是否需要 planner}
K -->|否| L{fusion 决策结果}
K -->|是| M[WorkflowPlanner.plan]
M --> M1[TemplateWorkflowPlanner]
M --> M2[HeuristicWorkflowPlanner]
M --> M3[DashScopeWorkflowPlanner 可选]
M1 --> N{planner accepted?}
M2 --> N
M3 --> N
N -->|是| O[构建 Workflow 并执行]
N -->|否| L
L -->|execute| P[槽位提取]
P --> Q{缺槽位?}
Q -->|是| R[ask_slot]
Q -->|否| S[执行单步插件]
L -->|clarify| T[clarify]
L -->|reject| U[reject]
L -->|route_to_cloud| V[clarify / fallback / reject]
O --> W{多步流程继续执行}
W -->|缺槽位| X[ask_slot]
W -->|需确认| Y[ask_confirmation]
W -->|条件不满足| Z[skip step]
W -->|可执行| AA[调用插件]
AA --> AB[workflow_summary]
4. 启动与装配流程
4.1 入口
应用入口是 app/main.py,FastAPI 在 import 阶段完成以下事情:
- 初始化
FastAPI(title=settings.app_name) - 初始化 demo runtime 配置
- 调用
build_agent_service_with_runtime(...) - 调用
build_intent_registry() - 暴露
/health、/demo、/api/v1/agent/chat、/api/v1/agent/chat-stream、/api/v1/agent/fill-slots
4.2 运行时装配
build_agent_service_with_runtime() 会组装完整执行链:
ConfigLoader.load()读取配置文件- 构建
IntentRegistry - 构建 classifier
- 构建 multi-intent detector
- 构建 matcher pipeline 和 router
- 构建 session store
- 构建
ResponsePolicy - 构建
DialogRuleEngine - 构建
DialogActEngine - 构建 planner
- 注册 mock plugin
- 构建
SocialRouter和DashScopeSocialResponder - 最终实例化
AgentService
4.3 启动装配图
flowchart TD
A[build_agent_service_with_runtime] --> B[ConfigLoader.load]
B --> C[IntentRegistry]
B --> D[Response templates]
B --> E[Dialog rules]
B --> F[Dialog acts]
B --> G[Workflow templates]
A --> H[build_classifier]
H --> H1[MockIntentClassifier]
H --> H2[BertIntentClassifier]
H --> H3[RemoteIntentClassifier]
A --> I[build_multi_intent_detector]
I --> I1[BertMultiIntentDetector]
A --> J[build_router]
J --> J1[build_matcher_pipeline]
J --> J2[HeuristicSlotExtractor]
A --> K[build_session_store]
K --> K1[InMemorySessionStore]
K --> K2[RedisSessionStore]
A --> L[build_planner]
L --> L1[TemplateWorkflowPlanner]
L --> L2[HeuristicWorkflowPlanner]
L --> L3[DashScopeWorkflowPlanner]
A --> M[MockPluginExecutor.register]
A --> N[SocialRouter]
A --> O[DashScopeSocialResponder]
A --> P[AgentService]
5. 配置驱动体系
当前运行时主要依赖这些配置文件:
config/domain.ymlconfig/actions.ymlconfig/forms.ymlconfig/responses.ymlconfig/rules.ymlconfig/dialog_acts.ymlconfig/workflows.yml
5.1 各配置文件职责
domain.yml
- 定义意图目录
- 定义
intent_id - 定义领域
domain - 定义 label、keywords、examples
- 指向
action_id
actions.yml
- 将
action_id绑定到plugin_id - 指定风险等级、描述等动作元信息
forms.yml
- 定义每个意图需要的
required_slots - 定义槽位缺失时的
ask_templates
responses.yml
- 定义系统通用话术模板
- 包含 ask / ack / reject / fallback / confirm 等模板
rules.yml
- 定义停止词
- 定义确认正负词
- 定义哪些 intent 或哪些 risk level 必须确认
dialog_acts.yml
- 定义
affirm / deny / cancel / modify / chitchat / request / inform
workflows.yml
- 定义局部固定 workflow 模板
- 当前已有顺序模板和条件模板
5.2 加载流程
flowchart LR
A[ConfigLoader] --> B[domain.yml]
A --> C[actions.yml]
A --> D[forms.yml]
A --> E[responses.yml]
A --> F[rules.yml]
A --> G[dialog_acts.yml]
A --> H[workflows.yml]
B --> I[DomainConfig]
C --> J[ActionsConfig]
D --> K[FormsConfig]
E --> L[ResponsesConfig]
F --> M[DialogRulesConfig]
G --> N[DialogActsConfig]
H --> O[WorkflowTemplatesConfig]
I --> P[IntentRegistry]
J --> P
K --> P
L --> Q[ResponsePolicy]
M --> R[DialogRuleEngine]
N --> S[DialogActEngine]
O --> T[WorkflowPlanner]
6. 请求入口层
6.1 /api/v1/agent/chat
这是主同步接口:
- 接收
ChatRequest - 直接调用
agent_service.handle_chat(request) - 返回
ChatResponse
6.2 /api/v1/agent/chat-stream
这是流式接口:
- 用线程池异步执行
agent_service.handle_chat - 如果 1 秒内拿到结果,直接返回
final - 如果 1 秒内没拿到结果:
- 先检查
_should_emit_processing_hint(text) - 如果命中工具型关键词,就先发一个
ack - 再等待最终结果
- 先检查
- 最终以 NDJSON 流输出
注意:
- 这里的流式
ack仍然是“基于输入文本 token 的启发式判断” - 它并不等于“真实插件已开始执行”
- 这是 HTTP streaming 层的反馈策略,不是 AgentService 内部 workflow 执行层
6.3 /api/v1/agent/fill-slots
这是补槽位和确认续跑接口:
- 根据
session_id取已有 session - 若没有有效 session 或没有
current_intent,返回 fallback - 如果当前在
waiting_confirmation,优先处理确认 - 如果当前是多步 workflow,继续推进 workflow
- 否则按当前 intent 继续抽槽并补全
7. Session 设计
7.1 SessionState 字段
SessionState 当前包含:
session_iduser_idchannelstatuscurrent_intentpending_slotsslotsworkflowrouting_debuglast_user_textlast_agent_textcontext_memory
7.2 状态含义
当前项目中常见状态:
idleunderstandingwaiting_slotwaiting_confirmationrunningcompletedrejectedfallbackstoppedsocial
7.3 Session Backend
支持两种 session backend:
memoryredis
memory
- 进程内字典保存
- 重启丢失
- 适合本地开发
redis
- JSON 序列化保存
- key 带前缀和 TTL
- 适合跨进程和长会话
7.4 Session 状态图
stateDiagram-v2
[*] --> idle
idle --> understanding: 收到普通任务
idle --> social: 收到社交闲聊
understanding --> waiting_slot: 缺槽位
understanding --> ready_to_execute: 槽位齐全
ready_to_execute --> completed: 单步插件执行完成
ready_to_execute --> running: 多步 workflow 开始
running --> waiting_slot: 某一步缺槽位
running --> waiting_confirmation: 某一步需确认
waiting_slot --> running: 用户补槽后继续
waiting_confirmation --> running: 用户确认继续
waiting_confirmation --> completed: 用户取消该步后流程继续或结束
understanding --> rejected: reject
understanding --> fallback: fallback
running --> stopped: 用户停止
completed --> idle: 下轮新任务
8. AgentService 主流程
AgentService.handle_chat() 是整个服务的核心编排器。
8.1 主链路顺序
- 读取或创建 session
- 更新 dialog act
- 检查是否停止任务
- 检查是否社交闲聊
- 运行 rewrite
- 路由匹配
- 判断是否要启 planner
- 如果 planner 接受,直接走多步 workflow
- 如果 planner 不接受,则按 fusion 决策处理
- 如果决策是 execute,则抽槽并执行
- 记录 turn
- 保存 session
- 填充 latency breakdown
8.2 主流程图
flowchart TD
A[handle_chat] --> B[get_or_create session]
B --> C[update dialog act]
C --> D{stop request?}
D -->|yes| E[reset active task + return stopped]
D -->|no| F{social turn?}
F -->|yes| G[build social response]
F -->|no| H[rewrite]
H --> I[router.route]
I --> J{should use planner?}
J -->|yes| K[planner.plan]
K --> L{accepted and has steps?}
L -->|yes| M[start planned workflow]
L -->|no| N[handle route decision]
J -->|no| N
N -->|has response| O[clarify / reject / route_to_cloud]
N -->|none| P{intent found?}
P -->|no| Q[fallback]
P -->|yes| R[extract slots]
R --> S[update session + context memory]
S --> T[build response from session]
T --> U[record turn + save session + finalize]
8.3 Timing 统计
当前 ChatResponse 会附带处理耗时细分,典型字段包括:
session_get_or_create_msdialog_act_msstop_check_mssocial_route_msrewrite_msroute_msplanner_msdecision_response_msslot_extract_msresponse_build_msrecord_turn_mssession_save_msmatch_pipeline_msfirst_response_latency_mstotal_latency_ms
9. Dialog Act 与停止分支
9.1 Dialog Act
系统会在请求一开始调用 DialogActEngine.detect(text),当前 act 包括:
affirmdenycancelmodifychitchatrequestinformunknown
当前 dialog act 的用途主要是:
- 保存会话理解上下文
- 给后续确认/修改/闲聊处理提供辅助信号
9.2 停止分支
停止请求由 DialogRuleEngine.is_stop_request() 判断,典型词包括:
- 不用了
- 算了
- 先这样吧
- 停一下
- 停止
- 结束这次操作
只有满足以下两个条件才会真正停止:
- 输入命中 stop phrase
- session 当前有 active task
命中后动作:
- reset active task
- 清空 pending_slots
- workflow 置空
- 返回
status=stopped
10. 社交闲聊分支
10.1 为什么先做社交分流
社交闲聊与任务型请求的目标不同:
- 任务型请求要落到 intent / slot / workflow / plugin
- 社交闲聊只需要自然回复,不应误触发任务执行
10.2 SocialRouter 路由逻辑
SocialRouter.route(text, session) 流程如下:
- 归一化文本
- 如果看起来像任务型请求,直接返回
category=none - 如果命中短社交模式,返回
open_social - 如果命中 capability regex,返回
open_social - 如果命中开放闲聊短语或 regex,返回
open_social - 如果上一轮是
open_social且当前文本很短,作为闲聊续接 - 否则不是社交
10.3 社交分支的两个层次
第一层:SocialRouter
- 只判断要不要走社交链路
第二层:DashScopeSocialResponder
- 真正生成自然语言回复
- 使用 DashScope 兼容 OpenAI 的
/chat/completions temperature=0.6max_tokens=120- 系统提示词要求:
- 简短
- 口语化
- 不编造已执行动作
- 不输出 JSON
10.4 社交回复的补充逻辑
如果当前 session 还有未完成任务:
ResponsePolicy.pending_task_hint()会追加提示- 例如还在等确认、还在等槽位、还在运行中
因此社交回复不一定纯闲聊,可能附带任务续接提示
10.5 社交流程图
flowchart TD
A[用户输入] --> B[SocialRouter.route]
B --> C{looks_like_task?}
C -->|yes| D[回主任务链路]
C -->|no| E{命中社交模式?}
E -->|no| D
E -->|yes| F{是否配置 social responder?}
F -->|no| G[open_social_fallback]
F -->|yes| H[DashScopeSocialResponder.reply]
H --> I{返回为空或报错?}
I -->|yes| G
I -->|no| J[自然回复]
G --> K[附加 pending task hint]
J --> K
K --> L[返回 social/text response]
11. Rewrite 流程
11.1 Rewrite 的定位
ContextRewriteEngine 不是通用 LLM 改写器,而是轻量、本地、规则型短句恢复器。
目的:
- 把“再低一点”“下一首”“不要高速”这种短句补成完整命令
- 让下一轮仍然能命中本地快链路
- 减少每轮都走 planner 或云端
11.2 当前支持的 rewrite 场景
空调 follow-up
- 当前 intent 属于空调相关:
cabin_set_accabin_ac_oncabin_ac_offcabin_fan_upcabin_fan_down
- 输入匹配“高一点 / 低一点 / 调高一点 / 调低一点”
- 根据
context_memory.last_temperature或session.slots.temperature - 生成显式句式:
把空调调到 21 度
音乐 follow-up
- 当前 intent 为
cabin_play_music - 输入匹配:
- 再来一首
- 换一首
- 下一首
- 改写为:
播放下一首歌
导航 follow-up
- 当前 intent 为
cabin_nav_to - 如果输入含“不要高速”
- 且 session 中能取到上次目的地
- 改写为:
导航去 xxx,不要高速
11.3 Rewrite 分支图
flowchart TD
A[原始输入] --> B{current_intent}
B -->|空调相关| C[_rewrite_ac_adjustment]
B -->|播放音乐| D[_rewrite_music_followup]
B -->|导航| E[_rewrite_navigation_followup]
B -->|其他| F[不改写]
C --> G{命中规则?}
D --> G
E --> G
G -->|yes| H[输出 rewritten_text + metadata]
G -->|no| F
12. Router 与本地多阶段匹配
12.1 Router 组成
当前 Router 是 RuleBasedRouter,内部包含:
matcher:MultiStageIntentMatcherslot_extractor:HeuristicSlotExtractor
12.2 Matcher Pipeline
可配置的匹配阶段:
keywordclassifierretrievalllm占位,当前未实现
默认项目原则上使用:
keyword,classifier,retrieval
12.3 各阶段职责
KeywordIntentMatcher
- 遍历每个 intent 的 keywords
- 命中即给 1.0 分
- 候选 reason 是
keyword:xxx
ClassifierIntentMatcher
- 调用
IntentClassifier.predict - 可能接后端:
mockbertremote
- 输出 top-k candidates
- 附带 raw_label、raw_candidates、top_margin、fallback_reason
RetrievalIntentMatcher
- 对输入做 token / n-gram 切分
- 与 intent 的 keywords + examples 做重叠评分
- 分数来源:
- overlap
- coverage
- keyword bonus
LlmIntentMatcher
- 当前是占位实现
- 永远返回 not implemented
12.4 Fusion 评分机制
fusion 会聚合所有 stage 的候选:
- keyword 权重:
1.15 - classifier 权重:
1.0 - retrieval 权重:
0.75 - llm 权重:
1.1
额外规则:
- 某 stage accepted 且 selected_intent 命中,会加 accepted bonus
- classifier 若走 fallback,会减分
- BERT classifier 会用不同归一化规则
- fusion 最终得到 ranked intents
12.5 Fusion 决策阈值
核心阈值来自环境变量:
local_execute_threshold = 1.65local_route_to_cloud_threshold = 0.75local_clarify_margin_threshold = 0.12local_classifier_execute_score_threshold = 0.55local_classifier_execute_margin_threshold = 0.18
12.6 Fusion 决策逻辑
execute
满足任一:
top_score >= execute_threshold- 至少两路 accepted 支持,或有强 symbolic support
- 纯 BERT 路径但分数和 margin 足够高
clarify
满足:
- top_score 介于
route_to_cloud_threshold和execute_threshold - top_margin 小于 clarify margin
- 存在多候选竞争
route_to_cloud
满足:
- 本地信号说明“像已知意图”
- 但不够稳定执行
reject
满足:
- 本地没有足够信号
- 且不认为是已知能力内请求
12.7 Router 总流程图
flowchart TD
A[rewrite 后文本] --> B[keyword]
A --> C[classifier]
A --> D[retrieval]
B --> E[fusion]
C --> E
D --> E
E --> F{top_score / margin / support}
F -->|高置信| G[decision=execute]
F -->|接近但歧义| H[decision=clarify]
F -->|像已知意图但不稳| I[decision=route_to_cloud]
F -->|未知或过低| J[decision=reject]
12.8 Routing Debug
每次 route 都会构造 RoutingDebug,包括:
selected_intentmatched_stagedecisiondecision_reasonconfidence_gradeunknown_detectedstagestotal_match_latency_ms
每个 stage 又包含:
- accepted
- selected_intent
- score
- reason
- model_name
- backend
- fallback_used
- raw_label
- error_message
- metadata
- candidates
这也是 demo 面板能展示详细匹配过程的原因。
13. Classifier 技术细节
13.1 支持的 classifier backend
mock
- 本地规则化 token overlap stub
- 主要用于开发或 fallback
bert
- 使用
transformers.pipeline("text-classification") - 模型目录来自
AGENT_CLASSIFIER_MODEL_PATH - 支持 label map
- 支持 warmup
remote
- 请求远端分类服务
- 传入 text、top_k、labels
- 返回 intent_id / score / raw candidates
13.2 BERT classifier 行为
本地 BERT 分类器:
- 初始化时不一定立刻加载模型,但
build_classifier()会按配置触发 warmup - warmup 默认文本:
打开车窗 - 输出 top-k candidates
- 分数低于阈值时可 fallback 到 mock
13.3 当前模型相关配置
classifier_backendclassifier_model_pathclassifier_label_map_pathclassifier_top_kclassifier_bert_thresholdclassifier_warmup_enabledclassifier_warmup_text
14. Multi-Intent Detector 技术细节
14.1 当前 detector 的角色
当前多标签 detector 不是 planner 主入口,而是 planner 二阶段中的先验信号。
它的职责是:
- 从整句维度给出可能共现的多个 intent
- 生成
detector_prior - 在 clause classifier 融合时增强多意图解析
14.2 当前实现方式
BertMultiIntentDetector
- 加载独立多标签模型目录
- 运行
AutoTokenizer+AutoModelForSequenceClassification - 对 logits 做 sigmoid
- 用 threshold 过滤
- 屏蔽:
__social____out_of_scope__
- 最多输出
max_labels
14.3 detector 配置
planner_multi_intent_detector_enabledplanner_multi_intent_detector_model_pathplanner_multi_intent_detector_thresholdplanner_multi_intent_detector_top_kplanner_multi_intent_detector_max_labels
15. Planner 触发机制
15.1 何时调用 planner
AgentService._should_use_planner() 当前规则:
满足任一就会进入 planner:
- 文本包含复杂连接词:
- 然后
- 并且
- 同时
- 如果
- 若
- 先
- 后
- 文本包含明显分隔符:
,,;;
- fusion stage 最终未 accepted
这意味着:
- planner 不是全量调用
- 单条明确命令通常不会调 planner
- 复杂句、歧义句、低置信句会调 planner
15.2 planner 组合结构
当前 build_planner() 构成如下:
本地层:
TemplateWorkflowPlannerHeuristicWorkflowPlanner
云端层:
DashScopeWorkflowPlanner
最终组合方式:
- 如果
planner_backend=heuristic- 返回
Composite(local_template, local_heuristic)
- 返回
- 如果
planner_backend=dashscope- 返回
Composite(local_first, dashscope)
- 返回
重点:
- 始终是 local-first
- 云端 planner 只是后面的补充层
- 云端失败时会 fallback 到本地 heuristic planner
15.3 planner 链路图
flowchart TD
A[planner.plan] --> B[TemplateWorkflowPlanner]
B --> C{accepted?}
C -->|yes| D[返回模板 workflow]
C -->|no| E[HeuristicWorkflowPlanner]
E --> F{accepted?}
F -->|yes| G[返回本地 heuristic workflow]
F -->|no| H{planner_backend=dashscope?}
H -->|no| I[返回未接受]
H -->|yes| J[DashScopeWorkflowPlanner]
J --> K{云端成功?}
K -->|yes| L[返回 cloud workflow]
K -->|no| M[fallback 到本地 heuristic 结果]
16. TemplateWorkflowPlanner 细节
16.1 作用
对已经定义好的典型固定组合优先做模板命中。
当前 workflows.yml 里已有:
window_then_ac_sequencequery_then_cancel_if_pending
16.2 工作方式
- 调
_analyze_multi_intent() - 拿到 clause 分析结果
- 如果匹配的 intent 少于 2 个,不接受
- 逐个比对 workflow 模板
- 如果模板命中,则生成
PlannedStep
16.3 模板命中条件
需要同时满足:
matched_ids[:len(intent_sequence)] == template.intent_sequence- 若模板定义了
trigger_keywords,文本中必须都出现
这是一种严格模板匹配,不是模糊相似模板匹配。
17. HeuristicWorkflowPlanner 细节
17.1 输入分析
_analyze_multi_intent() 做这些事:
- 如果配置了多标签 detector,先对整句做 multi-intent detect
- 生成
detector_prior - 按连接词和标点做 clause split
- 对每个 clause 做 heuristic + classifier + detector 融合
- 汇总成
MultiIntentParseResult
17.2 Clause Split 规则
当前切分词包括:
- 然后
- 并且
- 同时
- 再
- 顺便
- 接着
- 并
,,;;
17.3 Clause 评分信号
每个 clause 对每个 intent 的启发式评分来源:
- keyword 命中
- example 命中
- action 命中
- object 命中
- qualifier 命中
- shared context 命中
- 显式 temperature
- 显式 order_id
17.4 Clause 融合
最终 clause 分数 = 启发式分数 + model_score * classifier_weight + detector bonus + 一致性 bonus
补充规则:
- 如果启发式没有命中,但 model 分数足够高,允许
bert_bootstrap - 如果 clause 内看起来像并列复合子句,还会尝试抽出多个 parallel candidates
17.5 Workflow 类型推断
- 如果文本有条件模式:
如果若还没未发货没发货- 则推断
conditional
- 否则若存在多 clause,通常推断
sequence - 匹配数不足 2 个时,仍回落为
single
17.6 条件流程修正
_apply_conditional_hints() 当前专门处理:
cs_query_order -> cs_cancel_order- 且文本包含“还没发货 / 未发货 / 没发货”
则自动补:
depends_on=[query_step]condition.field=order_statuscondition.operator=equalscondition.value=pending_shipmentrequires_confirmation=true
18. DashScopeWorkflowPlanner 细节
18.1 调用方式
云端 planner 使用 DashScope 兼容 OpenAI 的 POST /chat/completions
配置项:
planner_base_urlplanner_api_keyplanner_model_nameplanner_timeout_seconds
18.2 Prompt 设计目标
云端 planner 的 system prompt 要求:
- 只返回严格 JSON
- 只能使用 catalog 中已有的
intent_id - 单命令返回一个 step
- 多命令返回 sequence steps
- 条件命令返回 conditional steps
- 显式抽取 slots
- 高风险动作标记
requires_confirmation=true
18.3 结果归一化
云端返回后会做:
- 提取 content
- 去掉 markdown code fence
- 解析 JSON
- 校验 intent 是否在 catalog 中
- 合并 cloud slots + clause slots + full_text slots
- 归一化 depends_on 和 condition
- 如果文本本身是条件句,再补条件 hints
18.4 云端 planner 失败分支
若出现以下问题:
- 未配置
- HTTP 请求失败
- 超时
- 返回空内容
- JSON 非法
则返回 fallback 结果:
- backend 记为
dashscope-fallback - 实际 steps 来自本地 heuristic planner
19. 单步执行流程
当 planner 没接管,且 fusion 决策为 execute 时,系统进入单步执行。
19.1 单步执行顺序
- 如果当前识别的 intent 与 session 上一个 intent 不同:
- 清空
pending_slots - 清空
slots - 清空
workflow
- 清空
- 更新
session.current_intent status=understanding- 抽取槽位
- 更新
session.slots - 更新
context_memory - 调
_build_response_from_session()
19.2 _build_response_from_session() 分支
如果缺槽位:
status=waiting_slot- 返回
ask_slot - 生成单步 workflow 展示缺失字段
如果槽位齐全:
- 直接调用 plugin
status=completed- 返回
workflow_result
19.3 单步执行图
flowchart TD
A[decision=execute] --> B[extract slots]
B --> C[update session.slots]
C --> D{pending slots?}
D -->|yes| E[ask_slot + waiting_slot]
D -->|no| F[plugins.execute]
F --> G[workflow_result]
G --> H[record turn + save session]
20. 多步 Workflow 执行流程
20.1 启动
如果 planner 返回:
accepted=True- 且
steps非空
则 AgentService._start_planned_workflow() 会:
- 调
_build_planned_workflow() - 将 workflow 写入 session
- 将 routing_debug 写入 session
- 立即调用
_continue_planned_workflow()
20.2 WorkflowStep 结构
每一步包含:
stepstep_idintent_idplugin_idactionstatusdepends_onslotsconditionrequires_confirmation
20.3 _continue_planned_workflow() 的核心逻辑
系统按 step 顺序遍历:
- 如果 step 已完成或已跳过,跳过
- 如果依赖步骤未完成,跳过
- 合并 session slots 与 step slots
- 做 intent 级 slot normalize
- 检查当前 step 是否缺必填槽位
- 如果缺槽位,暂停整个 workflow,返回
ask_slot - 若有 condition,先评估条件
- 条件不满足则
skipped - 如果此步需要确认且还未确认,返回
ask_confirmation - 否则执行 plugin
- 记录 step result
- 更新 session slots 与 context memory
- 收集每步 message
- 全部结束后生成自然语言 workflow summary
20.4 多步执行图
flowchart TD
A[workflow ready] --> B[for step in steps]
B --> C{已完成或已跳过?}
C -->|yes| B
C -->|no| D{depends_on satisfied?}
D -->|no| B
D -->|yes| E[merge slots]
E --> F{缺槽位?}
F -->|yes| G[ask_slot + pause workflow]
F -->|no| H{condition exists?}
H -->|yes| I[评估条件]
I -->|false| J[skip step]
I -->|true/none| K{requires confirmation?}
H -->|no| K
K -->|yes| L[ask_confirmation + pause workflow]
K -->|no| M[plugins.execute]
M --> N[记录 step_results]
N --> B
B --> O[全部结束]
O --> P[workflow_summary]
21. 条件流程与确认流程
21.1 条件流程
目前条件执行能力是 workflow 层完成的,不是 plugin 层完成的。
机制如下:
- 某 step 带
condition - 条件里描述:
source_stepfieldoperatorvalue
- 执行依赖步骤后,从
workflow.meta.step_results[source_step]里取data - 读出对应 field
- 做 equals / not_equals / in 判断
- 如果不满足:
- step.status = skipped
- 拼接 skip message
21.2 当前确认机制
确认触发来源有两种:
- workflow step 显式写了
requires_confirmation DialogRuleEngine.requires_confirmation(intent_id, risk_level)返回 true
当前典型需要确认的动作:
cs_cancel_order- 风险等级为
high的动作
21.3 确认处理流程
当 workflow 卡在确认步骤时:
status=waiting_confirmationpending_slots=["confirmation"]- session.workflow.meta 里写入
pending_confirmation
之后用户通过 fill-slots 或后续续聊输入:
- 如果明确为正确认:
- 将 step_id 加入
confirmed_steps - 继续跑 workflow
- 将 step_id 加入
- 如果明确为负确认:
- 将该 step 标记
skipped - 继续后面的 workflow
- 将该 step 标记
- 如果无法判断:
- 返回
confirm_retry
- 返回
21.4 确认时序图
sequenceDiagram
participant U as 用户
participant A as AgentService
participant W as Workflow
participant P as Plugin
A->>W: 发现当前 step requires_confirmation
W-->>U: ask_confirmation
U->>A: 确认 / 取消 / 模糊回复
A->>A: parse_confirmation_decision
alt 明确确认
A->>W: 标记 confirmed_steps
A->>P: 执行该 step
P-->>A: success
A-->>U: workflow_result
else 明确取消
A->>W: 标记 step skipped
A-->>U: 后续 summary
else 无法判断
A-->>U: confirm_retry
end
22. Fill-Slots 续跑流程
handle_fill_slots() 是状态恢复和续跑的重要入口。
22.1 主要分支
- 读取 session
- 如果无 session 或无 current_intent,fallback
- 更新 dialog act
- 检查 stop request
- 如果在
waiting_confirmation,优先尝试确认处理 - 如果是 social turn,也可先走社交
- 如果还在
waiting_confirmation,继续确认流程 - 如果 session 内已有非 single workflow:
- 只抽本轮补充槽位
- 继续
_continue_planned_workflow()
- 否则:
- 按当前单 intent 抽槽并继续
_build_response_from_session()
- 按当前单 intent 抽槽并继续
22.2 为什么 fill-slots 很关键
它让系统具备这些能力:
- 缺槽位后可续跑
- 条件确认后可续跑
- 多步 workflow 在中断后可继续
- 不需要整轮重新识别 planner
23. Plugin 执行层
23.1 抽象方式
当前插件层由 PluginRegistry 统一管理:
register(plugin_id, handler)execute(plugin_id, slots)
23.2 当前插件实现
现在实际接的是 MockPluginExecutor,它注册了一批 mock handler,包括:
客服类:
plugin.order.queryplugin.logistics.queryplugin.order.cancelplugin.service.transfer_human
座舱类:
plugin.cabin.navigationplugin.cabin.navigation.cancelplugin.cabin.ac.onplugin.cabin.ac.offplugin.cabin.ac_controlplugin.cabin.fan.upplugin.cabin.fan.downplugin.cabin.defog.front_onplugin.cabin.defog.rear_onplugin.cabin.window.openplugin.cabin.window.closeplugin.cabin.sunroof.openplugin.cabin.sunroof.closeplugin.cabin.doors.lockplugin.cabin.doors.unlockplugin.cabin.music_playplugin.cabin.music.pauseplugin.cabin.music.nextplugin.cabin.music.previousplugin.cabin.volume.upplugin.cabin.volume.downplugin.cabin.volume.muteplugin.cabin.lights.onplugin.cabin.lights.offplugin.cabin.seat_heat.onplugin.cabin.seat_heat.offplugin.cabin.mirror.foldplugin.cabin.mirror.unfoldplugin.cabin.wiper.onplugin.cabin.wiper.off
23.3 plugin 返回结构
每个 plugin 返回统一 dict:
successmessagedata
这使得:
- ResponsePolicy 能统一生成自然回复
- workflow condition 能统一读取
data.field
24. ResponsePolicy 与最终话术
24.1 ResponsePolicy 职责
ResponsePolicy 是统一话术策略层,负责:
ask_for_slotworkflow_resultworkflow_summaryask_for_confirmationconfirm_retryconfirm_cancelledstep_skippedackrejectshort_socialopen_social_fallbackwith_pending_hintpending_task_hinttask_stoppedclarifyfallback
24.2 workflow_summary 的特殊点
多步结果不是简单拼接,而会做一定“车机式口语化聚合”,例如:
车窗已经打开了空调也调到 20 度了也开始播放 民谣 了
最终形态类似:
好,车窗已经打开了,空调也调到 20 度了。
24.3 clarify / reject / fallback 区别
clarify
- 已知能力内
- 但候选有歧义
reject
- 当前判断超能力边界
- 或 planner 明确指出 out of scope
fallback
- 没有稳定理解
- 也没有足够候选可澄清
25. Debug 与可观测性
当前项目对调试非常友好,主要体现在:
- route 每个 stage 都保留详细 debug
- rewrite 会带 applied / reason / metadata
- planner 会追加 planner stage 到 routing_debug
- clause_analysis 会放入 planner metadata
- multi_intent_detector 原始 top scores 会保留
- processing breakdown 会附带每阶段耗时
因此一次响应通常能回放出:
- 原始输入
- 是否改写
- route 经过哪些 stage
- 每个 stage 给了什么 candidates
- fusion 为什么 execute / clarify / reject / route_to_cloud
- planner 是否触发
- planner 为什么 accepted / rejected
- workflow 长什么样
- 每步执行结果如何
26. 当前支持的核心能力
26.1 客服域
- 查订单
- 查物流
- 取消订单
- 转人工
26.2 座舱域
- 导航去某地
- 结束导航
- 打开/关闭空调
- 调空调温度
- 调大/调小风量
- 前挡除雾
- 后挡除雾
- 打开/关闭车窗
- 打开/关闭天窗
- 锁/解锁车门
- 播放/暂停音乐
- 上一首/下一首
- 调大/调小音量
- 静音
- 打开/关闭车灯
- 打开/关闭座椅加热
- 折叠/展开后视镜
- 打开/关闭雨刷
26.3 对话辅助能力
- 问候
- 感谢
- 再见
- 能力问答
- 开放闲聊
- 多轮短句改写
- 条件执行
- 高风险确认
- 停止当前任务
27. 分支矩阵
27.1 输入到输出的主要分支
| 输入类型 | 前置判断 | 走向 | 最终输出类型 |
|---|---|---|---|
| 停止词 + 有活动任务 | stop rule | reset task | text/stopped |
| 问候/感谢/闲聊 | social route | social responder | text/social |
| 单命令高置信 | fusion execute | 单步执行 | workflow_result |
| 单命令缺槽位 | execute + missing slots | ask slot | ask_slot |
| 多命令/条件句 | planner accepted | workflow | workflow_result / ask_slot / ask_confirmation |
| 本地歧义 | fusion clarify | clarify | clarify |
| 本地像已知意图但不稳 | route_to_cloud | clarify / fallback / reject | clarify/fallback/reject |
| 完全未知 | reject | reject | reject |
| session 丢失或无 current intent 的 fill-slots | invalid continuation | fallback | fallback |
27.2 route_to_cloud 的三种最终表现
当 fusion 决策为 route_to_cloud 时,不一定真的“去云端执行完就返回结果”,当前表现取决于 planner stage 和候选情况:
- planner 明确提示 out-of-scope
- 返回
reject
- 返回
- 还有可用候选 intent
- 返回
clarify
- 返回
- 没候选也没明确拒绝
- 返回
fallback
- 返回
28. 当前技术栈与模型清单
28.1 基础框架
- Python
- FastAPI
- Pydantic Settings
- YAML / JSON 配置文件
28.2 本地理解层
- keyword matcher
- heuristic retrieval matcher
- mock classifier
- local BERT classifier
- local multi-label BERT detector
28.3 云端能力层
- DashScope OpenAI-compatible chat completion
- 云端 workflow planner
- 云端 social responder
28.4 状态与数据层
- In-memory session
- Redis session
28.5 执行层
- PluginRegistry
- MockPluginExecutor
28.6 前端与调试
- demo.html
- runtime backend 切换
- routing debug panel
- workflow JSON 展示
29. 真实请求样例时序
29.1 单命令:打开车窗
sequenceDiagram
participant U as 用户
participant API as FastAPI
participant S as AgentService
participant R as Router
participant P as Plugin
U->>API: /chat 打开车窗
API->>S: handle_chat
S->>S: get/create session
S->>S: rewrite(无改写)
S->>R: route
R-->>S: decision=execute,intent=cabin_window_open
S->>S: extract slots(空)
S->>P: plugin.cabin.window.open
P-->>S: success + message
S-->>API: workflow_result
API-->>U: 好的,已打开车窗
29.2 条件句:查订单,如果没发货就取消
sequenceDiagram
participant U as 用户
participant S as AgentService
participant PL as Planner
participant W as Workflow
participant P as Plugin
U->>S: 查订单A123,如果没发货就取消
S->>PL: planner.plan
PL-->>S: conditional workflow
S->>W: build workflow
W->>P: query_order
P-->>W: data.order_status=pending_shipment
W-->>U: ask_confirmation
U->>S: 确认
S->>W: continue workflow
W->>P: cancel_order
P-->>W: success
W-->>U: workflow_summary
29.3 多轮补槽:导航去哪里
sequenceDiagram
participant U as 用户
participant S as AgentService
participant P as Plugin
U->>S: 导航
S-->>U: ask_slot(请告诉我要去哪里)
U->>S: 去公司
S->>S: fill-slots
S->>P: plugin.cabin.navigation(destination=公司)
P-->>S: success
S-->>U: workflow_result
30. 当前边界与限制
30.1 还不是完整语音链路
当前项目只有文本 Agent 服务:
- 没有内建 ASR
- 没有内建 TTS
- 没有真正的车机设备控制链路
30.2 plugin 仍然是 mock
虽然 plugin 结构已经有了,但当前执行结果仍然是 mock handler 返回,不是真实业务系统结果。
30.3 LLM matcher 尚未实现
matcher_pipeline 虽然支持 llm 这个 stage 名字,但实现仍是 placeholder。
30.4 流式 ack 与真实执行未完全打通
chat-stream 中 1 秒后的 ack 仍然依赖输入文本 token,不是插件真实启动事件。
30.5 多意图 detector 已独立训练,但泛化仍需继续补数据
目前多标签 detector 已接入为真正训练过的多标签模型,但对独立口语化长尾场景仍需要继续补强训练数据。
30.6 NER / Token Classification 尚未接入
当前动作-对象-槽位边界主要依赖:
- heuristic slot extraction
- clause heuristic
- classifier 与 detector 融合
还没有真正的 token classification 层。
31. 一句话总结当前项目真实流程
当前项目的真实运行方式可以概括为:
FastAPI 接收请求
-> AgentService 读取 session
-> 先处理 stop / social
-> rewrite 做短句补全
-> keyword/classifier/retrieval 多阶段并行打分
-> fusion 决定 execute / clarify / reject / route_to_cloud
-> 复杂句触发 local-first planner
-> 生成 single/sequence/conditional workflow
-> 缺槽位就 ask_slot
-> 高风险就 ask_confirmation
-> PluginRegistry 执行
-> ResponsePolicy 生成最终自然回复
-> Session 持久化并返回完整 debug 与时延指标
32. 后续阅读建议
如果要继续往下深挖,建议按这个顺序看代码:
app/main.pyapp/core/bootstrap.pyapp/services/agent_service.pyapp/services/router.pyapp/services/planner.pyapp/services/classifier.pyapp/services/multi_intent_detector.pyapp/services/rewrite_engine.pyapp/services/social.pyapp/services/session_store.pyconfig/domain.ymlconfig/workflows.yml