v3.1 + 批次0: 智能回复重构基线 - ApprovalMatcher + 关键词降级 + 文档速修 + v4.0任务书面化

This commit is contained in:
Simon
2026-07-17 23:08:59 +08:00
parent 5a77a89ab1
commit 3ed86d5fb3
181 changed files with 19738 additions and 2655 deletions
@@ -0,0 +1,83 @@
# 智能回复系统深度重构总方案(v4.0)
> **日期**2026-07-17
> **前置版本**v3.0(后端 ApprovalMatcher 统一匹配)/ v3.1Dify 无 action 降级 + 超时降级)
> **问题基线**:20 项已验证问题(后端 8 + 前端 6 + 配置 6),全部对照源码核实
> **用户决策**:Redis 密码立即轮换 ✅ / Triage 分诊链路整体删除 ✅ / D1 意图合并采用激进方案 ✅
> **工作方式**:敏捷批次交付 + DevOps(文档与代码同 PR、每批次 RELEASE-NOTES
---
## 一、目标分层架构
```
接入层 Ingressh5.py / ws.py
└─ 只鉴权、落库用户消息、立即返回、投递任务
编排层 Orchestrationh5_ai_task.py 管线化)
└─ 只做流程编排,不直接发起外部调用
推理层 Inferenceai_service.py,全系统唯一 Dify 调用点)
└─ 真单例;native 12s + proxy 12s 超时预算;一次调用返回 intent/路由/审批字段
匹配层 Matchingapproval_matcher.py,纯函数)
└─ match_and_build_card / match_by_keywords / get_all_categories
渲染层 Rendering(前端纯渲染)
└─ WS 契约单点 build_message_ws_payload();审批卡片渲染点 ≤ 2 处
```
**单一职责红线**ApprovalMatcher 不碰 WS/DBAIService 不认识"审批/路由/BYOD";编排层不 new httpxWS 推送统一出口。
## 二、关键设计决策
| # | 决策 | 理由 |
|---|------|------|
| D1 | 意图识别并入主 Dify 调用 | routing detect 与主对话是同一 Dify 应用同一 key,消除 15s+30s 串行叠加(最坏 45s → ~15s |
| D2 | 超时预算内化 httpx | native 12s + proxy 12s < wait_for 30s,修复 proxy 兜底数学不可达问题 |
| D3 | 匹配失败不静默 | ApprovalMatcher 末路返回全量卡片(get_all_categories),前端永不空白 |
| D4 | WS 消息契约单点化 | 修复 new_message 前端白名单丢字段(坐席图片/文件不渲染) |
| D5 | triage 分诊链路删除 | 前端零挂载点(已确认,grep 无引用) |
| D6 | 快捷申请走新端点 | `GET /approval/all-categories-card`,修复 showApprovalCard 空白气泡 P0 |
## 三、批次计划
### 批次 1(P0,~2 天,彼此独立可单独上线)
| 项 | 内容 | 工作量 |
|----|------|--------|
| P0-1 | 生产 workers=2 → 1(删除/修改 override 与 deploy-server compose | 0.5d |
| P0-2 | DIFY_NATIVE_* 生产配置(compose environment + .env.production | 0.5d |
| P0-3 | 快捷申请空白气泡修复(新 all-categories-card 端点 + store 改造) | 0.5d |
| P0-4 | RecommendCard invokeApproval ReferenceError 修复 | 0.5d |
| P0-5 | WS new_message 前端全字段透传 | 1d |
| P0-6 | 超时预算切分(native 12s / proxy 12s | 1d |
**上线前 git tag `pre-v4-refactor`**;文档同步:本目录 `01-批次1-P0执行记录.md` + RELEASE-NOTES v4.0.0。
### 批次 2P1 基础,~3 天)
P1-1 AIService 真单例(修复 httpx 连接泄漏)→ P1-2 统一 Dify 调用点(删除 approval/byod detect-intent 死链路、routing 改调 chat_native)→ P1-4 Matcher 死分支删除 + 失败兜底(D3)→ P1-7 配置治理(APP_ENV=production、**Redis 密码轮换(低峰期)**、os.getenv 旁路收敛、3 个潜伏 bug 修复:app_root/AsyncIOSScheduler 拼写/config.py logger)→ P1-6 dynamic_recommend 死逻辑清理。
文档同步:架构文档 v2 §15.4.5 重写(v3.0 纯渲染架构)。
### 批次 3P1 核心,~4 天,观察 24h)
P1-3 编排层管线化(**D1 激进合并**:先 5 条真实消息验证 Dify intent 字段稳定性,不稳定退回 gather 并行)→ P1-5 WS 死路由清理(ai_reply_chunk/pending_close_request/quiz_diagnostic_answer)。
观察指标:AI 回复到达率 ≥99%、平均响应 ≤20s、转人工率不升。文档同步:架构文档新增「智能回复链路 v4」章节。
### 批次 4P2,按需)
P2-1 死代码大扫除(含 3 个 .bak 文件、构建产物目录入库)→ P2-2 triage 整链删除 → P2-4 测试补齐 → P2-3 前端 store 拆分 → P2-5 审批回调 TODO 收口。
## 四、验收清单
- [ ] 生产 `--workers 1`AI 回复 WS 到达率 100%
- [ ] 日志走「Dify 原生 API」,无 proxy 路径、无 [object Object]
- [ ] Dify 调用点全系统唯一
- [ ] `process_h5_ai_reply` < 100 行,try/except ≤ 3 对;路由消息端到端 < 35s
- [ ] ApprovalMatcher 任意输入均有卡片输出(无 None)
- [ ] H5 快捷申请/AI 卡片/关键词兜底三场景渲染一致
- [ ] 坐席发图片/文件,H5 WS 实时渲染
- [ ] pytest + `npm run build` 全绿;/version 返回真实 git hash
## 五、回滚策略
每批次独立 PR + 独立部署;git tag `pre-v4-refactor` 全量回滚点;配置类(DIFY_NATIVE/APP_ENV/Redis)改回旧值重启即可;批次 3 异常回滚至批次 2 状态。
---
**执行记录**:见本目录 `01-批次1-P0执行记录.md`(批次 1 完成后填写)等。
@@ -0,0 +1,55 @@
# v4.0 重构 — 问题验证清单(20 项)
> **日期**2026-07-17
> **验证方式**:逐项对照源码核实(文件 + 行号)
> **用途**:新会话快速理解重构问题基线,无需重新探索
---
## 一、后端问题(B1-B8
| # | 问题 | 证据(文件:行号) | 现状 |
|---|------|------------------|------|
| B1 | 9 个匹配/识别入口(5 活 4 死) | 活:Dify 主 action、ApprovalMatcher、routing detect、Neo4j 图谱、关键词预过滤;死:`approval.py:1060``byod.py:348`、DifyTriageService、matchers.IntentMatcher | 待 P1-2 收敛 |
| B2 | 双重超时致 proxy 兜底不可达 | `ai_service.py` httpx timeout=30s`config.py:115`= `h5_ai_task.py:1197` wait_for(30)native→proxy 串行最坏 60s | 待 P0-6 |
| B3 | ApprovalMatcher 死分支 | `approval_matcher.py:66-69` 优先级 5 与 50-53 优先级 2 同调 `_match_by_keyword(approval_type)`,不可达 | 待 P1-4 |
| B4 | Matcher 匹配失败仅 warning | `h5_ai_task.py:461`action 无 card_data 透传 → 前端空白 | 待 P1-4(D3 兜底) |
| B5 | 同一 Dify 调用代码复制 3 遍 | `approval.py:999-1057`(死)、`routing_service.py:120-189`(活)、`byod.py:243-300`(死),各自新建 httpx.AsyncClient | 待 P1-2 |
| B6 | 路由 detect 与主 Dify 串行 45s | `h5_ai_task.py:1060` detect15s 超时)→ `:1197` 主调用(30s | 待 P1-3D1 合并) |
| B7 | 26 对 try/except | `h5_ai_task.py` 主函数 11 对,最深 4 层缩进(L1037→1196→1205→1227 | 待 P1-3 管线化 |
| B8 | 死代码 9 项 | 见 v4.0 方案 §3 表格(get_reply_stream、detect-intent×2、dynamic_recommend 死分支、matcher P5、前端死 API×2、handle_message 死分支、回调 TODO、.bak 文件) | 待 P2-1 |
| B9 | get_shared_ai_handler 伪单例 | `dependencies/__init__.py:98-106` 每次新建 AIHandler+AIService+2 个 httpx 池,从不 close | 待 P1-1 |
## 二、前端问题(F1-F6
| # | 问题 | 证据 | 现状 |
|---|------|------|------|
| F1 | showApprovalCard 空白气泡(P0 | `stores/conversation.ts:900-917` 构造 `extra_data={approval_type:'',confidence:0}`,但 MessageBubble 要求 `action.card_data` | 待 P0-3 |
| F2 | RecommendCard invokeApproval 崩溃(P0 | `RecommendCard.vue:178` 调用未定义函数(grep 确认无定义/导入/emit | 待 P0-4 |
| F3 | WS new_message 白名单丢字段(P0 | `stores/conversation.ts:395-429` 只取 7 字段;后端 `messages.py:278` 已下发全量 | 待 P0-5 |
| F4 | WS 3 种死路由 | `useH5WebSocket.ts:392/477/489`ai_reply_chunk/pending_close_request/quiz_diagnostic_answer),后端零产出 | 待 P1-5 |
| F5 | ApprovalCardModal 3 处渲染点 | `MessageBubble.vue:19/82/103`L82 text 分支自 v2.4 已死;approval_card msg_type 后端从未产出 | 待 P1-5 |
| F6 | 大量死代码 | store 死状态(approvalCardVisible 等)、MessageItem.vue 孤儿组件、死 CSS、前端死 APIconversation.ts:430/486/505 | 待 P2-1 |
## 三、配置/部署问题(C1-C6)
| # | 问题 | 证据 | 现状 |
|---|------|------|------|
| C1 | DIFY_NATIVE_* 生产从未配置 | 根 compose environment 无此 2 项;`.env.production``deploy-server/.env.production``backend/.env.example` 均无 → v2.1 原生直连未上线 | 待 P0-2 |
| C2 | workers=2 破坏单 worker 铁律 | `docker-compose-override.yml:4``deploy-server/docker-compose.yml:115``docker-compose-green.yml:46``--workers 2`;主文件已 1 但被 override 覆盖 | 待 P0-1 |
| C3 | APP_ENV 未传 | `config.py:182` 默认 dev → 生产 UA 校验/IP 白名单不生效 | 待 P1-7 |
| C4 | Redis 密码硬编码两处 | 根 compose L51requirepass 明文)、L120URL 编码硬编码);`.env` 的 REDIS_PASSWORD 未被引用;密码已进 git | 待 P1-7(轮换) |
| C5 | 15+ 处 os.getenv 旁路 | upload.py:35/49/51、auth_wecom_sso.py:65/83/161、dev_auth.py:42 等;DEV_MODE 判定重复 4 处 | 待 P1-7 |
| C6 | 3 个潜伏 bug | ① `main.py:1020` `app_root` 未定义 → /version 永远 unknown;② `tasks/scheduler.py:21` `AsyncIOSScheduler` 拼写错误(多一个 S,且零导入);③ `config.py:409` 使用未定义 `logger` | 待 P1-7 |
## 四、已完成的修复(v3.0/v3.1/批次 0,勿重复)
| 日期 | 修复 | 位置 |
|------|------|------|
| v3.0 | 后端 ApprovalMatcher 统一匹配;前端 ApprovalCardModal 纯渲染;APPROVAL_TEMPLATES 扩展 icon/desc/category;删除前端 APPROVAL_OPTIONS / APPROVAL_URL_MAP / getApprovalKeywords API | `approval_matcher.py``approval.py``ApprovalCardModal.vue``MessageBubble.vue``RecommendCard.vue``conversation.ts` |
| v3.1 | Dify 无 action 降级(h5_ai_task.py:1252-1272+ 超时降级(:1205-1241);修复 `message_content` 未定义 bug3 处改 `content` | `h5_ai_task.py` |
| 批次 0 | dify_main_chat_prompt v1.2 同步线上;DEPLOY-GUIDE §4.3 部署铁律;2 个 prompt 文档标废弃;本目录归档 | `docs/` |
---
**参考**:完整方案见 `00-v4.0重构总方案.md`;批次执行记录见 `01-批次1-P0执行记录.md` 等。
+78
View File
@@ -0,0 +1,78 @@
# 12-重构记录 — 目录索引与执行状态看板
> **创建**2026-07-17
> **目的**:智能回复系统 v4.0 深度重构的全部记录。当前会话不可用时,新会话读本目录即可继续推进。
> **工作方式**:敏捷批次交付 + DevOps(文档与代码同 PR
---
## 一、新会话快速上手指引(3 步)
1. **读方案**`00-v4.0重构总方案.md`(分层架构、批次计划、验收清单)
2. **读问题**`01-问题验证清单.md`(20 项问题 + 源码行号证据 + 已完成修复清单)
3. **看状态**:本文 §三(执行状态看板),找到「待开始」的任务说明书,按 `docs/10-项目管理/任务说明书/` 执行
## 二、目录结构
```
docs/12-重构记录/
├── README.md ← 本文件(索引 + 状态看板)
├── 00-v4.0重构总方案.md ← 目标架构、批次计划、验收清单、回滚策略
├── 01-问题验证清单.md ← 20 项问题源码证据(B1-B8/F1-F6/C1-C6
├── 02-批次1-P0执行记录.md ← 批次 1 完成后填写
├── 03-批次2-P1基础执行记录.md
├── 04-批次3-P1核心执行记录.md
└── 99-回顾报告.md ← 批次 3 观察 24h 后填写
```
**配套文档**
- 任务说明书:`docs/10-项目管理/任务说明书/任务说明书-78/79/84/85/86/87/88/89/90`
- 部署铁律:`docs/09-部署运维/DEPLOY-GUIDE.md` §4.3
- Dify 主 prompt 线上版本:`docs/02-产品需求/dify_main_chat_prompt_v1.md`v1.2
## 三、执行状态看板
> 更新规则:每完成一项即更新。新会话从这里接续。
| 批次 | 任务 | 任务说明书 | 状态 | 完成日期 |
|------|------|-----------|------|---------|
| — | v3.0 后端 ApprovalMatcher + 前端纯渲染 | — | ✅ 已完成 | 2026-07-17 |
| — | v3.1 Dify 无 action 降级 + message_content bug 修复 | — | ✅ 已完成 | 2026-07-17 |
| 批次 0 | 文档速修 4 项 + 本目录归档 | — | ✅ 已完成 | 2026-07-17 |
| 批次 1 | P0-1 workers=2→1 | #78 | ⬜ 待开始 | — |
| 批次 1 | P0-2 DIFY_NATIVE_* 生产配置 | #79 | ⬜ 待开始 | — |
| 批次 1 | P0-3 快捷申请空白气泡修复 | #87 | ⬜ 待开始 | — |
| 批次 1 | P0-4 RecommendCard invokeApproval 修复 | #88 | ⬜ 待开始 | — |
| 批次 1 | P0-5 WS new_message 全字段透传 | #89 | ⬜ 待开始 | — |
| 批次 1 | P0-6 超时预算切分 | #90 | ⬜ 待开始 | — |
| 批次 2 | P1 基础(单例/统一调用点/Matcher/配置治理) | #84 | ⬜ 待开始 | — |
| 批次 3 | P1 核心(编排层管线化 + WS 路由清理) | #85 | ⬜ 待开始 | — |
| 批次 4 | P2(死代码/triage 删除/测试) | #86 | ⬜ 待开始 | — |
## 四、关键上下文(新会话必读)
### 4.1 部署铁律(详 `docs/09-部署运维/DEPLOY-GUIDE.md` §4.3
1. backend 必须 `--workers 1`(override 会覆盖主文件,务必 `docker compose config | grep workers` 验证)
2. `.env` 不会自动传入容器,新变量必须在 compose `environment:` 显式声明
3. Redis 密码特殊字符必须 URL 编码(@→%40 #→%23 !→%21
### 4.2 服务器部署通道
- 堡垒机:`sxn@10.212.189.210:2222`OTP),工具 `C:\Users\simon\.workbuddy\skills\jumpserver-ops\scripts\jms_ops.py`
- 服务器项目根:`/opt/wecom-it-desk/`backend 卷挂载 `./app:/app/app`,改 .py 后 `docker compose restart backend`
- 前端部署:tar 上传 → 解压到 `frontend-h5/dist``docker compose up -d nginx`(容器重建非 reload
### 4.3 回滚点
- git tag `pre-v4-refactor`(批次 1 上线前打)
- 前端备份:`frontend-h5/dist_bak_v13`
### 4.4 用户已确认的决策
- Redis 密码**立即轮换**(批次 2,低峰期,新旧双备)
- Triage 分诊链路**整体删除**(批次 4)
- D1 意图合并**激进方案**(批次 3 先 5 条真实消息验证 Dify intent 字段,不稳定退回 gather 并行)
## 五、变更记录
| 日期 | 变更 | 说明 |
|------|------|------|
| 2026-07-17 | 创建目录 + 批次 0 完成 | 4 项文档速修 + 本索引 |
| 2026-07-17 | 任务说明书 #78-86 创建 | 批次 1-4 全部任务书面化 |