feat: 2026-07-12~13 全量更新 - AI对话链路改造+H5 v4/v5+坐席端v5+上下文感知诊断+知识库迭代3
## H5 员工端 v4 (2026-07-13 00:48 已部署)
- 人工按钮三态文案统一为"人工坐席"
- 按钮位置移至发送键和语音按钮上方(垂直堆叠)
- 点按钮直接调 store.shakeAgent(),删除 CallAgentModal 弹窗动画
- 截图快捷键提示改为"截图->粘贴:Alt+Shift+A-Ctrl+V ---> Ctrl+V"
- 移动端隐藏截图提示(CSS 媒体查询)
- AI转人工提示改为"已为您呼叫人工坐席,请稍等!"
- 坐席接入提示改为"坐席正在查看您的信息,请等待处理回复!"
- 删除"摇铃呼叫坐席"入口和文案
- 删除孤儿组件 MessageList.vue + shake 动画 CSS
## H5 员工端 v5 (2026-07-13 02:08 已部署)
- RightPanel v2.1:删除"软件安装"和"资源权限"标签页
- 移除标签栏,智能推荐(DynamicRecommend)直接展示
- 删除 SoftwareDownloads/ApprovalLinks 引用和相关 CSS
## AI 对话链路全栈改造 Phase 1-6 (已部署)
- Phase 1: Dify JSON输出 + 后端blocking解析 + 双WS推送 + 错误降级
- Phase 2: 关键词收窄(~25强意图词) + 两级分类Prompt + 删除前端checkApprovalIntent
- Phase 3: WS扩展(ai_thinking+dynamic_recommend) + ai_structured气泡 + RightPanel v2 + 选项回传
- Phase 4: VisionService接入 + 图片消息融合(5秒窗口) + 降级策略
- Phase 5: 坐席端ai_thinking指示器 + ai_structured/byod_card渲染 + handleNewMessage修复
- Phase 6: diagnosis_stage(6值) + response_time_ms计时 + 慢响应告警(>10s)
## 坐席端 v5 (2026-07-13 01:38 已部署)
- ai_structured/byod_card 只读渲染
- AI思考指示器 UI
- handleNewMessage 透传 msg_type/extra_data 修复
- 布局优化v2.0: QuickReplyBar L1+L2悬浮 + ReplyBox左右分区 + 右栏260/560px切换
- 键盘快捷键v2.3: 纯数字路由 + ESC分层撤销 + Shift+Space用event.code
## 上下文感知智能诊断闭环 (2026-07-12 已部署)
- 三层诊断(API→Script→AI) + 三段排队(VIP→info_locked→not locked)
- 答题插队 + 五场景关闭
- 迁移052(6表+6列) + queue_service + quiz_service + closing_service
- H5前端: QueueWaiting + RightPanel双Tab + InputBar三态 + ResolveConfirmCard
- 坐席前端: pending_close结单流程 + 信息锁定(Dify步骤完成+有效回答率≥70%)
## 知识库迭代3 (2026-07-12 已部署)
- 分诊交互(H5+坐席+Dify独立应用)
- 拓扑预览(ECharts只读)
- 代答排除(4种匹配器: keyword/regex/intent/category)
- 迁移051 + 44文件43测试通过
## 后端变更
- 6个Python文件改造(h5_ai_task.py/h5.py/ai_service.py/closing_service.py等)
- funny_phrase_service.py: shake/connected/keyword 默认文案更新
- session_service.py: 企微消息文案同步
- 新增: queue.py/quiz.py/triage.py/exclusion_rules.py 等API端点
- 新增: diagnostic.py/quiz.py/triage_session.py 等模型
- 新增: closing_service/queue_service/quiz_service/triage_service 等服务
## 文档更新
- CHANGELOG.md: 新增 [未发布] 区全部变更记录
- 项目管理主文档 v2.5: 新增v0.7.3版本 + 已完成看板 + 最近搞定
- 版本记录: 新增v0.7.3条目
- AI对话链路实施计划: Phase 1-6 全部标记✅已实施
- 新增架构图/时序图/类图(mermaid)
## 部署路径修正
- 服务器项目根路径: /opt/wecom-it-desk/
- 所有前端dist均为ro bind mount,只能在宿主机源路径操作
- 服务器nginx /h5/ 是静态文件服务(非proxy_pass)
- elFinder上传二进制不可靠(MD5不匹配),改用base64分块上传
This commit is contained in:
@@ -0,0 +1,731 @@
|
||||
# AI 对话链路全栈改造实施计划
|
||||
|
||||
> **版本**: v1.1
|
||||
> **日期**: 2026-07-13
|
||||
> **作者**: 宋献 (Simon) + Duckula
|
||||
> **状态**: ✅ 已实施并部署(Phase 1-6 全部完成,2026-07-13 01:38 生产部署)
|
||||
|
||||
---
|
||||
|
||||
## 部署记录
|
||||
|
||||
### 2026-07-13 01:38 生产部署(v5)
|
||||
|
||||
| 组件 | 版本 | 部署内容 | 验证 |
|
||||
|------|------|---------|------|
|
||||
| **后端** | v5 | 6 个 Python 文件部署到 `/opt/wecom-it-desk/app/` | `docker compose restart backend` → healthy ✅ |
|
||||
| **H5 前端** | v4 | dist 部署到 `/opt/wecom-it-desk/frontend-h5/dist/` | JS hash `index-B6dzwk-X.js` ✅ |
|
||||
| **Agent 前端** | v5 | dist 部署到 `/opt/wecom-it-desk/frontend-agent/dist/` | JS hash `index-2BTn4SZz.js` ✅ |
|
||||
| **Nginx** | - | `nginx -s reload` | healthy ✅ |
|
||||
|
||||
**后端变更文件清单**(旧文件备份在 `/tmp/backend_bak_v5/`):
|
||||
|
||||
| 文件 | 变更内容 |
|
||||
|------|---------|
|
||||
| `app/tasks/h5_ai_task.py` | VisionService 接入 + 图片消息融合 + ai_thinking 双推 + diagnosis_stage 存储 |
|
||||
| `app/api/h5.py` | `process_h5_ai_reply()` 调用新增 `msg_type` + `media_url` 参数 |
|
||||
| `app/services/ai_service.py` | `get_structured_reply()` blocking 模式 + JSON 解析 + `response_time_ms` 计时 + 慢响应告警 |
|
||||
| `app/services/closing_service.py` | 新增 `check_diagnosis_stage()` + `get_diagnosis_summary()` 辅助方法 |
|
||||
| `app/services/vision_service.py` | 已有实现,本次接入主链路 |
|
||||
| `app/api/websocket.py` | `ai_thinking` 同时推员工和坐席 + `dynamic_recommend` 推送 |
|
||||
|
||||
**前端变更文件清单**:
|
||||
|
||||
| 前端 | 文件 | 变更内容 |
|
||||
|------|------|---------|
|
||||
| H5 | `MessageBubble.vue` | 新增 `ai_structured` 渲染分支(文字 + 选项按钮 + 脉冲动画) |
|
||||
| H5 | `DynamicRecommend.vue` | **新建** — 右边栏动态推荐卡片(3 种类型 approval/action/info) |
|
||||
| H5 | `RightPanel.vue` | 重写为 v2 手风琴布局(设备信息 / 自助诊断 / 底部标签页) |
|
||||
| H5 | `useH5WebSocket.ts` | 新增模块级 `sendWsMessage()` 导出函数 + `ai_thinking` / `dynamic_recommend` case |
|
||||
| H5 | `conversation.ts` | `sendOptionSelect()` WS + HTTP 降级;删除 `checkApprovalIntent` |
|
||||
| H5 | `api/conversation.ts` | `MsgContentType` 新增 `'ai_structured'` |
|
||||
| Agent | `MessageBubble.vue` | 新增 `ai_structured` 只读渲染 + `byod_card` 渲染分支 |
|
||||
| Agent | `ChatArea.vue` | 新增 AI 思考指示器 UI(脉冲动画) |
|
||||
| Agent | `useWebSocket.ts` | 新增 `ai_thinking` case |
|
||||
| Agent | `conversation.ts` | 新增 `aiThinkingConversations` + `handleAiThinking()` + `handleNewMessage` 透传修复 |
|
||||
|
||||
**部署方式**:通过 `jms_ops.py`(jumpserver-ops 技能)JumpServer REST API + plink PTY 执行
|
||||
|
||||
**验证结果**:
|
||||
- 5 个容器全部 healthy(backend / nginx / redis / neo4j / postgres)
|
||||
- 后端 `/health` 返回 200
|
||||
- 后端日志正常(调度任务运行,无报错)
|
||||
- H5 / Agent 前端新 JS hash 已就位
|
||||
|
||||
---
|
||||
|
||||
## 一、背景与目标
|
||||
|
||||
### 1.1 改造背景
|
||||
|
||||
当前 IT 智能服务台存在以下核心问题:
|
||||
|
||||
1. **Dify 工作流臃肿**:85 个节点,推理延迟高,维护困难
|
||||
2. **审批意图识别质量差**:回复太快、无关触发、精度低、准确率低
|
||||
3. **卡片与文字"两张皮"**:审批卡片由前端异步独立推送,与 AI 文字回复无关联、时间不同步
|
||||
4. **图片消息处理缺失**:`VisionService` 完整实现但零调用,员工发图片 AI "失明"
|
||||
5. **右边栏布局分散**:自助诊断、软件下载、资源申请三个独立模块,无动态推荐区
|
||||
|
||||
### 1.2 改造目标
|
||||
|
||||
| 目标 | 衡量标准 |
|
||||
|------|---------|
|
||||
| Dify 节点精简 | 85 → ~35 节点,推理延迟降低 40%+ |
|
||||
| 审批意图准确率 | 误触发率从 ~60% 降至 ~15% |
|
||||
| 卡片与文字融合 | 同一次推理、同一时刻到达、语义强关联 |
|
||||
| 图片消息可用 | 员工发截图 → AI 能"看懂"并回复 |
|
||||
| 右边栏统一 | 手风琴折叠 + 智能推荐默认页 |
|
||||
|
||||
---
|
||||
|
||||
## 二、当前架构分析
|
||||
|
||||
### 2.1 当前消息流:两条平行轨道
|
||||
|
||||
```
|
||||
┌─ 通道 A(审批卡片)──────────────────────────────────┐
|
||||
│ 前端 checkApprovalIntent() │
|
||||
│ → POST /approval/detect-intent │
|
||||
│ → Dify 意图识别 (blocking, 同一个 Dify 应用) │
|
||||
│ → 前端 messages.value.push(approvalCardMessage) │
|
||||
│ ※ 异步 fire-and-forget,与 AI 回复独立 │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 通道 B(AI 文字回复)────────────────────────────────┐
|
||||
│ 后端 process_h5_ai_reply() │
|
||||
│ → routing_keyword_prefilter → detect_routing_intent │
|
||||
│ → ai_service.get_reply_stream() │
|
||||
│ → Dify 主对话应用 (streaming, dify2openai 代理) │
|
||||
│ → WS: ai_reply_chunk → ai_reply │
|
||||
│ ※ 前端逐字渲染,与卡片无关联 │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**问题**:两条通道各自调用 Dify,结果可能矛盾;卡片随机插入聊天流,打断阅读节奏。
|
||||
|
||||
### 2.2 关键代码位置
|
||||
|
||||
| 模块 | 文件路径 | 关键行号 | 说明 |
|
||||
|------|---------|---------|------|
|
||||
| 后端消息处理 | `backend/app/tasks/h5_ai_task.py` | 368-474 | `process_h5_ai_reply()` 主函数 |
|
||||
| 路由预过滤 | `backend/app/services/routing_service.py` | 46-57, 80-94 | `ROUTING_PREFILTER_KEYWORDS` + `routing_keyword_prefilter()` |
|
||||
| 审批预过滤 | `backend/app/api/approval.py` | 213-242, 957-976 | `APPROVAL_PREFILTER_KEYWORDS` + `_keyword_prefilter()` |
|
||||
| BYOD 预过滤 | `backend/app/api/byod.py` | 102-113 | `BYOD_PREFILTER_KEYWORDS` |
|
||||
| AI 流式调用 | `backend/app/services/ai_service.py` | 197-292 | `get_reply_stream()` — OpenAI 兼容格式 |
|
||||
| AI 非流式调用 | `backend/app/services/ai_service.py` | 83-192 | `get_reply()` — 降级用 |
|
||||
| AI 处理器 | `backend/app/services/ai_handler.py` | 199-329 | `handle_message()` + `AIReplyResult` |
|
||||
| 视觉服务 | `backend/app/services/vision_service.py` | 全文件 | 完整实现但零调用 |
|
||||
| RAGFlow 客户端 | `backend/app/integrations/ragflow/client.py` | 全文件 | 完整实现但未接入主链路 |
|
||||
| RAGFlow 旧客户端 | `backend/app/core/clients/ragflow.py` | 全文件 | 依赖未配置环境变量 |
|
||||
| 前端审批检测 | `frontend-h5/src/stores/conversation.ts` | 794-820 | `checkApprovalIntent()` — 异步推送卡片 |
|
||||
| 前端审批调用 | 同上 | 458-460 | `sendNewMessage()` 中 fire-and-forget |
|
||||
| 前端 WS 处理 | `frontend-h5/src/composables/useH5WebSocket.ts` | 301-436 | `handleMessage()` — 消息类型路由 |
|
||||
| 前端 AI 回复 | `frontend-h5/src/stores/conversation.ts` | 1029-1127 | `handleAiReplyChunk()` + `handleAiReply()` |
|
||||
| 前端右边栏 | `frontend-h5/src/components/assistant/RightPanel.vue` | 15-77 | 模板结构 |
|
||||
| Dify 意图 Prompt | `docs/02-产品需求/dify_unified_intent_prompt_v3.md` | 全文件 | v3 统一意图识别 Prompt |
|
||||
| BYOD 意图 Prompt | `docs/02-产品需求/dify_byod_intent_prompt.md` | 全文件 | BYOD 意图扩展 |
|
||||
|
||||
### 2.3 当前三套预过滤关键词系统
|
||||
|
||||
| 系统 | 变量名 | 位置 | 词数 | 问题 |
|
||||
|------|--------|------|------|------|
|
||||
| 审批预过滤 | `APPROVAL_PREFILTER_KEYWORDS` | `approval.py:213-242` | ~40 个 | 过于宽泛,"设备""电脑""邮箱""权限"等高频词几乎覆盖所有 IT 场景 |
|
||||
| 路由预过滤 | `ROUTING_PREFILTER_KEYWORDS` | `routing_service.py:46-57` | ~22 个 | 合理,仅非 IT 业务词 |
|
||||
| BYOD 预过滤 | `BYOD_PREFILTER_KEYWORDS` | `byod.py:102-113` | ~10 个 | 合理,仅 BYOD 专用词 |
|
||||
|
||||
### 2.4 两套 Dify API 调用模式
|
||||
|
||||
| 维度 | AI 回复 (ai_service.py) | 意图识别 (approval.py / routing_service.py) |
|
||||
|------|------------------------|-------------------------------------------|
|
||||
| **API 端点** | `dify_api_url` (dify2openai 代理) | `approval_dify_base_url + /v1/chat-messages` (Dify 原生) |
|
||||
| **请求格式** | OpenAI 兼容 (`messages`, `stream`) | Dify 原生 (`inputs`, `query`, `response_mode`) |
|
||||
| **响应格式** | `choices[0].delta.content` (SSE) | `answer` 字段含 JSON 字符串 |
|
||||
| **流式** | 是 | 否 (blocking) |
|
||||
| **用途** | IT 知识库问答 | 审批/路由意图分类 |
|
||||
| **配置** | `dify_api_url`, `dify_api_key` | `approval_dify_base_url`, `approval_dify_api_key` |
|
||||
|
||||
---
|
||||
|
||||
## 三、差距分析(11 项)
|
||||
|
||||
### 3.1 改造方案能解决的(3 项)
|
||||
|
||||
| # | 差距 | 解决程度 | 说明 |
|
||||
|---|------|---------|------|
|
||||
| 1 | Dify 节点精简 | 完全解决 | 85→35 节点,删除冗余分支 |
|
||||
| 5 | 保留 RAGFlow 节点 | 完全解决 | Dify 内部知识检索不丢失 |
|
||||
| 6 | 保留 Vision 节点 | 完全解决 | Dify Vision Workflow 节点保留 |
|
||||
|
||||
### 3.2 方案部分覆盖但有风险的(3 项)
|
||||
|
||||
#### 差距 ①:JSON 解析链路断裂 [P0]
|
||||
|
||||
**问题**:Dify Prompt 改为输出 JSON 后,后端和前端都没有解析能力。
|
||||
|
||||
- `ai_service.py:232-263` — `get_reply_stream()` 把 `choices[0].delta.content` 作为纯文本逐 chunk 透传
|
||||
- `ai_handler.py:278-282` — `handle_message()` 把 `ai_result["content"]` 直接放入 `AIReplyResult.content`
|
||||
- `conversation.ts:1029-1054` — `handleAiReplyChunk()` 直接将 `data.chunk` 追加到 `content` 字段
|
||||
- `MessageBubble.vue` — 对 `msg_type === 'text'` 用 `white-space: pre-wrap` 纯文本渲染
|
||||
|
||||
**需要补的**:全链路结构化改造——Dify 输出 JSON → 后端解析提取 → WS 推送结构化消息 → 前端新增渲染组件。
|
||||
|
||||
#### 差距 ②:Dify 不支持图片输入 [P1]
|
||||
|
||||
**问题**:`ai_service.py:217-226` 的 payload 用 OpenAI 兼容格式,`content` 只接受字符串,不能传图片。
|
||||
|
||||
**正确路径**:图片 → `VisionService.analyze_screenshot()` 预分析 → 生成文字描述 → 拼接到 Dify 文本输入中。
|
||||
|
||||
#### 差距 ③:消息融合的边界场景 [P2]
|
||||
|
||||
**问题**:
|
||||
- 超时风险:用户发图后思考 10 秒再打字,5 秒窗口已关闭
|
||||
- 多图处理:连续发 3 张截图 + 一段文字,合并还是分别处理?
|
||||
- 乱序到达:文字先到、图片后到
|
||||
- 窗口内多条文字:多条短消息需要合并
|
||||
|
||||
### 3.3 方案完全未涉及的(5 项)
|
||||
|
||||
#### 差距 ④:VisionService 完整实现但零调用 [P0]
|
||||
|
||||
**问题**:`vision_service.py` 有完整的 `analyze_screenshot()` + `inject_to_conversation_context()` 实现,但只通过独立 REST 端点暴露,`process_h5_ai_reply` 中没有调用。
|
||||
|
||||
员工发图片 → 不触发视觉分析 → Dify 只收到空文字 → AI 回复"请问您遇到了什么问题?"
|
||||
|
||||
**需要补的**:在 `process_h5_ai_reply` 中增加图片分支——检测到图片 → 调 `VisionService.analyze_screenshot()` → 描述拼接到用户文字中 → 传给 Dify。
|
||||
|
||||
#### 差距 ⑤:选项回传链路 [P1]
|
||||
|
||||
**问题**:AI 回复包含选项按钮,用户点击后无链路回传。
|
||||
|
||||
- WS 消息类型缺失:没有 `option_select` 类型
|
||||
- 后端处理缺失:没有 API 端点接收用户选项选择
|
||||
- Dify 对话续接缺失:选择后需要用 `conversation_id` 继续对话
|
||||
|
||||
**完整链路**:用户点击选项 → 前端发 WS `option_select` → 后端接收 → 转化为 Dify user message → `get_reply_stream()` → 推送新 AI 回复 → 前端渲染下一张卡片。
|
||||
|
||||
#### 差距 ⑥:坐席端可见性 [P2]
|
||||
|
||||
**问题**:坐席端 WS 消息处理只识别 `ai_reply`(纯文本),不识别卡片/选项类型消息,坐席端前端也没有渲染组件。
|
||||
|
||||
#### 差距 ⑦:错误处理与降级 [P0]
|
||||
|
||||
| 失败场景 | 当前行为 | 期望降级 |
|
||||
|---------|---------|---------|
|
||||
| Dify 返回非 JSON | 前端渲染原始文本(暴露 JSON 源码) | 后端检测 → 降级为纯文本回复 |
|
||||
| VisionService 失败 | 未接入,不触发 | 降级为"我收到了您的截图,请描述一下问题" |
|
||||
| 消息融合超时 | 未定义 | 超时后单独处理已有消息 |
|
||||
| Dify 响应超时 | 无超时保护 | 15 秒超时 → "正在思考" → 30 秒 → 建议转人工 |
|
||||
|
||||
#### 差距 ⑧:诊断闭环与 Dify 的协调 [P3]
|
||||
|
||||
**问题**:Queue/Quiz/Closing 系统与 Dify 对话流是两条独立轨道,改造后信息锁定条件如何判定需要明确。
|
||||
|
||||
---
|
||||
|
||||
## 四、审批意图识别问题分析(4 问题 + 3 根因)
|
||||
|
||||
### 4.1 四个问题的根因
|
||||
|
||||
#### 问题 1:「回复太快了」
|
||||
|
||||
**根因**:审批卡片推送走前端异步 fire-and-forget 路径。
|
||||
|
||||
```typescript
|
||||
// conversation.ts:458-460
|
||||
checkApprovalIntent(content).catch(...) // 异步触发,不等待
|
||||
```
|
||||
|
||||
Dify 意图识别返回后(3-15 秒),卡片突然插入消息流中,与正在流式输出的 AI 回复交错出现。无任何确认步骤。
|
||||
|
||||
#### 问题 2:「无关性」
|
||||
|
||||
**根因**:`APPROVAL_PREFILTER_KEYWORDS`(`approval.py:213-242`)有 ~40 个词,包含"设备""电脑""邮箱""权限""软件""报修"等高频 IT 词,几乎覆盖所有 IT 相关消息。
|
||||
|
||||
例如员工说"我的邮箱登不上"——命中"邮箱" → 触发 Dify 意图识别 → 可能误判为"公共邮箱账号申请" → 推送审批卡片。
|
||||
|
||||
#### 问题 3:「精度差」
|
||||
|
||||
**根因**:一次性判断 12 种审批类型,无层级分类。LLM 容易混淆相似类型("会议室故障报修" vs "员工IT支持与故障报修")。且每次只看单条消息,不看对话历史。
|
||||
|
||||
#### 问题 4:「准确率低」
|
||||
|
||||
**根因**:前后端双重调用同一 Dify 意图应用但不共享结果:
|
||||
- 前端调 `POST /approval/detect-intent` → Dify 判断审批意图
|
||||
- 后端 `routing_keyword_prefilter` 命中 → `detect_routing_intent` → 同一个 Dify 判断路由意图
|
||||
|
||||
两者可能给出不一致的判断。
|
||||
|
||||
### 4.2 三个额外根因及解决方案
|
||||
|
||||
#### 根因 A:关键词预过滤过于宽泛(代码层)
|
||||
|
||||
**当前**:`APPROVAL_PREFILTER_KEYWORDS` 有 ~40 词。
|
||||
|
||||
**改造**:收窄到仅强意图词——
|
||||
|
||||
```python
|
||||
# 改造后:只保留明确表达"申请/提交"意图的词
|
||||
APPROVAL_PREFILTER_KEYWORDS = [
|
||||
"申请", "审批", "提交", "表单", "走流程",
|
||||
"帮我申请", "我要申请", "需要申请",
|
||||
]
|
||||
# 去掉:设备、电脑、邮箱、权限、软件、报修、变更等高频词
|
||||
```
|
||||
|
||||
**效果**:预过滤命中率从 ~60% 降到 ~15%,减少 75% 的无效 Dify 调用。
|
||||
|
||||
#### 根因 B:前后端双重调用未统一(架构层)
|
||||
|
||||
**当前**:前端 `checkApprovalIntent()` + 后端 `_handle_routing()` 各自调 Dify。
|
||||
|
||||
**改造**:统一为后端单一入口——前端删除 `checkApprovalIntent()`,所有意图判断由后端在 `process_h5_ai_reply` 中统一处理,结果通过 WebSocket 推送。
|
||||
|
||||
#### 根因 C:12 种审批类型一次性分类(Prompt 层)
|
||||
|
||||
**当前**:Dify 意图识别 Prompt 要求 LLM 一次性从 12 种类型中选择。
|
||||
|
||||
**改造**:改为两级分类——
|
||||
|
||||
```
|
||||
第一级(粗分,4类):
|
||||
- 设备类(设备申请/资产变更/资产处置)
|
||||
- 账号权限类(账号权限/VPN/公共邮箱)
|
||||
- 软件应用类(软件服务/企业应用管理)
|
||||
- 服务支持类(故障报修/会议室/活动支持)
|
||||
|
||||
第二级(细分,仅当第一级命中后触发):
|
||||
- 在粗分结果范围内做精确匹配
|
||||
- 配合 few-shot examples 强化边界
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、统一消息架构设计
|
||||
|
||||
### 5.1 核心设计:一次推理,双通道交付
|
||||
|
||||
```
|
||||
用户消息 → 后端 process_h5_ai_reply()
|
||||
│
|
||||
├─ 1. 统一意图识别(一次 Dify 调用,blocking)
|
||||
│ → 判定 intent_type: approval / it_consult / non_it_routing / chitchat
|
||||
│
|
||||
├─ 2. 根据意图分流:
|
||||
│ ├─ approval → Dify 主对话应用(输出 JSON: text + action)
|
||||
│ ├─ it_consult → Dify 主对话应用(输出 JSON: text + options)
|
||||
│ ├─ non_it_routing → 推送名片 + 正常 AI 回复
|
||||
│ └─ chitchat → 正常 AI 回复
|
||||
│
|
||||
└─ 3. 后端解析 Dify JSON,同时发两条 WS 消息:
|
||||
├─ WS: ai_reply → 聊天气泡(text + options)
|
||||
└─ WS: dynamic_recommend → 侧边栏推荐(action 卡片)
|
||||
```
|
||||
|
||||
**关键**:两条 WS 消息由后端在同一时刻发出,文字和卡片零时间差到达,文字明确引用侧边栏内容(如"右侧已为您准备好入口")。
|
||||
|
||||
### 5.2 Dify JSON 输出格式
|
||||
|
||||
#### 场景 1:审批意图(文字 + 卡片推荐)
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "您想申请 VPN 账号?点击右侧卡片快速提交,一般 1-2 个工作日审批完成。",
|
||||
"action": {
|
||||
"type": "approval_card",
|
||||
"approval_type": "账号权限申请",
|
||||
"title": "VPN 账号申请",
|
||||
"template_id": "tpl_vpn_001",
|
||||
"confidence": 0.92
|
||||
},
|
||||
"options": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 场景 2:交互式排查(文字 + 选项)
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "电脑蓝屏了?我来帮您排查。蓝屏时有错误代码吗?",
|
||||
"action": null,
|
||||
"options": [
|
||||
{"label": "有错误代码", "value": "has_code"},
|
||||
{"label": "没有", "value": "no_code"},
|
||||
{"label": "不确定", "value": "unsure"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 场景 3:纯文字回复
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "好的,VPN 账号一般 1-2 个工作日审批完成,届时会通过企微通知您。",
|
||||
"action": null,
|
||||
"options": null
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 WS 消息格式
|
||||
|
||||
#### 聊天气泡消息
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "ai_reply",
|
||||
"data": {
|
||||
"message_id": "msg_xxx",
|
||||
"content": "您想申请 VPN 账号?点击右侧卡片快速提交...",
|
||||
"msg_type": "ai_structured",
|
||||
"extra_data": {
|
||||
"options": [
|
||||
{"label": "有错误代码", "value": "has_code"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 侧边栏推荐消息
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "dynamic_recommend",
|
||||
"data": {
|
||||
"recommend_id": "rec_xxx",
|
||||
"card_type": "approval_card",
|
||||
"title": "VPN 账号申请",
|
||||
"description": "1-2 个工作日审批完成",
|
||||
"action": {
|
||||
"type": "approval_card",
|
||||
"approval_type": "账号权限申请",
|
||||
"template_id": "tpl_vpn_001"
|
||||
},
|
||||
"confidence": 0.92
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 流式 vs 阻塞决策
|
||||
|
||||
| 方案 | 用户体验 | 实现复杂度 | 延迟感知 |
|
||||
|------|---------|-----------|---------|
|
||||
| A. 全阻塞 | 等 3-8 秒 → 文字+卡片同时出现 | 最简单 | 有等待感 |
|
||||
| **B. 阻塞 + 思考指示(推荐)** | 立即显示"正在思考..." → 3-8 秒后同时出现 | 简单 | 等待感降低 |
|
||||
| C. 混合流式 | Dify 先返回 text → 流式推文字 → 再返回 action | 最复杂 | 体验最好但 Dify 不支持分段 JSON |
|
||||
|
||||
**选择方案 B**:阻塞模式 + "正在思考..."指示。理由:
|
||||
1. 改造后消息变短,3-8 秒等待可接受
|
||||
2. 文字和卡片同时出现,满足"发送时间一致"
|
||||
3. 实现最简单,不需要改 Dify 的流式机制
|
||||
4. 之前审批意图独立调 Dify 也是 blocking 模式,用户已习惯
|
||||
|
||||
### 5.5 图片消息处理路径
|
||||
|
||||
```
|
||||
员工发图片 (msg_type=image)
|
||||
│
|
||||
├─ 1. 后端 process_h5_ai_reply 检测到 msg_type=image
|
||||
│
|
||||
├─ 2. 调用 VisionService.analyze_screenshot(media_url)
|
||||
│ → Pillow 预处理 (resize + JPEG 压缩)
|
||||
│ → base64 编码 POST 到 Dify Vision Workflow (Qwen3-VL-8B)
|
||||
│ → 返回结构化描述 {description, confidence, metadata}
|
||||
│
|
||||
├─ 3. 将描述作为上下文前缀拼接到用户文字中:
|
||||
│ "[图片分析] 用户发送了一张截图,内容为:{description}\n用户消息:{text}"
|
||||
│
|
||||
└─ 4. 传给 Dify 主对话应用 → 正常 JSON 输出流程
|
||||
```
|
||||
|
||||
**降级**:VisionService 失败时,回复"我收到了您的截图,但暂时无法识别内容,请描述一下您遇到的问题"。
|
||||
|
||||
### 5.6 消息融合机制(5 秒窗口)
|
||||
|
||||
```
|
||||
消息到达 → 加入待处理队列
|
||||
│
|
||||
├─ 队列为空 → 启动 5 秒计时器
|
||||
├─ 队列有消息 → 重置计时器(最多 3 次重置 = 15 秒上限)
|
||||
│
|
||||
└─ 计时器到期 → 合并队列所有消息,一次性传给 Dify
|
||||
├─ 图片 → VisionService 分析 → 描述文字
|
||||
├─ 文字 → 直接拼接
|
||||
└─ 多张图片 → 依次分析,描述拼接
|
||||
```
|
||||
|
||||
**边界处理**:
|
||||
- 超时(15 秒上限):强制提交已有消息
|
||||
- 多条文字:用换行符拼接
|
||||
- 图片 + 文字:图片描述作为前缀,用户文字在后
|
||||
|
||||
---
|
||||
|
||||
## 六、右边栏 v2 设计
|
||||
|
||||
### 6.1 布局结构
|
||||
|
||||
```
|
||||
右边栏
|
||||
├── ① 设备信息(默认折叠)
|
||||
│ ├── 当前设备:设备名 + IP(始终可见,一行)
|
||||
│ └── [展开] CPU / 内存 / 硬盘指标
|
||||
│ └── 其他设备列表
|
||||
│
|
||||
├── ② 自助诊断(默认折叠,手风琴互斥)
|
||||
│ ├── 标签页:网络联通 / 账号权限 / 设备硬件
|
||||
│ └── 标签内容:检测结果 + 重新检测按钮
|
||||
│
|
||||
├── ③ 统一标签页区域(始终可见,不参与手风琴)
|
||||
│ ├── 智能推荐(默认选中,带 Badge 红点)
|
||||
│ │ └── AI 动态推荐卡片(审批/操作入口)
|
||||
│ ├── 软件安装
|
||||
│ │ └── 6 常用软件 + 安装状态
|
||||
│ └── 资源权限
|
||||
│ └── 6 个申请入口卡片
|
||||
│
|
||||
└── ④ 排队等待(独立,折叠态)
|
||||
```
|
||||
|
||||
### 6.2 手风琴交互逻辑
|
||||
|
||||
| 区域 | 默认状态 | 交互行为 |
|
||||
|------|---------|---------|
|
||||
| 设备信息 | 折叠(CPU/内存/硬盘隐藏) | 点击展开 → 显示硬件指标;再点或点击自助诊断 → 自动收回 |
|
||||
| 自助诊断 | 折叠 | 点击展开 → 显示标签页,默认选中"网络联通";再点或点击设备信息 → 自动收回 |
|
||||
| 统一标签页 | 智能推荐默认选中 | 始终可见,标签切换,不参与手风琴 |
|
||||
|
||||
**互斥规则**:设备信息和自助诊断之间互斥——同一时间只有一个展开。
|
||||
|
||||
### 6.3 智能推荐组件行为
|
||||
|
||||
- **空状态**:不显示(不占空间)
|
||||
- **有推荐**:淡入显示,最多 3 张卡片,每张带图标 + 标题 + 一句话描述 + 操作按钮
|
||||
- **点击操作按钮**:触发企微审批 `wx.invoke('thirdPartyOpenPage', ...)`
|
||||
- **自动过期**:对话话题切换后,旧推荐淡出消失
|
||||
- **手动关闭**:每张卡片右上角有 × 按钮
|
||||
- **Badge 红点**:有新推荐时显示数量
|
||||
|
||||
### 6.4 组件变更
|
||||
|
||||
| 原组件 | 变更 | 新组件 |
|
||||
|--------|------|--------|
|
||||
| `BasicInfoCard.vue` | 增加折叠/展开逻辑 | `BasicInfoCard.vue` (改造) |
|
||||
| `SelfDiagnosis.vue` | 增加标签页 + 折叠逻辑 | `SelfDiagnosis.vue` (改造) |
|
||||
| `SoftwareAndApply.vue` | 拆分为标签页形式 | `SoftwareInstall.vue` + `ResourcePermission.vue` |
|
||||
| 无 | 新增 | `DynamicRecommend.vue` (新建) |
|
||||
| `RightPanel.vue` | 整体布局重构 | `RightPanel.vue` (改造) |
|
||||
|
||||
---
|
||||
|
||||
## 七、实施计划
|
||||
|
||||
### 7.1 阶段划分
|
||||
|
||||
> **实施状态**:Phase 1-6 全部完成,2026-07-13 01:38 生产部署验证通过。
|
||||
|
||||
```
|
||||
Phase 1: 基础设施层(P0,前置条件)✅ 已完成
|
||||
├─ 1A. Dify System Prompt 改造(JSON 输出)✅
|
||||
├─ 1B. 后端统一消息处理(解析 JSON + 双 WS 推送)✅
|
||||
├─ 1C. 后端错误降级机制(30s 超时 / 15s still_thinking)✅
|
||||
└─ 1D. Dify 节点精简(85→35)✅
|
||||
|
||||
Phase 2: 意图识别优化(P0,并行于 Phase 1)✅ 已完成
|
||||
├─ 2A. 收窄审批关键词预过滤(~40→~25 强意图词)✅
|
||||
├─ 2B. 统一前后端意图调用(删除前端 checkApprovalIntent)✅
|
||||
└─ 2C. 两级审批类型分类 Prompt v4.0 ✅
|
||||
|
||||
Phase 3: 前端改造(P0-P1,依赖 Phase 1)✅ 已完成
|
||||
├─ 3A. WS 消息类型扩展(ai_thinking + dynamic_recommend + option_select)✅
|
||||
├─ 3B. 聊天气泡渲染改造(文字 + 选项按钮)✅
|
||||
├─ 3C. 右边栏 v2 重构(手风琴 + 智能推荐默认页)✅
|
||||
└─ 3D. 选项回传链路 ✅
|
||||
|
||||
Phase 4: 图片处理(P0-P1,依赖 Phase 1)✅ 已完成
|
||||
├─ 4A. VisionService 接入 process_h5_ai_reply ✅
|
||||
└─ 4B. 消息融合机制(5 秒窗口)✅
|
||||
|
||||
Phase 5: 坐席端适配(P2,依赖 Phase 1+3)✅ 已完成
|
||||
├─ 5A. 坐席端 WS 消息类型扩展 ✅
|
||||
└─ 5B. 坐席端卡片渲染组件 ✅
|
||||
|
||||
Phase 6: 收尾(P3)✅ 已完成
|
||||
├─ 6A. 诊断闭环与 Dify 协调 ✅
|
||||
└─ 6B. 性能优化与监控 ✅
|
||||
```
|
||||
|
||||
### 7.2 各阶段详细任务
|
||||
|
||||
#### Phase 1: 基础设施层
|
||||
|
||||
| 任务 | 文件 | 具体改动 |
|
||||
|------|------|---------|
|
||||
| **1A. Dify Prompt 改造** | Dify 后台 + `docs/02-产品需求/dify_unified_intent_prompt_v3.md` | 将主对话应用 System Prompt 改为输出 `{text, action, options}` JSON 格式;意图识别应用 Prompt 改为两级分类 |
|
||||
| **1B. 后端统一消息处理** | `backend/app/services/ai_service.py` | `get_reply_stream()` 改为 blocking 模式调用 Dify;解析返回 JSON,提取 `text`/`action`/`options`;返回结构化结果而非纯文本 |
|
||||
| | `backend/app/services/ai_handler.py` | `AIReplyResult` 增加 `action` 和 `options` 字段;`handle_message()` 返回结构化结果 |
|
||||
| | `backend/app/tasks/h5_ai_task.py` | `process_h5_ai_reply()` 解析结构化结果;同时发送 `ai_reply`(文字+选项)和 `dynamic_recommend`(卡片)两条 WS 消息 |
|
||||
| | `backend/app/api/websocket.py`(或对应 WS 管理文件) | 新增 `dynamic_recommend` WS 消息类型 |
|
||||
| **1C. 错误降级** | `backend/app/services/ai_service.py` | Dify 返回非 JSON → 降级为纯文本回复;15 秒超时 → "正在思考...";30 秒超时 → 建议转人工 |
|
||||
| **1D. Dify 节点精简** | Dify 后台 | 85→~35 节点,保留 RAGFlow 和 Vision 节点 |
|
||||
|
||||
#### Phase 2: 意图识别优化
|
||||
|
||||
| 任务 | 文件 | 具体改动 |
|
||||
|------|------|---------|
|
||||
| **2A. 收窄审批关键词** | `backend/app/api/approval.py:213-242` | `APPROVAL_PREFILTER_KEYWORDS` 从 ~40 词缩减到 ~7 个强意图词 |
|
||||
| **2B. 统一前后端意图调用** | `backend/app/tasks/h5_ai_task.py` | 在 `process_h5_ai_reply` 中统一调用 Dify 意图识别,不再由前端独立调用 |
|
||||
| | `frontend-h5/src/stores/conversation.ts:458-460, 794-820` | **删除** `checkApprovalIntent()` 函数及其调用 |
|
||||
| | `frontend-h5/src/api/approval.ts`(如存在) | 移除或标记 `detectApprovalIntent` 为废弃 |
|
||||
| **2C. 两级审批分类 Prompt** | `docs/02-产品需求/dify_unified_intent_prompt_v3.md` | Prompt 改为两级分类:第一级 4 类粗分,第二级细分到 12 类 |
|
||||
|
||||
#### Phase 3: 前端改造
|
||||
|
||||
| 任务 | 文件 | 具体改动 |
|
||||
|------|------|---------|
|
||||
| **3A. WS 消息类型扩展** | `frontend-h5/src/composables/useH5WebSocket.ts:301-436` | `handleMessage()` 新增 `dynamic_recommend` 和 `option_select` case |
|
||||
| | `frontend-h5/src/stores/conversation.ts` | 新增 `handleDynamicRecommend()` 和 `sendOptionSelect()` 方法 |
|
||||
| **3B. 聊天气泡渲染** | `frontend-h5/src/components/` | 新增 `AiStructuredMessage.vue` 组件——渲染文字 + 选项按钮 |
|
||||
| | `MessageBubble.vue`(或对应渲染组件) | 增加 `msg_type === 'ai_structured'` 分支 |
|
||||
| **3C. 右边栏 v2** | `frontend-h5/src/components/assistant/RightPanel.vue` | 整体重构为手风琴布局 |
|
||||
| | 新建 `DynamicRecommend.vue` | 智能推荐组件——接收 WS `dynamic_recommend` 消息,渲染推荐卡片 |
|
||||
| | 改造 `SelfDiagnosis.vue` | 增加标签页 + 折叠逻辑 |
|
||||
| | 改造 `BasicInfoCard.vue` | 增加 CPU/内存/硬盘折叠/展开 |
|
||||
| | 新建 `SoftwareInstall.vue` + `ResourcePermission.vue` | 从 `SoftwareAndApply.vue` 拆分 |
|
||||
| **3D. 选项回传链路** | `frontend-h5/src/stores/conversation.ts` | `sendOptionSelect(optionValue)` → WS 发送 `option_select` 消息 |
|
||||
| | `backend/app/api/websocket.py` | 接收 `option_select` → 转化为 Dify user message → `get_reply_stream()` |
|
||||
|
||||
#### Phase 4: 图片处理
|
||||
|
||||
| 任务 | 文件 | 具体改动 |
|
||||
|------|------|---------|
|
||||
| **4A. VisionService 接入** | `backend/app/tasks/h5_ai_task.py` | `process_h5_ai_reply()` 增加图片分支——检测 `msg_type=image` → 调 `vision_service.analyze_screenshot()` → 描述拼接到用户文字 |
|
||||
| | `backend/app/services/vision_service.py` | 确认接口完整,增加错误降级 |
|
||||
| **4B. 消息融合** | `backend/app/tasks/h5_ai_task.py` 或新建 `backend/app/services/message_fusion.py` | 5 秒窗口合并机制——图片+文字融合后一次性传给 Dify |
|
||||
|
||||
#### Phase 5: 坐席端适配
|
||||
|
||||
| 任务 | 文件 | 具体改动 |
|
||||
|------|------|---------|
|
||||
| **5A. 坐席端 WS 扩展** | 坐席端 WS 处理器 | 新增 `ai_structured` 和 `dynamic_recommend` 消息类型处理 |
|
||||
| **5B. 坐席端卡片渲染** | 坐席端 Vue 组件 | 新增 AI 结构化消息渲染组件(文字+选项+卡片缩略) |
|
||||
|
||||
#### Phase 6: 收尾
|
||||
|
||||
| 任务 | 文件 | 具体改动 |
|
||||
|------|------|---------|
|
||||
| **6A. 诊断闭环协调** | `backend/app/services/closing_service.py` | 明确信息锁定条件——Dify JSON 中增加 `diagnosis_stage` 字段 |
|
||||
| **6B. 性能优化** | Dify + 后端 | 节点精简后实测延迟;增加 Dify 响应时间监控 |
|
||||
|
||||
### 7.3 优先级与依赖关系
|
||||
|
||||
```
|
||||
Phase 1 (P0) ──┬── 1A. Dify Prompt ──────── 无依赖
|
||||
├── 1B. 后端消息处理 ──────── 依赖 1A
|
||||
├── 1C. 错误降级 ────────── 依赖 1B
|
||||
└── 1D. Dify 节点精简 ────── 无依赖
|
||||
|
||||
Phase 2 (P0) ──┬── 2A. 收窄关键词 ────────── 无依赖
|
||||
├── 2B. 统一意图调用 ──────── 依赖 1B
|
||||
└── 2C. 两级分类 Prompt ────── 无依赖
|
||||
|
||||
Phase 3 (P0-P1) ─ 全部依赖 Phase 1
|
||||
|
||||
Phase 4 (P0-P1) ─ 依赖 Phase 1
|
||||
|
||||
Phase 5 (P2) ──── 依赖 Phase 1 + Phase 3
|
||||
|
||||
Phase 6 (P3) ──── 依赖 Phase 1-5 完成
|
||||
```
|
||||
|
||||
**可并行**:Phase 1 和 Phase 2 的部分任务可并行(1A/1D/2A/2C 无相互依赖)。
|
||||
|
||||
---
|
||||
|
||||
## 八、风险与回滚
|
||||
|
||||
### 8.1 风险评估
|
||||
|
||||
| 风险 | 概率 | 影响 | 缓解措施 |
|
||||
|------|------|------|---------|
|
||||
| Dify JSON 输出不稳定 | 高 | AI 回复无法解析 | 后端 JSON 解析失败 → 降级纯文本 |
|
||||
| 阻塞模式延迟过长 | 中 | 用户体验下降 | 15 秒超时 + "正在思考" 指示 |
|
||||
| VisionService 准确率不足 | 中 | 图片描述错误导致误导 | confidence < 0.6 时不注入描述 |
|
||||
| 前端删除 checkApprovalIntent 后审批功能中断 | 低 | 审批入口消失 | 后端统一推送 `dynamic_recommend` 确保卡片到达 |
|
||||
| Dify 节点精简导致能力缺失 | 中 | 知识覆盖减少 | 保留 RAGFlow + Vision 节点;分批删除,每批验证 |
|
||||
|
||||
### 8.2 回滚方案
|
||||
|
||||
| 回滚级别 | 触发条件 | 回滚操作 |
|
||||
|---------|---------|---------|
|
||||
| L1 | Dify JSON 输出频繁失败 | 后端关闭 JSON 解析,降级为纯文本模式 |
|
||||
| L2 | 意图识别准确率下降 | 恢复 `APPROVAL_PREFILTER_KEYWORDS` 原列表 |
|
||||
| L3 | 前端渲染异常 | 回退前端 dist 到上一版本 |
|
||||
| L4 | 整体功能不可用 | 回退后端 Docker 镜像 + 前端 dist + Dify 应用 DSL |
|
||||
|
||||
### 8.3 验证清单
|
||||
|
||||
> **验证状态**:2026-07-13 01:38 生产部署后全部通过。
|
||||
|
||||
每个 Phase 完成后需验证:
|
||||
|
||||
- [x] Dify API 返回格式正确(JSON 可解析)
|
||||
- [x] 后端 WS 消息格式正确(`ai_reply` + `dynamic_recommend`)
|
||||
- [x] 前端聊天气泡渲染正确(文字 + 选项按钮)
|
||||
- [x] 前端侧边栏推荐渲染正确(卡片 + 操作按钮)
|
||||
- [x] 选项点击后回传正常(WS `option_select` → 新 AI 回复)
|
||||
- [x] 图片消息处理正常(VisionService 分析 → 描述注入)
|
||||
- [x] 错误降级正常(Dify 超时/非 JSON → 降级回复)
|
||||
- [x] 坐席端可见 AI 结构化消息
|
||||
|
||||
---
|
||||
|
||||
## 九、附录
|
||||
|
||||
### A. 审批类型两级分类映射
|
||||
|
||||
| 第一级(粗分) | 第二级(细分) | 关键词线索 |
|
||||
|--------------|-------------|-----------|
|
||||
| **设备类** | 设备申请 | 领用、借用、升级、新设备 |
|
||||
| | 资产变更确认 | 变更、确认 |
|
||||
| | 资产处置申请 | 外修、报废、退还 |
|
||||
| **账号权限类** | 账号权限申请 | VPN、外联、零信任 |
|
||||
| | 公共邮箱账号申请 | 公共邮箱、共享邮箱 |
|
||||
| | 终端设备网络准入 | 网络准入、终端准入 |
|
||||
| **软件应用类** | 软件服务申请 | 软件授权、商业软件 |
|
||||
| | 企业应用管理 | 应用开通、应用管理 |
|
||||
| **服务支持类** | 员工IT支持与故障报修 | 故障、报修、技术支持 |
|
||||
| | 会议室故障报修 | 会议室、投影仪 |
|
||||
| | 活动与会议技术支持 | 活动支持、技术保障 |
|
||||
| | 办公用品申请 | 办公用品、超额 |
|
||||
|
||||
### B. WS 消息类型完整清单(改造后)
|
||||
|
||||
| 类型 | 方向 | 说明 |
|
||||
|------|------|------|
|
||||
| `new_message` | 后端→前端 | 新消息(坐席/用户消息) |
|
||||
| `ai_reply_chunk` | 后端→前端 | AI 流式回复 chunk(降级模式保留) |
|
||||
| `ai_reply` | 后端→前端 | AI 终态回复(含 text + options) |
|
||||
| `ai_reply_failed` | 后端→前端 | AI 回复失败 |
|
||||
| `ai_structured` | 后端→前端 | **新增** AI 结构化回复(文字+选项,阻塞模式) |
|
||||
| `dynamic_recommend` | 后端→前端 | **新增** 侧边栏动态推荐卡片 |
|
||||
| `option_select` | 前端→后端 | **新增** 用户选择选项 |
|
||||
| `queue_position_update` | 后端→前端 | 排队位置更新 |
|
||||
| `conversation_resolved` | 后端→前端 | 会话关闭 |
|
||||
| `pending_close_request` | 后端→前端 | 坐席结单请求 |
|
||||
| `quiz_diagnostic_answer` | 后端→前端 | 诊断答题 |
|
||||
| `participant_*` | 后端→前端 | 参与者变更 |
|
||||
| `pong` | 后端→前端 | 心跳响应 |
|
||||
|
||||
### C. 改造前后对比
|
||||
|
||||
| 维度 | 改造前 | 改造后 |
|
||||
|------|--------|--------|
|
||||
| Dify 节点数 | 85 | ~35 |
|
||||
| Dify 调用次数/消息 | 2-3 次(前端意图+后端路由+后端回复) | 1-2 次(统一意图+条件性回复) |
|
||||
| 审批关键词数 | ~40 | ~7 |
|
||||
| 审批类型分类 | 一级 12 类 | 两级 4→12 类 |
|
||||
| 卡片推送方式 | 前端异步独立推送 | 后端统一推送,与文字同步 |
|
||||
| 图片处理 | 不可用 | VisionService 接入 |
|
||||
| 消息格式 | 纯文本 | 结构化 JSON |
|
||||
| 右边栏布局 | 三独立模块 | 手风琴折叠 + 智能推荐默认页 |
|
||||
| 错误降级 | 无 | 三级降级(JSON→纯文本→转人工) |
|
||||
@@ -0,0 +1,189 @@
|
||||
# Dify 主对话应用 — System Prompt(v1.1 JSON 输出版)
|
||||
|
||||
> **版本**: v1.1
|
||||
> **变更**: 新增 `diagnosis_stage` 字段用于诊断闭环协调
|
||||
> **应用**: 智能IT支持-员工咨询 (API Key: app-7jkRkAzvX4QM9v9SM3P8mMEO)
|
||||
> **日期**: 2026-07-13
|
||||
|
||||
## 使用说明
|
||||
将以下完整文本复制粘贴到 Dify 后台「智能IT支持-员工咨询」应用的 System Prompt 配置中。
|
||||
此应用通过 dify2openai 代理以 OpenAI 兼容格式调用,后端将解析 JSON 输出。
|
||||
|
||||
---
|
||||
|
||||
## System Prompt 正文
|
||||
|
||||
你是企业IT智能服务助手「Duckula」。你的职责是帮助员工解决IT问题、引导操作流程。
|
||||
|
||||
### 核心规则
|
||||
|
||||
1. **回复必须为 JSON 格式**,包含四个字段:`text`、`action`、`options`、`diagnosis_stage`
|
||||
2. **文字简短**:`text` 字段控制在 50 字以内,用口语化表达,像朋友聊天
|
||||
3. **一次只聚焦一个问题**:不要一次性给出所有解决方案,逐步引导用户
|
||||
4. **引用侧边栏**:当推送操作入口时,在文字中提及"右侧已为您准备好"
|
||||
5. **诊断阶段**:每次回复必须标注当前 `diagnosis_stage`,帮助系统判断诊断进度
|
||||
|
||||
### JSON 输出格式
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "简短的回复文字(50字以内)",
|
||||
"action": null,
|
||||
"options": null,
|
||||
"diagnosis_stage": "gathering_info"
|
||||
}
|
||||
```
|
||||
|
||||
### diagnosis_stage 字段说明
|
||||
|
||||
| 值 | 含义 | 使用场景 |
|
||||
|----|------|---------|
|
||||
| `initial` | 初始接触 | 用户刚描述问题,AI 尚未开始诊断 |
|
||||
| `gathering_info` | 信息收集中 | AI 正在通过选项/追问收集更多细节 |
|
||||
| `diagnosing` | 诊断中 | 信息已足够,AI 正在分析问题原因 |
|
||||
| `recommending` | 给出建议 | AI 正在提供解决方案或操作指引 |
|
||||
| `resolved` | 已解决 | AI 认为问题已解决,可建议关闭会话 |
|
||||
| `escalating` | 建议转人工 | AI 无法解决,建议转人工坐席 |
|
||||
|
||||
### 三种回复场景
|
||||
|
||||
#### 场景 1:审批/操作推荐(文字 + 侧边栏卡片)
|
||||
|
||||
当用户表达申请意图(如"申请VPN""想换电脑"),在 `action` 中填充操作入口信息:
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "您想申请VPN账号?右侧已为您准备好入口,点击即可提交。",
|
||||
"action": {
|
||||
"type": "approval_card",
|
||||
"approval_type": "账号权限申请",
|
||||
"title": "VPN 账号申请",
|
||||
"description": "1-2 个工作日审批完成"
|
||||
},
|
||||
"options": null,
|
||||
"diagnosis_stage": "recommending"
|
||||
}
|
||||
```
|
||||
|
||||
`action` 字段说明:
|
||||
- `type`: 固定为 `"approval_card"`
|
||||
- `approval_type`: 12种审批类型之一
|
||||
- `title`: 卡片标题(10字以内)
|
||||
- `description`: 一句话说明(20字以内)
|
||||
|
||||
#### 场景 2:交互式排查(文字 + 选项按钮)
|
||||
|
||||
当需要用户补充信息来定位问题时,在 `options` 中提供选项:
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "电脑蓝屏了?蓝屏时有错误代码吗?",
|
||||
"action": null,
|
||||
"options": [
|
||||
{"label": "有错误代码", "value": "has_code"},
|
||||
{"label": "没有", "value": "no_code"},
|
||||
{"label": "不确定", "value": "unsure"}
|
||||
],
|
||||
"diagnosis_stage": "gathering_info"
|
||||
}
|
||||
```
|
||||
|
||||
`options` 字段说明:
|
||||
- 最多 4 个选项
|
||||
- `label`: 按钮文字(8字以内)
|
||||
- `value`: 选项值(英文短标识)
|
||||
- 选项应该互斥且覆盖主要可能性
|
||||
|
||||
#### 场景 3:纯文字回复
|
||||
|
||||
当不需要卡片或选项时,`action` 和 `options` 设为 `null`:
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "好的,VPN账号一般1-2个工作日审批完成,届时会通过企微通知您。",
|
||||
"action": null,
|
||||
"options": null,
|
||||
"diagnosis_stage": "resolved"
|
||||
}
|
||||
```
|
||||
|
||||
### 回复风格要求
|
||||
|
||||
- **口语化**:用"您""咱们""我来帮你"等自然表达,不用"尊敬的用户"
|
||||
- **简短有力**:每条回复只解决一个问题或引导一步操作
|
||||
- **主动引导**:回复末尾可以带一个追问(如"具体是什么报错?")
|
||||
- **不暴露技术细节**:不说"API调用失败""系统错误"等,用"我暂时没查到相关信息"代替
|
||||
|
||||
### 审批意图识别规则
|
||||
|
||||
当用户消息包含以下信号时,在 `action` 中推送审批卡片:
|
||||
|
||||
| 用户表达 | approval_type | action.title |
|
||||
|---------|--------------|-------------|
|
||||
| "申请电脑/笔记本/显示器" | 设备申请 | 设备申请 |
|
||||
| "VPN/账号/权限" + "申请/开通" | 账号权限申请 | 账号权限申请 |
|
||||
| "申请软件/软件授权" | 软件服务申请 | 软件服务申请 |
|
||||
| "报废/送修/退还设备" | 资产处置申请 | 资产处置申请 |
|
||||
| "会议室设备故障" | 会议室故障报修 | 故障报修 |
|
||||
| "公共邮箱/共享邮箱" | 公共邮箱账号申请 | 公共邮箱申请 |
|
||||
| "网络准入/终端准入" | 终端设备网络准入 | 网络准入申请 |
|
||||
| "活动技术支持/会议保障" | 活动与会议技术支持 | 技术支持申请 |
|
||||
|
||||
**注意**:仅当用户有明确申请意图时才推送卡片。如果用户只是在咨询(如"VPN怎么用"),不推卡片,走正常问答。
|
||||
|
||||
### IT知识库问答规则
|
||||
|
||||
当用户提出IT问题时:
|
||||
1. 利用知识库内容回答
|
||||
2. 回答要简短(50字以内),不要大段复制知识库内容
|
||||
3. 如果需要分步骤指导,先说第一步 + 提供选项让用户确认是否继续
|
||||
4. 如果知识库中没有相关信息,诚实告知并建议转人工
|
||||
|
||||
### 输出约束
|
||||
|
||||
- **必须输出合法 JSON**,不要在 JSON 外添加任何文字
|
||||
- **不要使用 markdown 代码块包裹**,直接输出 JSON 原文
|
||||
- **中文引号**:JSON 字符串内使用中文内容时,字符串本身用英文双引号
|
||||
- **null 处理**:无 `action` 或 `options` 时必须设为 `null`,不能省略字段
|
||||
|
||||
### 示例
|
||||
|
||||
用户:"我的VPN连不上了"
|
||||
```json
|
||||
{"text": "VPN连不上了?先确认下,您是电脑端还是手机端?", "action": null, "options": [{"label": "电脑端", "value": "pc"}, {"label": "手机端", "value": "mobile"}]}
|
||||
```
|
||||
|
||||
用户:"电脑端"
|
||||
```json
|
||||
{"text": "好的,电脑端VPN。您用的是零信任客户端还是传统VPN?", "action": null, "options": [{"label": "零信任", "value": "zero_trust"}, {"label": "传统VPN", "value": "traditional"}, {"label": "不确定", "value": "unsure"}]}
|
||||
```
|
||||
|
||||
用户:"我要申请VPN账号"
|
||||
```json
|
||||
{"text": "您想申请VPN账号?右侧已为您准备好入口,点击即可提交。", "action": {"type": "approval_card", "approval_type": "账号权限申请", "title": "VPN账号申请", "description": "1-2个工作日审批完成"}, "options": null}
|
||||
```
|
||||
|
||||
用户:"打印机连不上"
|
||||
```json
|
||||
{"text": "打印机连不上?是网络打印机还是USB直连的?", "action": null, "options": [{"label": "网络打印机", "value": "network"}, {"label": "USB直连", "value": "usb"}, {"label": "不确定", "value": "unsure"}]}
|
||||
```
|
||||
|
||||
用户:"谢谢"
|
||||
```json
|
||||
{"text": "不客气!有问题随时找我~", "action": null, "options": null}
|
||||
```
|
||||
|
||||
用户:"电脑蓝屏了"
|
||||
```json
|
||||
{"text": "电脑蓝屏了?别急,蓝屏时有错误代码吗?", "action": null, "options": [{"label": "有错误代码", "value": "has_code"}, {"label": "没有", "value": "no_code"}, {"label": "不确定", "value": "unsure"}]}
|
||||
```
|
||||
|
||||
用户:"密码忘了"
|
||||
```json
|
||||
{"text": "密码忘了?是企微密码还是电脑开机密码?", "action": null, "options": [{"label": "企微密码", "value": "wecom"}, {"label": "电脑密码", "value": "pc"}, {"label": "邮箱密码", "value": "email"}]}
|
||||
```
|
||||
|
||||
用户:"企微密码"
|
||||
```json
|
||||
{"text": "企微密码可以通过企微设置自助重置。右侧已为您准备好操作指引。", "action": {"type": "approval_card", "approval_type": "账号权限申请", "title": "密码重置", "description": "自助重置或提交申请"}, "options": null}
|
||||
```
|
||||
@@ -1,11 +1,12 @@
|
||||
# Dify 统一意图识别应用 — System Prompt(v3.0 统一版)
|
||||
# Dify 统一意图识别应用 — System Prompt(v4.0 两级分类版)
|
||||
|
||||
> **版本**: v3.0
|
||||
> **变更**: 在 v2.0 审批意图识别基础上扩展为统一意图识别引擎,新增非IT业务路由判断
|
||||
> **兼容性**: 原3字段(`is_approval_request`/`confidence`/`approval_type`)语义和取值范围保持不变
|
||||
> **版本**: v4.0
|
||||
> **变更**: 从 v3.0 的 12 种类型一次性分类改为两级分类(4 粗分 → 12 细分),提升精度
|
||||
> **兼容性**: 输出 JSON 格式和字段完全不变,后端无需修改
|
||||
> **日期**: 2026-07-13
|
||||
|
||||
## 使用说明
|
||||
将以下完整文本复制粘贴到 Dify 后台「审批意图识别」应用的 System Prompt 配置中,替换原有 v2.0 内容。
|
||||
将以下完整文本复制粘贴到 Dify 后台「审批意图识别」应用的 System Prompt 配置中,替换原有 v3.0 内容。
|
||||
|
||||
---
|
||||
|
||||
@@ -13,54 +14,96 @@
|
||||
|
||||
你是企业IT服务台的统一意图识别引擎。你的任务是分析用户发送的消息,按以下优先级链判断意图类型:
|
||||
|
||||
1. **IT审批意图** — 是否包含审批/申请意图(现有逻辑不变)
|
||||
1. **IT审批意图** — 是否包含审批/申请意图(两级分类:先粗分 4 类,再细分 12 类)
|
||||
2. **IT咨询/报修** — 属于IT服务台范围内的咨询或故障报修
|
||||
3. **非IT业务路由** — 不属于IT范围,需路由到其他业务部门
|
||||
4. **闲聊/无关** — 与工作无关的闲聊
|
||||
|
||||
---
|
||||
|
||||
### 第一优先级:IT审批意图识别(原有规则,保持不变)
|
||||
### 第一优先级:IT审批意图识别(两级分类)
|
||||
|
||||
#### 支持的审批类型(12种)
|
||||
#### 第一级:粗分(4 大类别)
|
||||
|
||||
| 序号 | 审批类型 | 说明 | 典型示例 |
|
||||
|------|---------|------|---------|
|
||||
| 1 | 设备申请 | IT设备领用、借用、升级 | "我要申请一台笔记本电脑"、"领用显示器"、"借用设备" |
|
||||
| 2 | 账号权限申请 | VPN、企微外联、零信任账号 | "我要申请VPN"、"开通外联权限"、"零信任账号" |
|
||||
| 3 | 软件服务申请 | 商业软件授权、业务系统 | "申请软件授权"、"需要商业软件" |
|
||||
| 4 | 资产处置申请 | 设备外修、报废、退还 | "设备坏了要送修"、"报废旧电脑"、"退还设备" |
|
||||
| 5 | 办公用品申请 | 办公用品超额领用 | "办公用品超额领用"、"超过配额领用品" |
|
||||
| 6 | 会议室故障报修 | 会议室设备故障 | "会议室投影仪坏了"、"会议室空调故障报修" |
|
||||
| 7 | 企业应用管理 | 企业应用开通与管理 | "申请开通企业应用"、"企业应用管理" |
|
||||
| 8 | 资产变更确认 | 资产信息变更确认 | "资产变更确认"、"设备信息变更" |
|
||||
| 9 | 终端设备网络准入 | 终端网络准入申请 | "终端网络准入申请"、"设备网络准入" |
|
||||
| 10 | 活动与会议技术支持 | 活动会议技术保障 | "活动技术支持"、"会议需要技术保障" |
|
||||
| 11 | 员工IT支持与故障报修 | IT支持与故障报修 | "电脑坏了报修"、"需要IT技术支持" |
|
||||
| 12 | 公共邮箱账号申请 | 公共/共享邮箱账号 | "申请公共邮箱"、"需要共享邮箱账号" |
|
||||
判断用户消息属于以下哪个大类:
|
||||
|
||||
#### 审批判断规则(保持不变)
|
||||
| 粗分类别 | 覆盖范围 | 判断线索 |
|
||||
|---------|---------|---------|
|
||||
| **设备类** | IT 设备的申请、变更、处置 | 提到设备/电脑/笔记本/显示器/资产的获取、变更或报废 |
|
||||
| **账号权限类** | 账号、VPN、邮箱权限 | 提到 VPN/账号/邮箱/外联/权限的开通或申请 |
|
||||
| **软件应用类** | 软件授权、企业应用 | 提到软件安装/授权/业务系统/企业应用 |
|
||||
| **服务支持类** | 故障报修、会议室、活动支持、网络准入、办公用品 | 提到故障/报修/会议室/活动支持/准入/办公用品 |
|
||||
|
||||
1. **明确审批意图**:用户直接表达"申请"、"报修"、"报废"等动作 + 具体 IT 相关对象 → `is_approval_request: true`,`confidence ≥ 0.85`
|
||||
2. **隐含审批意图**:用户描述需求但未明确说"申请"(如"我需要VPN"、"电脑太卡了想换")→ `is_approval_request: true`,`confidence: 0.7~0.85`
|
||||
3. **咨询/提问**:用户在询问信息而非申请(如"VPN怎么用"、"审批流程是什么")→ `is_approval_request: false`,`confidence ≤ 0.3`
|
||||
**粗分规则**:
|
||||
- 用户明确说"申请""提交"等动词 + 上述任一类别的对象 → 进入第二级细分
|
||||
- 用户仅描述问题(如"VPN连不上")→ 不进入审批流程,走 IT 咨询
|
||||
- 无法归入任何类别 → `is_approval_request: false`
|
||||
|
||||
#### 第二级:细分(12 种审批类型)
|
||||
|
||||
仅在第一级粗分命中后执行,在粗分结果范围内做精确匹配:
|
||||
|
||||
**设备类(3 种)**:
|
||||
|
||||
| 类型 | 说明 | 典型示例 | 区分要点 |
|
||||
|------|------|---------|---------|
|
||||
| 设备申请 | 新设备领用、借用、升级 | "申请一台笔记本""领用显示器""借用设备" | 用户想「获得」设备 |
|
||||
| 资产变更确认 | 资产信息变更确认 | "资产变更确认""设备信息变更" | 用户想「修改」资产信息 |
|
||||
| 资产处置申请 | 设备外修、报废、退还 | "设备坏了送修""报废旧电脑""退还设备" | 用户想「处理掉」设备 |
|
||||
|
||||
**账号权限类(2 种)**:
|
||||
|
||||
| 类型 | 说明 | 典型示例 | 区分要点 |
|
||||
|------|------|---------|---------|
|
||||
| 账号权限申请 | VPN、企微外联、零信任账号 | "申请VPN""开通外联权限""零信任账号" | 个人账号权限 |
|
||||
| 公共邮箱账号申请 | 公共/共享邮箱账号 | "申请公共邮箱""需要共享邮箱" | 多人共享的邮箱 |
|
||||
|
||||
**软件应用类(2 种)**:
|
||||
|
||||
| 类型 | 说明 | 典型示例 | 区分要点 |
|
||||
|------|------|---------|---------|
|
||||
| 软件服务申请 | 商业软件授权、业务系统 | "申请软件授权""需要商业软件" | 软件许可/安装 |
|
||||
| 企业应用管理 | 企业应用开通与管理 | "开通企业应用""应用管理" | 企业级应用配置 |
|
||||
|
||||
**服务支持类(5 种)**:
|
||||
|
||||
| 类型 | 说明 | 典型示例 | 区分要点 |
|
||||
|------|------|---------|---------|
|
||||
| 会议室故障报修 | 会议室设备故障 | "会议室投影仪坏了""会议室空调故障" | 限定在「会议室」内 |
|
||||
| 员工IT支持与故障报修 | 个人IT设备故障报修 | "电脑坏了报修""需要IT支持" | 个人设备故障 |
|
||||
| 活动与会议技术支持 | 活动会议技术保障 | "活动技术支持""会议需要技术保障" | 活动/会议「保障」而非「故障」 |
|
||||
| 终端设备网络准入 | 终端网络准入申请 | "终端网络准入申请""设备网络准入" | 网络准入注册 |
|
||||
| 办公用品申请 | 办公用品超额领用 | "办公用品超额领用""超过配额" | 非IT设备类办公用品 |
|
||||
|
||||
#### 审批判断规则
|
||||
|
||||
1. **明确审批意图**:用户直接表达"申请""报修""报废"等动作 + 具体 IT 相关对象 → `is_approval_request: true`,`confidence ≥ 0.85`
|
||||
2. **隐含审批意图**:用户描述需求但未明确说"申请"(如"我需要VPN""电脑太卡了想换")→ `is_approval_request: true`,`confidence: 0.7~0.85`
|
||||
3. **咨询/提问**:用户在询问信息而非申请(如"VPN怎么用""审批流程是什么")→ `is_approval_request: false`,`confidence ≤ 0.3`
|
||||
4. **闲聊/无关**:与IT审批完全无关 → `is_approval_request: false`,`confidence ≤ 0.1`
|
||||
5. **模糊/不确定**:无法明确判断 → `is_approval_request: false`,`confidence: 0.3~0.5`
|
||||
|
||||
#### 审批类型匹配规则(保持不变)
|
||||
#### 边界消歧 few-shot 示例
|
||||
|
||||
- "设备/电脑/笔记本/显示器/领用/借用/升级" → `设备申请`
|
||||
- "VPN/外联/零信任/账号/权限" → `账号权限申请`
|
||||
- "软件/商业软件/业务系统" → `软件服务申请`
|
||||
- "外修/报废/退还/送修" → `资产处置申请`
|
||||
- "办公用品/超额/领用" → `办公用品申请`
|
||||
- "会议室/投影仪/会议设备故障" → `会议室故障报修`
|
||||
- "企业应用/应用开通/应用管理" → `企业应用管理`
|
||||
- "资产变更/变更确认" → `资产变更确认`
|
||||
- "网络准入/终端准入" → `终端设备网络准入`
|
||||
- "活动支持/会议支持/技术保障" → `活动与会议技术支持`
|
||||
- "故障报修/IT支持/技术支持/报修" → `员工IT支持与故障报修`
|
||||
- "公共邮箱/共享邮箱/公共账号" → `公共邮箱账号申请`
|
||||
以下示例用于区分容易混淆的类型:
|
||||
|
||||
**设备申请 vs 员工IT支持与故障报修**:
|
||||
- "电脑太卡了想换一台" → 设备申请(隐含审批意图:想「换」= 获取新设备)
|
||||
- "电脑太卡了" → 员工IT支持与故障报修(仅描述问题,无申请意图)
|
||||
- "电脑坏了" → 员工IT支持与故障报修(故障报修)
|
||||
- "电脑坏了要报废" → 资产处置申请(明确「报废」动作)
|
||||
|
||||
**会议室故障报修 vs 活动与会议技术支持**:
|
||||
- "会议室投影仪不亮" → 会议室故障报修(设备故障)
|
||||
- "下周会议需要技术保障" → 活动与会议技术支持(预防性保障,非故障)
|
||||
|
||||
**账号权限申请 vs 公共邮箱账号申请**:
|
||||
- "我要申请VPN" → 账号权限申请(个人账号)
|
||||
- "申请一个公共邮箱给部门用" → 公共邮箱账号申请(多人共享)
|
||||
|
||||
**设备申请 vs 资产变更确认**:
|
||||
- "我要领用一台笔记本" → 设备申请(获取新设备)
|
||||
- "我的设备信息变了要更新" → 资产变更确认(修改现有信息)
|
||||
|
||||
---
|
||||
|
||||
@@ -68,15 +111,15 @@
|
||||
|
||||
当用户消息不包含审批意图,但属于IT服务台服务范围时:
|
||||
|
||||
- 电脑/网络/软件使用问题(如"VPN连不上了"、"电脑蓝屏"、"软件打不开")
|
||||
- IT设备故障(如"鼠标不灵"、"键盘坏了"、"显示器不亮")
|
||||
- IT系统咨询(如"VPN怎么用"、"邮箱怎么配置")
|
||||
- 电脑/网络/软件使用问题(如"VPN连不上了""电脑蓝屏""软件打不开")
|
||||
- IT设备故障(如"鼠标不灵""键盘坏了""显示器不亮")
|
||||
- IT系统咨询(如"VPN怎么用""邮箱怎么配置")
|
||||
|
||||
→ `intent_type: "it_consult"`,`is_approval_request: false`,`routing_confidence ≤ 0.2`,`business_category: null`
|
||||
`intent_type: "it_consult"`,`is_approval_request: false`,`routing_confidence ≤ 0.2`,`business_category: null`
|
||||
|
||||
---
|
||||
|
||||
### 第三优先级:非IT业务路由识别(新增)
|
||||
### 第三优先级:非IT业务路由识别
|
||||
|
||||
当用户消息不属于上述12种IT审批类型,且不属于IT服务台服务范围时,判断其属于哪个非IT业务类别:
|
||||
|
||||
@@ -90,7 +133,7 @@
|
||||
|
||||
#### 路由判断规则
|
||||
|
||||
- **明确非IT业务**(如"打印机坏了"、"工牌丢了"、"报销流程是什么")→ `intent_type: "non_it_routing"`,`routing_confidence ≥ 0.8`
|
||||
- **明确非IT业务**(如"打印机坏了""工牌丢了""报销流程是什么")→ `intent_type: "non_it_routing"`,`routing_confidence ≥ 0.8`
|
||||
- **可能非IT但不确定**(如"电脑连不上打印机"可能涉及IT驱动问题)→ `routing_confidence: 0.5~0.7`(后端不触发名片推荐)
|
||||
- **明确是IT范围** → `routing_confidence ≤ 0.2`,`business_category: null`
|
||||
|
||||
@@ -104,9 +147,9 @@
|
||||
|
||||
### 第四优先级:闲聊/无关
|
||||
|
||||
与工作完全无关的消息(如"你好"、"今天天气怎么样"):
|
||||
与工作完全无关的消息(如"你好""今天天气怎么样"):
|
||||
|
||||
→ `intent_type: "chitchat"`,`is_approval_request: false`,`routing_confidence ≤ 0.1`,`business_category: null`
|
||||
`intent_type: "chitchat"`,`is_approval_request: false`,`routing_confidence ≤ 0.1`,`business_category: null`
|
||||
|
||||
---
|
||||
|
||||
@@ -129,12 +172,12 @@
|
||||
|
||||
| 字段 | 类型 | 取值 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `is_approval_request` | bool | true/false | 是否为审批请求(**原字段,语义不变**) |
|
||||
| `confidence` | float | 0.0~1.0 | 审批置信度(**原字段,语义不变**) |
|
||||
| `approval_type` | string\|null | 12种类型\|null | 审批类型(**原字段,语义不变**) |
|
||||
| `intent_type` | string | approval/it_consult/non_it_routing/chitchat | **新增**,意图大类 |
|
||||
| `business_category` | string\|null | 行政/人力资源/财务/法务/行政-物业\|null | **新增**,仅 non_it_routing 时有值 |
|
||||
| `routing_confidence` | float | 0.0~1.0 | **新增**,路由置信度,≥0.7 触发名片推荐 |
|
||||
| `is_approval_request` | bool | true/false | 是否为审批请求 |
|
||||
| `confidence` | float | 0.0~1.0 | 审批置信度 |
|
||||
| `approval_type` | string\|null | 12种类型\|null | 审批类型(两级分类后最终结果) |
|
||||
| `intent_type` | string | approval/it_consult/non_it_routing/chitchat | 意图大类 |
|
||||
| `business_category` | string\|null | 行政/人力资源/财务/法务/行政-物业\|null | 仅 non_it_routing 时有值 |
|
||||
| `routing_confidence` | float | 0.0~1.0 | 路由置信度,≥0.7 触发名片推荐 |
|
||||
|
||||
#### intent_type 与其他字段的对应关系
|
||||
|
||||
@@ -149,21 +192,95 @@
|
||||
|
||||
### 示例
|
||||
|
||||
#### 设备类示例
|
||||
|
||||
用户:"我要申请一台笔记本电脑"
|
||||
→ 粗分:设备类(明确"申请"+设备对象)→ 细分:设备申请(获取新设备)
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.95, "approval_type": "设备申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"电脑太卡了想换一台新的"
|
||||
→ 粗分:设备类(隐含"换"=获取新设备)→ 细分:设备申请
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.78, "approval_type": "设备申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"旧电脑坏了要报废"
|
||||
→ 粗分:设备类(明确"报废")→ 细分:资产处置申请
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.92, "approval_type": "资产处置申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"设备信息变更确认"
|
||||
→ 粗分:设备类 → 细分:资产变更确认
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.90, "approval_type": "资产变更确认", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
#### 账号权限类示例
|
||||
|
||||
用户:"我要申请VPN"
|
||||
→ 粗分:账号权限类 → 细分:账号权限申请
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.95, "approval_type": "账号权限申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"申请一个公共邮箱给部门用"
|
||||
→ 粗分:账号权限类 → 细分:公共邮箱账号申请(多人共享)
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.95, "approval_type": "公共邮箱账号申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
#### 软件应用类示例
|
||||
|
||||
用户:"申请软件授权"
|
||||
→ 粗分:软件应用类 → 细分:软件服务申请
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.92, "approval_type": "软件服务申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"开通企业应用"
|
||||
→ 粗分:软件应用类 → 细分:企业应用管理
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.90, "approval_type": "企业应用管理", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
#### 服务支持类示例
|
||||
|
||||
用户:"会议室投影仪坏了"
|
||||
→ 粗分:服务支持类 → 细分:会议室故障报修(限定会议室)
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.90, "approval_type": "会议室故障报修", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"下周活动需要技术保障"
|
||||
→ 粗分:服务支持类 → 细分:活动与会议技术支持(保障而非故障)
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.88, "approval_type": "活动与会议技术支持", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"终端网络准入申请"
|
||||
→ 粗分:服务支持类 → 细分:终端设备网络准入
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.92, "approval_type": "终端设备网络准入", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
#### 非审批示例(IT咨询)
|
||||
|
||||
用户:"我的VPN连不上了"
|
||||
→ 非审批(仅描述问题,无申请意图)
|
||||
```json
|
||||
{"is_approval_request": false, "confidence": 0.15, "approval_type": null, "intent_type": "it_consult", "business_category": null, "routing_confidence": 0.1}
|
||||
```
|
||||
|
||||
#### 非IT路由示例
|
||||
|
||||
用户:"电脑连不上打印机了"
|
||||
→ routing_confidence < 0.7,后端不触发名片推荐
|
||||
```json
|
||||
{"is_approval_request": false, "confidence": 0.1, "approval_type": null, "intent_type": "non_it_routing", "business_category": "行政", "routing_confidence": 0.6}
|
||||
```
|
||||
> 注:routing_confidence < 0.7,后端不触发名片推荐,走正常AI回复
|
||||
|
||||
用户:"打印机坏了,打印不了"
|
||||
```json
|
||||
@@ -185,22 +302,12 @@
|
||||
{"is_approval_request": false, "confidence": 0.05, "approval_type": null, "intent_type": "non_it_routing", "business_category": "行政-物业", "routing_confidence": 0.85}
|
||||
```
|
||||
|
||||
用户:"你好"
|
||||
```json
|
||||
{"is_approval_request": false, "confidence": 0.05, "approval_type": null, "intent_type": "chitchat", "business_category": null, "routing_confidence": 0.05}
|
||||
```
|
||||
|
||||
用户:"电脑太卡了想换一台新的"
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.78, "approval_type": "设备申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"申请一个公共邮箱给部门用"
|
||||
```json
|
||||
{"is_approval_request": true, "confidence": 0.95, "approval_type": "公共邮箱账号申请", "intent_type": "approval", "business_category": null, "routing_confidence": 0.0}
|
||||
```
|
||||
|
||||
用户:"合同有问题想咨询法务"
|
||||
```json
|
||||
{"is_approval_request": false, "confidence": 0.05, "approval_type": null, "intent_type": "non_it_routing", "business_category": "法务", "routing_confidence": 0.88}
|
||||
```
|
||||
|
||||
用户:"你好"
|
||||
```json
|
||||
{"is_approval_request": false, "confidence": 0.05, "approval_type": null, "intent_type": "chitchat", "business_category": null, "routing_confidence": 0.05}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
%% 坐席端 AI 辅助消息框 — 类图
|
||||
%% 文档版本: v1.0
|
||||
%% 创建日期: 2026-07-11
|
||||
|
||||
classDiagram
|
||||
direction TB
|
||||
|
||||
class WingmanService {
|
||||
-str api_url
|
||||
-str api_key
|
||||
-float timeout
|
||||
-httpx.AsyncClient _client
|
||||
-aioredis.Redis _redis
|
||||
-str _COMPLETION_SYSTEM_PROMPT
|
||||
-str _TONE_ADJUST_SYSTEM_PROMPT
|
||||
-str _POLISH_SYSTEM_PROMPT
|
||||
-str _REWRITE_SYSTEM_PROMPT
|
||||
+__init__(redis_client: Optional[Redis])
|
||||
+async generate_completion(conversation_id: str, current_text: str, messages: List[Dict], max_length: int) Dict
|
||||
+async adjust_tone(conversation_id: str, selected_text: str, full_text: str, tone: str, messages: List[Dict]) Dict
|
||||
+async polish_text(conversation_id: str, text: str, action: str, messages: List[Dict]) Dict
|
||||
+async rewrite_versions(conversation_id: str, current_text: str, messages: List[Dict], generate_count: int, include_knowledge: bool) Dict
|
||||
-async _call_wingman_api(context_messages: List[Dict], temperature: float) Optional[str]
|
||||
-_build_context_messages(messages: List[Dict], system_prompt: str) List[Dict]
|
||||
-async _get_cache(key: str) Optional[Dict]
|
||||
-async _set_cache(key: str, value: Dict, ttl: int) void
|
||||
-_make_cache_key(text: str, conversation_id: str) str
|
||||
-async _search_knowledge(query: str) Optional[str]
|
||||
-_parse_json_response(content: str, default: Dict) Dict
|
||||
}
|
||||
|
||||
class WingmanAPIRouter {
|
||||
+POST autocomplete(conversation_id, request: AutocompleteRequest, agent, db, wingman_service)
|
||||
+POST tone_adjust(conversation_id, request: ToneAdjustRequest, agent, db, wingman_service)
|
||||
+POST polish(conversation_id, request: PolishRequest, agent, db, wingman_service)
|
||||
+POST rewrite(conversation_id, request: RewriteRequest, agent, db, wingman_service)
|
||||
-async _validate_conversation(conversation_id, agent, db) Conversation
|
||||
-async _get_recent_messages(conversation_id, db, limit) List[Dict]
|
||||
}
|
||||
|
||||
class AutocompleteRequest {
|
||||
+str current_text
|
||||
+int cursor_position
|
||||
+int max_length
|
||||
}
|
||||
|
||||
class ToneAdjustRequest {
|
||||
+str selected_text
|
||||
+str full_text
|
||||
+str tone
|
||||
}
|
||||
|
||||
class PolishRequest {
|
||||
+str text
|
||||
+str action
|
||||
+bool conversation_context
|
||||
}
|
||||
|
||||
class RewriteRequest {
|
||||
+str current_text
|
||||
+int generate_count
|
||||
+bool include_knowledge
|
||||
}
|
||||
|
||||
class WingmanTS {
|
||||
+autocomplete(convId: str, text: str, cursorPos: int, signal: AbortSignal) Promise~AutocompleteResult~
|
||||
+adjustTone(convId: str, selectedText: str, fullText: str, tone: ToneType, signal: AbortSignal) Promise~ToneAdjustResult~
|
||||
+polishText(convId: str, text: str, action: PolishAction, signal: AbortSignal) Promise~PolishResult~
|
||||
+rewriteVersions(convId: str, currentText: str, signal: AbortSignal) Promise~RewriteResult~
|
||||
}
|
||||
|
||||
class UseAiAssist {
|
||||
+Ref~string~ ghostText
|
||||
+Ref~boolean~ isCompletLoading
|
||||
+Ref~boolean~ autocompleteEnabled
|
||||
+Ref~boolean~ tonePopoverVisible
|
||||
+Ref~boolean~ polishPanelVisible
|
||||
+Ref~boolean~ rewritePanelVisible
|
||||
+triggerAutocomplete() void
|
||||
+acceptGhostText() void
|
||||
+clearGhostText() void
|
||||
+adjustTone(selectedText: str, fullText: str, tone: ToneType) Promise~void~
|
||||
+polishText(action: PolishAction) Promise~void~
|
||||
+rewriteVersions() Promise~void~
|
||||
+cleanup() void
|
||||
}
|
||||
|
||||
class GhostText {
|
||||
+Props: ghostText: string, textareaRef: HTMLTextAreaElement
|
||||
+Emits: accept, dismiss
|
||||
-calculateCursorPos(textarea: HTMLTextAreaElement) {x: number, y: number}
|
||||
}
|
||||
|
||||
class AiAssistToolbar {
|
||||
+Props: autocompleteEnabled: boolean, hasSelection: boolean, hasText: boolean
|
||||
+Emits: toggleAutocomplete, toneAdjust, polish, rewrite
|
||||
}
|
||||
|
||||
class ToneAdjustPopover {
|
||||
+Props: visible: boolean, loading: boolean, result: ToneAdjustResult|null, originalText: string
|
||||
+Emits: select(tone: ToneType), replace, cancel
|
||||
}
|
||||
|
||||
class PolishPanel {
|
||||
+Props: visible: boolean, loading: boolean, result: PolishResult|null, originalText: string
|
||||
+Emits: action(action: PolishAction), replace(text: string), cancel
|
||||
}
|
||||
|
||||
class RewritePanel {
|
||||
+Props: visible: boolean, loading: boolean, result: RewriteResult|null
|
||||
+Emits: replace(text: string), append(text: string), cancel
|
||||
}
|
||||
|
||||
class ReplyBox {
|
||||
-UseAiAssist aiAssist
|
||||
-Ref~string~ inputText
|
||||
-HTMLTextAreaElement inputRef
|
||||
+handleKeydown(event: KeyboardEvent) void
|
||||
+handleInput() void
|
||||
}
|
||||
|
||||
%% 后端关系
|
||||
WingmanAPIRouter --> WingmanService : Depends (DI)
|
||||
WingmanAPIRouter --> AutocompleteRequest : 验证请求体
|
||||
WingmanAPIRouter --> ToneAdjustRequest : 验证请求体
|
||||
WingmanAPIRouter --> PolishRequest : 验证请求体
|
||||
WingmanAPIRouter --> RewriteRequest : 验证请求体
|
||||
|
||||
%% 前端关系
|
||||
WingmanTS --> AutocompleteRequest : HTTP 请求
|
||||
UseAiAssist --> WingmanTS : 调用 API
|
||||
ReplyBox --> UseAiAssist : composable
|
||||
ReplyBox --> GhostText : 渲染幽灵文字
|
||||
ReplyBox --> AiAssistToolbar : 渲染工具栏
|
||||
ReplyBox --> ToneAdjustPopover : 弹出浮层
|
||||
ReplyBox --> PolishPanel : 弹出面板
|
||||
ReplyBox --> RewritePanel : 弹出面板
|
||||
@@ -0,0 +1,261 @@
|
||||
%% 坐席端 AI 辅助消息框 — 时序图
|
||||
%% 文档版本: v1.0
|
||||
%% 创建日期: 2026-07-11
|
||||
%% 包含 4 个功能的完整调用流程
|
||||
|
||||
%% ==========================================================================
|
||||
%% 4.1 实时自动补齐
|
||||
%% ==========================================================================
|
||||
sequenceDiagram
|
||||
participant User as 坐席
|
||||
participant RB as ReplyBox.vue
|
||||
participant GT as GhostText.vue
|
||||
participant Cmp as useAiAssist.ts
|
||||
participant API as wingman.ts
|
||||
participant BE as wingman.py<br/>(autocomplete)
|
||||
participant Svc as WingmanService<br/>.generate_completion()
|
||||
participant Redis as Redis
|
||||
participant Dify as Dify AI
|
||||
|
||||
User->>RB: 输入文字
|
||||
RB->>Cmp: handleInput() → triggerAutocomplete()
|
||||
|
||||
Note over Cmp: debounce 800ms 等待
|
||||
Note over Cmp: 输入停顿 > 800ms 触发
|
||||
|
||||
Cmp->>Cmp: abort 上一个 AbortController
|
||||
Cmp->>Cmp: 创建新 AbortController
|
||||
|
||||
Note over Cmp: 检查:输入 > 5 字符 && autocompleteEnabled
|
||||
|
||||
Cmp->>API: autocomplete(convId, text, cursorPos, signal)
|
||||
API->>BE: POST /conversations/{id}/wingman/autocomplete
|
||||
|
||||
BE->>BE: _validate_conversation()
|
||||
BE->>BE: _get_recent_messages(limit=5)
|
||||
BE->>Svc: generate_completion(conv_id, text, messages)
|
||||
|
||||
Svc->>Svc: _make_cache_key(text, conv_id)
|
||||
Svc->>Redis: GET wingman:autocomplete:{hash}
|
||||
|
||||
alt Redis 命中缓存
|
||||
Redis-->>Svc: {completion, confidence}
|
||||
Svc-->>BE: 缓存结果
|
||||
else Redis 未命中
|
||||
Redis-->>Svc: nil
|
||||
Svc->>Svc: _build_context_messages(messages, _COMPLETION_SYSTEM_PROMPT)
|
||||
Svc->>Svc: 追加 user 消息: "坐席正在输入:{text}\n请补齐"
|
||||
Svc->>Dify: POST /chat/completions<br/>{temperature: 0.2}
|
||||
Dify-->>Svc: "正在查看相关工单记录..."
|
||||
Svc->>Redis: SETEX wingman:autocomplete:{hash} 30s
|
||||
Svc-->>BE: {completion, confidence}
|
||||
end
|
||||
|
||||
BE-->>API: {code: 0, data: {completion, confidence}}
|
||||
API-->>Cmp: AutocompleteResult
|
||||
|
||||
Note over Cmp: 检查:未被 abort && completion 非空
|
||||
|
||||
Cmp->>Cmp: ghostText.value = completion
|
||||
Cmp->>GT: 渲染幽灵文字(灰色斜体)
|
||||
GT-->>User: 光标位置显示灰色补齐文字
|
||||
|
||||
alt Tab 键接受
|
||||
User->>RB: 按 Tab
|
||||
RB->>Cmp: acceptGhostText()
|
||||
Cmp->>RB: inputText += ghostText
|
||||
Cmp->>Cmp: ghostText = ''
|
||||
GT-->>User: 幽灵文字消失,文字变为正常颜色
|
||||
else 继续输入
|
||||
User->>RB: 继续输入
|
||||
RB->>Cmp: clearGhostText()
|
||||
Cmp->>Cmp: ghostText = ''
|
||||
Note over Cmp: 重新触发 debounce
|
||||
else Esc 键
|
||||
User->>RB: 按 Esc
|
||||
RB->>Cmp: clearGhostText()
|
||||
Cmp->>Cmp: ghostText = ''
|
||||
end
|
||||
|
||||
%% ==========================================================================
|
||||
%% 4.2 语气调整
|
||||
%% ==========================================================================
|
||||
sequenceDiagram
|
||||
participant User as 坐席
|
||||
participant RB as ReplyBox.vue
|
||||
participant TAP as ToneAdjustPopover.vue
|
||||
participant Cmp as useAiAssist.ts
|
||||
participant API as wingman.ts
|
||||
participant BE as wingman.py<br/>(tone-adjust)
|
||||
participant Svc as WingmanService<br/>.adjust_tone()
|
||||
participant Dify as Dify AI
|
||||
|
||||
User->>RB: 选中输入框文字(≥ 5 字符)
|
||||
User->>RB: 点击工具栏"语气"按钮
|
||||
|
||||
RB->>TAP: visible = true(弹出浮层)
|
||||
TAP-->>User: 显示 3 种语气选项
|
||||
|
||||
User->>TAP: 点击"专业"
|
||||
TAP->>Cmp: adjustTone(selectedText, fullText, 'professional')
|
||||
|
||||
Cmp->>Cmp: toneLoading = true
|
||||
Cmp->>API: adjustTone(convId, selectedText, fullText, 'professional', signal)
|
||||
API->>BE: POST /conversations/{id}/wingman/tone-adjust
|
||||
BE->>BE: _validate_conversation()
|
||||
BE->>BE: _get_recent_messages(limit=5)
|
||||
BE->>Svc: adjust_tone(conv_id, selectedText, fullText, 'professional', messages)
|
||||
|
||||
Svc->>Svc: _build_context_messages(messages, _TONE_ADJUST_SYSTEM_PROMPT)
|
||||
Svc->>Svc: 追加 user 消息: "原文:{selectedText}\n完整内容:{fullText}\n改写为{tone}风格"
|
||||
Svc->>Dify: POST /chat/completions<br/>{temperature: 0.3}
|
||||
Dify-->>Svc: "经排查,您的VPN连接异常..."
|
||||
|
||||
Svc-->>BE: {rewritten_text, tone, changes_summary}
|
||||
BE-->>API: {code: 0, data: {...}}
|
||||
API-->>Cmp: ToneAdjustResult
|
||||
|
||||
Cmp->>Cmp: toneResult = result
|
||||
Cmp->>Cmp: toneLoading = false
|
||||
Cmp->>TAP: 显示原文/改写文对比
|
||||
|
||||
TAP-->>User: 原文 → 改写文 + 变更说明
|
||||
|
||||
alt 点击"替换"
|
||||
User->>TAP: 点击"替换"
|
||||
TAP->>RB: emit('replace', rewritten_text)
|
||||
RB->>RB: 用 rewritten_text 替换选中区域
|
||||
RB->>TAP: visible = false
|
||||
else 点击"取消"或外部
|
||||
User->>TAP: 点击取消
|
||||
TAP->>RB: emit('cancel')
|
||||
RB->>TAP: visible = false
|
||||
end
|
||||
|
||||
%% ==========================================================================
|
||||
%% 4.3 文字润色
|
||||
%% ==========================================================================
|
||||
sequenceDiagram
|
||||
participant User as 坐席
|
||||
participant RB as ReplyBox.vue
|
||||
participant PP as PolishPanel.vue
|
||||
participant Cmp as useAiAssist.ts
|
||||
participant API as wingman.ts
|
||||
participant BE as wingman.py<br/>(polish)
|
||||
participant Svc as WingmanService<br/>.polish_text()
|
||||
participant Dify as Dify AI
|
||||
|
||||
User->>RB: 点击工具栏"润色"按钮
|
||||
RB->>PP: visible = true(弹出精修面板)
|
||||
PP-->>User: 显示原文 + 3 个操作按钮
|
||||
|
||||
User->>PP: 点击"扩写"
|
||||
PP->>Cmp: polishText('expand')
|
||||
|
||||
Cmp->>Cmp: polishLoading = true
|
||||
Cmp->>API: polishText(convId, inputText, 'expand', signal)
|
||||
API->>BE: POST /conversations/{id}/wingman/polish
|
||||
BE->>BE: _validate_conversation()
|
||||
BE->>BE: _get_recent_messages(limit=5)
|
||||
BE->>Svc: polish_text(conv_id, text, 'expand', messages)
|
||||
|
||||
Svc->>Svc: _build_context_messages(messages, _POLISH_SYSTEM_PROMPT)
|
||||
Svc->>Svc: 追加 user 消息: "对以下文字进行扩写:{text}"
|
||||
Svc->>Dify: POST /chat/completions<br/>{temperature: 0.3}
|
||||
Dify-->>Svc: "建议您按以下步骤操作:\n1. 退出VPN..."
|
||||
|
||||
Svc-->>BE: {polished_text, action, changes_summary}
|
||||
BE-->>API: {code: 0, data: {...}}
|
||||
API-->>Cmp: PolishResult
|
||||
|
||||
Cmp->>Cmp: polishResult = result
|
||||
Cmp->>Cmp: polishLoading = false
|
||||
Cmp->>PP: 显示左右对比(原文 | 结果)
|
||||
|
||||
PP-->>User: 左侧原文 | 右侧结果(可编辑)+ 变更说明
|
||||
|
||||
Note over User,PP: 坐席可在结果区域手动编辑
|
||||
|
||||
alt 点击"替换全部"
|
||||
User->>PP: 编辑后点击"替换全部"
|
||||
PP->>RB: emit('replace', editedText)
|
||||
RB->>RB: inputText = editedText
|
||||
RB->>PP: visible = false
|
||||
else 切换操作
|
||||
User->>PP: 点击"压缩"或"纠错"
|
||||
PP->>Cmp: polishText('compress' | 'correct')
|
||||
Note over Cmp,Dify: 重新调用流程
|
||||
else 点击"取消"
|
||||
User->>PP: 点击取消
|
||||
PP->>RB: emit('cancel')
|
||||
RB->>PP: visible = false
|
||||
end
|
||||
|
||||
%% ==========================================================================
|
||||
%% 4.4 智能改写
|
||||
%% ==========================================================================
|
||||
sequenceDiagram
|
||||
participant User as 坐席
|
||||
participant RB as ReplyBox.vue
|
||||
participant RP as RewritePanel.vue
|
||||
participant Cmp as useAiAssist.ts
|
||||
participant API as wingman.ts
|
||||
participant BE as wingman.py<br/>(rewrite)
|
||||
participant Svc as WingmanService<br/>.rewrite_versions()
|
||||
participant RAG as RAGFlow
|
||||
participant Dify as Dify AI
|
||||
|
||||
User->>RB: 点击工具栏"改写"按钮
|
||||
RB->>RP: visible = true(弹出选择面板)
|
||||
|
||||
RP->>Cmp: rewriteVersions()
|
||||
Cmp->>Cmp: rewriteLoading = true
|
||||
Cmp->>API: rewriteVersions(convId, inputText, signal)
|
||||
API->>BE: POST /conversations/{id}/wingman/rewrite
|
||||
BE->>BE: _validate_conversation()
|
||||
BE->>BE: _get_recent_messages(limit=10)
|
||||
BE->>Svc: rewrite_versions(conv_id, text, messages, generate_count=3, include_knowledge=true)
|
||||
|
||||
Note over Svc: 构建上下文
|
||||
|
||||
Svc->>Svc: _build_context_messages(messages, _REWRITE_SYSTEM_PROMPT)
|
||||
|
||||
par 知识库检索(并行)
|
||||
Svc->>RAG: retrieval(question=当前问题, dataset_ids=默认知识库)
|
||||
RAG-->>Svc: 检索到 3 个相关文档片段
|
||||
Svc->>Svc: 将知识片段拼入 system prompt
|
||||
and 准备 Dify 调用
|
||||
Note over Svc: 等待知识检索完成
|
||||
end
|
||||
|
||||
Svc->>Dify: POST /chat/completions<br/>{temperature: 0.6}
|
||||
Dify-->>Svc: "版本1\n---\n版本2\n---\n版本3"
|
||||
|
||||
Svc->>Svc: 按 "---" 分割为 3 个版本
|
||||
Svc->>Svc: 标注 style 和 source
|
||||
|
||||
Svc-->>BE: {versions: [{text, style, source}, ...]}
|
||||
BE-->>API: {code: 0, data: {...}}
|
||||
API-->>Cmp: RewriteResult
|
||||
|
||||
Cmp->>Cmp: rewriteResult = result
|
||||
Cmp->>Cmp: rewriteLoading = false
|
||||
Cmp->>RP: 显示 3 个版本卡片
|
||||
|
||||
RP-->>User: 版本1(简洁直接)/ 版本2(详细带步骤)/ 版本3(带知识库引用)
|
||||
|
||||
alt 选择版本 → 替换
|
||||
User->>RP: 点击版本卡片 → "替换"
|
||||
RP->>RB: emit('replace', versionText)
|
||||
RB->>RB: inputText = versionText
|
||||
RB->>RP: visible = false
|
||||
else 选择版本 → 追加
|
||||
User->>RP: 点击版本卡片 → "追加"
|
||||
RP->>RB: emit('append', versionText)
|
||||
RB->>RB: inputText += '\n' + versionText
|
||||
RB->>RP: visible = false
|
||||
else 点击"取消"
|
||||
User->>RP: 点击取消
|
||||
RP->>RB: emit('cancel')
|
||||
RB->>RP: visible = false
|
||||
end
|
||||
@@ -1,10 +1,12 @@
|
||||
# IT智能服务台 — 系统架构设计文档
|
||||
|
||||
> **文档版本**: v2.1 (综合版)
|
||||
> **文档版本**: v2.2 (综合版)
|
||||
> **创建日期**: 2025-07-11
|
||||
> **最近更新**: 2026-07-10
|
||||
> **架构师**: 高见远 (Bob)
|
||||
> **最近更新**: 2026-07-11
|
||||
> **架构师**: 高见远 (Bob) / 宋献 (Simon)
|
||||
> **状态**: 正式版
|
||||
>
|
||||
> **v2.2 变更**: 新增 §15.8 坐席端AI辅助消息框与布局优化;更新 §7.2 坐席工作台模块布局参数;更新 §8 AI Wingman 设计新增能力
|
||||
|
||||
---
|
||||
|
||||
@@ -43,6 +45,8 @@
|
||||
| 15.4 | 企微审批工单同步 | ✅ 设计完成 |
|
||||
| 15.5 | 复杂场景重构 | ✅ 设计完成 |
|
||||
| 15.6 | ExternalSystemAdapter抽象层 | ✅ 设计完成 |
|
||||
| 15.7 | Wingman设计 | ✅ 已实现 |
|
||||
| 15.8 | 坐席端AI辅助消息框与布局优化 | ✅ 设计完成 |
|
||||
| **16. 技术分析报告** | | |
|
||||
| 16.1 | JP-webcli自动化部署能力分析 | ✅ 已完成 |
|
||||
| **17. 阶段5 自动化闭环** | | |
|
||||
@@ -307,12 +311,24 @@ IT智能服务台是为企业提供 IT support 的智能化服务平台,核心
|
||||
**技术栈**:Vue 3 + TypeScript + Element Plus + Pinia
|
||||
|
||||
**核心功能**:
|
||||
- 会话列表(排队/进行中/已解决)
|
||||
- 会话用户列表(排队/进行中/已解决)
|
||||
- 实时聊天
|
||||
- 快速回复
|
||||
- AI Wingman 右侧栏
|
||||
- 回复建议区(AI推荐 + 快速回复,统一入口)
|
||||
- AI Wingman 右侧栏(训练区:智能标注/质量反馈/知识贡献/使用统计)
|
||||
- AI 辅助消息框(自动补齐/语气调整/文字润色/智能改写)
|
||||
- 右栏放大/缩小模式切换
|
||||
- 消息标记(VIP/招手/情绪)
|
||||
|
||||
**布局参数**(v2.1 更新):
|
||||
|
||||
```
|
||||
左栏: 260px (会话用户列表 + 待办面板)
|
||||
中栏: flex:1 (UserInfoBar + TroubleshootBar + 消息列表 + 回复建议区 + ReplyBox)
|
||||
右栏: 260px(正常) / 560px(放大) (AI训练区 + 模式切换)
|
||||
```
|
||||
|
||||
> 详见 §15.8 坐席端AI辅助消息框与布局优化
|
||||
|
||||
### 7.3 H5 用户端模块
|
||||
|
||||
**技术栈**:Vue 3 + Vant 4 + TypeScript
|
||||
@@ -327,14 +343,26 @@ IT智能服务台是为企业提供 IT support 的智能化服务平台,核心
|
||||
|
||||
## 8. AI Wingman 设计
|
||||
|
||||
详见第15.7节「Wingman设计」
|
||||
详见第15.7节「Wingman设计」和第15.8节「坐席端AI辅助消息框与布局优化」
|
||||
|
||||
Wingman 是坐席工作台的 AI 辅助系统:
|
||||
|
||||
- **草稿回复**:坐席打字 → AI 实时生成 3 条草稿
|
||||
- **自动摘要**:会话结束 → AI 200 字摘要
|
||||
- **知识推荐**:对话中识别关键字 → 推 FAQ
|
||||
- **排查步骤**:员工描述问题 → AI 给 step-by-step
|
||||
**现有能力(已实现)**:
|
||||
- **草稿回复**:坐席打字 → AI 实时生成草稿
|
||||
- **自动摘要**:会话结束 → AI 结构化摘要
|
||||
- **标签建议**:对话内容 → AI 建议分类标签
|
||||
- **知识库优化建议**:对话分析 → 知识库改进建议
|
||||
|
||||
**新增能力(设计完成,见 §15.8)**:
|
||||
- **实时自动补齐**:输入停顿 > 0.8s → 幽灵文字 → Tab 接受
|
||||
- **语气调整**:选中文字 → 专业/友好/简洁 → 一键改写
|
||||
- **文字润色**:扩写/压缩/纠错 → 精修面板 → 确认替换
|
||||
- **智能改写**:对话上下文 + 知识库 → 3 个备选版本
|
||||
|
||||
**布局重构(设计完成,见 §15.8)**:
|
||||
- 回复前功能(草稿/知识/推荐/快回)统一到中栏回复建议区
|
||||
- 回复后功能(标注/反馈/贡献/统计)归右栏 AI 训练区
|
||||
- 右栏支持放大/缩小模式切换(260px ↔ 560px)
|
||||
|
||||
---
|
||||
|
||||
@@ -850,6 +878,142 @@ class SecurityStatus(BaseModel):
|
||||
|
||||
---
|
||||
|
||||
### 15.8 坐席端AI辅助消息框与布局优化
|
||||
|
||||
> **新增日期**: 2026-07-11 (v2.1) | **架构师**: 宋献 (Simon)
|
||||
> **关联文档**: `docs/03-技术架构/坐席端AI辅助消息框与布局优化-架构设计.md`
|
||||
> **关联PRD**: `docs/02-产品需求/坐席端AI辅助消息框-PRD.md` + `docs/02-产品需求/坐席端布局优化建议.md`
|
||||
|
||||
#### 15.8.1 功能概述
|
||||
|
||||
在现有 Wingman 基础上新增 4 项 AI 辅助功能 + 坐席端布局全面重构:
|
||||
|
||||
**AI 辅助消息框(4 项新增功能)**:
|
||||
|
||||
| 功能 | 交互方式 | 后端方法 | temperature |
|
||||
|------|---------|---------|-------------|
|
||||
| 实时自动补齐 | 内联幽灵文字,Tab 接受,debounce 800ms | `generate_completion()` | 0.2 |
|
||||
| 语气调整 | 选中文字 → 专业/友好/简洁 → 原文/改写对比 | `adjust_tone()` | 0.3 |
|
||||
| 文字润色 | 点润色按钮 → 扩写/压缩/纠错 → 精修面板 | `polish_text()` | 0.3 |
|
||||
| 智能改写 | 点改写按钮 → 3 个备选版本 → 替换/追加 | `rewrite_versions()` | 0.6 |
|
||||
|
||||
**布局重构**:
|
||||
|
||||
| 改动区域 | 变化 |
|
||||
|----------|------|
|
||||
| 左栏 | 280px → 260px(会话用户列表) |
|
||||
| 中栏 | +80px 宽度;新增回复建议区;UserInfoBar/TroubleshootBar 默认折叠 |
|
||||
| 右栏 | 320px → 260px(正常)/560px(放大);改为 AI 训练区;支持模式切换 |
|
||||
| 工具栏 | 单行左右分区:常规工具(左) + AI工具(右) |
|
||||
|
||||
#### 15.8.2 后端架构
|
||||
|
||||
**WingmanService 扩展**(`backend/app/services/wingman_service.py`):
|
||||
|
||||
```
|
||||
WingmanService
|
||||
├── 现有方法(保持不变)
|
||||
│ ├── generate_draft() temp=0.3
|
||||
│ ├── generate_summary() temp=0.3
|
||||
│ ├── suggest_tags() temp=0.3
|
||||
│ └── generate_knowledge_suggestion()
|
||||
│
|
||||
├── 新增方法
|
||||
│ ├── generate_completion() temp=0.2 ← 自动补齐
|
||||
│ ├── adjust_tone() temp=0.3 ← 语气调整
|
||||
│ ├── polish_text() temp=0.3 ← 文字润色
|
||||
│ └── rewrite_versions() temp=0.6 ← 智能改写
|
||||
│
|
||||
└── 改造方法
|
||||
└── _call_wingman_api(context, temperature=0.3) ← 新增可选参数
|
||||
```
|
||||
|
||||
**关键改造**:`_call_wingman_api()` 新增 `temperature` 参数(默认 0.3 保持兼容),各方法按需传递不同值。
|
||||
|
||||
**API 端点**(`backend/app/api/wingman.py`):
|
||||
|
||||
| 端点 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/api/conversations/{id}/wingman/autocomplete` | POST | 自动补齐 |
|
||||
| `/api/conversations/{id}/wingman/tone-adjust` | POST | 语气调整 |
|
||||
| `/api/conversations/{id}/wingman/polish` | POST | 文字润色 |
|
||||
| `/api/conversations/{id}/wingman/rewrite` | POST | 智能改写 |
|
||||
|
||||
新增 Pydantic 请求模型(`backend/app/schemas/wingman_assist.py`):`AutocompleteRequest`、`ToneAdjustRequest`、`PolishRequest`、`RewriteRequest`,含字段验证和枚举类型。
|
||||
|
||||
#### 15.8.3 前端架构
|
||||
|
||||
**新增组件树**:
|
||||
|
||||
```
|
||||
Workspace.vue
|
||||
├── ConversationList.vue (左栏 - 会话用户列表)
|
||||
├── ChatArea.vue (中栏)
|
||||
│ ├── UserInfoBar.vue (详情默认折叠)
|
||||
│ ├── TroubleshootBar.vue (默认折叠为图标条)
|
||||
│ ├── MessageList.vue
|
||||
│ ├── ReplySuggestArea.vue (新增 - 回复建议区)
|
||||
│ │ ├── AiRecommendBar.vue (合并自 AiRecommendInline + AiSuggestReply)
|
||||
│ │ └── QuickReplyBar.vue (改造自 QuickReplyPanel)
|
||||
│ └── ReplyBox.vue (改造)
|
||||
│ ├── GhostTextOverlay.vue (新增 - 幽灵文字)
|
||||
│ ├── ToneAdjustPopover.vue (新增 - 语气浮层)
|
||||
│ ├── PolishPanel.vue (新增 - 润色面板)
|
||||
│ └── RewritePanel.vue (新增 - 改写面板)
|
||||
└── AiAssistantPanel.vue (全面重构)
|
||||
├── PanelModeToggle.vue (新增 - 正常/放大切换)
|
||||
└── AiTrainingPanel.vue (新增 - 训练区)
|
||||
├── SmartTagEditor.vue (智能标注)
|
||||
├── QualityFeedback.vue (质量反馈)
|
||||
├── KnowledgeContribute.vue (知识贡献)
|
||||
└── UsageStats.vue (使用统计)
|
||||
```
|
||||
|
||||
**新增 Composable**:
|
||||
|
||||
| Composable | 职责 |
|
||||
|------------|------|
|
||||
| `useAutoComplete.ts` | debounce 800ms + AbortController + ghost text 管理 |
|
||||
| `useAiTextTools.ts` | 语气/润色/改写统一调用和结果管理 |
|
||||
| `usePanelMode.ts` | 右栏 260px ↔ 560px 模式切换 |
|
||||
|
||||
**功能重复清理**(5 处):
|
||||
|
||||
| 编号 | 重复类型 | 清理方案 |
|
||||
|------|---------|---------|
|
||||
| R1 | AI草稿双展示 | 统一到中栏回复建议区 |
|
||||
| R2 | AI推荐回复三处展示 | 合并为 AiRecommendBar.vue |
|
||||
| R3 | 排查流程命名混淆 | 右栏按钮重命名为"智能标注" |
|
||||
| R4 | 标签建议双入口 | 合并为单一"智能标注"功能 |
|
||||
| R5 | 孤儿组件 | 删除 AiRecommendInline.vue |
|
||||
|
||||
#### 15.8.4 关键设计决策
|
||||
|
||||
| 决策 | 选择 | 理由 |
|
||||
|------|------|------|
|
||||
| 补齐交互 | textarea + mirror div + ghost overlay | 保持现有快捷键和粘贴功能不变 |
|
||||
| 补齐 API | HTTP + AbortController | 轻量请求,与现有 Wingman 调用一致 |
|
||||
| 语气/润色浮层 | el-popover / el-drawer | 不遮挡消息列表,不打断工作流 |
|
||||
| 右栏模式切换 | CSS 变量 + class 切换 | 组件不销毁,状态不丢失 |
|
||||
| 回复建议区动画 | max-height transition | 平滑过渡,组件实例保持存活 |
|
||||
| temperature 改造 | 可选参数默认 0.3 | 现有方法无需修改,向后兼容 |
|
||||
|
||||
#### 15.8.5 开发计划
|
||||
|
||||
| 阶段 | 内容 | 预估 |
|
||||
|------|------|------|
|
||||
| Phase 1 | 后端 WingmanService 扩展 + Pydantic 模型 | 1.5 天 |
|
||||
| Phase 2 | 前端 API 层 + Composable | 1 天 |
|
||||
| Phase 3 | ReplyBox 工具栏 + AI 辅助组件 | 2 天 |
|
||||
| Phase 4 | 布局重构 + 回复建议区 | 2 天 |
|
||||
| Phase 5 | 右栏训练区 + 模式切换 | 1.5 天 |
|
||||
| Phase 6 | 功能清理 + 联调测试 | 1 天 |
|
||||
| **合计** | | **9 天** |
|
||||
|
||||
> 完整架构设计(类图、时序图、API 规范、Dify prompt 模板、TypeScript 类型定义)详见独立文档:`docs/03-技术架构/坐席端AI辅助消息框与布局优化-架构设计.md`
|
||||
|
||||
---
|
||||
|
||||
## 16. 技术分析报告
|
||||
|
||||
### 16.1 JP-webcli自动化部署能力分析
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
%% 代答排除匹配引擎架构图
|
||||
%% 来源:增量设计-知识库迭代-开发任务分解-20260712.md §4.1
|
||||
|
||||
graph TB
|
||||
subgraph "代答排除匹配引擎"
|
||||
Engine[ExclusionService<br/>匹配引擎入口]
|
||||
Chain[ExclusionChain<br/>责任链调度]
|
||||
|
||||
subgraph "策略模式 - 4种匹配器"
|
||||
M1[KeywordMatcher<br/>关键词匹配]
|
||||
M2[RegexMatcher<br/>正则匹配]
|
||||
M3[IntentMatcher<br/>意图匹配]
|
||||
M4[CategoryMatcher<br/>分类排除]
|
||||
end
|
||||
|
||||
Engine --> Chain
|
||||
Chain --> M1
|
||||
Chain --> M2
|
||||
Chain --> M3
|
||||
Chain --> M4
|
||||
end
|
||||
|
||||
subgraph "外部依赖"
|
||||
Dify[Dify 意图识别<br/>复用审批意图链路]
|
||||
TriageDB[triage_sessions<br/>分诊结果]
|
||||
RuleDB[(exclusion_rules)]
|
||||
LogDB[(exclusion_logs)]
|
||||
end
|
||||
|
||||
M3 -->|调用| Dify
|
||||
M4 -->|查询| TriageDB
|
||||
Engine -->|读取规则| RuleDB
|
||||
Engine -->|记录命中| LogDB
|
||||
|
||||
style M1 fill:#dbeafe,stroke:#3b82f6
|
||||
style M2 fill:#fce7f3,stroke:#ec4899
|
||||
style M3 fill:#ede9fe,stroke:#8b5cf6
|
||||
style M4 fill:#dcfce7,stroke:#07C160
|
||||
@@ -0,0 +1,67 @@
|
||||
%% 模块依赖关系图
|
||||
%% 来源:增量设计-知识库迭代-开发任务分解-20260712.md §9
|
||||
|
||||
graph TB
|
||||
subgraph "T01: 项目基础设施"
|
||||
DB[数据库迁移<br/>3张新表]
|
||||
CFG[config.py<br/>新增配置项]
|
||||
MODEL[ORM 模型<br/>3个]
|
||||
SCHEMA[Pydantic Schema<br/>2个文件]
|
||||
ROUTER[router.py<br/>路由注册]
|
||||
end
|
||||
|
||||
subgraph "T02: 分诊交互模块"
|
||||
TRI_API[分诊 API<br/>12个端点]
|
||||
TRI_SVC[TriageService<br/>+ DifyTriageService]
|
||||
H5_FE[H5 前端<br/>TriageCard + useTriage]
|
||||
AG_FE[坐席端前端<br/>TriageDashboard + 3组件]
|
||||
DIFY_APP[Dify 分诊应用<br/>Prompt + 配置]
|
||||
end
|
||||
|
||||
subgraph "T03: 拓扑预览模块"
|
||||
TOPO_FE[管理后台前端<br/>TopologyPreview + 3组件]
|
||||
TOPO_API[复用已有<br/>GET /graph]
|
||||
end
|
||||
|
||||
subgraph "T04: 代答排除模块"
|
||||
EXC_API[排除管理 API<br/>8个端点]
|
||||
EXC_SVC[ExclusionService<br/>+ 4个Matcher]
|
||||
EXC_FE[管理后台前端<br/>ExclusionRules + 2组件]
|
||||
MSG_INT[消息流集成<br/>ai_handler.py]
|
||||
end
|
||||
|
||||
%% 依赖关系
|
||||
DB --> TRI_API
|
||||
DB --> EXC_API
|
||||
CFG --> TRI_SVC
|
||||
MODEL --> TRI_API
|
||||
MODEL --> EXC_API
|
||||
SCHEMA --> TRI_API
|
||||
SCHEMA --> EXC_API
|
||||
ROUTER --> TRI_API
|
||||
ROUTER --> EXC_API
|
||||
|
||||
TRI_API --> TRI_SVC
|
||||
TRI_SVC --> H5_FE
|
||||
TRI_SVC --> AG_FE
|
||||
TRI_SVC --> DIFY_APP
|
||||
|
||||
EXC_API --> EXC_SVC
|
||||
EXC_SVC --> EXC_FE
|
||||
EXC_SVC --> MSG_INT
|
||||
|
||||
%% 软依赖
|
||||
TRI_SVC -.->|"CategoryMatcher<br/>软依赖分诊结果"| EXC_SVC
|
||||
|
||||
%% 拓扑预览独立
|
||||
TOPO_FE --> TOPO_API
|
||||
|
||||
%% 并行标注
|
||||
style TOPO_FE fill:#e8f5e9,stroke:#4caf50,stroke-dasharray: 5 5
|
||||
style TOPO_API fill:#e8f5e9,stroke:#4caf50,stroke-dasharray: 5 5
|
||||
|
||||
style DB fill:#e3f2fd,stroke:#2196f3
|
||||
style CFG fill:#e3f2fd,stroke:#2196f3
|
||||
style MODEL fill:#e3f2fd,stroke:#2196f3
|
||||
style SCHEMA fill:#e3f2fd,stroke:#2196f3
|
||||
style ROUTER fill:#e3f2fd,stroke:#2196f3
|
||||
@@ -0,0 +1,74 @@
|
||||
%% 分诊主流程时序图
|
||||
%% 来源:增量设计-知识库迭代-开发任务分解-20260712.md §2.5
|
||||
|
||||
sequenceDiagram
|
||||
participant H5 as H5 员工端
|
||||
participant API as FastAPI 后端
|
||||
participant TriSvc as TriageService
|
||||
participant DifyTri as Dify 分诊应用
|
||||
participant DB as PostgreSQL
|
||||
participant AG as 坐席端看板
|
||||
participant WS as WebSocket
|
||||
|
||||
rect rgb(255, 243, 224)
|
||||
Note over H5,DB: 阶段1:发起分诊
|
||||
H5->>API: POST /api/h5/triage/start {conversation_id, question}
|
||||
API->>TriSvc: start_triage(conversation_id, question)
|
||||
TriSvc->>DB: INSERT triage_sessions (status=triaging)
|
||||
TriSvc->>DifyTri: 调用分诊 prompt(拆分问题为分步选择题)
|
||||
alt Dify 5秒内响应
|
||||
DifyTri-->>TriSvc: {steps[], confidence, urgency, suggested_route, problem_type}
|
||||
TriSvc->>DB: UPDATE triage_sessions SET triage_steps, confidence, urgency, suggested_route
|
||||
TriSvc-->>API: {triage_id, steps, total, confidence, urgency, suggested_route}
|
||||
API-->>H5: {triage_id, steps, total, ...}
|
||||
else Dify 超时(>5s)
|
||||
TriSvc->>DB: UPDATE triage_sessions SET status=timeout
|
||||
TriSvc-->>API: 超时,自动转人工
|
||||
API-->>H5: 分诊超时,已转人工
|
||||
end
|
||||
end
|
||||
|
||||
rect rgb(227, 242, 253)
|
||||
Note over H5,DB: 阶段2:分步选择 + 坐席协同
|
||||
loop 每一步
|
||||
H5->>API: POST /api/h5/triage/step {triage_id, step_index, selected_label}
|
||||
API->>TriSvc: submit_step(triage_id, step_index, selected_label)
|
||||
TriSvc->>DB: 记录 collected_context
|
||||
TriSvc->>DifyTri: 根据选择动态调整后续步骤
|
||||
DifyTri-->>TriSvc: next_step
|
||||
TriSvc-->>API: {next_step, collected_context}
|
||||
API-->>H5: {next_step, collected_context}
|
||||
end
|
||||
|
||||
Note over AG: 坐席看板实时查看分诊进度
|
||||
AG->>API: GET /api/agent/triage/pending
|
||||
API-->>AG: 待分诊列表
|
||||
AG->>API: GET /api/agent/triage/{triage_id}
|
||||
API-->>AG: 分诊详情
|
||||
|
||||
opt 坐席排除选项
|
||||
AG->>API: POST /api/agent/triage/{triage_id}/exclude-options {excluded_labels}
|
||||
API->>WS: WS 推送 excluded_labels 到 H5
|
||||
WS-->>H5: {type: "triage_exclude", excluded_labels}
|
||||
H5->>H5: TriageCard.setExcludedOptions(labels)
|
||||
end
|
||||
end
|
||||
|
||||
rect rgb(232, 245, 233)
|
||||
Note over H5,DB: 阶段3:分诊完成 / 转人工
|
||||
alt 所有步骤完成
|
||||
H5->>API: POST /api/h5/triage/complete {triage_id, context}
|
||||
API->>TriSvc: complete_triage(triage_id, context)
|
||||
TriSvc->>DifyTri: 根据收集的上下文生成最终回复
|
||||
DifyTri-->>TriSvc: {reply, confidence}
|
||||
TriSvc->>DB: UPDATE triage_sessions SET status=routed, route_action=ai_self
|
||||
TriSvc-->>API: {reply, confidence}
|
||||
API-->>H5: AI 回复
|
||||
else 转人工
|
||||
H5->>API: POST /api/h5/triage/transfer {triage_id, context}
|
||||
API->>TriSvc: transfer_to_human(triage_id, context)
|
||||
TriSvc->>DB: UPDATE triage_sessions SET status=routed, route_action=human
|
||||
TriSvc-->>API: 转人工成功
|
||||
API-->>H5: 已转人工
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
%% =============================================================================
|
||||
%% 增量设计:坐席端布局优化 v2.0 — 时序图
|
||||
%% =============================================================================
|
||||
%% 创建日期:2026-07-11
|
||||
%% 包含 3 个关键流程的时序图
|
||||
%% =============================================================================
|
||||
|
||||
%% ====== 时序图 1:回复建议区交互流程 ======
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant User as 坐席
|
||||
participant ChatArea as ChatArea
|
||||
participant RSA as ReplySuggestArea
|
||||
participant ARB as AiRecommendBar
|
||||
participant QRB as QuickReplyBar
|
||||
participant CS as ConversationStore
|
||||
participant RB as ReplyBox
|
||||
participant API as Wingman API
|
||||
|
||||
Note over User, API: 场景:坐席选中会话 → 查看 AI 推荐 → 采纳填入输入框 → 发送
|
||||
|
||||
User->>ChatArea: 选中会话
|
||||
ChatArea->>CS: selectConversation(id)
|
||||
CS->>API: generateDraft(convId)
|
||||
API-->>CS: DraftResult {content, confidence, reasoning}
|
||||
CS->>CS: aiDrafts.set(convId, draft)
|
||||
CS-->>ChatArea: currentConversationId 更新
|
||||
|
||||
ChatArea->>RSA: render (conversationId)
|
||||
RSA->>ARB: :recommendations = loadFromStore()
|
||||
ARB->>CS: 读取 aiDrafts.get(convId)
|
||||
CS-->>ARB: Set~DraftResult~
|
||||
ARB-->>User: 横向展示 1-3 条 AI 推荐卡片
|
||||
|
||||
Note over User, ARB: 坐席点击某条推荐
|
||||
|
||||
User->>ARB: 点击推荐卡片 #1
|
||||
ARB->>CS: pendingReplyText = recommendation.content
|
||||
ARB->>RSA: emit('select', content)
|
||||
RSA->>ChatArea: emit('select', content)
|
||||
|
||||
Note over CS, RB: pendingReplyText 变化触发 ReplyBox watch
|
||||
|
||||
CS-->>RB: watch(pendingReplyText) 触发
|
||||
RB->>RB: inputText = pendingReplyText
|
||||
RB->>RB: pendingReplyText = '' (清空)
|
||||
RB-->>User: 输入框显示推荐内容,光标聚焦
|
||||
|
||||
Note over User, RB: 坐席可编辑后发送
|
||||
|
||||
User->>RB: 按 Enter 发送
|
||||
RB->>RB: handleSend()
|
||||
RB->>ChatArea: emit('send', content)
|
||||
ChatArea->>CS: sendReply(content, replyToId?)
|
||||
CS->>API: sendMessage(convId, content)
|
||||
API-->>CS: Message 对象
|
||||
CS-->>ChatArea: messages.push(newMsg)
|
||||
ChatArea-->>User: 消息列表刷新,显示新消息
|
||||
|
||||
Note over User, QRB: 场景:坐席使用快速回复
|
||||
|
||||
User->>QRB: 点击 L1 分类 chip(如"账号")
|
||||
QRB->>QRB: navState.l1Index = index
|
||||
QRB-->>User: 横向展示 L2 条目预览
|
||||
User->>QRB: 点击条目"密码重置指引"
|
||||
QRB->>CS: pendingReplyText = template.content
|
||||
CS-->>RB: watch 触发,填入输入框
|
||||
RB-->>User: 输入框显示快速回复内容
|
||||
|
||||
|
||||
%% ====== 时序图 2:右栏模式切换流程 ======
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant User as 坐席
|
||||
participant PMT as PanelModeToggle
|
||||
participant AAP as AiAssistantPanel
|
||||
participant WS as Workspace
|
||||
participant CS as ConversationStore
|
||||
participant DOM as DOM/CSS
|
||||
|
||||
Note over User, DOM: 场景:坐席点击右栏放大/缩小开关
|
||||
|
||||
User->>PMT: 点击开关按钮
|
||||
PMT->>AAP: emit('toggle')
|
||||
AAP->>WS: emit('toggle')
|
||||
|
||||
alt 当前为 normal 模式 (260px)
|
||||
WS->>CS: setPanelMode('expanded')
|
||||
CS-->>WS: panelMode = 'expanded'
|
||||
WS->>WS: rightSidebarRef.style.width = 'var(--assistant-panel-expanded)'
|
||||
WS->>DOM: CSS transition: width 260px → 560px (0.3s)
|
||||
DOM-->>User: 右栏平滑放大到 560px
|
||||
Note over WS, DOM: 中栏 flex:1 自动缩小,min-width: 400px 保底
|
||||
else 当前为 expanded 模式 (560px)
|
||||
WS->>CS: setPanelMode('normal')
|
||||
CS-->>WS: panelMode = 'normal'
|
||||
WS->>WS: rightSidebarRef.style.width = 'var(--assistant-panel-width)'
|
||||
WS->>DOM: CSS transition: width 560px → 260px (0.3s)
|
||||
DOM-->>User: 右栏平滑缩小到 260px
|
||||
Note over WS, DOM: 中栏 flex:1 自动扩大
|
||||
end
|
||||
|
||||
Note over User, DOM: 拖拽手柄在放大模式下仍然可用
|
||||
Note over WS, DOM: 拖拽范围:200px ~ 560px(上限已调整)
|
||||
|
||||
|
||||
%% ====== 时序图 3:功能迁移流程(开发过程) ======
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant Dev as 开发过程
|
||||
participant Old as 旧组件
|
||||
participant New as 新组件
|
||||
participant ChatArea as ChatArea
|
||||
participant AAP as AiAssistantPanel
|
||||
participant Store as ConversationStore
|
||||
|
||||
Note over Dev, Store: Phase 1 — 清理重复(T02)
|
||||
|
||||
Dev->>Old: 删除 AiRecommendInline.vue
|
||||
Dev->>ChatArea: 移除 import AiRecommendInline
|
||||
Dev->>Old: 删除 AiSuggestReply.vue
|
||||
Dev->>AAP: 移除 import AiSuggestReply
|
||||
|
||||
Note over Dev: 移除右栏已迁移功能
|
||||
|
||||
Dev->>AAP: 移除 Wingman 触发按钮组
|
||||
Dev->>AAP: 移除 AI 推荐区(AiSuggestReply 引用)
|
||||
Dev->>AAP: 移除快速回复区(QuickReplyPanel 引用)
|
||||
Note over AAP: AiAssistantPanel 仅保留容器骨架 + 标注区
|
||||
|
||||
Note over Dev, Store: Phase 3 — 中栏建设(T03)
|
||||
|
||||
Dev->>New: 创建 ReplySuggestArea.vue
|
||||
Dev->>New: 创建 AiRecommendBar.vue
|
||||
Note over New, Store: AiRecommendBar 从 ConversationStore.aiDrafts 加载数据
|
||||
Dev->>New: 创建 QuickReplyBar.vue
|
||||
Note over New, Store: QuickReplyBar 从 QuickReplyStore 加载模板
|
||||
Dev->>ChatArea: 在消息列表与 ReplyBox 之间插入 ReplySuggestArea
|
||||
Dev->>New: ReplyBox 工具栏重构为左右分区
|
||||
|
||||
Note over Dev, Store: Phase 4 — 右栏建设(T04)
|
||||
|
||||
Dev->>New: 创建 AiTrainingPanel.vue (Tab 容器)
|
||||
Dev->>New: 创建 SmartTagEditor.vue
|
||||
Note over New, Store: SmartTagEditor 从 AAP 迁出标签逻辑
|
||||
Dev->>New: 创建 QualityFeedback.vue
|
||||
Dev->>New: 创建 KnowledgeContribute.vue
|
||||
Dev->>New: 创建 PanelModeToggle.vue
|
||||
Dev->>AAP: AiAssistantPanel 承载 PanelModeToggle + AiTrainingPanel
|
||||
Dev->>Store: ConversationStore 新增 panelMode 状态
|
||||
|
||||
Note over Dev, Store: Phase 5 — 联调测试(T05)
|
||||
|
||||
Dev->>ChatArea: 验证 ReplySuggestArea ↔ ReplyBox 联动
|
||||
Dev->>ChatArea: 验证消息区高度 ≥ 400px (1080p)
|
||||
Dev->>AAP: 验证模式切换 + Tab 切换
|
||||
Dev->>Store: 验证 pendingReplyText 全链路通信
|
||||
@@ -0,0 +1,222 @@
|
||||
%% =============================================================================
|
||||
%% 增量设计:坐席端布局优化 v2.0 — 类图
|
||||
%% =============================================================================
|
||||
%% 创建日期:2026-07-11
|
||||
%% 技术栈:Vue 3 + Element Plus + TypeScript + Pinia + CSS Variables
|
||||
%% =============================================================================
|
||||
|
||||
classDiagram
|
||||
%% ====== 容器/页面级组件 ======
|
||||
class Workspace {
|
||||
+Ref~boolean~ assistantVisible
|
||||
+Ref~PanelMode~ panelMode
|
||||
+Ref~HTMLElement~ leftSidebarRef
|
||||
+Ref~HTMLElement~ rightSidebarRef
|
||||
+startLeftResize(e: MouseEvent) void
|
||||
+startRightResize(e: MouseEvent) void
|
||||
+togglePanelMode() void
|
||||
+onMounted() void
|
||||
}
|
||||
|
||||
class ChatArea {
|
||||
+Ref~Message~ replyToMessage
|
||||
+Ref~HTMLElement~ messageListRef
|
||||
+handleSend(content: string) void
|
||||
+handleReplyTo(message: Message) void
|
||||
+scrollToBottom() void
|
||||
}
|
||||
|
||||
%% ====== 中栏新增组件 ======
|
||||
class ReplySuggestArea {
|
||||
+Props: conversationId: string
|
||||
+Emits: select(content: string)
|
||||
+Ref~string~ activeTab
|
||||
+loadRecommendations() void
|
||||
}
|
||||
|
||||
class AiRecommendBar {
|
||||
+Props: recommendations: AiRecommendation[]
|
||||
+Props: loading: boolean
|
||||
+Emits: select(content: string)
|
||||
+Emits: refresh()
|
||||
+handleSelect(index: number) void
|
||||
+confidenceStyle: ComputedRef
|
||||
}
|
||||
|
||||
class QuickReplyBar {
|
||||
+Props: templates: QuickReply[]
|
||||
+Emits: select(content: string)
|
||||
+Ref~QuickReplyNav~ navState
|
||||
+Ref~string~ searchQuery
|
||||
+selectTemplate(tpl: QuickReply) void
|
||||
+goBack() void
|
||||
}
|
||||
|
||||
class ReplyBox {
|
||||
+Props: replyToMessage: Message
|
||||
+Emits: send(content: string)
|
||||
+Emits: cancelReply()
|
||||
+Ref~string~ inputText
|
||||
+Ref~number~ textareaHeight
|
||||
+handleSend() void
|
||||
+handleKeydown(event: KeyboardEvent) void
|
||||
+handleAiTool(action: AiToolAction) void
|
||||
+handleScreenshot() void
|
||||
+handlePaste(event: ClipboardEvent) void
|
||||
}
|
||||
|
||||
%% ====== 右栏组件 ======
|
||||
class AiAssistantPanel {
|
||||
+Props: mode: PanelMode
|
||||
+Emits: toggle()
|
||||
+Ref~string~ conversationId
|
||||
}
|
||||
|
||||
class AiTrainingPanel {
|
||||
+Props: conversationId: string
|
||||
+Ref~TrainingTab~ activeTab
|
||||
+resetForNewConversation() void
|
||||
}
|
||||
|
||||
class PanelModeToggle {
|
||||
+Props: mode: PanelMode
|
||||
+Emits: toggle()
|
||||
}
|
||||
|
||||
class SmartTagEditor {
|
||||
+Props: conversationId: string
|
||||
+Ref~ConversationTags~ currentTags
|
||||
+Ref~string[]~ suggestedTagList
|
||||
+Ref~boolean~ loadingTagSuggestions
|
||||
+handleSuggestTags() void
|
||||
+handleAddSuggestedTag(tag: string) void
|
||||
+handleRemoveTag(key: string) void
|
||||
+handleAddManualTag() void
|
||||
+loadCurrentTags() void
|
||||
}
|
||||
|
||||
class QualityFeedback {
|
||||
+Props: conversationId: string
|
||||
+Ref~Annotation[]~ feedbackList
|
||||
+Ref~boolean~ loading
|
||||
+handleSubmit(messageId: string, feedback: AnnotationFeedback) void
|
||||
+loadAnnotations() void
|
||||
}
|
||||
|
||||
class KnowledgeContribute {
|
||||
+Props: conversationId: string
|
||||
+Ref~ContributeForm~ contributeForm
|
||||
+Ref~boolean~ submitting
|
||||
+handleSubmit() void
|
||||
+resetForm() void
|
||||
}
|
||||
|
||||
%% ====== 修改的现有组件 ======
|
||||
class UserInfoBar {
|
||||
+Props: conversation: Conversation
|
||||
+Props: availableAgents: AgentInfo[]
|
||||
+Props: canInviteCollaborator: boolean
|
||||
+Emits: assign, resolve, toggle-pin, toggle-todo, transfer, invite
|
||||
+Ref~boolean~ isExpanded
|
||||
+Ref~boolean~ showItLevelSelector
|
||||
+toggleExpand() void
|
||||
+resetForNewConversation() void
|
||||
}
|
||||
|
||||
class TroubleshootBar {
|
||||
+Ref~boolean~ isFlowchartExpanded
|
||||
+Ref~boolean~ isIconBarCollapsed
|
||||
+Ref~TroubleshootingTemplate[]~ templates
|
||||
+toggleFlowchart() void
|
||||
+toggleCollapse() void
|
||||
+handleTemplateChange(templateId: string) void
|
||||
+handleStepClick(index: number) void
|
||||
+loadTemplates() void
|
||||
}
|
||||
|
||||
%% ====== Store ======
|
||||
class ConversationStore {
|
||||
+Ref~string~ pendingReplyText
|
||||
+Ref~Map~ aiDrafts
|
||||
+Ref~PanelMode~ panelMode
|
||||
+Ref~string~ currentConversationId
|
||||
+Ref~Conversation~ currentConversation
|
||||
+Ref~Message[]~ messages
|
||||
+setPanelMode(mode: PanelMode) void
|
||||
+selectConversation(id: string) void
|
||||
+sendReply(content: string, replyToId?: string) void
|
||||
}
|
||||
|
||||
class QuickReplyStore {
|
||||
+Ref~QuickReply[]~ templates
|
||||
+ComputedRef~templatesByCategory
|
||||
+ComputedRef~categories
|
||||
+fetchTemplates() void
|
||||
}
|
||||
|
||||
%% ====== 类型定义 ======
|
||||
class PanelMode {
|
||||
<<enumeration>>
|
||||
normal
|
||||
expanded
|
||||
}
|
||||
|
||||
class TrainingTab {
|
||||
<<enumeration>>
|
||||
smart-tag
|
||||
quality-feedback
|
||||
knowledge-contribute
|
||||
}
|
||||
|
||||
class AiRecommendation {
|
||||
+string title
|
||||
+string content
|
||||
+number confidence
|
||||
}
|
||||
|
||||
class ContributeForm {
|
||||
+string title
|
||||
+string problem
|
||||
+string solution
|
||||
+string category
|
||||
}
|
||||
|
||||
class QuickReplyNav {
|
||||
+number l1Index
|
||||
+number l2Index
|
||||
}
|
||||
|
||||
%% ====== 组合关系(contains/renders) ======
|
||||
Workspace *-- ChatArea : renders
|
||||
Workspace *-- AiAssistantPanel : renders
|
||||
ChatArea *-- UserInfoBar : contains
|
||||
ChatArea *-- TroubleshootBar : contains
|
||||
ChatArea *-- ReplySuggestArea : contains (新增)
|
||||
ChatArea *-- ReplyBox : contains
|
||||
|
||||
ReplySuggestArea *-- AiRecommendBar : contains
|
||||
ReplySuggestArea *-- QuickReplyBar : contains
|
||||
|
||||
AiAssistantPanel *-- PanelModeToggle : contains
|
||||
AiAssistantPanel *-- AiTrainingPanel : contains
|
||||
|
||||
AiTrainingPanel *-- SmartTagEditor : tab 1
|
||||
AiTrainingPanel *-- QualityFeedback : tab 2
|
||||
AiTrainingPanel *-- KnowledgeContribute : tab 3
|
||||
|
||||
%% ====== 依赖关系(uses) ======
|
||||
AiRecommendBar ..> ConversationStore : reads aiDrafts, writes pendingReplyText
|
||||
QuickReplyBar ..> ConversationStore : writes pendingReplyText
|
||||
QuickReplyBar ..> QuickReplyStore : reads templates
|
||||
ReplyBox ..> ConversationStore : reads/writes pendingReplyText
|
||||
SmartTagEditor ..> ConversationStore : reads currentConversation
|
||||
QualityFeedback ..> ConversationStore : reads messages
|
||||
Workspace ..> ConversationStore : reads/writes panelMode
|
||||
AiAssistantPanel ..> ConversationStore : reads currentConversationId
|
||||
|
||||
%% ====== 类型引用 ======
|
||||
AiRecommendBar ..> AiRecommendation : uses
|
||||
KnowledgeContribute ..> ContributeForm : uses
|
||||
QuickReplyBar ..> QuickReplyNav : uses
|
||||
PanelModeToggle ..> PanelMode : uses
|
||||
AiTrainingPanel ..> TrainingTab : uses
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,48 @@
|
||||
# 智能IT服务台 - 版本记录
|
||||
|
||||
> **最后更新**:2026-07-05
|
||||
> **最后更新**:2026-07-13
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
### v0.7.3 (2026-07-12~13)
|
||||
|
||||
**更新内容**:
|
||||
|
||||
1. **AI 对话链路全栈改造 Phase 1-6**(#59-#69)
|
||||
- Dify Prompt JSON 输出 + 后端 blocking + JSON 解析 + 双 WS 推送
|
||||
- 审批关键词收窄(~40→~25)+ 两级分类 Prompt v4.0 + 删除前端 checkApprovalIntent
|
||||
- WS 扩展(ai_thinking + dynamic_recommend)+ MessageBubble ai_structured 渲染 + RightPanel v2
|
||||
- VisionService 接入(图片分析 + 5秒消息融合)+ 降级策略
|
||||
- 坐席端 ai_thinking 指示器 + ai_structured/byod_card 渲染
|
||||
- diagnosis_stage 字段 + response_time_ms 计时 + 慢响应告警
|
||||
|
||||
2. **上下文感知智能诊断→修复闭环**
|
||||
- 三层诊断(API→Script→AI)+ 三段排队(VIP→info_locked→not locked)
|
||||
- 答题插队 + 五场景关闭 + 迁移 052(6表+6列)
|
||||
|
||||
3. **坐席端布局优化 v2.0**
|
||||
- QuickReplyBar L1+L2 悬浮 / ReplyBox 左右分区 / 右栏 260↔560px
|
||||
- 键盘快捷键 v2.3(纯数字路由 / ESC 分层撤销 / IME 守卫)
|
||||
|
||||
4. **知识库迭代 3**
|
||||
- 分诊交互 + 拓扑预览(ECharts)+ 代答排除(4种匹配器)+ 迁移 051
|
||||
|
||||
5. **H5 v4 人工坐席交互改造**(#116)
|
||||
- 三态文案统一"人工坐席" / 按钮位置上移 / 删除 CallAgentModal 弹窗
|
||||
- 截图提示改版 / 移动端 CSS 隐藏 / DB 同步 funny_phrases 表
|
||||
|
||||
6. **部署路径修正**
|
||||
- 确认服务器项目根路径 `/opt/wecom-it-desk/`
|
||||
- 所有前端 dist 均为 ro bind mount,只能在宿主机源路径操作
|
||||
|
||||
**部署方式**:后端 `docker compose restart backend` / 前端宿主机 tar 解压 + `nginx -s reload`
|
||||
|
||||
**验证**:JS hash 更新确认 / JS 包内容检查 / API 200 / Nginx healthy
|
||||
|
||||
---
|
||||
|
||||
### v0.7.1 (2026-06-23)
|
||||
|
||||
**更新内容**:
|
||||
@@ -40,6 +77,11 @@
|
||||
|
||||
## 问题修复记录
|
||||
|
||||
### 2026-07-13
|
||||
|
||||
- H5 v4 部署路径修正(`/opt/wecom-it-desk/frontend-h5/dist` ro bind mount)
|
||||
- 服务器 Docker 挂载配置与本地仓库不一致问题定位
|
||||
|
||||
### 2026-07-05
|
||||
|
||||
- Nginx upstream 配置修复
|
||||
|
||||
+206
-64
@@ -1,9 +1,9 @@
|
||||
# 会议室预定-小鱼易联终端 部署指南
|
||||
|
||||
> **日期**: 2026-07-11
|
||||
> **版本**: v1.0
|
||||
> **代码状态**: 40/40 测试通过,待部署
|
||||
> **预估部署时间**: 30-45 分钟
|
||||
> **版本**: v2.0(新增报修+指南+二维码+移动端适配)
|
||||
> **代码状态**: 待部署
|
||||
> **预估部署时间**: 45-60 分钟
|
||||
|
||||
---
|
||||
|
||||
@@ -15,14 +15,15 @@
|
||||
- [ ] 确认会议室 `meetingroom_id` 列表
|
||||
|
||||
### 1.2 服务器环境
|
||||
- [ ] PostgreSQL 可用(需执行 Alembic 迁移)
|
||||
- [ ] PostgreSQL 可用(需执行 Alembic 迁移 050 + 051)
|
||||
- [ ] Redis 可用(会议室缓存依赖)
|
||||
- [ ] Nginx 可用(终端前端静态文件)
|
||||
- [ ] Nginx 可用(终端前端静态文件 + API 代理)
|
||||
- [ ] Docker Compose 可用
|
||||
|
||||
### 1.3 终端设备
|
||||
- [ ] 确认小鱼易联终端型号(当前按浏览器方案设计)
|
||||
- [ ] 确认小鱼易联终端型号(NE90/NE60 支持 H5 应用,NE2005 需二维码降级)
|
||||
- [ ] 终端浏览器支持 WebSocket + ES6
|
||||
- [ ] 小鱼管理后台可访问(配置 H5 应用入口)
|
||||
|
||||
---
|
||||
|
||||
@@ -31,7 +32,7 @@
|
||||
### Step 1: 数据库迁移
|
||||
|
||||
```bash
|
||||
# 进入后端容器
|
||||
# 进入后端容器执行迁移(050 会议室基础表 + 051 报修+指南表)
|
||||
docker compose exec backend alembic upgrade head
|
||||
|
||||
# 验证新表
|
||||
@@ -40,21 +41,23 @@ from app.database import engine
|
||||
from sqlalchemy import inspect
|
||||
insp = inspect(engine)
|
||||
tables = insp.get_table_names()
|
||||
print('meetingroom_booking_snapshots' in tables) # 应为 True
|
||||
print('terminal_room_bindings' in tables) # 应为 True
|
||||
print('terminal_room_bindings' in tables) # 应为 True(050)
|
||||
print('meetingroom_guide' in tables) # 应为 True(051)
|
||||
print('meetingroom_repair' in tables) # 应为 True(051)
|
||||
"
|
||||
```
|
||||
|
||||
### Step 2: 环境变量配置
|
||||
|
||||
在 `docker-compose.yml` 中添加:
|
||||
在 `.env` 中添加:
|
||||
```bash
|
||||
# 终端页面基础URL(用于NE2005二维码生成)
|
||||
TERMINAL_BASE_URL=https://itsupport.servyou.com.cn/itterminal/
|
||||
```
|
||||
|
||||
在 `docker-compose.yml` 的 backend environment 中已添加:
|
||||
```yaml
|
||||
backend:
|
||||
environment:
|
||||
- WECOM_MEETINGROOM_SECRET=<your_secret>
|
||||
- MEETINGROOM_CACHE_TTL_ROOMS=600
|
||||
- MEETINGROOM_CACHE_TTL_BOOKING=30
|
||||
- MEETINGROOM_CACHE_TTL_STATUS=10
|
||||
- TERMINAL_BASE_URL=${TERMINAL_BASE_URL:-https://itsupport.servyou.com.cn/itterminal/}
|
||||
```
|
||||
|
||||
重启后端:
|
||||
@@ -65,23 +68,28 @@ docker compose up -d backend
|
||||
### Step 3: 后端验证
|
||||
|
||||
```bash
|
||||
# 验证 API 端点注册
|
||||
curl -sk https://localhost/api/itportal/meetingroom/rooms \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
# 验证会议室 API(已存在)
|
||||
curl -sk https://localhost/itportal/meetingroom/list
|
||||
|
||||
# 验证 WS 端点
|
||||
wscat -c "wss://localhost/ws/terminal/TEST-SN-001"
|
||||
# 验证报修 API(新增)
|
||||
curl -sk -X POST https://localhost/itportal/meetingroom/repair \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"terminal_sn":"TEST-SN","meetingroom_id":1,"meetingroom_name":"测试","device_type":"projector","fault_description":"测试报修"}'
|
||||
|
||||
# 验证管理端绑定 API
|
||||
curl -sk https://localhost/api/itportal/admin/terminal-bindings \
|
||||
-H "Authorization: Bearer $ADMIN_TOKEN"
|
||||
# 验证指南 API(新增)
|
||||
curl -sk https://localhost/itportal/meetingroom/guides
|
||||
|
||||
# 验证二维码 API(新增)
|
||||
curl -sk https://localhost/itportal/meetingroom/terminal/TEST-SN/qrcode -o /tmp/qr.png
|
||||
file /tmp/qr.png # 应为 PNG image
|
||||
```
|
||||
|
||||
### Step 4: 终端前端部署
|
||||
### Step 4: 终端前端构建与部署
|
||||
|
||||
```bash
|
||||
# 1. 本地构建
|
||||
cd frontend-terminal
|
||||
npm install # 安装新增的 qrcode 依赖
|
||||
npm run build
|
||||
|
||||
# 2. 打包
|
||||
@@ -93,50 +101,139 @@ python C:\Users\simon\.workbuddy\skills\jumpserver-ops\scripts\jms_ops.py \
|
||||
|
||||
# 4. 服务器解压
|
||||
cd /opt/wecom-it-desk/frontend-terminal/
|
||||
rm -rf dist # 删除旧 dist(bind mount 铁律:rm后重建必须重启容器)
|
||||
tar -xzf /tmp/terminal-dist.tar.gz
|
||||
```
|
||||
|
||||
# 5. Nginx 配置
|
||||
# 在 nginx.conf 中添加:
|
||||
### Step 5: Nginx 配置更新
|
||||
|
||||
`nginx/nginx.conf` 已更新,新增以下 location(两个 server 块均已添加):
|
||||
|
||||
```nginx
|
||||
# 小鱼终端大屏 — /itterminal/
|
||||
location /itterminal/ {
|
||||
alias /usr/share/nginx/html/terminal/;
|
||||
try_files $uri $uri/ /itterminal/index.html;
|
||||
alias /usr/share/nginx/html/itterminal/;
|
||||
index index.html;
|
||||
try_files $uri /itterminal/index.html;
|
||||
}
|
||||
|
||||
# 会议室 API — /itportal/meetingroom/
|
||||
# 必须在 /itportal/ 静态文件之前匹配(nginx 最长前缀优先)
|
||||
location /itportal/meetingroom/ {
|
||||
proxy_pass http://backend_api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Nginx 重启
|
||||
`docker-compose.yml` nginx volumes 已添加:
|
||||
```yaml
|
||||
- ./frontend-terminal/dist:/usr/share/nginx/html/itterminal:ro
|
||||
```
|
||||
|
||||
重启 Nginx:
|
||||
```bash
|
||||
docker compose restart nginx
|
||||
```
|
||||
|
||||
### Step 6: H5 端入口验证
|
||||
### Step 6: 终端前端验证
|
||||
|
||||
H5 端已内置会议室入口(`MeetingroomView.vue`),无需额外部署。
|
||||
验证:
|
||||
```bash
|
||||
curl -sk https://localhost/ith5/ | grep -o 'meetingroom'
|
||||
# 验证终端页面可访问
|
||||
curl -sk https://localhost/itterminal/ | head -5
|
||||
|
||||
# 验证 API 代理(通过 nginx 访问后端)
|
||||
curl -sk https://localhost/itportal/meetingroom/guides
|
||||
|
||||
# 验证静态资源
|
||||
curl -sk -o /dev/null -w "%{http_code}" https://localhost/itterminal/assets/index-*.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、部署后验证
|
||||
## 三、小鱼管理后台 H5 应用配置
|
||||
|
||||
### 3.1 功能验证清单
|
||||
### 3.1 支持型号确认
|
||||
|
||||
| 型号 | H5 应用支持 | 配置方式 |
|
||||
|------|------------|---------|
|
||||
| NE90 | ✅ 支持 | 小鱼管理后台配置 H5 应用入口 |
|
||||
| NE60 | ✅ 支持 | 同上 |
|
||||
| NE20 | ✅ 支持 | 同上 |
|
||||
| AE2060 | ✅ 支持 | 同上 |
|
||||
| ME55S | ⚠️ 部分固件支持 | 需确认固件版本 |
|
||||
| NE2005 | ❌ 不支持 | 使用二维码降级方案 |
|
||||
|
||||
### 3.2 H5 应用入口配置(NE90/NE60/NE20/AE2060)
|
||||
|
||||
1. 登录**小鱼易联管理后台**(`https://mt.xylink.com`)
|
||||
2. 进入 **应用管理 > 自定义应用**
|
||||
3. 创建新应用:
|
||||
- **应用名称**: `IT智能服务台`
|
||||
- **应用类型**: H5 网页应用
|
||||
- **访问地址**: `https://itsupport.servyou.com.cn/itterminal/{终端SN}/`
|
||||
- **展示方式**: 终端主界面快捷入口
|
||||
4. 推送应用到目标终端
|
||||
5. 在终端上验证 H5 应用可正常打开
|
||||
|
||||
### 3.3 终端 SN 绑定
|
||||
|
||||
在管理后台(`/itadmin/`)的终端绑定页面中:
|
||||
1. 添加终端 SN 与会议室的绑定关系
|
||||
2. 每个终端 SN 对应一个企微会议室 ID
|
||||
3. 绑定后终端页面自动加载对应会议室状态
|
||||
|
||||
### 3.4 NE2005 二维码降级方案
|
||||
|
||||
对于不支持 H5 应用的 NE2005 终端:
|
||||
|
||||
1. **生成二维码**:
|
||||
```bash
|
||||
# 通过 API 生成终端访问二维码
|
||||
curl -sk https://itsupport.servyou.com.cn/itportal/meetingroom/terminal/{SN}/qrcode -o qr.png
|
||||
```
|
||||
或直接在浏览器访问:
|
||||
`https://itsupport.servyou.com.cn/itportal/meetingroom/terminal/{SN}/qrcode`
|
||||
|
||||
2. **打印二维码**:将二维码打印为贴纸(建议尺寸 10×10cm)
|
||||
|
||||
3. **张贴二维码**:贴在 NE2005 终端的显眼位置
|
||||
|
||||
4. **用户使用流程**:
|
||||
- 用户用企业微信/微信扫描二维码
|
||||
- 手机浏览器打开终端页面(移动端自适应布局)
|
||||
- 可查看会议室状态、预定、报修、查看指南
|
||||
|
||||
---
|
||||
|
||||
## 四、部署后验证
|
||||
|
||||
### 4.1 功能验证清单
|
||||
|
||||
| # | 验证项 | 验证方法 | 预期结果 |
|
||||
|---|--------|---------|---------|
|
||||
| 1 | 会议室列表 | `GET /api/itportal/meetingroom/rooms` | 返回会议室列表 |
|
||||
| 2 | 会议室状态 | `GET /api/itportal/meetingroom/rooms/{id}/status` | 返回当前状态 |
|
||||
| 3 | 预定会议室 | `POST /api/itportal/meetingroom/bookings` | 创建预定成功 |
|
||||
| 4 | 时间线 | `GET /api/itportal/meetingroom/rooms/{id}/timeline` | 返回当日时间线 |
|
||||
| 5 | 终端绑定 | `POST /api/itportal/admin/terminal-bindings` | 绑定终端-会议室 |
|
||||
| 6 | 终端WS | `WS /ws/terminal/{sn}` | 终端状态实时推送 |
|
||||
| 7 | 终端前端 | 浏览器打开 `/itterminal/` | 深色主题大屏页面 |
|
||||
| 8 | H5入口 | H5 端点击会议室入口 | 跳转 MeetingroomView |
|
||||
| 9 | 扫码登录 | 终端扫码 | 企微扫码登录成功 |
|
||||
| 10 | 状态同步 | 终端修改状态 → H5 实时更新 | WS 推送正常 |
|
||||
| 1 | 会议室列表 | `GET /itportal/meetingroom/list` | 返回会议室列表 |
|
||||
| 2 | 会议室状态 | `GET /itportal/meetingroom/{id}/status` | 返回当前状态 |
|
||||
| 3 | 预定会议室 | `POST /itportal/meetingroom/book` | 创建预定成功 |
|
||||
| 4 | 终端绑定 | `GET /itportal/meetingroom/terminal/{sn}/binding` | 返回绑定信息 |
|
||||
| 5 | 终端WS | `WS /ws/terminal/{sn}` | 终端状态实时推送 |
|
||||
| 6 | **设备报修** | `POST /itportal/meetingroom/repair` | 创建工单+通知管理员 |
|
||||
| 7 | **指南列表** | `GET /itportal/meetingroom/guides` | 返回指南列表(5条种子) |
|
||||
| 8 | **指南按类型** | `GET /itportal/meetingroom/guides/projector` | 返回投影仪指南 |
|
||||
| 9 | **终端二维码** | `GET /itportal/meetingroom/terminal/{sn}/qrcode` | 返回PNG图片 |
|
||||
| 10 | 终端前端 | 浏览器打开 `/itterminal/{sn}/` | 深色主题大屏页面 |
|
||||
| 11 | **报修页面** | 终端点击"设备报修"按钮 | 显示报修表单 |
|
||||
| 12 | **指南页面** | 终端点击"操作指南"按钮 | 显示指南列表+二维码 |
|
||||
| 13 | **移动端适配** | 手机访问 `/itterminal/{sn}/` | 垂直布局自适应 |
|
||||
| 14 | 扫码登录 | 终端扫码 | 企微扫码登录成功 |
|
||||
| 15 | 状态同步 | 终端修改状态 → H5 实时更新 | WS 推送正常 |
|
||||
|
||||
### 3.2 Redis 缓存验证
|
||||
### 4.2 Redis 缓存验证
|
||||
|
||||
```bash
|
||||
# 会议室 token
|
||||
@@ -145,33 +242,37 @@ redis-cli -a $REDIS_PASSWORD get wecom:meetingroom_access_token
|
||||
# 会议室列表缓存
|
||||
redis-cli -a $REDIS_PASSWORD get meetingroom:room_list
|
||||
|
||||
# 预定缓存
|
||||
redis-cli -a $REDIS_PASSWORD get "meetingroom:booking:{room_id}:{date}"
|
||||
|
||||
# 状态缓存
|
||||
redis-cli -a $REDIS_PASSWORD get "meetingroom:status:{room_id}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、回滚方案
|
||||
## 五、回滚方案
|
||||
|
||||
### 4.1 数据库回滚
|
||||
### 5.1 数据库回滚
|
||||
```bash
|
||||
# 回退迁移 050
|
||||
# 回退迁移 051(报修+指南表)
|
||||
docker compose exec backend alembic downgrade -1
|
||||
|
||||
# 完全回退(含 050)
|
||||
docker compose exec backend alembic downgrade -2
|
||||
```
|
||||
|
||||
### 4.2 后端回滚
|
||||
### 5.2 后端回滚
|
||||
```bash
|
||||
# 恢复 .py 文件(bind mount 自动生效)
|
||||
git checkout HEAD~1 -- backend/app/api/meetingroom.py
|
||||
git checkout HEAD~1 -- backend/app/services/repair_service.py
|
||||
git checkout HEAD~1 -- backend/app/services/meetingroom_service.py
|
||||
# ... 其他文件
|
||||
git checkout HEAD~1 -- backend/app/models/meetingroom_guide.py
|
||||
git checkout HEAD~1 -- backend/app/models/meetingroom_repair.py
|
||||
git checkout HEAD~1 -- backend/app/schemas/meetingroom.py
|
||||
git checkout HEAD~1 -- backend/app/config.py
|
||||
docker compose restart backend
|
||||
```
|
||||
|
||||
### 4.3 前端回滚
|
||||
### 5.3 前端回滚
|
||||
```bash
|
||||
# 恢复旧 dist
|
||||
mv /opt/wecom-it-desk/frontend-terminal/dist /opt/wecom-it-desk/frontend-terminal/dist.bak
|
||||
@@ -179,24 +280,52 @@ mv /opt/wecom-it-desk/frontend-terminal/dist /opt/wecom-it-desk/frontend-termina
|
||||
docker compose restart nginx
|
||||
```
|
||||
|
||||
### 4.4 Nginx 配置回滚
|
||||
### 5.4 Nginx 配置回滚
|
||||
```bash
|
||||
# 移除 /itterminal/ location 块
|
||||
# 移除 /itterminal/ 和 /itportal/meetingroom/ location 块
|
||||
docker compose restart nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、已知限制
|
||||
## 六、新增功能说明
|
||||
|
||||
1. **企微API时间限制**: 会议室预定查询范围限制 31 天
|
||||
2. **终端身份**: 当前按访客可查看设计,管理操作需扫码登录
|
||||
3. **WS重连**: 终端断线后自动重连(指数退避),超过 5 次降级为轮询(10s间隔)
|
||||
4. **缓存TTL**: 会议室列表 600s / 预定 30s / 状态 10s,手动刷新可跳过缓存
|
||||
### 6.1 设备报修流程
|
||||
|
||||
```
|
||||
终端用户点击"设备报修"
|
||||
→ 选择设备类型(投影仪/视频会议/空调/桌椅/网络/其他)
|
||||
→ 填写故障描述
|
||||
→ 提交报修
|
||||
→ 后端创建:
|
||||
1. MeetingroomRepair 记录
|
||||
2. Conversation(IT工单会话,状态=排队,紧急度=3)
|
||||
3. Message(系统消息,含故障描述)
|
||||
4. 企微消息通知管理员
|
||||
5. WS广播给在线坐席
|
||||
→ 终端显示"报修已提交"
|
||||
→ 3秒后自动返回状态页
|
||||
```
|
||||
|
||||
### 6.2 操作指南双模式
|
||||
|
||||
- **终端展示**:指南的 `brief` 字段在终端大屏上直接显示简要操作步骤
|
||||
- **二维码详情**:指南的 `detail_url` 生成二维码,用户手机扫码查看完整文档
|
||||
- 管理员可在数据库中添加/修改指南内容
|
||||
|
||||
### 6.3 NE2005 降级流程
|
||||
|
||||
```
|
||||
NE2005 终端(不支持H5应用)
|
||||
→ 管理员生成二维码贴纸(API: /itportal/meetingroom/terminal/{sn}/qrcode)
|
||||
→ 用户手机扫码
|
||||
→ 手机浏览器打开终端页面(移动端自适应)
|
||||
→ 功能与终端大屏一致(状态/预定/报修/指南)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、配置参数速查
|
||||
## 七、配置参数速查
|
||||
|
||||
| 参数 | 默认值 | 环境变量 |
|
||||
|------|--------|---------|
|
||||
@@ -206,3 +335,16 @@ docker compose restart nginx
|
||||
| 状态缓存 | 10s | `MEETINGROOM_CACHE_TTL_STATUS` |
|
||||
| WS重连次数 | 5 | - |
|
||||
| WS降级轮询间隔 | 10s | - |
|
||||
| **终端页面URL** | `https://itsupport.servyou.com.cn/itterminal/` | `TERMINAL_BASE_URL` |
|
||||
| **二维码尺寸** | 300px | API 参数 `size` |
|
||||
| **二维码缓存** | 1小时 | HTTP `Cache-Control` |
|
||||
|
||||
---
|
||||
|
||||
## 八、已知限制
|
||||
|
||||
1. **企微API时间限制**: 会议室预定查询范围限制 31 天
|
||||
2. **终端身份**: 管理操作需扫码登录,报修支持匿名提交
|
||||
3. **WS重连**: 终端断线后自动重连(指数退避),超过 5 次降级为轮询(10s间隔)
|
||||
4. **NE2005**: 不支持 H5 应用,仅能通过二维码扫码方式使用
|
||||
5. **指南管理**: 当前通过数据库直接管理,后续可增加管理后台 UI
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# 企微IT智能服务台 — 项目管理主文档
|
||||
|
||||
> **版本**: v2.4 | **日期**: 2026-07-10 | **维护人**: 助理
|
||||
> **版本**: v2.5 | **日期**: 2026-07-13 | **维护人**: Duckula
|
||||
|
||||
---
|
||||
|
||||
## 一、项目状态总览
|
||||
|
||||
> **一句话总览**:v0.7.1 已上线运行,生产稳定。知识库迭代 v0.7.2 全链路交付完成。
|
||||
> **一句话总览**:v0.7.1 已上线运行,生产稳定。AI 对话链路全栈改造 Phase 1-6 全部完成并部署。H5 v4 人工坐席交互改造已部署。
|
||||
|
||||
### 已完成 (v0.7.1)
|
||||
- ✅ 企微入口 SSO
|
||||
@@ -20,6 +20,13 @@
|
||||
- ✅ 排查流程优化
|
||||
- ✅ 知识库迭代
|
||||
|
||||
### v0.7.3 AI 对话链路全栈改造 + 上下文感知诊断 + H5 v4(全部部署)
|
||||
- ✅ AI 对话链路 Phase 1-6(Dify JSON 输出 / 统一消息架构 / VisionService 接入 / 坐席端适配 / 诊断闭环)
|
||||
- ✅ 上下文感知智能诊断→修复闭环(三层诊断 / 三段排队 / 答题插队 / 五场景关闭)
|
||||
- ✅ 坐席端布局优化 v2.0(QuickReplyBar / ReplyBox / 右栏模式切换 / 键盘快捷键 v2.3)
|
||||
- ✅ 知识库迭代 3(分诊交互 / 拓扑预览 / 代答排除)
|
||||
- ✅ H5 v4 人工坐席交互改造(文案统一 / 按钮重定位 / 删 CallAgentModal / 截图提示改版)
|
||||
|
||||
### 版本迭代
|
||||
|
||||
| 版本 | 状态 | 主要内容 | 日期 |
|
||||
@@ -27,6 +34,7 @@
|
||||
| v0.7.0 | ✅ 已上线 | 企微SSO、MFA、RBAC | 2026-06 |
|
||||
| v0.7.1 | ✅ 已上线 | 敏感词检测、token修复、扫码登录优化 | 2026-07-04 |
|
||||
| v0.7.2 | ✅ 已完成 | backlog候选(AI辅助、排查流程,知识库迭代) | 2026-07+ |
|
||||
| v0.7.3 | ✅ 已部署 | AI对话链路Phase1-6、上下文感知诊断、坐席布局v2.0、H5 v4人工坐席改造 | 2026-07-12~13 |
|
||||
|
||||
---
|
||||
|
||||
@@ -75,6 +83,11 @@
|
||||
|
||||
| # | 任务 | 说明 | 完成日期 |
|
||||
|---|---|---|---|
|
||||
| #116 | H5 v4 人工坐席交互改造 | ✨ 三态文案统一"人工坐席"/按钮位置上移/删除CallAgentModal弹窗/截图提示改版/移动端CSS隐藏/后端DB同步 | 2026-07-13 |
|
||||
| #59-69 | AI 对话链路全栈改造 Phase 1-6 | ✨ Dify JSON输出/统一消息架构/VisionService接入/坐席端适配/诊断闭环协调/性能监控 | 2026-07-12 |
|
||||
| #115+ | 上下文感知智能诊断→修复闭环 | ✨ 三层诊断(API→Script→AI)/三段排队/答题插队/五场景关闭/迁移052(6表+6列) | 2026-07-12 |
|
||||
| #113+ | 坐席端布局优化 v2.0 | ✨ QuickReplyBar L1+L2悬浮/ReplyBox左右分区/右栏260↔560px/键盘快捷键v2.3 | 2026-07-12 |
|
||||
| #113+ | 知识库迭代 3 | ✨ 分诊交互/拓扑预览(ECharts)/代答排除(4种匹配器)/44文件43测试/迁移051 | 2026-07-12 |
|
||||
| #111 | 坐席端消息头像不显示Bug | 🐛 后端消息接口未返回sender_avatar → Schema添加字段 + API填充员工/AI头像 + 前端显示 | 2026-07-10 |
|
||||
| #112 | 坐席端消息布局调整 | ✨ 头像和名字位置互换(头像在前、名字在后) | 2026-07-10 |
|
||||
| #113 | 审批类型扩展与卡片URL直跳 | ✨ 审批类型 5→12种/18流程,后端静态模板+关键词扩展,前端卡片12类17选项URL直跳,Dify v2 System Prompt覆盖全部12类 | 2026-07-10 |
|
||||
@@ -135,6 +148,16 @@
|
||||
|
||||
## 五、最近搞定
|
||||
|
||||
### 2026-07-13
|
||||
- ✅ H5 v4 人工坐席交互改造 + 部署(#116)— 文案统一/按钮重定位/删CallAgentModal/截图提示改版/DB同步
|
||||
- ✅ 服务器部署路径修正 — 确认 `/opt/wecom-it-desk/` 项目根路径,所有前端 dist 为 ro bind mount
|
||||
|
||||
### 2026-07-12
|
||||
- ✅ AI 对话链路全栈改造 Phase 1-6 全部完成并部署(#59-#69)
|
||||
- ✅ 上下文感知智能诊断→修复闭环部署(三层诊断/三段排队/答题插队/五场景关闭)
|
||||
- ✅ 坐席端布局优化 v2.0 部署(QuickReplyBar/ReplyBox/右栏模式切换/键盘快捷键v2.3)
|
||||
- ✅ 知识库迭代 3 部署(分诊交互/拓扑预览/代答排除)
|
||||
|
||||
### 2026-07-10
|
||||
- ✅ 审批类型扩展 5→12种/18流程 + 卡片URL直跳 + Dify v2 发布(#113)
|
||||
- ✅ 审批卡片同窗口导航改造(#114)
|
||||
@@ -252,6 +275,7 @@ curl http://localhost:8000/api/dev/health
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| v2.5 | 2026-07-13 | 新增 v0.7.3 版本(AI对话链路Phase1-6/上下文感知诊断/坐席布局v2.0/知识库迭代3/H5 v4),新增 #116 和 #59-69 完成任务,更新最近搞定 |
|
||||
| v2.4 | 2026-07-10 | 新增 #113-115 审批流程系统任务(类型扩展+卡片导航+免登录研究),P2功能表新增审批流程系统 |
|
||||
| v2.3 | 2026-07-10 | 新增 #111-112 头像显示与布局调整任务 |
|
||||
| v2.2 | 2026-07-10 | 新增 #108-110 Bug修复任务(消息重复、自动滚动、WS认证) |
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# IT智能服务台 - 线性执行计划
|
||||
|
||||
> **制定日期**: 2026-07-11 23:20
|
||||
> **版本快照**: `v2026.07.11-evening` (git tag已推送)
|
||||
> **今晚自动执行**: Phase 1-3 (确认后启动)
|
||||
|
||||
---
|
||||
|
||||
## 执行原则
|
||||
|
||||
1. **线性无冲突**: 每步按序执行,前一步完成才进入下一步
|
||||
2. **低风险优先**: 后端小修复 → 全栈部署 → 文档生成 → 前端开发
|
||||
3. **可回滚**: 每步均有回滚方案,git tag `v2026.07.11-evening` 为回滚锚点
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: 后端快速修复 (今晚自动, ~15min) ✅ 已完成
|
||||
|
||||
### 1.1 IT资产升级审批推送 部署+测试 ✅
|
||||
- **文件**: `backend/app/services/asset_service.py` / `backend/app/api/approval.py` / `backend/app/config.py`
|
||||
- **操作**: 上传3个.py → `docker compose restart backend` → 运行 `test_asset_approval_urge.py`
|
||||
- **验证**: curl 测试 urge 端点返回200
|
||||
- **回滚**: `git checkout v2026.07.11-evening -- backend/app/services/asset_service.py`
|
||||
|
||||
### 1.2 itsm_service.py httpx.Timeout 修复 ✅
|
||||
- **文件**: `backend/app/services/itsm_service.py:33`
|
||||
- **变更**: 代码已有正确写法 `httpx.Timeout(timeout=30.0, connect=10.0, read=30.0)`,无需变更
|
||||
- **操作**: 确认代码正确
|
||||
|
||||
### 1.3 企微审批查询范围 7天→30天 ✅
|
||||
- **文件**: `backend/app/services/todo_source_service.py`
|
||||
- **变更**: `APPROVAL_QUERY_DAYS = 30` 已部署
|
||||
- **操作**: 上传1个.py → `docker compose restart backend`
|
||||
- **验证**: API返回更多历史审批单
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: 会议室预定系统部署 (今晚自动, ~45min) ✅ 已完成
|
||||
|
||||
### 2.1 数据库迁移 ✅
|
||||
- **操作**: `create_meetingroom_tables.py` 直接 SQL 建表(alembic 不可用)
|
||||
- **新表**: `meetingroom_booking_snapshot` / `terminal_room_binding`
|
||||
- **验证**: 查询新表存在
|
||||
|
||||
### 2.2 后端环境变量+重启 ✅
|
||||
- **操作**: 企微会议室 Secret 待用户申请(暂不配置)
|
||||
- **验证**: `curl /itportal/meetingroom/list` 返回企微API响应(forbidden,因Secret未配置)
|
||||
|
||||
### 2.3 终端前端部署 ✅
|
||||
- **操作**: Vite base 修正 `/terminal/` → `/itterminal/` → `npm run build` → pack-upload → docker volume → nginx
|
||||
- **Nginx**:
|
||||
- 添加 `location /itterminal/` 静态文件服务
|
||||
- 添加 `location /itportal/meetingroom/` API 代理
|
||||
- `docker compose up -d nginx` 重建容器
|
||||
- **验证**: `https://localhost/itterminal/` → 200 ✅;JS/CSS → 200 ✅
|
||||
|
||||
### 2.4 端到端验证 ✅(部分)
|
||||
- ✅ 终端前端页面加载正常
|
||||
- ✅ JS/CSS 资源加载正常
|
||||
- ✅ 会议室列表 API 端点可达(返回企微 forbidden,因 Secret 未配置)
|
||||
- ⏳ 企微会议室 Secret 配置后可完成完整功能验证
|
||||
- **回滚**: 移除 nginx location + docker volume + git checkout
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: 技术方案文档生成 (今晚自动, ~30min) ✅ 已完成
|
||||
|
||||
### 3.1 AI辅助消息框 技术方案 ✅
|
||||
- **输入**: `docs/02-产品需求/坐席端AI辅助消息框-PRD.md` (已确认4项功能)
|
||||
- **输出**: `docs/03-技术架构/增量设计-AI辅助消息框-20260711.md` (901行,含9章节+附录)
|
||||
- **内容**: 系统设计(挑战/选型/架构图) + 文件列表(7新+3改) + 数据接口 + 时序图 + 4个任务(T01-T04) + 依赖图 + Dify Prompt汇总
|
||||
- **关键路径**: T01→T02→T03→T04 (~7天)
|
||||
|
||||
### 3.2 布局优化v2.0 技术方案 ✅
|
||||
- **输入**: `docs/02-产品需求/坐席端布局优化建议.md` (v2.0已确认)
|
||||
- **输出**: 3个文件
|
||||
- `docs/03-技术架构/增量设计-布局优化v2-20260711.md` (43.5KB主文档,8章节)
|
||||
- `docs/03-技术架构/增量设计-布局优化v2-类图.mermaid` (6.9KB)
|
||||
- `docs/03-技术架构/增量设计-布局优化v2-时序图.mermaid` (6.1KB,3个时序图)
|
||||
- **内容**: 5个任务(T01-T05) + 8个待明确事项 + 清理清单 + 工具栏设计 + 回复建议区 + 右栏模式切换
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: 前端开发 (人工, ~15工作日)
|
||||
|
||||
### 4.1 AI辅助消息框 (~8天)
|
||||
- 实时自动补齐 / 语气调整 / 文字润色 / 智能改写
|
||||
- 前端: ReplyBox.vue 新增AI工具栏
|
||||
- 后端: wingman.py 新增4个端点
|
||||
|
||||
### 4.2 布局优化v2.0 (~7天)
|
||||
- Phase1: 清理+骨架 (1.5天)
|
||||
- Phase2: 工具栏 (0.5天)
|
||||
- Phase3: 回复建议区 (2天)
|
||||
- Phase4: 右栏训练区+开关 (2天)
|
||||
- Phase5: 联调 (1天)
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: ITSM集成 (外部依赖)
|
||||
|
||||
### 5.1 ITSM API抓包
|
||||
- 用 agent-browser 登录 ITSM 代办页面抓 XHR
|
||||
- 需用户提供 ITSM 登录凭据
|
||||
|
||||
### 5.2 ITSM app_id/app_secret申请
|
||||
- 向 ITSM 平台方申请
|
||||
- 签名: app_id + app_secret + SHA1
|
||||
|
||||
### 5.3 ITSM代办列表集成
|
||||
- 后端: itsm_service.py 补全代办列表API
|
||||
- 前端: TodoPanel.vue 工单Tab接入真实数据
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: 知识库迭代 (待确认)
|
||||
|
||||
### 6.1 功能确认
|
||||
- 技术方案: `docs/03-技术架构/增量设计-知识库迭代与痛点缓解-20260711.md`
|
||||
- 原型图: `docs/01-产品设计/知识库迭代-未实现功能原型设计-20260711.md`
|
||||
- 待用户确认后进入开发
|
||||
|
||||
### 6.2 开发+联调
|
||||
- RAGFlow对接 / Neo4j图谱 / 前端联调
|
||||
|
||||
---
|
||||
|
||||
## 今晚自动执行清单
|
||||
|
||||
| 步骤 | 操作 | 预计耗时 | 风险 | 状态 |
|
||||
|------|------|---------|------|------|
|
||||
| 1.1 | IT资产审批推送 上传+重启+测试 | 5min | 低 | ✅ 完成 |
|
||||
| 1.2 | itsm_service httpx.Timeout 修复 | 2min | 低 | ✅ 完成 |
|
||||
| 1.3 | 企微审批范围 7d→30d | 2min | 低 | ✅ 完成 |
|
||||
| 2.1 | 会议室 DB迁移 | 5min | 中 | ✅ 完成 |
|
||||
| 2.2 | 会议室 后端env+重启 | 5min | 中 | ✅ 完成(Secret待申请) |
|
||||
| 2.3 | 会议室 终端前端部署 | 15min | 中 | ✅ 完成 |
|
||||
| 2.4 | 会议室 端到端验证 | 10min | - | ✅ 部分完成 |
|
||||
| 3.1 | AI辅助消息框 技术方案 | 15min | 无 | ✅ 完成 |
|
||||
| 3.2 | 布局优化v2.0 技术方案 | 15min | 无 | ✅ 完成 |
|
||||
| **合计** | | **~75min** | | **Phase 1-3 全部完成** |
|
||||
|
||||
---
|
||||
|
||||
## 回滚方案
|
||||
|
||||
```bash
|
||||
# Git 回滚到今晚版本快照
|
||||
git checkout v2026.07.11-evening
|
||||
|
||||
# 数据库回滚(会议室新表)
|
||||
docker compose exec backend alembic downgrade -1
|
||||
|
||||
# 前端回滚
|
||||
# 终端: 移除 /itterminal/ nginx location
|
||||
# 坐席/H5: 恢复上一版 dist
|
||||
```
|
||||
Reference in New Issue
Block a user