1723 lines
39 KiB
Markdown
1723 lines
39 KiB
Markdown
# 当前项目完整流程说明
|
||
|
||
## 1. 文档目标
|
||
|
||
本文档描述当前项目在代码层面的真实运行流程,不是目标态蓝图,而是“现在这个仓库实际如何工作”。
|
||
|
||
覆盖范围包括:
|
||
|
||
- 服务启动与运行时装配
|
||
- API 请求入口与返回结构
|
||
- 会话状态管理
|
||
- 输入改写
|
||
- 本地路由与多阶段融合
|
||
- 社交闲聊分流
|
||
- planner 触发与多步骤 workflow 生成
|
||
- 单步执行、多步执行、条件执行、确认执行
|
||
- 配置驱动加载方式
|
||
- 当前使用的技术、模型、阈值、分支条件
|
||
- 主要风险点与当前边界
|
||
|
||
---
|
||
|
||
## 2. 系统定位
|
||
|
||
当前项目是一个面向“智能座舱 + 客服”的执行型 Agent 服务,后端基于 FastAPI,核心特点如下:
|
||
|
||
- 配置驱动:意图、动作、响应模板、表单、规则、workflow 模板都来自 `config/`
|
||
- 本地优先:优先走 `rewrite -> keyword/classifier/retrieval -> fusion`
|
||
- planner 不是默认入口:只有复杂句、多意图、条件句、低置信句才触发 planner
|
||
- 会话显式维护:多轮状态不依赖 LLM 记忆,而依赖 `SessionState`
|
||
- 社交闲聊单独分流:问候、感谢、能力问答、开放闲聊走 `SocialRouter`
|
||
- 插件执行统一抽象:所有意图最终映射到 `plugin_id`
|
||
|
||
---
|
||
|
||
## 3. 总体架构图
|
||
|
||
```mermaid
|
||
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 阶段完成以下事情:
|
||
|
||
1. 初始化 `FastAPI(title=settings.app_name)`
|
||
2. 初始化 demo runtime 配置
|
||
3. 调用 `build_agent_service_with_runtime(...)`
|
||
4. 调用 `build_intent_registry()`
|
||
5. 暴露 `/health`、`/demo`、`/api/v1/agent/chat`、`/api/v1/agent/chat-stream`、`/api/v1/agent/fill-slots`
|
||
|
||
### 4.2 运行时装配
|
||
|
||
`build_agent_service_with_runtime()` 会组装完整执行链:
|
||
|
||
1. `ConfigLoader.load()` 读取配置文件
|
||
2. 构建 `IntentRegistry`
|
||
3. 构建 classifier
|
||
4. 构建 multi-intent detector
|
||
5. 构建 matcher pipeline 和 router
|
||
6. 构建 session store
|
||
7. 构建 `ResponsePolicy`
|
||
8. 构建 `DialogRuleEngine`
|
||
9. 构建 `DialogActEngine`
|
||
10. 构建 planner
|
||
11. 注册 mock plugin
|
||
12. 构建 `SocialRouter` 和 `DashScopeSocialResponder`
|
||
13. 最终实例化 `AgentService`
|
||
|
||
### 4.3 启动装配图
|
||
|
||
```mermaid
|
||
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.yml`
|
||
- `config/actions.yml`
|
||
- `config/forms.yml`
|
||
- `config/responses.yml`
|
||
- `config/rules.yml`
|
||
- `config/dialog_acts.yml`
|
||
- `config/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 加载流程
|
||
|
||
```mermaid
|
||
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`
|
||
|
||
这是主同步接口:
|
||
|
||
1. 接收 `ChatRequest`
|
||
2. 直接调用 `agent_service.handle_chat(request)`
|
||
3. 返回 `ChatResponse`
|
||
|
||
### 6.2 `/api/v1/agent/chat-stream`
|
||
|
||
这是流式接口:
|
||
|
||
1. 用线程池异步执行 `agent_service.handle_chat`
|
||
2. 如果 1 秒内拿到结果,直接返回 `final`
|
||
3. 如果 1 秒内没拿到结果:
|
||
- 先检查 `_should_emit_processing_hint(text)`
|
||
- 如果命中工具型关键词,就先发一个 `ack`
|
||
- 再等待最终结果
|
||
4. 最终以 NDJSON 流输出
|
||
|
||
注意:
|
||
|
||
- 这里的流式 `ack` 仍然是“基于输入文本 token 的启发式判断”
|
||
- 它并不等于“真实插件已开始执行”
|
||
- 这是 HTTP streaming 层的反馈策略,不是 AgentService 内部 workflow 执行层
|
||
|
||
### 6.3 `/api/v1/agent/fill-slots`
|
||
|
||
这是补槽位和确认续跑接口:
|
||
|
||
1. 根据 `session_id` 取已有 session
|
||
2. 若没有有效 session 或没有 `current_intent`,返回 fallback
|
||
3. 如果当前在 `waiting_confirmation`,优先处理确认
|
||
4. 如果当前是多步 workflow,继续推进 workflow
|
||
5. 否则按当前 intent 继续抽槽并补全
|
||
|
||
---
|
||
|
||
## 7. Session 设计
|
||
|
||
### 7.1 SessionState 字段
|
||
|
||
`SessionState` 当前包含:
|
||
|
||
- `session_id`
|
||
- `user_id`
|
||
- `channel`
|
||
- `status`
|
||
- `current_intent`
|
||
- `pending_slots`
|
||
- `slots`
|
||
- `workflow`
|
||
- `routing_debug`
|
||
- `last_user_text`
|
||
- `last_agent_text`
|
||
- `context_memory`
|
||
|
||
### 7.2 状态含义
|
||
|
||
当前项目中常见状态:
|
||
|
||
- `idle`
|
||
- `understanding`
|
||
- `waiting_slot`
|
||
- `waiting_confirmation`
|
||
- `running`
|
||
- `completed`
|
||
- `rejected`
|
||
- `fallback`
|
||
- `stopped`
|
||
- `social`
|
||
|
||
### 7.3 Session Backend
|
||
|
||
支持两种 session backend:
|
||
|
||
- `memory`
|
||
- `redis`
|
||
|
||
`memory`
|
||
|
||
- 进程内字典保存
|
||
- 重启丢失
|
||
- 适合本地开发
|
||
|
||
`redis`
|
||
|
||
- JSON 序列化保存
|
||
- key 带前缀和 TTL
|
||
- 适合跨进程和长会话
|
||
|
||
### 7.4 Session 状态图
|
||
|
||
```mermaid
|
||
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 主链路顺序
|
||
|
||
1. 读取或创建 session
|
||
2. 更新 dialog act
|
||
3. 检查是否停止任务
|
||
4. 检查是否社交闲聊
|
||
5. 运行 rewrite
|
||
6. 路由匹配
|
||
7. 判断是否要启 planner
|
||
8. 如果 planner 接受,直接走多步 workflow
|
||
9. 如果 planner 不接受,则按 fusion 决策处理
|
||
10. 如果决策是 execute,则抽槽并执行
|
||
11. 记录 turn
|
||
12. 保存 session
|
||
13. 填充 latency breakdown
|
||
|
||
### 8.2 主流程图
|
||
|
||
```mermaid
|
||
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_ms`
|
||
- `dialog_act_ms`
|
||
- `stop_check_ms`
|
||
- `social_route_ms`
|
||
- `rewrite_ms`
|
||
- `route_ms`
|
||
- `planner_ms`
|
||
- `decision_response_ms`
|
||
- `slot_extract_ms`
|
||
- `response_build_ms`
|
||
- `record_turn_ms`
|
||
- `session_save_ms`
|
||
- `match_pipeline_ms`
|
||
- `first_response_latency_ms`
|
||
- `total_latency_ms`
|
||
|
||
---
|
||
|
||
## 9. Dialog Act 与停止分支
|
||
|
||
### 9.1 Dialog Act
|
||
|
||
系统会在请求一开始调用 `DialogActEngine.detect(text)`,当前 act 包括:
|
||
|
||
- `affirm`
|
||
- `deny`
|
||
- `cancel`
|
||
- `modify`
|
||
- `chitchat`
|
||
- `request`
|
||
- `inform`
|
||
- `unknown`
|
||
|
||
当前 dialog act 的用途主要是:
|
||
|
||
- 保存会话理解上下文
|
||
- 给后续确认/修改/闲聊处理提供辅助信号
|
||
|
||
### 9.2 停止分支
|
||
|
||
停止请求由 `DialogRuleEngine.is_stop_request()` 判断,典型词包括:
|
||
|
||
- 不用了
|
||
- 算了
|
||
- 先这样吧
|
||
- 停一下
|
||
- 停止
|
||
- 结束这次操作
|
||
|
||
只有满足以下两个条件才会真正停止:
|
||
|
||
1. 输入命中 stop phrase
|
||
2. 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)` 流程如下:
|
||
|
||
1. 归一化文本
|
||
2. 如果看起来像任务型请求,直接返回 `category=none`
|
||
3. 如果命中短社交模式,返回 `open_social`
|
||
4. 如果命中 capability regex,返回 `open_social`
|
||
5. 如果命中开放闲聊短语或 regex,返回 `open_social`
|
||
6. 如果上一轮是 `open_social` 且当前文本很短,作为闲聊续接
|
||
7. 否则不是社交
|
||
|
||
### 10.3 社交分支的两个层次
|
||
|
||
第一层:`SocialRouter`
|
||
|
||
- 只判断要不要走社交链路
|
||
|
||
第二层:`DashScopeSocialResponder`
|
||
|
||
- 真正生成自然语言回复
|
||
- 使用 DashScope 兼容 OpenAI 的 `/chat/completions`
|
||
- `temperature=0.6`
|
||
- `max_tokens=120`
|
||
- 系统提示词要求:
|
||
- 简短
|
||
- 口语化
|
||
- 不编造已执行动作
|
||
- 不输出 JSON
|
||
|
||
### 10.4 社交回复的补充逻辑
|
||
|
||
如果当前 session 还有未完成任务:
|
||
|
||
- `ResponsePolicy.pending_task_hint()` 会追加提示
|
||
- 例如还在等确认、还在等槽位、还在运行中
|
||
|
||
因此社交回复不一定纯闲聊,可能附带任务续接提示
|
||
|
||
### 10.5 社交流程图
|
||
|
||
```mermaid
|
||
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_ac`
|
||
- `cabin_ac_on`
|
||
- `cabin_ac_off`
|
||
- `cabin_fan_up`
|
||
- `cabin_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 分支图
|
||
|
||
```mermaid
|
||
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`: `MultiStageIntentMatcher`
|
||
- `slot_extractor`: `HeuristicSlotExtractor`
|
||
|
||
### 12.2 Matcher Pipeline
|
||
|
||
可配置的匹配阶段:
|
||
|
||
- `keyword`
|
||
- `classifier`
|
||
- `retrieval`
|
||
- `llm` 占位,当前未实现
|
||
|
||
默认项目原则上使用:
|
||
|
||
- `keyword,classifier,retrieval`
|
||
|
||
### 12.3 各阶段职责
|
||
|
||
`KeywordIntentMatcher`
|
||
|
||
- 遍历每个 intent 的 keywords
|
||
- 命中即给 1.0 分
|
||
- 候选 reason 是 `keyword:xxx`
|
||
|
||
`ClassifierIntentMatcher`
|
||
|
||
- 调用 `IntentClassifier.predict`
|
||
- 可能接后端:
|
||
- `mock`
|
||
- `bert`
|
||
- `remote`
|
||
- 输出 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.65`
|
||
- `local_route_to_cloud_threshold = 0.75`
|
||
- `local_clarify_margin_threshold = 0.12`
|
||
- `local_classifier_execute_score_threshold = 0.55`
|
||
- `local_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 总流程图
|
||
|
||
```mermaid
|
||
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_intent`
|
||
- `matched_stage`
|
||
- `decision`
|
||
- `decision_reason`
|
||
- `confidence_grade`
|
||
- `unknown_detected`
|
||
- `stages`
|
||
- `total_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_backend`
|
||
- `classifier_model_path`
|
||
- `classifier_label_map_path`
|
||
- `classifier_top_k`
|
||
- `classifier_bert_threshold`
|
||
- `classifier_warmup_enabled`
|
||
- `classifier_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_enabled`
|
||
- `planner_multi_intent_detector_model_path`
|
||
- `planner_multi_intent_detector_threshold`
|
||
- `planner_multi_intent_detector_top_k`
|
||
- `planner_multi_intent_detector_max_labels`
|
||
|
||
---
|
||
|
||
## 15. Planner 触发机制
|
||
|
||
### 15.1 何时调用 planner
|
||
|
||
`AgentService._should_use_planner()` 当前规则:
|
||
|
||
满足任一就会进入 planner:
|
||
|
||
1. 文本包含复杂连接词:
|
||
- 然后
|
||
- 并且
|
||
- 同时
|
||
- 如果
|
||
- 若
|
||
- 先
|
||
- 后
|
||
2. 文本包含明显分隔符:
|
||
- `,`
|
||
- `,`
|
||
- `;`
|
||
- `;`
|
||
3. fusion stage 最终未 accepted
|
||
|
||
这意味着:
|
||
|
||
- planner 不是全量调用
|
||
- 单条明确命令通常不会调 planner
|
||
- 复杂句、歧义句、低置信句会调 planner
|
||
|
||
### 15.2 planner 组合结构
|
||
|
||
当前 `build_planner()` 构成如下:
|
||
|
||
本地层:
|
||
|
||
- `TemplateWorkflowPlanner`
|
||
- `HeuristicWorkflowPlanner`
|
||
|
||
云端层:
|
||
|
||
- `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 链路图
|
||
|
||
```mermaid
|
||
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_sequence`
|
||
- `query_then_cancel_if_pending`
|
||
|
||
### 16.2 工作方式
|
||
|
||
1. 调 `_analyze_multi_intent()`
|
||
2. 拿到 clause 分析结果
|
||
3. 如果匹配的 intent 少于 2 个,不接受
|
||
4. 逐个比对 workflow 模板
|
||
5. 如果模板命中,则生成 `PlannedStep`
|
||
|
||
### 16.3 模板命中条件
|
||
|
||
需要同时满足:
|
||
|
||
- `matched_ids[:len(intent_sequence)] == template.intent_sequence`
|
||
- 若模板定义了 `trigger_keywords`,文本中必须都出现
|
||
|
||
这是一种严格模板匹配,不是模糊相似模板匹配。
|
||
|
||
---
|
||
|
||
## 17. HeuristicWorkflowPlanner 细节
|
||
|
||
### 17.1 输入分析
|
||
|
||
`_analyze_multi_intent()` 做这些事:
|
||
|
||
1. 如果配置了多标签 detector,先对整句做 multi-intent detect
|
||
2. 生成 `detector_prior`
|
||
3. 按连接词和标点做 clause split
|
||
4. 对每个 clause 做 heuristic + classifier + detector 融合
|
||
5. 汇总成 `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_status`
|
||
- `condition.operator=equals`
|
||
- `condition.value=pending_shipment`
|
||
- `requires_confirmation=true`
|
||
|
||
---
|
||
|
||
## 18. DashScopeWorkflowPlanner 细节
|
||
|
||
### 18.1 调用方式
|
||
|
||
云端 planner 使用 DashScope 兼容 OpenAI 的 `POST /chat/completions`
|
||
|
||
配置项:
|
||
|
||
- `planner_base_url`
|
||
- `planner_api_key`
|
||
- `planner_model_name`
|
||
- `planner_timeout_seconds`
|
||
|
||
### 18.2 Prompt 设计目标
|
||
|
||
云端 planner 的 system prompt 要求:
|
||
|
||
- 只返回严格 JSON
|
||
- 只能使用 catalog 中已有的 `intent_id`
|
||
- 单命令返回一个 step
|
||
- 多命令返回 sequence steps
|
||
- 条件命令返回 conditional steps
|
||
- 显式抽取 slots
|
||
- 高风险动作标记 `requires_confirmation=true`
|
||
|
||
### 18.3 结果归一化
|
||
|
||
云端返回后会做:
|
||
|
||
1. 提取 content
|
||
2. 去掉 markdown code fence
|
||
3. 解析 JSON
|
||
4. 校验 intent 是否在 catalog 中
|
||
5. 合并 cloud slots + clause slots + full_text slots
|
||
6. 归一化 depends_on 和 condition
|
||
7. 如果文本本身是条件句,再补条件 hints
|
||
|
||
### 18.4 云端 planner 失败分支
|
||
|
||
若出现以下问题:
|
||
|
||
- 未配置
|
||
- HTTP 请求失败
|
||
- 超时
|
||
- 返回空内容
|
||
- JSON 非法
|
||
|
||
则返回 fallback 结果:
|
||
|
||
- backend 记为 `dashscope-fallback`
|
||
- 实际 steps 来自本地 heuristic planner
|
||
|
||
---
|
||
|
||
## 19. 单步执行流程
|
||
|
||
当 planner 没接管,且 fusion 决策为 `execute` 时,系统进入单步执行。
|
||
|
||
### 19.1 单步执行顺序
|
||
|
||
1. 如果当前识别的 intent 与 session 上一个 intent 不同:
|
||
- 清空 `pending_slots`
|
||
- 清空 `slots`
|
||
- 清空 `workflow`
|
||
2. 更新 `session.current_intent`
|
||
3. `status=understanding`
|
||
4. 抽取槽位
|
||
5. 更新 `session.slots`
|
||
6. 更新 `context_memory`
|
||
7. 调 `_build_response_from_session()`
|
||
|
||
### 19.2 `_build_response_from_session()` 分支
|
||
|
||
如果缺槽位:
|
||
|
||
- `status=waiting_slot`
|
||
- 返回 `ask_slot`
|
||
- 生成单步 workflow 展示缺失字段
|
||
|
||
如果槽位齐全:
|
||
|
||
- 直接调用 plugin
|
||
- `status=completed`
|
||
- 返回 `workflow_result`
|
||
|
||
### 19.3 单步执行图
|
||
|
||
```mermaid
|
||
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()` 会:
|
||
|
||
1. 调 `_build_planned_workflow()`
|
||
2. 将 workflow 写入 session
|
||
3. 将 routing_debug 写入 session
|
||
4. 立即调用 `_continue_planned_workflow()`
|
||
|
||
### 20.2 WorkflowStep 结构
|
||
|
||
每一步包含:
|
||
|
||
- `step`
|
||
- `step_id`
|
||
- `intent_id`
|
||
- `plugin_id`
|
||
- `action`
|
||
- `status`
|
||
- `depends_on`
|
||
- `slots`
|
||
- `condition`
|
||
- `requires_confirmation`
|
||
|
||
### 20.3 `_continue_planned_workflow()` 的核心逻辑
|
||
|
||
系统按 step 顺序遍历:
|
||
|
||
1. 如果 step 已完成或已跳过,跳过
|
||
2. 如果依赖步骤未完成,跳过
|
||
3. 合并 session slots 与 step slots
|
||
4. 做 intent 级 slot normalize
|
||
5. 检查当前 step 是否缺必填槽位
|
||
6. 如果缺槽位,暂停整个 workflow,返回 `ask_slot`
|
||
7. 若有 condition,先评估条件
|
||
8. 条件不满足则 `skipped`
|
||
9. 如果此步需要确认且还未确认,返回 `ask_confirmation`
|
||
10. 否则执行 plugin
|
||
11. 记录 step result
|
||
12. 更新 session slots 与 context memory
|
||
13. 收集每步 message
|
||
14. 全部结束后生成自然语言 workflow summary
|
||
|
||
### 20.4 多步执行图
|
||
|
||
```mermaid
|
||
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 层完成的。
|
||
|
||
机制如下:
|
||
|
||
1. 某 step 带 `condition`
|
||
2. 条件里描述:
|
||
- `source_step`
|
||
- `field`
|
||
- `operator`
|
||
- `value`
|
||
3. 执行依赖步骤后,从 `workflow.meta.step_results[source_step]` 里取 `data`
|
||
4. 读出对应 field
|
||
5. 做 equals / not_equals / in 判断
|
||
6. 如果不满足:
|
||
- step.status = skipped
|
||
- 拼接 skip message
|
||
|
||
### 21.2 当前确认机制
|
||
|
||
确认触发来源有两种:
|
||
|
||
1. workflow step 显式写了 `requires_confirmation`
|
||
2. `DialogRuleEngine.requires_confirmation(intent_id, risk_level)` 返回 true
|
||
|
||
当前典型需要确认的动作:
|
||
|
||
- `cs_cancel_order`
|
||
- 风险等级为 `high` 的动作
|
||
|
||
### 21.3 确认处理流程
|
||
|
||
当 workflow 卡在确认步骤时:
|
||
|
||
1. `status=waiting_confirmation`
|
||
2. `pending_slots=["confirmation"]`
|
||
3. session.workflow.meta 里写入 `pending_confirmation`
|
||
|
||
之后用户通过 `fill-slots` 或后续续聊输入:
|
||
|
||
- 如果明确为正确认:
|
||
- 将 step_id 加入 `confirmed_steps`
|
||
- 继续跑 workflow
|
||
- 如果明确为负确认:
|
||
- 将该 step 标记 `skipped`
|
||
- 继续后面的 workflow
|
||
- 如果无法判断:
|
||
- 返回 `confirm_retry`
|
||
|
||
### 21.4 确认时序图
|
||
|
||
```mermaid
|
||
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 主要分支
|
||
|
||
1. 读取 session
|
||
2. 如果无 session 或无 current_intent,fallback
|
||
3. 更新 dialog act
|
||
4. 检查 stop request
|
||
5. 如果在 `waiting_confirmation`,优先尝试确认处理
|
||
6. 如果是 social turn,也可先走社交
|
||
7. 如果还在 `waiting_confirmation`,继续确认流程
|
||
8. 如果 session 内已有非 single workflow:
|
||
- 只抽本轮补充槽位
|
||
- 继续 `_continue_planned_workflow()`
|
||
9. 否则:
|
||
- 按当前单 intent 抽槽并继续 `_build_response_from_session()`
|
||
|
||
### 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.query`
|
||
- `plugin.logistics.query`
|
||
- `plugin.order.cancel`
|
||
- `plugin.service.transfer_human`
|
||
|
||
座舱类:
|
||
|
||
- `plugin.cabin.navigation`
|
||
- `plugin.cabin.navigation.cancel`
|
||
- `plugin.cabin.ac.on`
|
||
- `plugin.cabin.ac.off`
|
||
- `plugin.cabin.ac_control`
|
||
- `plugin.cabin.fan.up`
|
||
- `plugin.cabin.fan.down`
|
||
- `plugin.cabin.defog.front_on`
|
||
- `plugin.cabin.defog.rear_on`
|
||
- `plugin.cabin.window.open`
|
||
- `plugin.cabin.window.close`
|
||
- `plugin.cabin.sunroof.open`
|
||
- `plugin.cabin.sunroof.close`
|
||
- `plugin.cabin.doors.lock`
|
||
- `plugin.cabin.doors.unlock`
|
||
- `plugin.cabin.music_play`
|
||
- `plugin.cabin.music.pause`
|
||
- `plugin.cabin.music.next`
|
||
- `plugin.cabin.music.previous`
|
||
- `plugin.cabin.volume.up`
|
||
- `plugin.cabin.volume.down`
|
||
- `plugin.cabin.volume.mute`
|
||
- `plugin.cabin.lights.on`
|
||
- `plugin.cabin.lights.off`
|
||
- `plugin.cabin.seat_heat.on`
|
||
- `plugin.cabin.seat_heat.off`
|
||
- `plugin.cabin.mirror.fold`
|
||
- `plugin.cabin.mirror.unfold`
|
||
- `plugin.cabin.wiper.on`
|
||
- `plugin.cabin.wiper.off`
|
||
|
||
### 23.3 plugin 返回结构
|
||
|
||
每个 plugin 返回统一 dict:
|
||
|
||
- `success`
|
||
- `message`
|
||
- `data`
|
||
|
||
这使得:
|
||
|
||
- ResponsePolicy 能统一生成自然回复
|
||
- workflow condition 能统一读取 `data.field`
|
||
|
||
---
|
||
|
||
## 24. ResponsePolicy 与最终话术
|
||
|
||
### 24.1 ResponsePolicy 职责
|
||
|
||
`ResponsePolicy` 是统一话术策略层,负责:
|
||
|
||
- `ask_for_slot`
|
||
- `workflow_result`
|
||
- `workflow_summary`
|
||
- `ask_for_confirmation`
|
||
- `confirm_retry`
|
||
- `confirm_cancelled`
|
||
- `step_skipped`
|
||
- `ack`
|
||
- `reject`
|
||
- `short_social`
|
||
- `open_social_fallback`
|
||
- `with_pending_hint`
|
||
- `pending_task_hint`
|
||
- `task_stopped`
|
||
- `clarify`
|
||
- `fallback`
|
||
|
||
### 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 会附带每阶段耗时
|
||
|
||
因此一次响应通常能回放出:
|
||
|
||
1. 原始输入
|
||
2. 是否改写
|
||
3. route 经过哪些 stage
|
||
4. 每个 stage 给了什么 candidates
|
||
5. fusion 为什么 execute / clarify / reject / route_to_cloud
|
||
6. planner 是否触发
|
||
7. planner 为什么 accepted / rejected
|
||
8. workflow 长什么样
|
||
9. 每步执行结果如何
|
||
|
||
---
|
||
|
||
## 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 和候选情况:
|
||
|
||
1. planner 明确提示 out-of-scope
|
||
- 返回 `reject`
|
||
2. 还有可用候选 intent
|
||
- 返回 `clarify`
|
||
3. 没候选也没明确拒绝
|
||
- 返回 `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 单命令:打开车窗
|
||
|
||
```mermaid
|
||
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 条件句:查订单,如果没发货就取消
|
||
|
||
```mermaid
|
||
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 多轮补槽:导航去哪里
|
||
|
||
```mermaid
|
||
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. 一句话总结当前项目真实流程
|
||
|
||
当前项目的真实运行方式可以概括为:
|
||
|
||
```text
|
||
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. 后续阅读建议
|
||
|
||
如果要继续往下深挖,建议按这个顺序看代码:
|
||
|
||
1. `app/main.py`
|
||
2. `app/core/bootstrap.py`
|
||
3. `app/services/agent_service.py`
|
||
4. `app/services/router.py`
|
||
5. `app/services/planner.py`
|
||
6. `app/services/classifier.py`
|
||
7. `app/services/multi_intent_detector.py`
|
||
8. `app/services/rewrite_engine.py`
|
||
9. `app/services/social.py`
|
||
10. `app/services/session_store.py`
|
||
11. `config/domain.yml`
|
||
12. `config/workflows.yml`
|
||
|