bea288e414
== 已部署上线 (9项) == - 代办事项真实数据源集成 (企微审批API 8bug修复链) - H5/坐席端 Logo样式统一+绿色背景 - 视频引导页修复 (localStorage key v2) - 坐席端 v9 Vue版本修复 (ElMessage._context) - 截图按钮 v10 修复 (getDisplayMedia user gesture) - 扫码样式恢复+H5扫码登录跳转修复 - H5截图快捷键提示 == 代码完成待部署 (3项) == - 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查) - 会议室预定-小鱼易联终端 (40文件, 40/40测试通过) - IT资产升级审批推送 (asset_service.py) == 需求文档 (2项) == - 坐席端AI辅助消息框-PRD (4项新功能确认) - 坐席端布局优化建议 v2.0 (7天计划) == 新增文档 == - 日报-2026-07-11.md - 知识迭代Bug修复报告-20260711.md - 会议室预定-部署指南.md - CHANGELOG.md 更新 == 测试 == - test_todo_integration.py: 40/40 - test_meetingroom.py: 40/40 - test_bugfix_ki_suggestions.py: 21/21
1167 lines
53 KiB
Markdown
1167 lines
53 KiB
Markdown
# 复杂场景重构第一阶段 — 架构设计文档
|
||
|
||
> **版本**: v1.0
|
||
> **日期**: 2026-07-20
|
||
> **架构师**: 高见远(Bob)
|
||
> **状态**: 待评审
|
||
> **关联文档**: `复杂场景重构第一阶段-增量PRD.md` / `重构方案-复杂场景技术方案.md` v1.1 / `IT智能服务台-系统架构设计文档v2.md` §15.5
|
||
|
||
---
|
||
|
||
## 1. 实现方案与框架选型
|
||
|
||
### 1.1 核心技术挑战
|
||
|
||
| 挑战 | 说明 | 对策 |
|
||
|------|------|------|
|
||
| **不引入 Neo4j 实现 TeliChat 三重约束** | 技术方案 v1.1 依赖 Neo4j 图数据库做拓扑结构和状态图谱,本阶段约束不引入 | 三重约束映射:拓扑 → `ScenarioConfig.actions` 有序列表 + Python 代码路由;信息状态 → `auto_information_items` PostgreSQL 表;业务判断 → Python 代码 |
|
||
| **全局意图识别与现有场景识别的兼容** | 现有 IntentRouter 仅识别 4 种场景意图,新增 PAUSE/RESUME_TASK/CORRECT/SUPPLEMENT 4 种全局意图 | 在 IntentRouter.detect() 前置一层全局意图检测,命中全局意图时跳过场景识别;未命中时走原有场景识别流程 |
|
||
| **暂停状态持久化与恢复点一致性** | 暂停时需保存完整上下文(当前动作、信息项快照、步骤描述),恢复时需从断点继续 | PostgreSQL 持久化会话状态 + Redis 存储恢复点快照(含 TTL 25h 自动过期),双重保障 |
|
||
| **信息项版本管理与更正锁定** | 信息更正需保留变更历史,`固定`修饰符标记的字段在动作执行后锁定不可更正 | `auto_information_items` 表记录 `version` + `update_history`(JSON 数组),`is_locked` 字段控制更正锁定 |
|
||
| **24 小时超时自动关闭** | 暂停超过 24 小时需自动关闭会话 | 后台定时任务扫描 `paused` 状态会话,超时则标记 `closed`;Redis 恢复点 TTL 25h 作为兜底清理 |
|
||
| **坐席端实时感知暂停/恢复/更正事件** | 坐席工作台需实时看到会话状态变化 | 复用现有 WS 推送机制(progress_publisher.py),新增 5 种 WS 事件 |
|
||
|
||
### 1.2 总体架构思路
|
||
|
||
本阶段在现有自动化引擎骨架(阶段5)上增量扩展,**不引入 Neo4j**,用 PostgreSQL + Redis + Python 代码逻辑替代图数据库实现 TeliChat 三重约束:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 员工 H5 / 坐席工作台 │
|
||
└──────────────────────────────┬──────────────────────────────────────┘
|
||
│ HTTP / WebSocket
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ FastAPI 路由层 (api/automation.py) │
|
||
│ 新增: /pause /resume /correct /supplement /info-items /paused │
|
||
└──────────────────────────────┬──────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ 自动化服务层 (services/automation/) │
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────────┐ ┌────────────────────┐ │
|
||
│ │ IntentRouter │ │ SessionManager │ │ InformationItem │ │
|
||
│ │ +全局意图检测 │ │ +pause/resume │ │ Service (新增) │ │
|
||
│ │ │ │ +correct/suppl │ │ │ │
|
||
│ └──────┬───────┘ └────────┬─────────┘ └─────────┬──────────┘ │
|
||
│ │ │ │ │
|
||
│ ┌──────▼───────┐ ┌────────▼─────────┐ ┌────────▼──────────┐ │
|
||
│ │ DifyClient │ │ TimeoutCleaner │ │ ProgressPublisher │ │
|
||
│ │ +全局意图Prompt│ │ (新增, 24h扫描) │ │ +5种新WS事件 │ │
|
||
│ └──────────────┘ └──────────────────┘ └───────────────────┘ │
|
||
└──────────────────────────────┬──────────────────────────────────────┘
|
||
│
|
||
┌──────────┼──────────┐
|
||
▼ ▼ ▼
|
||
┌──────────┐ ┌────────┐ ┌────────┐
|
||
│PostgreSQL│ │ Redis │ │ Dify │
|
||
│+新表 │ │+恢复点 │ │ AI │
|
||
│auto_info │ │快照 │ │ │
|
||
└──────────┘ └────────┘ └────────┘
|
||
```
|
||
|
||
**TeliChat 三重约束在本阶段的映射**:
|
||
|
||
| 约束 | 原方案(Neo4j) | 本阶段方案(PG + Redis + 代码) |
|
||
|------|----------------|-------------------------------|
|
||
| **拓扑结构限制** | Neo4j DAG 边定义 | `ScenarioConfig.actions` 有序列表 + `ActionExecutor.run()` 顺序遍历 + `action.status` 跳过已完成动作 |
|
||
| **信息状态约束** | 信息项组合状态(图节点) | `auto_information_items` 表:`is_filled` + `modifiers`(`必需`修饰符控制流程阻塞) |
|
||
| **Python 代码约束** | FastAPI 业务逻辑 | `SessionManager` 中的 `pause/resume/correct/supplement` 方法 + `InformationItemService` 的更正锁定逻辑 |
|
||
|
||
### 1.3 复用现有代码的策略
|
||
|
||
| 现有模块 | 复用方式 | 变更要点 |
|
||
|---------|---------|---------|
|
||
| `IntentRouter` | 保留原有 `detect()` 方法,新增 `detect_global_intent()` 前置调用 | 在 `detect()` 内部先调全局意图检测,命中则返回全局意图,未命中则走原场景识别 |
|
||
| `DifyClient` (core/clients) | 扩展 `_SYSTEM_PROMPT` 增加全局意图判断指令 | Prompt 中新增 PAUSE/RESUME_TASK/CORRECT/SUPPLEMENT 的判断逻辑和输出格式 |
|
||
| `AutoSessionService` | 保留原有编排流程,新增暂停/恢复/更正/补充方法 | `start()` 方法中编排前先检查全局意图;新增 `pause_session()` / `resume_session()` 等 |
|
||
| `ActionExecutor` | 保留原有 `run()` / `resume()`,`run()` 支持从指定动作续行 | `run()` 已有跳过已完成动作的逻辑(`action.status in ("success","failed","rejected","skipped")` → continue),恢复时直接调用即可 |
|
||
| `progress_publisher` | 保留现有推送机制,新增 5 种事件 publish 函数 | 新增 `publish_paused()` / `publish_resumed()` / `publish_timeout_closed()` / `publish_info_corrected()` / `publish_info_supplemented()` |
|
||
| `constants.py` | 新增全局意图常量、WS 事件名、超时配置 | 不修改现有常量,仅追加 |
|
||
| WS 前端 store | H5/Agent 的 `automation.ts` store 保留现有 WS 连接逻辑,扩展事件处理 | `handleWsMessage()` 中新增 5 种事件 case |
|
||
|
||
### 1.4 新增模块与现有模块的关系
|
||
|
||
```
|
||
现有模块 新增模块
|
||
───────── ─────────
|
||
IntentRouter ──────扩展───────> GlobalIntentDetector (内嵌)
|
||
│ ├─ PAUSE / RESUME_TASK / CORRECT / SUPPLEMENT
|
||
│ └─ 关键词兜底扩展
|
||
│
|
||
AutoSessionService ───扩展──────> pause_session() / resume_session()
|
||
│ ├─ correct_info() / supplement_info()
|
||
│ └─ list_paused_sessions()
|
||
│
|
||
ActionExecutor ─────复用────────> run() 续行(无需修改)
|
||
│
|
||
progress_publisher ──扩展──────> 5种新WS事件 publish 函数
|
||
│
|
||
(无) ──────────────新增────────> InformationItemService
|
||
│ ├─ create / update / correct / supplement
|
||
│ └─ check_downstream_impact()
|
||
│
|
||
(无) ──────────────新增────────> TimeoutCleaner (定时任务)
|
||
└─ 扫描 paused 会话,24h超时关闭
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 文件列表及相对路径
|
||
|
||
### 2.1 后端新增文件
|
||
|
||
| # | 文件路径 | 说明 |
|
||
|---|---------|------|
|
||
| 1 | `backend/app/services/automation/information_item_service.py` | 信息项管理服务(CRUD + 更正 + 补充 + 下游影响检测) |
|
||
| 2 | `backend/app/services/automation/timeout_cleaner.py` | 暂停超时清理定时任务(24h 扫描 + 自动关闭 + 通知) |
|
||
| 3 | `backend/alembic/versions/xxxx_add_information_items.py` | 数据库迁移:新建 `auto_information_items` 表 + `auto_sessions` 新增 `paused_at` 字段 |
|
||
|
||
### 2.2 后端修改文件
|
||
|
||
| # | 文件路径 | 修改要点 |
|
||
|---|---------|---------|
|
||
| 4 | `backend/app/models/automation.py` | 新增 `InformationItem` 模型;`AutoSession` 新增 `paused_at` 字段 |
|
||
| 5 | `backend/app/schemas/automation.py` | 新增 `PauseRequest` / `ResumeRequest` / `CorrectRequest` / `SupplementRequest` / `InformationItemResponse` / `ResumePointResponse` 等 Schema |
|
||
| 6 | `backend/app/constants.py` | 新增全局意图常量(`GLOBAL_INTENT_*`)、WS 事件名(`AUTOMATION_WS_PAUSED` 等)、超时配置(`PAUSE_TIMEOUT_HOURS = 24`)、Redis key 前缀 |
|
||
| 7 | `backend/app/services/automation/intent_router.py` | 新增 `detect_global_intent()` 方法;`detect()` 内前置全局意图检测;扩展关键词兜底 |
|
||
| 8 | `backend/app/core/clients/dify.py` | 扩展 `_SYSTEM_PROMPT` 增加全局意图判断;`detect_intent()` 返回新增 `global_intent` 字段 |
|
||
| 9 | `backend/app/services/automation/session_manager.py` | 新增 `pause_session()` / `resume_session()` / `list_paused_sessions()` / `correct_info()` / `supplement_info()` / `agent_resume()` / `agent_close()` 方法 |
|
||
| 10 | `backend/app/services/automation/progress_publisher.py` | 新增 `publish_paused()` / `publish_resumed()` / `publish_timeout_closed()` / `publish_info_corrected()` / `publish_info_supplemented()` |
|
||
| 11 | `backend/app/services/automation/__init__.py` | 导出新增的 `InformationItemService` / `TimeoutCleaner` |
|
||
| 12 | `backend/app/api/automation.py` | 新增 REST 端点:`/pause` `/resume` `/correct` `/supplement` `/info-items` `/paused` `/agent-resume` `/agent-close` |
|
||
|
||
### 2.3 前端 H5 端修改文件
|
||
|
||
| # | 文件路径 | 修改要点 |
|
||
|---|---------|---------|
|
||
| 13 | `frontend-h5/src/api/automation.ts` | 新增 API 调用函数:`pauseSession` / `resumeSession` / `listPausedSessions` / `correctInfo` / `supplementInfo` / `getInfoItems` |
|
||
| 14 | `frontend-h5/src/stores/automation.ts` | WS 事件处理扩展:`automation.paused` / `automation.resumed` / `automation.info_corrected` / `automation.info_supplemented` / `automation.timeout_closed`;新增暂停会话列表状态 |
|
||
| 15 | `frontend-h5/src/views/AutomationProgress.vue` | 新增暂停状态展示、恢复点卡片、多任务选择列表、更正/补充确认消息、信息面板折叠区 |
|
||
|
||
### 2.4 前端坐席端修改文件
|
||
|
||
| # | 文件路径 | 修改要点 |
|
||
|---|---------|---------|
|
||
| 16 | `frontend-agent/src/api/automation.ts` | 新增 API 调用函数:`listPausedSessions` / `agentResume` / `agentClose` / `getInfoItems` |
|
||
| 17 | `frontend-agent/src/stores/automation.ts` | WS 事件处理扩展(同 H5 端);新增暂停会话列表状态 |
|
||
| 18 | `frontend-agent/src/views/automation/SessionWorkbench.vue` | 新增暂停状态展示、恢复点信息、信息项面板、坐席代恢复/关闭按钮 |
|
||
| 19 | `frontend-agent/src/components/automation/InformationItemPanel.vue` | **新增**:信息项折叠面板组件(展示名称/值/版本/修饰符/变更历史) |
|
||
|
||
### 2.5 文件按实现顺序排列
|
||
|
||
```
|
||
第1层(数据基础):
|
||
① models/automation.py → ② schemas/automation.py → ③ constants.py → ④ alembic迁移
|
||
|
||
第2层(服务层):
|
||
⑤ intent_router.py → ⑥ core/clients/dify.py → ⑦ information_item_service.py
|
||
⑧ session_manager.py → ⑨ progress_publisher.py → ⑩ timeout_cleaner.py
|
||
⑪ __init__.py
|
||
|
||
第3层(API路由):
|
||
⑫ api/automation.py
|
||
|
||
第4层(前端H5):
|
||
⑬ api/automation.ts → ⑭ stores/automation.ts → ⑮ AutomationProgress.vue
|
||
|
||
第5层(前端坐席):
|
||
⑯ api/automation.ts → ⑰ stores/automation.ts → ⑱ SessionWorkbench.vue → ⑲ InformationItemPanel.vue
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 数据结构和接口(类图)
|
||
|
||
### 3.1 新增 PostgreSQL 表结构
|
||
|
||
#### 3.1.1 `auto_information_items` 表 DDL
|
||
|
||
```sql
|
||
CREATE TABLE auto_information_items (
|
||
id VARCHAR(36) PRIMARY KEY,
|
||
session_id VARCHAR(36) NOT NULL,
|
||
name VARCHAR(128) NOT NULL,
|
||
value TEXT NOT NULL DEFAULT '',
|
||
modifiers JSON NOT NULL DEFAULT '[]',
|
||
is_filled BOOLEAN NOT NULL DEFAULT FALSE,
|
||
is_locked BOOLEAN NOT NULL DEFAULT FALSE,
|
||
version INTEGER NOT NULL DEFAULT 1,
|
||
update_history JSON NOT NULL DEFAULT '[]',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX idx_info_items_session_id ON auto_information_items(session_id);
|
||
CREATE INDEX idx_info_items_session_name ON auto_information_items(session_id, name);
|
||
```
|
||
|
||
**字段说明**:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | VARCHAR(36) PK | UUID 主键 |
|
||
| `session_id` | VARCHAR(36) | 关联 `auto_sessions.id`(弱关联,不建外键) |
|
||
| `name` | VARCHAR(128) | 信息项名称(如"用户名"、"终端ID"、"部门") |
|
||
| `value` | TEXT | 当前值 |
|
||
| `modifiers` | JSON | 修饰符列表,如 `["固定","必需"]` |
|
||
| `is_filled` | BOOLEAN | 是否已填写 |
|
||
| `is_locked` | BOOLEAN | 是否已锁定(`固定`修饰符 + 关联动作已执行 → True,不可更正) |
|
||
| `version` | INTEGER | 版本号,每次更正/补充 +1 |
|
||
| `update_history` | JSON | 变更历史数组:`[{version, old_value, new_value, action, timestamp}]` |
|
||
| `created_at` | TIMESTAMPTZ | 创建时间 |
|
||
| `updated_at` | TIMESTAMPTZ | 最后更新时间 |
|
||
|
||
#### 3.1.2 `auto_sessions` 表变更
|
||
|
||
```sql
|
||
ALTER TABLE auto_sessions ADD COLUMN paused_at TIMESTAMPTZ;
|
||
```
|
||
|
||
**新增字段说明**:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `paused_at` | TIMESTAMPTZ | 暂停时间戳,用于超时计算;恢复后置 NULL |
|
||
|
||
### 3.2 新增/修改的 Pydantic Schema
|
||
|
||
```python
|
||
# --- 全局意图识别结果(扩展 IntentResult) ---
|
||
class GlobalIntentResult(BaseModel):
|
||
"""全局意图识别结果。"""
|
||
global_intent: Optional[str] = None # pause / resume_task / correct / supplement / null
|
||
scenario_key: Optional[str] = None # 未命中全局意图时走场景识别
|
||
confidence: float = 0.0
|
||
corrected_field: Optional[str] = None # CORRECT: 更正的字段名
|
||
old_value: Optional[str] = None # CORRECT: 旧值
|
||
new_value: Optional[str] = None # CORRECT: 新值
|
||
supplement_field: Optional[str] = None # SUPPLEMENT: 补充的字段名
|
||
supplement_value: Optional[str] = None # SUPPLEMENT: 补充的值
|
||
raw: str = ""
|
||
error: str = ""
|
||
|
||
# --- 请求模型 ---
|
||
class PauseRequest(BaseModel):
|
||
"""暂停会话请求(通常由意图识别触发,也可直接调用)。"""
|
||
reason: Optional[str] = None
|
||
|
||
class ResumeRequest(BaseModel):
|
||
"""恢复会话请求。"""
|
||
session_id: Optional[str] = None # 多任务时指定恢复哪个;None 则自动选择唯一的
|
||
|
||
class CorrectRequest(BaseModel):
|
||
"""信息更正请求。"""
|
||
field: str = Field(..., description="更正的字段名")
|
||
new_value: str = Field(..., description="新值")
|
||
old_value: Optional[str] = None
|
||
|
||
class SupplementRequest(BaseModel):
|
||
"""信息补充请求。"""
|
||
field: str = Field(..., description="补充的字段名")
|
||
value: str = Field(..., description="补充的值")
|
||
|
||
class AgentResumeRequest(BaseModel):
|
||
"""坐席代恢复请求。"""
|
||
note: Optional[str] = None
|
||
|
||
class AgentCloseRequest(BaseModel):
|
||
"""坐席关闭会话请求。"""
|
||
note: Optional[str] = None
|
||
|
||
# --- 响应模型 ---
|
||
class InformationItemResponse(BaseModel):
|
||
"""信息项响应。"""
|
||
id: str
|
||
session_id: str
|
||
name: str
|
||
value: str
|
||
modifiers: List[str] = Field(default_factory=list)
|
||
is_filled: bool
|
||
is_locked: bool
|
||
version: int
|
||
update_history: List[dict] = Field(default_factory=list)
|
||
updated_at: Optional[str] = None
|
||
|
||
class ResumePointResponse(BaseModel):
|
||
"""恢复点响应。"""
|
||
session_id: str
|
||
title: str
|
||
scenario_key: Optional[str] = None
|
||
current_step: str
|
||
paused_at: Optional[str] = None
|
||
pending_items: List[str] = Field(default_factory=list)
|
||
info_items: List[InformationItemResponse] = Field(default_factory=list)
|
||
|
||
class PausedSessionItem(BaseModel):
|
||
"""暂停会话列表项。"""
|
||
session_id: str
|
||
title: str
|
||
scenario_key: Optional[str] = None
|
||
paused_at: Optional[str] = None
|
||
paused_duration: str = "" # 如 "2h 15min"
|
||
```
|
||
|
||
### 3.3 类图(Mermaid)
|
||
|
||
> 完整类图见 `docs/03-技术架构/复杂场景重构-类图.mermaid`
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class AutoSession {
|
||
+String id
|
||
+String employee_id
|
||
+String scenario_key
|
||
+String status
|
||
+String current_action_id
|
||
+String title
|
||
+DateTime paused_at
|
||
+JSON meta
|
||
+DateTime created_at
|
||
}
|
||
|
||
class InformationItem {
|
||
+String id
|
||
+String session_id
|
||
+String name
|
||
+String value
|
||
+JSON modifiers
|
||
+Boolean is_filled
|
||
+Boolean is_locked
|
||
+Integer version
|
||
+JSON update_history
|
||
+DateTime updated_at
|
||
}
|
||
|
||
class IntentRouter {
|
||
+detect(description, employee_id) Dict
|
||
+detect_global_intent(text) Dict
|
||
-_keyword_fallback_global(text) Dict
|
||
}
|
||
|
||
class DifyClient {
|
||
+detect_intent(description, employee_id) Dict
|
||
-_parse_global_intent(answer) Dict
|
||
-_fallback_global_intent(text) Dict
|
||
}
|
||
|
||
class AutoSessionService {
|
||
+start(session_id) void
|
||
+pause_session(session_id, reason) AutoSession
|
||
+resume_session(session_id, employee_id) AutoSession
|
||
+list_paused_sessions(employee_id) List
|
||
+correct_info(session_id, field, new_value) InformationItem
|
||
+supplement_info(session_id, field, value) InformationItem
|
||
+agent_resume(session_id, agent_id) AutoSession
|
||
+agent_close(session_id, agent_id) AutoSession
|
||
}
|
||
|
||
class InformationItemService {
|
||
+create_item(session_id, name, value, modifiers) InformationItem
|
||
+get_items(session_id) List
|
||
+get_item(session_id, name) InformationItem
|
||
+correct_value(session_id, name, new_value) InformationItem
|
||
+supplement_value(session_id, name, value) InformationItem
|
||
+lock_items(session_id, action_id) void
|
||
+check_downstream_impact(session_id, field) bool
|
||
}
|
||
|
||
class TimeoutCleaner {
|
||
+run_scheduled() void
|
||
-_scan_and_close() void
|
||
-_notify_timeout(session_id) void
|
||
}
|
||
|
||
class ProgressPublisher {
|
||
+publish_paused(session_id, data) void
|
||
+publish_resumed(session_id, data) void
|
||
+publish_timeout_closed(session_id, data) void
|
||
+publish_info_corrected(session_id, data) void
|
||
+publish_info_supplemented(session_id, data) void
|
||
}
|
||
|
||
AutoSession "1" --> "*" InformationItem : session_id
|
||
AutoSessionService --> AutoSession : manages
|
||
AutoSessionService --> InformationItemService : delegates
|
||
IntentRouter --> DifyClient : uses
|
||
AutoSessionService --> IntentRouter : uses
|
||
TimeoutCleaner --> AutoSessionService : calls auto_close
|
||
ProgressPublisher --> AutoSession : pushes events
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 程序调用流程(时序图)
|
||
|
||
> 完整时序图见 `docs/03-技术架构/复杂场景重构-时序图.mermaid`
|
||
|
||
### 4.1 任务暂停流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant H5 as 员工H5
|
||
participant API as FastAPI路由
|
||
participant SM as AutoSessionService
|
||
participant IR as IntentRouter
|
||
participant DB as PostgreSQL
|
||
participant Redis as Redis
|
||
participant WS as ProgressPublisher
|
||
|
||
H5->>API: POST /sessions/{id}/pause {reason}
|
||
API->>SM: pause_session(session_id, reason)
|
||
SM->>DB: SELECT AutoSession WHERE id = ?
|
||
SM->>SM: 校验状态 (running → paused)
|
||
SM->>DB: UPDATE status='paused', paused_at=NOW()
|
||
SM->>SM: 构建恢复点快照
|
||
Note over SM: 快照内容: title, scenario_key,<br/>current_action_id, step_desc,<br/>info_items 快照, paused_at
|
||
SM->>Redis: SET auto:resume_point:{id} = {snapshot} TTL=25h
|
||
SM->>Redis: SADD auto:paused_sessions:{emp_id} = {id}
|
||
SM->>WS: publish_paused(id, {title, paused_at, resume_hint})
|
||
WS->>H5: automation.paused 事件
|
||
SM-->>API: 返回 AutoSession
|
||
API-->>H5: {code:0, data:session}
|
||
H5->>H5: 展示暂停确认消息
|
||
```
|
||
|
||
### 4.2 任务恢复流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant H5 as 员工H5
|
||
participant API as FastAPI路由
|
||
participant SM as AutoSessionService
|
||
participant IR as IntentRouter
|
||
participant Redis as Redis
|
||
participant DB as PostgreSQL
|
||
participant Exec as ActionExecutor
|
||
participant WS as ProgressPublisher
|
||
|
||
H5->>API: POST /sessions/resume {session_id?}
|
||
API->>SM: resume_session(employee_id, session_id?)
|
||
alt session_id 未指定
|
||
SM->>DB: SELECT * FROM auto_sessions WHERE employee_id=? AND status='paused'
|
||
alt 多个暂停会话
|
||
SM-->>API: 返回暂停会话列表
|
||
API-->>H5: 返回多任务选择卡片
|
||
H5->>API: POST /sessions/{selected_id}/resume
|
||
API->>SM: resume_session(employee_id, selected_id)
|
||
end
|
||
end
|
||
SM->>Redis: GET auto:resume_point:{id}
|
||
SM->>SM: 加载恢复点快照
|
||
SM->>DB: UPDATE status='running', paused_at=NULL
|
||
SM->>Redis: SREM auto:paused_sessions:{emp_id} {id}
|
||
SM->>Redis: DEL auto:resume_point:{id}
|
||
SM->>SM: 检查必需信息项完整性
|
||
alt 有缺失必需项
|
||
SM-->>API: 返回需补全的信息项
|
||
API-->>H5: 提示补全缺失项
|
||
else 信息完整
|
||
SM->>Exec: run(session_id) 续行
|
||
Note over Exec: 跳过已完成的动作<br/>从 current_action_id 继续执行
|
||
end
|
||
SM->>WS: publish_resumed(id, {title, current_step})
|
||
WS->>H5: automation.resumed 事件
|
||
SM-->>API: 返回 AutoSession + 恢复点信息
|
||
API-->>H5: {code:0, data:{session, resume_point}}
|
||
H5->>H5: 展示恢复点回顾卡片
|
||
```
|
||
|
||
### 4.3 信息更正流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant H5 as 员工H5
|
||
participant API as FastAPI路由
|
||
participant SM as AutoSessionService
|
||
participant IIS as InformationItemService
|
||
participant DB as PostgreSQL
|
||
participant WS as ProgressPublisher
|
||
|
||
H5->>API: POST /sessions/{id}/correct {field, new_value, old_value?}
|
||
API->>SM: correct_info(session_id, field, new_value)
|
||
SM->>IIS: correct_value(session_id, field, new_value)
|
||
IIS->>DB: SELECT InformationItem WHERE session_id=? AND name=?
|
||
alt is_locked == True
|
||
IIS-->>SM: 抛出异常 "该字段已锁定,不可更正"
|
||
SM-->>API: 错误响应
|
||
API-->>H5: {code:4013, message:"字段已锁定"}
|
||
else is_locked == False
|
||
IIS->>IIS: 旧值存入 update_history
|
||
IIS->>IIS: value = new_value, version += 1
|
||
IIS->>DB: UPDATE InformationItem
|
||
IIS->>IIS: check_downstream_impact(session_id, field)
|
||
alt 影响已生成动作计划
|
||
IIS-->>SM: impact=True
|
||
SM->>SM: 重新校验映射/动作计划
|
||
SM-->>API: 返回更正结果 + 影响提示
|
||
else 无下游影响
|
||
IIS-->>SM: impact=False
|
||
end
|
||
SM->>WS: publish_info_corrected(id, {field, old_value, new_value, version})
|
||
WS->>H5: automation.info_corrected 事件
|
||
SM-->>API: 返回 InformationItem
|
||
API-->>H5: {code:0, data:item}
|
||
H5->>H5: 展示更正确认消息(旧值→新值)
|
||
end
|
||
```
|
||
|
||
### 4.4 信息补充流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant H5 as 员工H5
|
||
participant API as FastAPI路由
|
||
participant SM as AutoSessionService
|
||
participant IIS as InformationItemService
|
||
participant DB as PostgreSQL
|
||
participant WS as ProgressPublisher
|
||
|
||
H5->>API: POST /sessions/{id}/supplement {field, value}
|
||
API->>SM: supplement_info(session_id, field, value)
|
||
SM->>IIS: supplement_value(session_id, field, value)
|
||
IIS->>DB: SELECT InformationItem WHERE session_id=? AND name=?
|
||
alt 信息项不存在
|
||
IIS->>IIS: 创建新信息项 (modifiers=["增量"])
|
||
IIS->>DB: INSERT InformationItem
|
||
else 信息项已存在
|
||
alt modifiers 含 "增量"
|
||
IIS->>IIS: value += "; " + new_value (追加)
|
||
else 不含 "增量"
|
||
IIS->>IIS: 同更正处理(旧值存历史,覆盖)
|
||
end
|
||
IIS->>IIS: version += 1, update_history 追加记录
|
||
IIS->>DB: UPDATE InformationItem
|
||
end
|
||
SM->>WS: publish_info_supplemented(id, {field, supplement_value, new_value})
|
||
WS->>H5: automation.info_supplemented 事件
|
||
SM-->>API: 返回 InformationItem
|
||
API-->>H5: {code:0, data:item}
|
||
H5->>H5: 展示补充确认消息
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 任务列表
|
||
|
||
> **工程师按此顺序实现**,每个任务的依赖关系已标注。
|
||
|
||
### T01: 后端数据层基础 — 模型 + Schema + 常量 + 迁移
|
||
|
||
| 项目 | 内容 |
|
||
|------|------|
|
||
| **任务编号** | T01 |
|
||
| **任务名称** | 后端数据层基础:新增 InformationItem 模型、扩展 Schema、扩展常量、数据库迁移 |
|
||
| **涉及文件** | `backend/app/models/automation.py`(修改)<br>`backend/app/schemas/automation.py`(修改)<br>`backend/app/constants.py`(修改)<br>`backend/alembic/versions/xxxx_add_information_items.py`(新增) |
|
||
| **依赖关系** | 无(第一个任务) |
|
||
| **优先级** | P0 |
|
||
| **复杂度** | 中等 |
|
||
|
||
**实现要点**:
|
||
|
||
1. **`models/automation.py`**:
|
||
- 新增 `InformationItem` 类(对应 `auto_information_items` 表),字段见 §3.1.1
|
||
- `AutoSession` 类新增 `paused_at` 字段:`paused_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)`
|
||
|
||
2. **`schemas/automation.py`**:
|
||
- 新增 §3.2 中列出的全部 Schema(`GlobalIntentResult` / `PauseRequest` / `ResumeRequest` / `CorrectRequest` / `SupplementRequest` / `AgentResumeRequest` / `AgentCloseRequest` / `InformationItemResponse` / `ResumePointResponse` / `PausedSessionItem`)
|
||
- 新增 `serialize_information_item(item)` 序列化辅助函数
|
||
- `SessionResponse` 新增 `paused_at: Optional[str]` 字段
|
||
|
||
3. **`constants.py`**:
|
||
- 新增全局意图常量:
|
||
```python
|
||
GLOBAL_INTENT_PAUSE = "pause"
|
||
GLOBAL_INTENT_RESUME_TASK = "resume_task"
|
||
GLOBAL_INTENT_CORRECT = "correct"
|
||
GLOBAL_INTENT_SUPPLEMENT = "supplement"
|
||
GLOBAL_INTENT_NONE = None
|
||
```
|
||
- 新增 WS 事件名:
|
||
```python
|
||
AUTOMATION_WS_PAUSED = "automation.paused"
|
||
AUTOMATION_WS_RESUMED = "automation.resumed"
|
||
AUTOMATION_WS_TIMEOUT_CLOSED = "automation.timeout_closed"
|
||
AUTOMATION_WS_INFO_CORRECTED = "automation.info_corrected"
|
||
AUTOMATION_WS_INFO_SUPPLEMENTED = "automation.info_supplemented"
|
||
```
|
||
- 新增超时配置:
|
||
```python
|
||
PAUSE_TIMEOUT_HOURS = 24
|
||
PAUSE_TIMEOUT_SECONDS = 24 * 3600
|
||
RESUME_POINT_REDIS_TTL = 25 * 3600 # 恢复点 Redis TTL(25小时,比超时多1小时兜底)
|
||
```
|
||
- 新增 Redis key 前缀:
|
||
```python
|
||
REDIS_KEY_RESUME_POINT = "auto:resume_point:{session_id}"
|
||
REDIS_KEY_PAUSED_SESSIONS = "auto:paused_sessions:{employee_id}"
|
||
```
|
||
- 新增全局意图关键词:
|
||
```python
|
||
GLOBAL_INTENT_KEYWORDS = {
|
||
"pause": ["先去开会", "等会继续", "先处理别的", "暂停", "我去忙一下", "晚点再说"],
|
||
"resume_task": ["继续", "继续刚才", "好了继续吧", "接着来", "恢复", "回来了"],
|
||
"correct": ["刚才说错了", "不是", "应该是", "更正", "说错了"],
|
||
"supplement": ["再补充一下", "顺便说一下", "还有", "对了补充", "另外"],
|
||
}
|
||
```
|
||
- 新增错误码:
|
||
```python
|
||
AutomationErrorCode.SESSION_NOT_PAUSABLE = 4013 # 会话不可暂停(终态)
|
||
AutomationErrorCode.SESSION_NOT_RESUMABLE = 4014 # 会话不可恢复(已关闭/超时)
|
||
AutomationErrorCode.INFO_ITEM_LOCKED = 4015 # 信息项已锁定
|
||
AutomationErrorCode.MULTIPLE_PAUSED_SESSIONS = 4016 # 多个暂停会话需选择
|
||
```
|
||
|
||
4. **Alembic 迁移脚本**:
|
||
- 新建 `auto_information_items` 表(DDL 见 §3.1.1)
|
||
- `auto_sessions` 表新增 `paused_at` 列
|
||
- 索引:`idx_info_items_session_id`、`idx_info_items_session_name`
|
||
|
||
---
|
||
|
||
### T02: 后端服务层(一)— 全局意图识别扩展 + 信息项管理服务
|
||
|
||
| 项目 | 内容 |
|
||
|------|------|
|
||
| **任务编号** | T02 |
|
||
| **任务名称** | 全局意图识别扩展(IntentRouter + DifyClient)+ InformationItemService 新增 |
|
||
| **涉及文件** | `backend/app/services/automation/intent_router.py`(修改)<br>`backend/app/core/clients/dify.py`(修改)<br>`backend/app/services/automation/information_item_service.py`(新增) |
|
||
| **依赖关系** | T01 |
|
||
| **优先级** | P0 |
|
||
| **复杂度** | 复杂 |
|
||
|
||
**实现要点**:
|
||
|
||
1. **`intent_router.py` 扩展**:
|
||
- 新增 `detect_global_intent(text: str) -> Dict[str, Any]` 方法:
|
||
- 优先调用 Dify(复用现有客户端),Prompt 中增加全局意图判断
|
||
- Dify 不可用时走关键词兜底(使用 `GLOBAL_INTENT_KEYWORDS`)
|
||
- 返回 `{global_intent, corrected_field, old_value, new_value, supplement_field, supplement_value, confidence}`
|
||
- 修改 `detect(description, employee_id)` 方法:
|
||
- 先调 `detect_global_intent(description)`
|
||
- 若 `global_intent` 非 None → 返回全局意图结果(跳过场景识别)
|
||
- 若 `global_intent` 为 None → 走原有场景识别流程
|
||
- 输出格式在原有 `{scenario_key, confidence, raw, error}` 基础上新增 `global_intent` 字段(值为 `pause` / `resume_task` / `correct` / `supplement` / `null`)
|
||
|
||
2. **`core/clients/dify.py` 扩展**:
|
||
- `_SYSTEM_PROMPT` 扩展:在现有 4 场景分类基础上,增加全局对话控制意图判断指令
|
||
- Prompt 要求模型输出格式扩展为:
|
||
```json
|
||
{
|
||
"global_intent": "pause|resume_task|correct|supplement|null",
|
||
"scenario_key": "password_reset|software_install|virus_dispose|terminal_locate|unknown",
|
||
"confidence": 0.0~1.0,
|
||
"corrected_field": "字段名(仅correct时)",
|
||
"old_value": "旧值(仅correct时)",
|
||
"new_value": "新值(仅correct时)",
|
||
"supplement_field": "字段名(仅supplement时)",
|
||
"supplement_value": "补充值(仅supplement时)"
|
||
}
|
||
```
|
||
- `_parse_intent()` 扩展解析 `global_intent` 及更正/补充字段
|
||
- `_fallback_intent()` 扩展:调用 `GLOBAL_INTENT_KEYWORDS` 做关键词匹配
|
||
- 关键词兜底扩展:PAUSE/RESUME_TASK/CORRECT/SUPPLEMENT 关键词匹配
|
||
|
||
3. **`information_item_service.py` 新增**:
|
||
- `InformationItemService` 类,方法签名:
|
||
```python
|
||
class InformationItemService:
|
||
def __init__(self, db: AsyncSession, redis=None)
|
||
async def create_item(session_id, name, value, modifiers) -> InformationItem
|
||
async def get_items(session_id) -> List[InformationItem]
|
||
async def get_item(session_id, name) -> Optional[InformationItem]
|
||
async def correct_value(session_id, name, new_value, old_value=None) -> InformationItem
|
||
async def supplement_value(session_id, name, value) -> InformationItem
|
||
async def lock_items_for_action(session_id, action_id) -> None # 动作执行后锁定关联信息项
|
||
async def check_downstream_impact(session_id, field_name) -> bool # 检查更正是否影响已生成动作
|
||
async def get_pending_required_items(session_id) -> List[str] # 获取未填写的必需信息项
|
||
```
|
||
- `correct_value()` 逻辑:
|
||
- 检查 `is_locked`,若 True → 抛出 `InfoItemLocked` 异常
|
||
- 旧值存入 `update_history`:`{version, old_value, new_value, action: "correct", timestamp}`
|
||
- `value = new_value`,`version += 1`,`is_filled = True`
|
||
- 若 modifiers 含 `复述` → 返回需确认标记(由调用方处理确认消息)
|
||
- `supplement_value()` 逻辑:
|
||
- 若信息项不存在 → 创建新项(modifiers 默认 `["增量"]`)
|
||
- 若 modifiers 含 `增量` → `value = value + "; " + new_value`(追加)
|
||
- 否则同 correct 处理(覆盖)
|
||
- `version += 1`,`update_history` 追加记录
|
||
- `lock_items_for_action()` 逻辑:
|
||
- 查找与该 action 关联的信息项(通过 `action.payload` 中的参数名匹配)
|
||
- 对含 `固定` 修饰符的信息项设置 `is_locked = True`
|
||
- `check_downstream_impact()` 逻辑:
|
||
- 查询 `auto_actions` 表中 `status in ('pending', 'await_approval')` 的动作
|
||
- 检查动作 `payload` 是否引用了被更正的字段
|
||
- 返回 True/False
|
||
|
||
---
|
||
|
||
### T03: 后端服务层(二)— 暂停/恢复/更正/补充编排 + WS事件 + 超时清理
|
||
|
||
| 项目 | 内容 |
|
||
|------|------|
|
||
| **任务编号** | T03 |
|
||
| **任务名称** | SessionManager 暂停/恢复/更正/补充编排逻辑 + ProgressPublisher 新WS事件 + TimeoutCleaner 定时任务 |
|
||
| **涉及文件** | `backend/app/services/automation/session_manager.py`(修改)<br>`backend/app/services/automation/progress_publisher.py`(修改)<br>`backend/app/services/automation/timeout_cleaner.py`(新增)<br>`backend/app/services/automation/__init__.py`(修改) |
|
||
| **依赖关系** | T01, T02 |
|
||
| **优先级** | P0 |
|
||
| **复杂度** | 复杂 |
|
||
|
||
**实现要点**:
|
||
|
||
1. **`session_manager.py` 扩展**:
|
||
- 新增 `pause_session(session_id, reason=None) -> AutoSession`:
|
||
- 校验状态:`running` / `await_approval` → `paused`;终态不可暂停
|
||
- 设置 `status = "paused"`, `paused_at = datetime.now(timezone.utc)`
|
||
- 构建恢复点快照(title, scenario_key, current_action_id, step_desc, info_items 快照, paused_at)
|
||
- Redis: `SET auto:resume_point:{id}` + `SADD auto:paused_sessions:{emp_id}`
|
||
- 调用 `publish_paused()`
|
||
- 若 `await_approval` 状态暂停 → 同时挂起审批计时(记录到 meta)
|
||
- 新增 `resume_session(employee_id, session_id=None) -> dict`:
|
||
- 若 `session_id` 为 None → 查询 `list_paused_sessions(employee_id)`
|
||
- 若多个暂停会话 → 返回列表供前端选择(不直接恢复)
|
||
- 若单个 → 直接恢复
|
||
- 恢复逻辑:从 Redis 加载恢复点 → `status = "running"`, `paused_at = None` → Redis 清理 → 检查必需信息项 → 调用 `ActionExecutor.run()` 续行
|
||
- 调用 `publish_resumed()`
|
||
- 新增 `list_paused_sessions(employee_id) -> List[PausedSessionItem]`:
|
||
- 查询 `status = "paused"` 且 `employee_id` 匹配的会话
|
||
- 计算暂停时长(`paused_at` 与当前时间差)
|
||
- 新增 `correct_info(session_id, field, new_value, old_value=None) -> InformationItem`:
|
||
- 委托 `InformationItemService.correct_value()`
|
||
- 检查下游影响,若有影响则重新校验动作计划
|
||
- 调用 `publish_info_corrected()`
|
||
- 新增 `supplement_info(session_id, field, value) -> InformationItem`:
|
||
- 委托 `InformationItemService.supplement_value()`
|
||
- 调用 `publish_info_supplemented()`
|
||
- 新增 `agent_resume(session_id, agent_id, note=None) -> AutoSession`:
|
||
- 坐席代恢复(无需员工授权)
|
||
- `closed_by = "agent:{agent_id}(resume)"` 标记坐席代恢复
|
||
- 其余逻辑同 `resume_session()`
|
||
- 新增 `agent_close(session_id, agent_id, note=None) -> AutoSession`:
|
||
- 坐席手动关闭暂停会话
|
||
- `status = "closed"`, `closed_by = agent_id`
|
||
- Redis 清理恢复点
|
||
- 修改 `start()` 方法:
|
||
- 在意图识别后检查 `global_intent`
|
||
- 若为 `pause` → 调用 `pause_session()`
|
||
- 若为 `resume_task` → 调用 `resume_session()`
|
||
- 若为 `correct` → 调用 `correct_info()`
|
||
- 若为 `supplement` → 调用 `supplement_info()`
|
||
- 若为 None → 走原有编排流程
|
||
|
||
2. **`progress_publisher.py` 扩展**:
|
||
- 新增 5 个 publish 函数:
|
||
```python
|
||
async def publish_paused(session_id, title, paused_at, resume_hint) -> None
|
||
async def publish_resumed(session_id, title, resumed_at, current_step) -> None
|
||
async def publish_timeout_closed(session_id, closed_at, reason) -> None
|
||
async def publish_info_corrected(session_id, field, old_value, new_value, version) -> None
|
||
async def publish_info_supplemented(session_id, field, supplement_value, new_value) -> None
|
||
```
|
||
- 复用现有 `_publish()` 推送机制(专用 WS + 坐席/员工兜底 WS)
|
||
|
||
3. **`timeout_cleaner.py` 新增**:
|
||
- `TimeoutCleaner` 类:
|
||
```python
|
||
class TimeoutCleaner:
|
||
def __init__(self, db_factory, redis=None)
|
||
async def run_once() -> int # 执行一次扫描,返回关闭的会话数
|
||
async def run_scheduled(interval=3600) -> None # 每小时扫描一次
|
||
```
|
||
- `run_once()` 逻辑:
|
||
- 查询 `status = "paused"` 且 `paused_at < NOW() - INTERVAL '24 hours'` 的会话
|
||
- 对每个超时会话:`status = "closed"`, `closed_by = "system(timeout)"`
|
||
- Redis 清理恢复点和暂停会话集合
|
||
- 调用 `publish_timeout_closed()`
|
||
- 可通过 FastAPI `lifespan` 或 `asyncio.create_task` 启动定时任务
|
||
|
||
4. **`__init__.py` 扩展**:
|
||
- 导出 `InformationItemService` 和 `TimeoutCleaner`
|
||
- 更新 `__all__`
|
||
|
||
---
|
||
|
||
### T04: 后端 API 路由 + H5 员工端前端
|
||
|
||
| 项目 | 内容 |
|
||
|------|------|
|
||
| **任务编号** | T04 |
|
||
| **任务名称** | 后端新增 REST 端点 + H5 端 API/Store/页面改造 |
|
||
| **涉及文件** | `backend/app/api/automation.py`(修改)<br>`frontend-h5/src/api/automation.ts`(修改)<br>`frontend-h5/src/stores/automation.ts`(修改)<br>`frontend-h5/src/views/AutomationProgress.vue`(修改) |
|
||
| **依赖关系** | T01, T02, T03 |
|
||
| **优先级** | P0 |
|
||
| **复杂度** | 复杂 |
|
||
|
||
**实现要点**:
|
||
|
||
1. **`api/automation.py` 新增端点**:
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | `/sessions/{id}/pause` | 暂停会话(员工/坐席均可) |
|
||
| POST | `/sessions/resume` | 恢复会话(员工端,支持多任务选择) |
|
||
| POST | `/sessions/{id}/resume` | 恢复指定会话 |
|
||
| GET | `/sessions/paused` | 获取员工暂停会话列表 |
|
||
| POST | `/sessions/{id}/correct` | 信息更正 |
|
||
| POST | `/sessions/{id}/supplement` | 信息补充 |
|
||
| GET | `/sessions/{id}/info-items` | 获取信息项列表 |
|
||
| POST | `/sessions/{id}/agent-resume` | 坐席代恢复 |
|
||
| POST | `/sessions/{id}/agent-close` | 坐席关闭暂停会话 |
|
||
|
||
2. **H5 `api/automation.ts`**:
|
||
- 新增类型:`InformationItem` / `ResumePoint` / `PausedSession` / `CorrectPayload` / `SupplementPayload`
|
||
- 新增 API 函数:`pauseSession` / `resumeSession` / `listPausedSessions` / `correctInfo` / `supplementInfo` / `getInfoItems`
|
||
|
||
3. **H5 `stores/automation.ts`**:
|
||
- `handleWsMessage()` 新增 5 种事件处理:
|
||
- `automation.paused` → 设置暂停状态,展示暂停提示
|
||
- `automation.resumed` → 刷新会话详情,展示恢复点回顾
|
||
- `automation.info_corrected` → 追加更正确认消息到时间线
|
||
- `automation.info_supplemented` → 追加补充确认消息到时间线
|
||
- `automation.timeout_closed` → 展示超时关闭提示
|
||
- 新增状态:`pausedSessions`(暂停会话列表)、`resumePoint`(恢复点数据)、`infoItems`(信息项列表)
|
||
|
||
4. **H5 `AutomationProgress.vue`**:
|
||
- 暂停状态展示:`paused` 状态显示"已暂停"标签 + 暂停时长 + "继续处理"按钮
|
||
- 恢复点卡片:恢复时展示 Vant 卡片(标题 + 场景 + 暂停时间 + 当前进度 + 继续按钮)
|
||
- 多任务选择列表:多个暂停会话时展示 Vant Cell 列表(标题 + 暂停时间 + 场景图标),点击选择
|
||
- 更正确认消息:对话流中展示带"已更正"标签的系统消息(字段名 + 旧值→新值)
|
||
- 补充确认消息:对话流中展示带"已补充"标签的系统消息
|
||
- 信息面板:新增"已收集信息"折叠面板(Vant Collapse),展示信息项名称/值/状态
|
||
|
||
---
|
||
|
||
### T05: 坐席端前端 — 会话列表/详情增强 + 信息项面板
|
||
|
||
| 项目 | 内容 |
|
||
|------|------|
|
||
| **任务编号** | T05 |
|
||
| **任务名称** | 坐席端 API/Store/工作台增强 + 信息项面板组件 |
|
||
| **涉及文件** | `frontend-agent/src/api/automation.ts`(修改)<br>`frontend-agent/src/stores/automation.ts`(修改)<br>`frontend-agent/src/views/automation/SessionWorkbench.vue`(修改)<br>`frontend-agent/src/components/automation/InformationItemPanel.vue`(新增) |
|
||
| **依赖关系** | T01, T03, T04 |
|
||
| **优先级** | P1 |
|
||
| **复杂度** | 中等 |
|
||
|
||
**实现要点**:
|
||
|
||
1. **坐席端 `api/automation.ts`**:
|
||
- 新增 API 函数:`listPausedSessions` / `agentResume` / `agentClose` / `getInfoItems`
|
||
- 新增类型:`InformationItem` / `PausedSession`
|
||
|
||
2. **坐席端 `stores/automation.ts`**:
|
||
- WS 事件处理扩展(同 H5 端 5 种新事件)
|
||
- 新增状态:`pausedSessions` / `infoItems`
|
||
- 新增 action:`fetchPausedSessions` / `agentResume` / `agentClose` / `fetchInfoItems`
|
||
|
||
3. **坐席端 `SessionWorkbench.vue`**:
|
||
- 会话列表增加 `paused` 状态筛选选项
|
||
- paused 会话显示暂停时长(如"已暂停 2h 15min")
|
||
- 接近 24 小时的暂停会话显示橙色预警标记
|
||
- 会话详情页展示恢复点信息(暂停时间、当前步骤、已收集信息项)
|
||
- 会话时间线中展示更正/补充事件:`[信息更正] 用户名: zhangsan → lisi (v2)`
|
||
- 新增"恢复任务"按钮(坐席代恢复)和"关闭会话"按钮
|
||
- 恢复后标记"坐席代恢复"
|
||
|
||
4. **`InformationItemPanel.vue` 新增**:
|
||
- Element Plus 折叠面板(el-collapse)
|
||
- 展示所有信息项:名称、当前值、版本号、修饰符标签
|
||
- 点击信息项展开完整变更历史(版本号、旧值、新值、变更时间)
|
||
- 锁定状态标记(`is_locked = True` 的项显示锁图标)
|
||
|
||
---
|
||
|
||
## 6. 依赖包列表
|
||
|
||
### 6.1 后端新增 Python 包
|
||
|
||
本阶段**无需新增第三方 Python 包**。所有功能基于现有技术栈实现:
|
||
- FastAPI + SQLAlchemy 2.0 + PostgreSQL + Redis(已有)
|
||
- `apscheduler` 或 `asyncio.create_task`(定时任务,已有 asyncio 环境)
|
||
|
||
### 6.2 前端新增依赖
|
||
|
||
本阶段**无需新增前端依赖包**。所有 UI 组件基于现有库实现:
|
||
- H5 端:Vant 4(Collapse / Cell / Card / Tag 等组件已有)
|
||
- 坐席端:Element Plus(Collapse / Timeline / Tag / Button 等组件已有)
|
||
|
||
---
|
||
|
||
## 7. 共享知识(跨文件约定)
|
||
|
||
### 7.1 全局意图识别调用约定
|
||
|
||
```python
|
||
# 调用入口:IntentRouter.detect(description, employee_id)
|
||
# 返回格式:
|
||
{
|
||
"global_intent": "pause" | "resume_task" | "correct" | "supplement" | None,
|
||
"scenario_key": "password_reset" | "software_install" | "virus_dispose" | "terminal_locate" | None,
|
||
"confidence": 0.0~1.0,
|
||
"corrected_field": str | None, # 仅 correct 时有值
|
||
"old_value": str | None, # 仅 correct 时有值
|
||
"new_value": str | None, # 仅 correct 时有值
|
||
"supplement_field": str | None, # 仅 supplement 时有值
|
||
"supplement_value": str | None, # 仅 supplement 时有值
|
||
"raw": str,
|
||
"error": str
|
||
}
|
||
|
||
# 优先级:global_intent 非 None 时,scenario_key 可能为 None(不影响)
|
||
# global_intent 为 None 时,走原场景识别逻辑
|
||
```
|
||
|
||
### 7.2 InformationItem CRUD 约定
|
||
|
||
```python
|
||
# 创建信息项
|
||
InformationItemService.create_item(
|
||
session_id: str, # 关联会话ID
|
||
name: str, # 信息项名称
|
||
value: str, # 初始值
|
||
modifiers: List[str] # 修饰符列表,如 ["固定", "必需"]
|
||
) -> InformationItem
|
||
|
||
# 更正信息项(CORRECT 意图)
|
||
InformationItemService.correct_value(
|
||
session_id: str,
|
||
name: str, # 字段名
|
||
new_value: str, # 新值
|
||
old_value: str = None # 旧值(可选,Dify 提取时可能有)
|
||
) -> InformationItem
|
||
# 异常:is_locked=True 时抛出 AutomationErrorCode.INFO_ITEM_LOCKED
|
||
|
||
# 补充信息项(SUPPLEMENT 意图)
|
||
InformationItemService.supplement_value(
|
||
session_id: str,
|
||
name: str, # 字段名
|
||
value: str # 补充值
|
||
) -> InformationItem
|
||
# 逻辑:modifiers 含 "增量" → 追加;否则同 correct 覆盖
|
||
|
||
# 锁定信息项(动作执行后调用)
|
||
InformationItemService.lock_items_for_action(
|
||
session_id: str,
|
||
action_id: str # 关联动作ID
|
||
) -> None
|
||
# 逻辑:查找 action.payload 引用的信息项,对含 "固定" 修饰符的设置 is_locked=True
|
||
```
|
||
|
||
### 7.3 Redis key 命名约定
|
||
|
||
```
|
||
# 恢复点快照(JSON,TTL 25h)
|
||
auto:resume_point:{session_id}
|
||
# 值:{"title": "...", "scenario_key": "...", "current_action_id": "...", "step_desc": "...", "info_items": [...], "paused_at": "..."}
|
||
|
||
# 员工暂停会话集合(SET,无TTL,由超时清理任务维护)
|
||
auto:paused_sessions:{employee_id}
|
||
# 值:SET of session_id
|
||
|
||
# 现有 key(不变):
|
||
# agent:token:{token} — 坐席 token
|
||
# employee:token:{token} — 员工 token
|
||
```
|
||
|
||
### 7.4 WS 事件命名约定
|
||
|
||
```
|
||
# 现有事件(不变):
|
||
automation.progress — 进度推送
|
||
automation.action_required — 需要审批/确认
|
||
automation.resolved — 处置成功
|
||
automation.takeover — 转人工接管
|
||
automation.error — 异常
|
||
|
||
# 新增事件:
|
||
automation.paused — 会话暂停
|
||
data: {session_id, title, paused_at, resume_hint}
|
||
|
||
automation.resumed — 会话恢复
|
||
data: {session_id, title, resumed_at, current_step}
|
||
|
||
automation.timeout_closed — 暂停超时关闭
|
||
data: {session_id, closed_at, reason}
|
||
|
||
automation.info_corrected — 信息更正
|
||
data: {session_id, field, old_value, new_value, version}
|
||
|
||
automation.info_supplemented — 信息补充
|
||
data: {session_id, field, supplement_value, new_value}
|
||
```
|
||
|
||
### 7.5 API 响应格式约定
|
||
|
||
所有 API 响应沿用项目既有 `{code, data, message}` 格式:
|
||
|
||
```json
|
||
// 成功
|
||
{"code": 0, "data": {...}, "message": "success"}
|
||
|
||
// 失败
|
||
{"code": 4013, "data": null, "message": "会话不可暂停(终态)"}
|
||
```
|
||
|
||
新增错误码:
|
||
- `4013` — 会话不可暂停(终态)
|
||
- `4014` — 会话不可恢复(已关闭/超时)
|
||
- `4015` — 信息项已锁定,不可更正
|
||
- `4016` — 多个暂停会话需选择
|
||
|
||
### 7.6 状态机扩展约定
|
||
|
||
```
|
||
现有状态机:
|
||
created → running → resolved → closed
|
||
→ handoff
|
||
→ error
|
||
→ paused(等待审批/确认时)
|
||
|
||
扩展后状态机(新增暂停/恢复流转):
|
||
created → running → resolved → closed
|
||
→ handoff
|
||
→ error
|
||
running ⇄ paused(PAUSE 意图 → paused;RESUME_TASK 意图 → running)
|
||
paused → closed(24h 超时 → system(timeout) 关闭)
|
||
paused → closed(坐席手动关闭)
|
||
paused → running(坐席代恢复)
|
||
|
||
边界规则:
|
||
- 终态(closed/handoff/error)不可暂停、不可恢复
|
||
- await_approval 状态可暂停(同时挂起审批计时)
|
||
- 超时关闭的会话不可恢复,提示员工重新发起
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 任务依赖图
|
||
|
||
```mermaid
|
||
graph TD
|
||
T01[T01: 数据层基础<br/>模型+Schema+常量+迁移]
|
||
T02[T02: 全局意图识别<br/>+信息项管理服务]
|
||
T03[T03: 暂停/恢复/更正/补充编排<br/>+WS事件+超时清理]
|
||
T04[T04: 后端API路由<br/>+H5员工端前端]
|
||
T05[T05: 坐席端前端<br/>+信息项面板]
|
||
|
||
T01 --> T02
|
||
T01 --> T03
|
||
T02 --> T03
|
||
T01 --> T04
|
||
T03 --> T04
|
||
T01 --> T05
|
||
T03 --> T05
|
||
T04 --> T05
|
||
|
||
style T01 fill:#4CAF50,color:#fff
|
||
style T02 fill:#2196F3,color:#fff
|
||
style T03 fill:#2196F3,color:#fff
|
||
style T04 fill:#FF9800,color:#fff
|
||
style T05 fill:#FF9800,color:#fff
|
||
```
|
||
|
||
**依赖说明**:
|
||
- T01 是所有任务的基础(数据模型先行)
|
||
- T02 和 T03 依赖 T01(需要模型和常量)
|
||
- T03 依赖 T02(需要 InformationItemService)
|
||
- T04 依赖 T01 + T03(需要后端服务和数据模型)
|
||
- T05 依赖 T01 + T03 + T04(需要后端 API 就绪后前端联调)
|
||
|
||
---
|
||
|
||
## 9. 待明确事项
|
||
|
||
| # | 事项 | 影响范围 | 当前假设 | 建议后续处理 |
|
||
|---|------|---------|---------|-------------|
|
||
| 1 | **Dify Prompt 扩展后的准确率验证** | 意图识别 | 假设扩展 Prompt 后现有 4 场景识别准确率不受影响 | 上线前需用测试集验证全局意图与场景意图的识别准确率,确保不互相干扰 |
|
||
| 2 | **信息项与动作参数的映射关系** | 更正下游影响检测 | 假设通过 `action.payload` 的 key 名匹配信息项 name | 需要为每个场景的 action params 定义明确的信息项映射规则,可能在 `DEFAULT_SCENARIO_CONFIGS` 中补充 `info_fields` 定义 |
|
||
| 3 | **暂停期间审批单的超时处理** | 审批流程 | 假设暂停时审批计时同步挂起,恢复后继续计时 | 需确认 `ApprovalTicket` 是否有独立超时机制,若有需联动暂停 |
|
||
| 4 | **信息项的初始创建时机** | 信息收集流程 | 假设在编排流程中由 `MappingResolver` 或动作执行时创建信息项 | 当前自动化引擎的信息收集是隐式的(通过 mapping),可能需要显式的信息收集步骤来创建 InformationItem |
|
||
| 5 | **多个暂停会话的 Redis 集合一致性** | 恢复流程 | 假设 Redis SET 与 PostgreSQL 查询结果一致 | 超时清理任务同时清理 Redis 和 PG,但极端情况(Redis 宕机恢复)可能出现不一致,建议以 PG 查询为主、Redis 为缓存辅助 |
|
||
| 6 | **企微通知发送方式** | 超时关闭通知 | 假设通过现有 WS 推送 + 前端展示即可 | PRD 提到"发送企微通知",但当前系统无主动推送企微消息能力,需确认是否通过应用消息 API 推送或仅 WS 提示 |
|
||
|
||
---
|
||
|
||
## 附录 A: 文件清单汇总
|
||
|
||
### 后端新增文件(2个)
|
||
1. `backend/app/services/automation/information_item_service.py`
|
||
2. `backend/app/services/automation/timeout_cleaner.py`
|
||
3. `backend/alembic/versions/xxxx_add_information_items.py`
|
||
|
||
### 后端修改文件(9个)
|
||
4. `backend/app/models/automation.py`
|
||
5. `backend/app/schemas/automation.py`
|
||
6. `backend/app/constants.py`
|
||
7. `backend/app/services/automation/intent_router.py`
|
||
8. `backend/app/core/clients/dify.py`
|
||
9. `backend/app/services/automation/session_manager.py`
|
||
10. `backend/app/services/automation/progress_publisher.py`
|
||
11. `backend/app/services/automation/__init__.py`
|
||
12. `backend/app/api/automation.py`
|
||
|
||
### 前端 H5 端修改文件(3个)
|
||
13. `frontend-h5/src/api/automation.ts`
|
||
14. `frontend-h5/src/stores/automation.ts`
|
||
15. `frontend-h5/src/views/AutomationProgress.vue`
|
||
|
||
### 前端坐席端文件(4个,含1个新增)
|
||
16. `frontend-agent/src/api/automation.ts`(修改)
|
||
17. `frontend-agent/src/stores/automation.ts`(修改)
|
||
18. `frontend-agent/src/views/automation/SessionWorkbench.vue`(修改)
|
||
19. `frontend-agent/src/components/automation/InformationItemPanel.vue`(新增)
|
||
|
||
**合计:19个文件(3个新增 + 16个修改)**
|
||
|
||
---
|
||
|
||
## 附录 B: 消息模板
|
||
|
||
### 暂停回复消息
|
||
```
|
||
好的,您先忙~需要继续时跟我说一声「继续」就好。
|
||
当前进度:{step_desc}
|
||
```
|
||
|
||
### 恢复点回顾消息
|
||
```
|
||
欢迎回来!您之前在处理「{title}」,当前进度:{step_desc},我们继续吧~
|
||
```
|
||
|
||
### 多任务选择消息
|
||
```
|
||
您有{count}个未完成的任务,请选择要继续的:
|
||
① {title_1}(暂停于 {time_1})
|
||
② {title_2}(暂停于 {time_2})
|
||
```
|
||
|
||
### 更正确认消息
|
||
```
|
||
已更正:{field} 从「{old_value}」改为「{new_value}」
|
||
```
|
||
|
||
### 补充确认消息
|
||
```
|
||
已补充记录:{field}:{value}
|
||
```
|
||
|
||
### 超时关闭消息
|
||
```
|
||
您的任务「{title}」因长时间未恢复已自动关闭,如需帮助请重新发起。
|
||
```
|
||
|
||
### 更正影响下游提示
|
||
```
|
||
信息已更新,正在重新评估处置方案...
|
||
```
|
||
|
||
### 更正已执行动作提示
|
||
```
|
||
部分操作已执行,无法撤回。已更正的信息将在后续步骤中生效。
|
||
```
|
||
|
||
---
|
||
|
||
*本文档为复杂场景重构第一阶段的架构设计,工程师按 §5 任务列表顺序实现。*
|