2026-07-11 23:13:10 +08:00
|
|
|
|
# 增量设计:知识库迭代与痛点缓解
|
|
|
|
|
|
|
|
|
|
|
|
> **文档版本**:v1.0
|
|
|
|
|
|
> **创建日期**:2026-07-11
|
|
|
|
|
|
> **文档类型**:回溯文档(已部署功能)+ 前瞻设计(未实现功能)
|
2026-08-07 22:31:32 +08:00
|
|
|
|
> **测试报告引用**:`docs/03-测试文档/Tier0-测试报告-20260708.md`(89/89 通过)
|
2026-07-11 23:13:10 +08:00
|
|
|
|
> **技术栈**:FastAPI + SQLAlchemy + PostgreSQL + Redis + Neo4j / Vue3 + Element Plus + Vant4 + ECharts
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 目录
|
|
|
|
|
|
|
|
|
|
|
|
1. [概述](#1-概述)
|
|
|
|
|
|
2. [系统架构总览](#2-系统架构总览)
|
|
|
|
|
|
3. [各功能模块技术方案](#3-各功能模块技术方案)
|
|
|
|
|
|
- 3.1 [分诊交互](#31-分诊交互)
|
|
|
|
|
|
- 3.2 [置信门控](#32-置信门控)
|
|
|
|
|
|
- 3.3 [内联审批卡片](#33-内联审批卡片)
|
|
|
|
|
|
- 3.4 [拓扑预览](#34-拓扑预览)
|
|
|
|
|
|
- 3.5 [重复检测](#35-重复检测)
|
|
|
|
|
|
- 3.6 [代答排除](#36-代答排除)
|
|
|
|
|
|
- 3.7 [知识迭代管理](#37-知识迭代管理)
|
|
|
|
|
|
- 3.8 [图谱可视化](#38-图谱可视化)
|
|
|
|
|
|
- 3.9 [合并去重](#39-合并去重)
|
|
|
|
|
|
- 3.10 [会话关闭→建议→审核→写图](#310-会话关闭建议审核写图)
|
|
|
|
|
|
4. [功能依赖关系图](#4-功能依赖关系图)
|
|
|
|
|
|
5. [全链路数据流图](#5-全链路数据流图)
|
|
|
|
|
|
6. [未实现功能设计](#6-未实现功能设计)
|
|
|
|
|
|
7. [已知问题与后续优化方向](#7-已知问题与后续优化方向)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 概述
|
|
|
|
|
|
|
|
|
|
|
|
### 1.1 功能背景
|
|
|
|
|
|
|
|
|
|
|
|
IT智能服务台在持续运营中暴露出三大痛点:
|
|
|
|
|
|
|
|
|
|
|
|
1. **知识库更新滞后**:AI 回复不准确的问题需要人工发现→人工编写→人工录入,平均更新周期超过 2 周。
|
|
|
|
|
|
2. **低置信回复无兜底**:AI 回复 confidence 低于阈值时,员工无感知,直接收到低质量回答,体验差。
|
|
|
|
|
|
3. **重复知识堆积**:多个来源(会话分析、标注分析、手动录入)生成的建议缺乏去重机制,导致知识图谱中出现重复 Issue 节点。
|
|
|
|
|
|
|
|
|
|
|
|
为解决上述痛点,本项目实施了"知识库迭代与痛点缓解"功能集,包含 10 个功能模块,覆盖从 AI 回复质量保障到知识图谱自动维护的完整闭环。
|
|
|
|
|
|
|
|
|
|
|
|
### 1.2 目标
|
|
|
|
|
|
|
|
|
|
|
|
| 目标 | 衡量指标 |
|
|
|
|
|
|
|------|---------|
|
|
|
|
|
|
| 知识库自动迭代 | 会话关闭后自动生成知识建议,训练师审核后自动写入知识图谱 |
|
|
|
|
|
|
| 低置信兜底 | confidence < 0.7 时前端展示转人工入口,携带上下文快照 |
|
|
|
|
|
|
| 知识去重 | 采纳建议前检测重复,支持合并去重操作 |
|
|
|
|
|
|
| 图谱可视化 | 管理后台 ECharts 力导向图展示 Neo4j 知识图谱全貌 |
|
|
|
|
|
|
| 分步分诊 | 复杂问题拆分为分步选择题,降低员工认知负担 |
|
|
|
|
|
|
|
|
|
|
|
|
### 1.3 范围
|
|
|
|
|
|
|
|
|
|
|
|
本功能集涉及 10 个功能模块,按部署状态分为两类:
|
|
|
|
|
|
|
|
|
|
|
|
| # | 功能 | 代码状态 | 部署状态 | 文档类型 |
|
|
|
|
|
|
|---|------|---------|---------|---------|
|
|
|
|
|
|
| 1 | 分诊交互 | 仅前端组件 | 未接入后端 | 前瞻设计 |
|
|
|
|
|
|
| 2 | 置信门控 | 后端配置 + 前端组件 | 生产在线 | 回溯文档 |
|
|
|
|
|
|
| 3 | 内联审批卡片 | 后端 + 前端 | 生产在线 | 回溯文档 |
|
|
|
|
|
|
| 4 | 拓扑预览 | 仅原型 SVG | 未实现后端子图查询 API 对接 | 前瞻设计 |
|
|
|
|
|
|
| 5 | 重复检测 | 后端 + 前端 | 生产在线 | 回溯文档 |
|
|
|
|
|
|
| 6 | 代答排除 | 仅前端组件方法 | 未实现 | 前瞻设计 |
|
|
|
|
|
|
| 7 | 知识迭代管理 | 47KB 服务 + 21KB API | 生产在线 | 回溯文档 |
|
|
|
|
|
|
| 8 | 图谱可视化 | Neo4j + ECharts | Neo4j 运行中 | 回溯文档 |
|
|
|
|
|
|
| 9 | 合并去重 | 后端 + 前端 | 生产在线 | 回溯文档 |
|
|
|
|
|
|
| 10 | 会话关闭→建议→审核→写图 | 全链路 | 生产在线 | 回溯文档 |
|
|
|
|
|
|
|
|
|
|
|
|
### 1.4 术语表
|
|
|
|
|
|
|
|
|
|
|
|
| 术语 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| KnowledgeSuggestion | 知识建议,AI 分析生成的待审核知识条目 |
|
|
|
|
|
|
| Issue | 知识图谱中的问题节点(Neo4j :Issue 标签) |
|
|
|
|
|
|
| Action | 知识图谱中的动作/解决方案节点(Neo4j :Action 标签) |
|
|
|
|
|
|
| confidence | AI 生成置信度(0.0-1.0),门控阈值 0.7 |
|
|
|
|
|
|
| audience | 受众类型:employee_quick_reply(员工快捷回复)/ engineer_workguide(工程师作业指导) |
|
|
|
|
|
|
| 五态流转 | pending → queued → approved → applied → graph_synced |
|
|
|
|
|
|
| 通道 A | 会话/标注/AI不确定 → 自动生成知识建议 |
|
|
|
|
|
|
| 通道 B | 训练师手动录入知识建议 |
|
|
|
|
|
|
| 通道 C | RAGFlow 文档 ETL → 知识建议(预留,未实现) |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 系统架构总览
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 架构总览图
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
graph TB
|
|
|
|
|
|
subgraph "H5 员工端"
|
|
|
|
|
|
H5_Triage[分诊卡片 TriageCard]
|
|
|
|
|
|
H5_ConfGate[置信门控 ConfidenceGateBanner]
|
|
|
|
|
|
H5_Chat[AI 对话]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "Agent 坐席端"
|
|
|
|
|
|
AG_Approval[内联审批卡片 ApprovalInlineCard]
|
|
|
|
|
|
AG_Queue[独立审批队列 ApprovalQueue]
|
|
|
|
|
|
AG_Chat[坐席会话]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "Admin 管理后台"
|
|
|
|
|
|
ADM_Knowledge[知识迭代管理 KnowledgeIteration]
|
|
|
|
|
|
ADM_Graph[图谱可视化 ECharts]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "Backend FastAPI"
|
|
|
|
|
|
API_Conv[会话 API conversations.py]
|
|
|
|
|
|
API_KI[知识迭代 API knowledge_iteration.py]
|
|
|
|
|
|
API_Queue[审批队列 API approval_queue.py]
|
|
|
|
|
|
Svc_KI[知识迭代服务 KnowledgeIterationService]
|
|
|
|
|
|
Svc_Wingman[Wingman AI 服务]
|
|
|
|
|
|
Neo4j_Client[Neo4j 客户端]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "数据存储"
|
|
|
|
|
|
PG[(PostgreSQL)]
|
|
|
|
|
|
Redis[(Redis)]
|
|
|
|
|
|
Neo4j[(Neo4j 图数据库)]
|
|
|
|
|
|
Dify[Dify AI 平台]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
%% H5 交互
|
|
|
|
|
|
H5_Chat -->|AI回复| H5_ConfGate
|
|
|
|
|
|
H5_Triage -->|分步选择| H5_Chat
|
|
|
|
|
|
H5_ConfGate -->|confidence<0.7| API_Conv
|
|
|
|
|
|
|
|
|
|
|
|
%% 会话关闭触发
|
|
|
|
|
|
AG_Chat -->|结单| API_Conv
|
|
|
|
|
|
API_Conv -->|异步触发| Svc_KI
|
|
|
|
|
|
Svc_KI -->|调用AI| Svc_Wingman
|
|
|
|
|
|
Svc_Wingman --> Dify
|
|
|
|
|
|
Svc_KI -->|写入建议| PG
|
|
|
|
|
|
|
|
|
|
|
|
%% 审批流程
|
|
|
|
|
|
AG_Approval -->|采纳/驳回/改写| API_KI
|
|
|
|
|
|
AG_Queue -->|队列审批| API_Queue
|
|
|
|
|
|
ADM_Knowledge -->|管理审核| API_KI
|
|
|
|
|
|
|
|
|
|
|
|
%% 知识落库 + 写图
|
|
|
|
|
|
API_KI --> Svc_KI
|
|
|
|
|
|
Svc_KI -->|创建KB条目| PG
|
|
|
|
|
|
Svc_KI -->|写图| Neo4j_Client
|
|
|
|
|
|
Neo4j_Client --> Neo4j
|
|
|
|
|
|
|
|
|
|
|
|
%% 图谱可视化
|
|
|
|
|
|
ADM_Graph -->|查询图数据| API_KI
|
|
|
|
|
|
API_KI --> Neo4j_Client
|
|
|
|
|
|
|
|
|
|
|
|
%% 重复检测
|
|
|
|
|
|
ADM_Knowledge -->|检查重复| API_KI
|
|
|
|
|
|
API_KI --> Svc_KI
|
|
|
|
|
|
Svc_KI -->|查SQL| PG
|
|
|
|
|
|
Svc_KI -->|查图| Neo4j_Client
|
|
|
|
|
|
|
|
|
|
|
|
style H5_Triage fill:#fff3e0,stroke:#ff9800
|
|
|
|
|
|
style H5_ConfGate fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style AG_Approval fill:#e3f2fd,stroke:#2196f3
|
|
|
|
|
|
style Neo4j fill:#e8eaf6,stroke:#3f51b5
|
|
|
|
|
|
style Dify fill:#fce4ec,stroke:#e91e63
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 技术栈分布
|
|
|
|
|
|
|
|
|
|
|
|
| 层级 | 技术选型 | 说明 |
|
|
|
|
|
|
|------|---------|------|
|
|
|
|
|
|
| 后端框架 | FastAPI + SQLAlchemy 2.0 (async) | 异步 ORM,AsyncSession |
|
|
|
|
|
|
| 关系数据库 | PostgreSQL | knowledge_suggestions、knowledge_base 表 |
|
|
|
|
|
|
| 图数据库 | Neo4j 6.2.0 (AsyncDriver) | Issue/Action 节点 + 关系边 |
|
|
|
|
|
|
| 缓存 | Redis | 会话状态、恢复点 |
|
|
|
|
|
|
| AI 平台 | Dify (Wingman Agent) | 知识建议生成、意图识别 |
|
|
|
|
|
|
| 管理后台 | Vue3 + Element Plus + ECharts | 列表管理 + 力导向图 |
|
|
|
|
|
|
| 坐席端 | Vue3 + Element Plus | 内联审批卡片 + 队列 |
|
|
|
|
|
|
| H5 员工端 | Vue3 + Vant4 | 分诊卡片 + 置信门控横幅 |
|
|
|
|
|
|
| 风格 | 企微浅色扁平 | accent=#07C160 |
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 API 路由前缀
|
|
|
|
|
|
|
|
|
|
|
|
| 模块 | 前缀 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| 知识迭代管理 | `/api/admin/knowledge-iteration/*` | 12 条路由 |
|
|
|
|
|
|
| 独立审批队列 | `/api/admin/approval-queue/*` | 3 条路由 |
|
|
|
|
|
|
| 会话管理 | `/api/conversations/*` | 含结单触发 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 各功能模块技术方案
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 分诊交互
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
AI 分诊式回复,将复杂 IT 问题拆分为分步选择题(是/否/含概率推荐),卡片置顶悬浮展示,支持专家模式切换。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:仅前端组件(`TriageCard.vue`),未接入后端 API。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class TriageStep {
|
|
|
|
|
|
+String question
|
|
|
|
|
|
+List~TriageOption~ options
|
|
|
|
|
|
+List~String~ collectedContext
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TriageOption {
|
|
|
|
|
|
+String label
|
|
|
|
|
|
+Boolean selected
|
|
|
|
|
|
+Number probability
|
|
|
|
|
|
+Boolean recommended
|
|
|
|
|
|
+Boolean excluded
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TriageCard {
|
|
|
|
|
|
+Boolean visible
|
|
|
|
|
|
+Number step
|
|
|
|
|
|
+Number total
|
|
|
|
|
|
+List~TriageStep~ steps
|
|
|
|
|
|
+Number confidence
|
|
|
|
|
|
+toggleCollapse()
|
|
|
|
|
|
+selectOption(idx)
|
|
|
|
|
|
+handleConfirm()
|
|
|
|
|
|
+handleSkip()
|
|
|
|
|
|
+setExcludedOptions(labels)
|
|
|
|
|
|
+setRecommendedOption(label)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TriageCard --> TriageStep : contains
|
|
|
|
|
|
TriageStep --> TriageOption : contains
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计(前瞻 — 未实现)
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|------|------|------|
|
|
|
|
|
|
| POST | `/api/h5/triage/start` | `{conversation_id, question}` | `{steps: TriageStep[], total: int}` | 发起分诊,AI 拆分复杂问题为分步选择题 |
|
|
|
|
|
|
| POST | `/api/h5/triage/step` | `{conversation_id, step_index, selected_label}` | `{next_step: TriageStep, collected_context: string[]}` | 提交当前步骤选择,获取下一步 |
|
|
|
|
|
|
| POST | `/api/h5/triage/skip` | `{conversation_id, step_index}` | `{next_step: TriageStep}` | 跳过当前步骤 |
|
|
|
|
|
|
| POST | `/api/h5/triage/transfer` | `{conversation_id, context: string[]}` | `{conversation_id, status: "waiting_agent"}` | 分诊上下文转人工 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心流程(前瞻设计)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant H5 as H5 员工端
|
|
|
|
|
|
participant API as FastAPI 后端
|
|
|
|
|
|
participant Dify as Dify AI
|
|
|
|
|
|
participant DB as PostgreSQL
|
|
|
|
|
|
|
|
|
|
|
|
H5->>API: POST /api/h5/triage/start {conversation_id, question}
|
|
|
|
|
|
API->>Dify: 调用 Dify 分诊 prompt(拆分复杂问题为分步)
|
|
|
|
|
|
Dify-->>API: 返回 steps[] (question + options + probability)
|
|
|
|
|
|
API-->>H5: {steps, total}
|
|
|
|
|
|
|
|
|
|
|
|
loop 每一步
|
|
|
|
|
|
H5->>H5: 展示 TriageCard,员工选择选项
|
|
|
|
|
|
H5->>API: POST /api/h5/triage/step {step_index, selected_label}
|
|
|
|
|
|
API->>DB: 记录已收集上下文
|
|
|
|
|
|
API->>Dify: 根据选择动态调整后续步骤
|
|
|
|
|
|
Dify-->>API: 返回 next_step
|
|
|
|
|
|
API-->>H5: {next_step, collected_context}
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
alt 所有步骤完成
|
|
|
|
|
|
H5->>API: POST /api/h5/triage/complete
|
|
|
|
|
|
API->>Dify: 根据收集的上下文生成最终答案
|
|
|
|
|
|
Dify-->>API: 返回最终回复
|
|
|
|
|
|
API-->>H5: 返回 AI 回复
|
|
|
|
|
|
else 转人工
|
|
|
|
|
|
H5->>API: POST /api/h5/triage/transfer {context}
|
|
|
|
|
|
API->>DB: 会话状态 → waiting_agent
|
|
|
|
|
|
API-->>H5: 转人工成功
|
|
|
|
|
|
end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
**组件文件**:`frontend-h5/src/components/TriageCard.vue`
|
|
|
|
|
|
|
|
|
|
|
|
| 交互元素 | 说明 |
|
|
|
|
|
|
|---------|------|
|
|
|
|
|
|
| 置顶悬浮 | `position: sticky; top: 0; z-index: 100` |
|
|
|
|
|
|
| 步骤进度 | "第 X/Y 步" 显示在标题栏 |
|
|
|
|
|
|
| 选项列表 | 单选模式,点击选中/取消 |
|
|
|
|
|
|
| 概率展示 | 百分比标签(≥70% 绿色高亮),不披露原始 confidence |
|
|
|
|
|
|
| 推荐标记 | ⭐推荐 标签(坐席侧设置) |
|
|
|
|
|
|
| 排除标记 | 已排除 标签 + 灰显 + 不可点击 |
|
|
|
|
|
|
| 专家模式 | van-switch 开关,开启后展示后续步骤预览 |
|
|
|
|
|
|
| 折叠/展开 | 点击标题栏切换 |
|
|
|
|
|
|
| 底部操作 | "跳过" + "下一步/完成" |
|
|
|
|
|
|
|
|
|
|
|
|
**关键设计约束(D4 硬约束)**:
|
|
|
|
|
|
- 一次给几步由 AI 判复杂度自适应
|
|
|
|
|
|
- 概率展示为百分比(不披露原始 confidence 给员工)
|
|
|
|
|
|
- 专家模式默认关(分步),老手可开一把梭
|
|
|
|
|
|
- 卡片置顶/悬浮
|
|
|
|
|
|
|
|
|
|
|
|
#### 技术选型与依赖
|
|
|
|
|
|
|
|
|
|
|
|
| 依赖 | 版本 | 用途 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| Vue3 | ^3.4 | 响应式框架 |
|
|
|
|
|
|
| Vant4 | ^4.8 | 移动端 UI(van-switch, van-button, van-tag) |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**未实现** — 前端组件已开发(530 行),但后端 API 未实现,Dify 分诊 prompt 未配置。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 置信门控
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
当 AI 回复的 confidence 低于全局阈值 0.7 时,在 H5 前端渲染"转人工"入口并附已收集的上下文快照。门控阈值可通过 `settings.confidence_gate_threshold` 配置。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:生产在线。后端配置项 + 前端组件 + composable 逻辑封装。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class ConfidenceGateConfig {
|
|
|
|
|
|
+Float confidence_gate_threshold = 0.7
|
|
|
|
|
|
+String source = "settings.confidence_gate_threshold"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ConfidenceGateResult {
|
|
|
|
|
|
+Boolean triggered
|
|
|
|
|
|
+Number displayProbability
|
|
|
|
|
|
+String severity
|
|
|
|
|
|
+Boolean shouldShowTransfer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class useConfidenceGate {
|
|
|
|
|
|
+Ref~Float~ gateThreshold
|
|
|
|
|
|
+Ref~Number~ lastConfidence
|
|
|
|
|
|
+Ref~String[]~ contextSnapshot
|
|
|
|
|
|
+Computed~ConfidenceGateResult~ gateResult
|
|
|
|
|
|
+Computed~Boolean~ showGateBanner
|
|
|
|
|
|
+evaluateConfidence(confidence, context)
|
|
|
|
|
|
+addContext(items)
|
|
|
|
|
|
+prepareTransferToHuman() String[]
|
|
|
|
|
|
+reset()
|
|
|
|
|
|
+updateThreshold(newThreshold)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ConfidenceGateBanner {
|
|
|
|
|
|
+Boolean visible
|
|
|
|
|
|
+Number confidence
|
|
|
|
|
|
+String[] contextSnapshot
|
|
|
|
|
|
+String reason
|
|
|
|
|
|
+displayProbability
|
|
|
|
|
|
+severityClass
|
|
|
|
|
|
+handleTransferToHuman()
|
|
|
|
|
|
+handleContinueAI()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
useConfidenceGate --> ConfidenceGateResult : produces
|
|
|
|
|
|
ConfidenceGateBanner --> useConfidenceGate : consumes
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 配置项
|
|
|
|
|
|
|
|
|
|
|
|
| 配置项 | 默认值 | 来源 | 说明 |
|
|
|
|
|
|
|--------|--------|------|------|
|
|
|
|
|
|
| `confidence_gate_threshold` | 0.7 | `config.py` → `CONFIDENCE_GATE_THRESHOLD` 环境变量 | 全局置信门控阈值 |
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# backend/app/config.py
|
|
|
|
|
|
confidence_gate_threshold: float = 0.7
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant H5 as H5 员工端
|
|
|
|
|
|
participant Gate as useConfidenceGate
|
|
|
|
|
|
participant Banner as ConfidenceGateBanner
|
|
|
|
|
|
participant API as FastAPI 后端
|
|
|
|
|
|
|
|
|
|
|
|
H5->>API: 发送问题
|
|
|
|
|
|
API->>API: AI 回复 + confidence 值
|
|
|
|
|
|
API-->>H5: {reply, confidence: 0.45}
|
|
|
|
|
|
|
|
|
|
|
|
H5->>Gate: evaluateConfidence(0.45, context)
|
|
|
|
|
|
Gate->>Gate: triggered = 0.45 < 0.7 = true
|
|
|
|
|
|
Gate->>Gate: severity = "warning" (0.3 ≤ 0.45 < 0.5)
|
|
|
|
|
|
Gate-->>H5: gateResult = {triggered: true, shouldShowTransfer: true}
|
|
|
|
|
|
|
|
|
|
|
|
H5->>Banner: visible=true, confidence=0.45
|
|
|
|
|
|
Banner->>Banner: displayProbability = 45%
|
|
|
|
|
|
Banner->>Banner: severityClass = "warning"
|
|
|
|
|
|
Banner-->>H5: 展示横幅 + "转人工" + "继续询问 AI"
|
|
|
|
|
|
|
|
|
|
|
|
alt 员工点击转人工
|
|
|
|
|
|
Banner->>Gate: prepareTransferToHuman()
|
|
|
|
|
|
Gate-->>Banner: contextSnapshot[]
|
|
|
|
|
|
Banner->>API: POST /api/conversations/transfer {context}
|
|
|
|
|
|
API-->>Banner: 转人工成功
|
|
|
|
|
|
else 员工点击继续询问 AI
|
|
|
|
|
|
Banner->>Gate: dismissGate()
|
|
|
|
|
|
Gate-->>H5: dismissed = true
|
|
|
|
|
|
end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
**组件文件**:`frontend-h5/src/components/ConfidenceGateBanner.vue`
|
|
|
|
|
|
**逻辑封装**:`frontend-h5/src/composables/useConfidenceGate.ts`
|
|
|
|
|
|
|
|
|
|
|
|
| 严重程度 | 条件 | 配色 | 图标 | 文案 |
|
|
|
|
|
|
|---------|------|------|------|------|
|
|
|
|
|
|
| critical | confidence < 0.3 | 红色背景 `#fff0f0` + 红色左边框 `#ee0a24` | 🚨 | AI 非常不确定此回复,建议转人工处理 |
|
|
|
|
|
|
| warning | 0.3 ≤ confidence < 0.5 | 橙色背景 `#fff7f0` + 橙色左边框 `#ff976a` | ⚠️ | AI 对此回复把握较低,可能需要人工协助 |
|
|
|
|
|
|
| caution | 0.5 ≤ confidence < 0.7 | 蓝色背景 `#f0f7ff` + 蓝色左边框 `#1989fa` | 💡 | AI 对此回复不太确定,你可选择转人工确认 |
|
|
|
|
|
|
|
|
|
|
|
|
**展示元素**:
|
|
|
|
|
|
- AI 把握度:百分比整数(如 "45%"),不显示原始 0.45
|
|
|
|
|
|
- 已收集上下文快照:标签列表
|
|
|
|
|
|
- 操作按钮:"转人工处理"(danger)+ "继续询问 AI"(default)
|
|
|
|
|
|
- 反馈理由选项:答非所问/信息不完整/回答不准确/过于笼统/其他
|
|
|
|
|
|
|
|
|
|
|
|
#### 技术选型与依赖
|
|
|
|
|
|
|
|
|
|
|
|
| 依赖 | 版本 | 用途 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| Vue3 | ^3.4 | Composition API |
|
|
|
|
|
|
| Vant4 | ^4.8 | van-button, van-tag |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — 后端配置项 `confidence_gate_threshold=0.7` 已在 config.py 中定义,前端 `ConfidenceGateBanner.vue` + `useConfidenceGate.ts` 已部署。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 内联审批卡片
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
坐席在会话中直接审批知识建议的内联卡片,支持采纳/驳回/改写操作,展示拓扑预览、confidence、audience 下拉编辑。未处理的提案在会话关闭后进入独立审批队列。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:生产在线。后端 API + 前端组件完整实现。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class KnowledgeSuggestion {
|
|
|
|
|
|
+String id
|
|
|
|
|
|
+String suggestion_type
|
|
|
|
|
|
+String status
|
|
|
|
|
|
+String title
|
|
|
|
|
|
+String content
|
|
|
|
|
|
+String category
|
|
|
|
|
|
+List~String~ tags
|
|
|
|
|
|
+String source_type
|
|
|
|
|
|
+List~String~ source_data
|
|
|
|
|
|
+Float confidence
|
|
|
|
|
|
+String audience
|
|
|
|
|
|
+String issue
|
|
|
|
|
|
+String action
|
|
|
|
|
|
+String relation_type
|
|
|
|
|
|
+String parent_issue
|
|
|
|
|
|
+Dict graph_meta
|
|
|
|
|
|
+String graph_sync_status
|
|
|
|
|
|
+Boolean source_failed
|
|
|
|
|
|
+DateTime queued_at
|
|
|
|
|
|
+DateTime applied_at
|
|
|
|
|
|
+String reviewer_id
|
|
|
|
|
|
+DateTime reviewed_at
|
|
|
|
|
|
+String reject_reason
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class SuggestionStatusEnum {
|
|
|
|
|
|
<<enumeration>>
|
|
|
|
|
|
pending
|
|
|
|
|
|
queued
|
|
|
|
|
|
approved
|
|
|
|
|
|
rejected
|
|
|
|
|
|
applied
|
|
|
|
|
|
graph_synced
|
|
|
|
|
|
expired
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ApprovalInlineCard {
|
|
|
|
|
|
+SuggestionData suggestion
|
|
|
|
|
|
+Boolean readonly
|
|
|
|
|
|
+DuplicateItem[] duplicates
|
|
|
|
|
|
+handleApprove()
|
|
|
|
|
|
+handleReject()
|
|
|
|
|
|
+toggleRewrite()
|
|
|
|
|
|
+submitRewrite()
|
|
|
|
|
|
+onAudienceChange()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApprovalInlineCard --> KnowledgeSuggestion : displays
|
|
|
|
|
|
KnowledgeSuggestion --> SuggestionStatusEnum : status
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 状态机
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
stateDiagram-v2
|
|
|
|
|
|
[*] --> pending : AI生成/手动录入
|
|
|
|
|
|
|
|
|
|
|
|
pending --> queued : 会话关闭未处理
|
|
|
|
|
|
pending --> approved : 内联审批通过
|
|
|
|
|
|
pending --> rejected : 驳回
|
|
|
|
|
|
pending --> expired : 超时
|
|
|
|
|
|
|
|
|
|
|
|
queued --> approved : 队列审批通过
|
|
|
|
|
|
queued --> rejected : 队列驳回
|
|
|
|
|
|
queued --> expired : 超时
|
|
|
|
|
|
|
|
|
|
|
|
approved --> applied : KB条目落库
|
|
|
|
|
|
approved --> rejected : 撤销
|
|
|
|
|
|
|
|
|
|
|
|
applied --> graph_synced : Neo4j写图成功
|
|
|
|
|
|
|
|
|
|
|
|
rejected --> [*] : 终态
|
|
|
|
|
|
graph_synced --> [*] : 终态
|
|
|
|
|
|
expired --> [*] : 终态
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**合法状态转换表**(`schemas/enums.py`):
|
|
|
|
|
|
|
|
|
|
|
|
| 当前状态 | 允许转换到 |
|
|
|
|
|
|
|---------|-----------|
|
|
|
|
|
|
| pending | queued, approved, rejected, expired |
|
|
|
|
|
|
| queued | approved, rejected, expired |
|
|
|
|
|
|
| approved | applied, rejected |
|
|
|
|
|
|
| applied | graph_synced |
|
|
|
|
|
|
| graph_synced | (终态) |
|
|
|
|
|
|
| rejected | (终态) |
|
|
|
|
|
|
| expired | (终态) |
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求体 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|--------|------|------|
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/approve` | `{}` | `{code:0, data: KnowledgeSuggestionResponse}` | 审核通过(触发 KB 落库 + Neo4j 写图) |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/reject` | `{reject_reason: string}` | `{code:0, data: KnowledgeSuggestionResponse}` | 审核拒绝 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/rewrite` | `{title?, content?, category?, ...}` | `{code:0, data: KnowledgeSuggestionResponse}` | 改写提案(重置为 pending) |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/queue` | — | `{code:0, data: KnowledgeSuggestionResponse}` | 放入独立队列 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/dequeue-approve` | — | `{code:0, data: KnowledgeSuggestionResponse}` | 队列中审批通过 |
|
|
|
|
|
|
| GET | `/api/admin/approval-queue/queued` | `?status=&audience=&page=&page_size=` | `{code:0, data:{total, items[]}}` | 获取队列列表 |
|
|
|
|
|
|
| GET | `/api/admin/approval-queue/queued/stats` | — | `{code:0, data:{queued_total, pending_total, by_audience, by_source_type}}` | 队列统计 |
|
|
|
|
|
|
| POST | `/api/admin/approval-queue/queued/{id}/dequeue-approve` | — | `{code:0, data: KnowledgeSuggestionResponse}` | 队列审批通过 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant AG as 坐席端 ApprovalInlineCard
|
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
|
participant Svc as KnowledgeIterationService
|
|
|
|
|
|
participant DB as PostgreSQL
|
|
|
|
|
|
participant Neo4j as Neo4j
|
|
|
|
|
|
|
|
|
|
|
|
Note over AG: 提案 status=pending/queued
|
|
|
|
|
|
|
|
|
|
|
|
alt 采纳
|
|
|
|
|
|
AG->>API: POST /suggestions/{id}/approve
|
|
|
|
|
|
API->>Svc: approve_suggestion(db, id, reviewer_id, neo4j_client)
|
|
|
|
|
|
Svc->>Svc: 校验状态转换 pending/queued → approved
|
|
|
|
|
|
Svc->>DB: 更新 status=approved, reviewer_id, reviewed_at
|
|
|
|
|
|
Svc->>DB: 创建 KnowledgeBase 条目 → status=applied
|
|
|
|
|
|
Svc->>Neo4j: sync_to_neo4j (merge_issue + merge_action + create_relation)
|
|
|
|
|
|
alt 写图成功
|
|
|
|
|
|
Svc->>DB: status=graph_synced, graph_sync_status=synced
|
|
|
|
|
|
Svc->>DB: 回填 kb.graph_node_uuid
|
|
|
|
|
|
else 写图失败
|
|
|
|
|
|
Svc->>DB: graph_sync_status=failed
|
|
|
|
|
|
end
|
|
|
|
|
|
Svc-->>API: suggestion (graph_synced)
|
|
|
|
|
|
API-->>AG: {code:0, data: suggestion}
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
alt 驳回
|
|
|
|
|
|
AG->>API: POST /suggestions/{id}/reject {reject_reason}
|
|
|
|
|
|
API->>Svc: reject_suggestion(db, id, reviewer_id, reason)
|
|
|
|
|
|
Svc->>DB: status=rejected, reject_reason
|
|
|
|
|
|
Svc-->>API: suggestion (rejected)
|
|
|
|
|
|
API-->>AG: {code:0, data: suggestion}
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
alt 改写
|
|
|
|
|
|
AG->>API: POST /suggestions/{id}/rewrite {title, content, ...}
|
|
|
|
|
|
API->>Svc: rewrite_suggestion(db, id, reviewer_id, data)
|
|
|
|
|
|
Svc->>DB: 更新字段 + status=pending (重置)
|
|
|
|
|
|
Svc-->>API: suggestion (pending)
|
|
|
|
|
|
API-->>AG: {code:0, data: suggestion}
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
alt 入队
|
|
|
|
|
|
AG->>API: POST /suggestions/{id}/queue
|
|
|
|
|
|
API->>Svc: queue_suggestion(db, id)
|
|
|
|
|
|
Svc->>Svc: 校验 pending → queued
|
|
|
|
|
|
Svc->>DB: status=queued, queued_at
|
|
|
|
|
|
Svc-->>API: suggestion (queued)
|
|
|
|
|
|
API-->>AG: {code:0, data: suggestion}
|
|
|
|
|
|
end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
**组件文件**:`frontend-agent/src/components/chat/ApprovalInlineCard.vue`
|
|
|
|
|
|
|
|
|
|
|
|
| 卡片区域 | 元素 | 说明 |
|
|
|
|
|
|
|---------|------|------|
|
|
|
|
|
|
| 头部 | 类型图标 + 类型文本 | 💡新FAQ / 🔄内容更新 / 🔀合并去重 |
|
|
|
|
|
|
| 头部 | 置信度标签 | ≥70% success / ≥50% warning / <50% danger |
|
|
|
|
|
|
| 头部 | 状态标签 | pending/queued/approved/rejected/applied/graph_synced |
|
|
|
|
|
|
| 头部 | 重复标记 | ⚠可能重复(danger, effect=dark) |
|
|
|
|
|
|
| 重复警告 | 重复项列表 | 名称 + 类型标签 + 相似度百分比 |
|
|
|
|
|
|
| 核心信息 | 标题 + 内容 | 内容截断 150 字符 |
|
|
|
|
|
|
| 拓扑预览 | SVG 缩略图 | parent_issue → issue → action 节点链 |
|
|
|
|
|
|
| 拓扑预览 | 文本流 | 蓝色 parent → 绿色 issue → 橙色 action |
|
|
|
|
|
|
| audience | 下拉选择 | employee_quick_reply / engineer_workguide |
|
|
|
|
|
|
| 改写表单 | 标题/内容/分类输入框 | 展开时显示,提交后重置 pending |
|
|
|
|
|
|
| 操作按钮 | 采纳(success) / 改写(warning) / 驳回(danger) | readonly 时显示已处理状态 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 技术选型与依赖
|
|
|
|
|
|
|
|
|
|
|
|
| 依赖 | 版本 | 用途 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| Vue3 | ^3.4 | Composition API |
|
|
|
|
|
|
| Element Plus | ^2.6 | el-tag, el-select, el-input, el-button |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — 后端 `knowledge_iteration.py` + `approval_queue.py` + 前端 `ApprovalInlineCard.vue` + `ApprovalQueue.vue` 均已部署。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.4 拓扑预览
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
在审批卡片中展示知识建议对应的图谱拓扑结构(Issue → Action 小缩略图),帮助训练师直观理解建议的图谱关系。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:仅前端 SVG 原型缩略图。后端 `query_issue_subgraph` 方法已实现但未通过 API 暴露给前端调用。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
拓扑预览数据来源于 `KnowledgeSuggestion` 的图字段:
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class TopologyPreview {
|
|
|
|
|
|
+String parent_issue
|
|
|
|
|
|
+String issue
|
|
|
|
|
|
+String action
|
|
|
|
|
|
+String relation_type
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class MiniGraphNode {
|
|
|
|
|
|
+Number x
|
|
|
|
|
|
+Number y
|
|
|
|
|
|
+String label
|
|
|
|
|
|
+String type
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class MiniGraphEdge {
|
|
|
|
|
|
+Number x1
|
|
|
|
|
|
+Number y1
|
|
|
|
|
|
+Number x2
|
|
|
|
|
|
+Number y2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TopologyPreview --> MiniGraphNode : generates
|
|
|
|
|
|
TopologyPreview --> MiniGraphEdge : generates
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 已实现部分
|
|
|
|
|
|
|
|
|
|
|
|
**前端 SVG 缩略图**(`ApprovalInlineCard.vue`):
|
|
|
|
|
|
- 根据 `suggestion.parent_issue`、`suggestion.issue`、`suggestion.action` 三个字段生成节点
|
|
|
|
|
|
- 节点颜色:parent=蓝色 `#409eff`、issue=绿色 `#67c23a`、action=橙色 `#e6a23c`
|
|
|
|
|
|
- 节点间距 90px,半径 issue=12px / action=9px
|
|
|
|
|
|
- 虚线连线 `stroke-dasharray="4,2"`
|
|
|
|
|
|
- 标签超过 6 字符截断为 "前6字…"
|
|
|
|
|
|
|
|
|
|
|
|
**后端子图查询**(`neo4j_client.py`):
|
|
|
|
|
|
- `query_issue_subgraph(issue_name, depth=1)` 方法已实现
|
|
|
|
|
|
- 以指定 Issue 为中心,向外扩展 depth 层关系
|
|
|
|
|
|
- 返回 ECharts 格式的 `{nodes, links}`
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计(前瞻 — 需新增)
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|------|------|------|
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/suggestions/{id}/topology` | — | `{code:0, data:{nodes:[], links:[]}}` | 获取建议对应的图谱子图拓扑 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 前瞻设计方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **新增 API 端点**:在 `knowledge_iteration.py` 中添加 `/suggestions/{id}/topology` 路由
|
|
|
|
|
|
2. **调用链**:API → `neo4j_client.query_issue_subgraph(issue_name, depth=1)` → 返回子图 JSON
|
|
|
|
|
|
3. **前端增强**:`ApprovalInlineCard.vue` 中将 SVG 缩略图替换为 ECharts mini graph(或保留 SVG + 可点击展开)
|
|
|
|
|
|
4. **交互**:点击缩略图弹出全屏子图预览 modal
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**部分实现** — 前端 SVG 缩略图已实现(基于 suggestion 字段静态渲染),后端子图查询方法已实现但未通过 API 暴露。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.5 重复检测
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
在采纳知识建议前检测是否存在重复,利用 Neo4j 图结构(同名 Issue)+ SQL 文本相似(标题模糊匹配)双重检测,返回重复项列表供训练师参考。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:生产在线。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class DuplicateResult {
|
|
|
|
|
|
+String type
|
|
|
|
|
|
+String name
|
|
|
|
|
|
+String suggestion_id
|
|
|
|
|
|
+String suggestion_type
|
|
|
|
|
|
+String issue
|
|
|
|
|
|
+String action
|
|
|
|
|
|
+String status
|
|
|
|
|
|
+Float similarity
|
|
|
|
|
|
+String source
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class FindDuplicatesParams {
|
|
|
|
|
|
+String issue_name
|
|
|
|
|
|
+String title
|
|
|
|
|
|
+String suggestion_id
|
|
|
|
|
|
+Neo4jClient neo4j_client
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class KnowledgeIterationService {
|
|
|
|
|
|
+find_duplicates(db, issue_name, title, suggestion_id, neo4j_client) List~DuplicateResult~
|
|
|
|
|
|
+_calc_similarity(a, b) Float
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KnowledgeIterationService --> DuplicateResult : produces
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 重复检测类型
|
|
|
|
|
|
|
|
|
|
|
|
| 类型 | 来源 | 检测方式 | 相似度计算 |
|
|
|
|
|
|
|------|------|---------|-----------|
|
|
|
|
|
|
| `same_issue` | Neo4j | 同名 Issue 节点精确匹配 | 1.0 |
|
|
|
|
|
|
| `similar_issue` | Neo4j | Issue 名称前缀匹配(前 10 字符) | 公共前缀 / 最大长度 |
|
|
|
|
|
|
| `title_similar` | SQL | 标题 ILIKE 模糊匹配(前 20 字符) | 前缀匹配 + 长度比 |
|
|
|
|
|
|
|
|
|
|
|
|
**相似度计算算法**(`_calc_similarity`):
|
|
|
|
|
|
1. 完全匹配 → 1.0
|
|
|
|
|
|
2. 包含匹配 → 0.5 + 0.5 × (shorter / longer)
|
|
|
|
|
|
3. 公共前缀匹配 → common_prefix_len / max_len
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|------|------|------|
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/suggestions/{id}/duplicates` | — | `{code:0, data:{suggestion_id, has_duplicates: bool, duplicates: DuplicateResult[]}}` | 检查指定建议是否存在重复 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant ADM as 管理后台
|
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
|
participant Svc as KnowledgeIterationService
|
|
|
|
|
|
participant DB as PostgreSQL
|
|
|
|
|
|
participant Neo4j as Neo4j
|
|
|
|
|
|
|
|
|
|
|
|
ADM->>API: GET /suggestions/{id}/duplicates
|
|
|
|
|
|
API->>DB: 查询 suggestion (获取 issue, title)
|
|
|
|
|
|
DB-->>API: suggestion
|
|
|
|
|
|
|
|
|
|
|
|
API->>Svc: find_duplicates(db, issue, title, id, neo4j_client)
|
|
|
|
|
|
|
|
|
|
|
|
rect rgb(245, 247, 250)
|
|
|
|
|
|
Note over Svc,DB: 1. SQL 层面:标题模糊匹配
|
|
|
|
|
|
Svc->>DB: SELECT * FROM knowledge_suggestions WHERE status IN (approved, applied, graph_synced) AND title ILIKE '%keyword%' AND id != suggestion_id
|
|
|
|
|
|
DB-->>Svc: sql_duplicates[]
|
|
|
|
|
|
Svc->>Svc: 计算 title_similar 相似度
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
rect rgb(232, 234, 246)
|
|
|
|
|
|
Note over Svc,Neo4j: 2. Neo4j 层面:同名 Issue
|
|
|
|
|
|
Svc->>Neo4j: find_issue_by_name(issue_name)
|
|
|
|
|
|
Neo4j-->>Svc: existing_issue (含 source_suggestion_id)
|
|
|
|
|
|
Svc->>DB: 查关联 suggestion
|
|
|
|
|
|
Svc->>Svc: 记录 same_issue (similarity=1.0)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
rect rgb(232, 234, 246)
|
|
|
|
|
|
Note over Svc,Neo4j: 3. Neo4j 层面:相似 Issue(前缀匹配)
|
|
|
|
|
|
Svc->>Neo4j: MATCH (i:Issue) WHERE i.name STARTS WITH $prefix AND i.name <> $exact_name
|
|
|
|
|
|
Neo4j-->>Svc: similar_issues[]
|
|
|
|
|
|
Svc->>Svc: 计算 similar_issue 相似度
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Svc->>Svc: 按相似度降序排列
|
|
|
|
|
|
Svc-->>API: duplicates[]
|
|
|
|
|
|
API-->>ADM: {code:0, data:{has_duplicates, duplicates}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
| 交互 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| 触发 | 详情弹窗中点击"检查重复"按钮 |
|
|
|
|
|
|
| 结果展示 | 弹窗显示重复项表格 |
|
|
|
|
|
|
| 无重复 | 绿色文字 "✅ 未发现重复,可安全采纳" |
|
|
|
|
|
|
| 有重复 | 橙色 Alert 警告 + 重复项表格 |
|
|
|
|
|
|
| 表格列 | 名称 / 匹配类型(同名Issue/相似Issue/标题相似)/ 相似度百分比 / 操作(合并) |
|
|
|
|
|
|
| 合并操作 | 点击"合并"调用 merge API |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — 后端 `find_duplicates` 方法 + API 路由 + 前端重复检查弹窗均已部署。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.6 代答排除
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
坐席在分诊卡片中排除某些选项,被排除的选项灰显且不可点击,引导员工选择更合适的路径。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:仅前端组件方法(`setExcludedOptions`),未接入后端。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class TriageOption {
|
|
|
|
|
|
+String label
|
|
|
|
|
|
+Boolean selected
|
|
|
|
|
|
+Boolean excluded
|
|
|
|
|
|
+Boolean recommended
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ExclusionRequest {
|
|
|
|
|
|
+String conversation_id
|
|
|
|
|
|
+List~String~ excluded_labels
|
|
|
|
|
|
+String reason
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 已实现部分
|
|
|
|
|
|
|
|
|
|
|
|
**前端方法**(`TriageCard.vue`):
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 暴露方法供父组件调用
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
/** 设置坐席排除项 */
|
|
|
|
|
|
setExcludedOptions(labels: string[]) {
|
|
|
|
|
|
currentOptions.value.forEach(o => {
|
|
|
|
|
|
if (labels.includes(o.label)) {
|
|
|
|
|
|
o.excluded = true
|
|
|
|
|
|
o.selected = false
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
/** 设置坐席推荐项 */
|
|
|
|
|
|
setRecommendedOption(label: string) {
|
|
|
|
|
|
currentOptions.value.forEach(o => {
|
|
|
|
|
|
o.recommended = o.label === label
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**排除样式**:
|
|
|
|
|
|
- 边框:`#ebedf0`(灰)
|
|
|
|
|
|
- 背景:`#f5f5f5`(浅灰)
|
|
|
|
|
|
- 透明度:0.5
|
|
|
|
|
|
- 光标:`not-allowed`
|
|
|
|
|
|
- 文字:删除线
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计(前瞻 — 未实现)
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|------|------|------|
|
|
|
|
|
|
| POST | `/api/agent/triage/exclude` | `{conversation_id, excluded_labels: string[]}` | `{code:0, data:{excluded: true}}` | 坐席排除分诊选项 |
|
|
|
|
|
|
| POST | `/api/agent/triage/recommend` | `{conversation_id, recommended_label: string}` | `{code:0, data:{recommended: true}}` | 坐席推荐分诊选项 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 前瞻设计方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **后端新增**:在 conversations API 或新建 triage API 中添加排除/推荐端点
|
|
|
|
|
|
2. **WebSocket 推送**:坐席排除选项后,通过 WS 实时推送到 H5 员工端
|
|
|
|
|
|
3. **Dify Prompt 增强**:将排除的选项传入 Dify,影响后续步骤生成
|
|
|
|
|
|
4. **审计日志**:记录坐席排除/推荐操作
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**未实现** — 前端 `TriageCard.vue` 中 `setExcludedOptions` / `setRecommendedOption` 方法已定义,但无后端 API 对接,无 WS 推送机制。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.7 知识迭代管理
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
管理后台的知识迭代提案管理页面,支持提案列表(含筛选/分页)、审阅提案详情、图字段编辑(issue/action/relation/parent)、训练师手动录入入口(通道 B)、触发分析。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:生产在线。47KB 服务 + 21KB API + 完整前端页面。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class KnowledgeSuggestion {
|
|
|
|
|
|
+String id : UUID
|
|
|
|
|
|
+String suggestion_type : "new_faq"|"update"|"outdated"
|
|
|
|
|
|
+String status : "pending"|"queued"|"approved"|"rejected"|"applied"|"graph_synced"|"expired"
|
|
|
|
|
|
+String title
|
|
|
|
|
|
+String content
|
|
|
|
|
|
+String category : "硬件"|"软件"|"网络"|"安全"|"账号"|"其他"
|
|
|
|
|
|
+List~String~ tags : JSON
|
|
|
|
|
|
+String source_type : "annotation"|"conversation"|"ai_uncertain"|"manual"|"document_ragflow"|"merge"
|
|
|
|
|
|
+List~String~ source_data : JSON
|
|
|
|
|
|
+String reason
|
|
|
|
|
|
+Float confidence
|
|
|
|
|
|
+String audience : "employee_quick_reply"|"engineer_workguide"
|
|
|
|
|
|
+String issue
|
|
|
|
|
|
+String action
|
|
|
|
|
|
+String relation_type : "LEADS_TO"|"RELATES_TO"|"CAN_JUMP_TO"
|
|
|
|
|
|
+String parent_issue
|
|
|
|
|
|
+Dict graph_meta : JSON
|
|
|
|
|
|
+String graph_sync_status : "pending"|"synced"|"failed"
|
|
|
|
|
|
+Boolean source_failed
|
|
|
|
|
|
+DateTime queued_at
|
|
|
|
|
|
+DateTime applied_at
|
|
|
|
|
|
+String reviewer_id
|
|
|
|
|
|
+DateTime reviewed_at
|
|
|
|
|
|
+String reject_reason
|
|
|
|
|
|
+DateTime created_at
|
|
|
|
|
|
+DateTime updated_at
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class KnowledgeBase {
|
|
|
|
|
|
+String id : UUID
|
|
|
|
|
|
+String category
|
|
|
|
|
|
+String title
|
|
|
|
|
|
+String content
|
|
|
|
|
|
+List~String~ tags : JSON
|
|
|
|
|
|
+Integer view_count
|
|
|
|
|
|
+Integer use_count
|
|
|
|
|
|
+String graph_sync_status
|
|
|
|
|
|
+String graph_node_uuid
|
|
|
|
|
|
+DateTime created_at
|
|
|
|
|
|
+DateTime updated_at
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class KnowledgeIterationService {
|
|
|
|
|
|
+Float confidence_gate_threshold
|
|
|
|
|
|
+generate_knowledge_suggestion(db, source_type, source_data, reason) KnowledgeSuggestion
|
|
|
|
|
|
+analyze_and_generate_suggestions(db, days) Dict
|
|
|
|
|
|
+_analyze_annotation_data(db, days) Dict
|
|
|
|
|
|
+_analyze_conversation_data(db, days) Dict
|
|
|
|
|
|
+_generate_update_suggestion(db, source_type, source_data, reason) KnowledgeSuggestion
|
|
|
|
|
|
+_generate_new_faq_suggestion(db, source_type, source_data, reason) KnowledgeSuggestion
|
|
|
|
|
|
+_build_context_from_source(db, source_type, source_data) List
|
|
|
|
|
|
+_auto_tag_audience(db, source_type, source_data) AudienceEnum
|
|
|
|
|
|
+_apply_confidence_gate(confidence) Boolean
|
|
|
|
|
|
+_check_existing_suggestion(db, source_id) Boolean
|
|
|
|
|
|
+approve_suggestion(db, id, reviewer_id, neo4j_client) KnowledgeSuggestion
|
|
|
|
|
|
+reject_suggestion(db, id, reviewer_id, reason) KnowledgeSuggestion
|
|
|
|
|
|
+rewrite_suggestion(db, id, reviewer_id, data) KnowledgeSuggestion
|
|
|
|
|
|
+queue_suggestion(db, id) KnowledgeSuggestion
|
|
|
|
|
|
+dequeue_approve(db, id, reviewer_id, neo4j_client) KnowledgeSuggestion
|
|
|
|
|
|
+sync_to_neo4j(neo4j_client, suggestion) Boolean
|
|
|
|
|
|
+get_suggestion_stats(db) Dict
|
|
|
|
|
|
+get_queue_stats(db) Dict
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KnowledgeIterationService --> KnowledgeSuggestion : manages
|
|
|
|
|
|
KnowledgeIterationService --> KnowledgeBase : creates
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### ER 图
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
erDiagram
|
|
|
|
|
|
knowledge_suggestions ||--o| knowledge_base : "approved → creates KB"
|
|
|
|
|
|
knowledge_suggestions {
|
|
|
|
|
|
string id PK
|
|
|
|
|
|
string suggestion_type
|
|
|
|
|
|
string status
|
|
|
|
|
|
string title
|
|
|
|
|
|
text content
|
|
|
|
|
|
string category
|
|
|
|
|
|
json tags
|
|
|
|
|
|
string source_type
|
|
|
|
|
|
json source_data
|
|
|
|
|
|
float confidence
|
|
|
|
|
|
string audience
|
|
|
|
|
|
string issue
|
|
|
|
|
|
string action
|
|
|
|
|
|
string relation_type
|
|
|
|
|
|
string parent_issue
|
|
|
|
|
|
json graph_meta
|
|
|
|
|
|
string graph_sync_status
|
|
|
|
|
|
boolean source_failed
|
|
|
|
|
|
datetime queued_at
|
|
|
|
|
|
datetime applied_at
|
|
|
|
|
|
string reviewer_id
|
|
|
|
|
|
datetime reviewed_at
|
|
|
|
|
|
text reject_reason
|
|
|
|
|
|
text reason
|
|
|
|
|
|
datetime created_at
|
|
|
|
|
|
datetime updated_at
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
knowledge_base {
|
|
|
|
|
|
string id PK
|
|
|
|
|
|
string category
|
|
|
|
|
|
string title
|
|
|
|
|
|
text content
|
|
|
|
|
|
json tags
|
|
|
|
|
|
integer view_count
|
|
|
|
|
|
integer use_count
|
|
|
|
|
|
string graph_sync_status
|
|
|
|
|
|
string graph_node_uuid
|
|
|
|
|
|
datetime created_at
|
|
|
|
|
|
datetime updated_at
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据库索引
|
|
|
|
|
|
|
|
|
|
|
|
| 索引名 | 字段 | 用途 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| idx_suggestion_status | status | 按状态筛选 |
|
|
|
|
|
|
| idx_suggestion_type | suggestion_type | 按类型筛选 |
|
|
|
|
|
|
| idx_suggestion_created | created_at | 按时间排序 |
|
|
|
|
|
|
| idx_suggestion_audience | audience | 按受众筛选 |
|
|
|
|
|
|
| idx_suggestion_confidence | confidence | 按置信度范围筛选 |
|
|
|
|
|
|
| idx_suggestion_graph_sync | graph_sync_status | 按图同步状态筛选 |
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求参数 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|---------|------|------|
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/analyze` | `?days=7` | `{code:0, data:{annotations_analyzed, conversations_analyzed, suggestions_generated}}` | 触发分析并生成建议 |
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/suggestions` | `?status=&suggestion_type=&audience=&confidence_min=&confidence_max=&page=&page_size=` | `{code:0, data:{total, items[]}}` | 获取建议列表 |
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/suggestions/{id}` | — | `{code:0, data: KnowledgeSuggestionResponse}` | 获取建议详情 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/approve` | `{}` | `{code:0, data: KnowledgeSuggestionResponse}` | 审核通过 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/reject` | `{reject_reason}` | `{code:0, data: KnowledgeSuggestionResponse}` | 审核拒绝 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/rewrite` | `{title?, content?, ...}` | `{code:0, data: KnowledgeSuggestionResponse}` | 改写提案 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/queue` | — | `{code:0, data: KnowledgeSuggestionResponse}` | 放入独立队列 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/dequeue-approve` | — | `{code:0, data: KnowledgeSuggestionResponse}` | 队列中审批 |
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/stats` | — | `{code:0, data: KnowledgeSuggestionStatsResponse}` | 获取统计 |
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/graph` | `?limit=100&issue_name=` | `{code:0, data:{nodes:[], links:[]}}` | 获取知识图谱数据 |
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/suggestions/{id}/duplicates` | — | `{code:0, data:{suggestion_id, has_duplicates, duplicates[]}}` | 检查重复 |
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/merge` | `{duplicate_id}` | `{code:0, data: KnowledgeSuggestionResponse}` | 合并重复建议 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 分析与生成流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant ADM as 管理后台
|
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
|
participant Svc as KnowledgeIterationService
|
|
|
|
|
|
participant Wingman as WingmanService
|
|
|
|
|
|
participant Dify as Dify AI
|
|
|
|
|
|
participant DB as PostgreSQL
|
|
|
|
|
|
|
|
|
|
|
|
ADM->>API: POST /analyze?days=7
|
|
|
|
|
|
API->>Svc: analyze_and_generate_suggestions(db, days=7)
|
|
|
|
|
|
|
|
|
|
|
|
rect rgb(255, 245, 230)
|
|
|
|
|
|
Note over Svc,DB: 1. 分析标注数据(useless 标注 ≥3 次)
|
|
|
|
|
|
Svc->>DB: SELECT * FROM conversation_annotations WHERE feedback='useless' AND created_at >= since
|
|
|
|
|
|
DB-->>Svc: annotations[]
|
|
|
|
|
|
Svc->>Svc: 按 message_id 分组统计高频错误
|
|
|
|
|
|
loop 每个高频错误 (count ≥ 3)
|
|
|
|
|
|
Svc->>Svc: _generate_update_suggestion()
|
|
|
|
|
|
Svc->>Wingman: generate_knowledge_suggestion(context_messages)
|
|
|
|
|
|
Wingman->>Dify: 调用 Dify API
|
|
|
|
|
|
Dify-->>Wingman: {title, content, category, tags, confidence, issue, action, ...}
|
|
|
|
|
|
Wingman-->>Svc: ai_result
|
|
|
|
|
|
Svc->>Svc: 置信门控: confidence < 0.7 → source_failed=True
|
|
|
|
|
|
Svc->>Svc: audience 自动标注
|
|
|
|
|
|
Svc->>DB: INSERT knowledge_suggestion
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
rect rgb(230, 245, 255)
|
|
|
|
|
|
Note over Svc,DB: 2. 分析会话数据(waiting_agent/agentServing)
|
|
|
|
|
|
Svc->>DB: SELECT * FROM conversations WHERE status IN ('waiting_agent','agentServing') AND created_at >= since
|
|
|
|
|
|
DB-->>Svc: conversations[]
|
|
|
|
|
|
Svc->>Svc: 采样 min(20, len)
|
|
|
|
|
|
loop 每个采样会话
|
|
|
|
|
|
Svc->>Svc: 检查是否已有 pending 建议(避免重复)
|
|
|
|
|
|
Svc->>Svc: _generate_new_faq_suggestion()
|
|
|
|
|
|
Svc->>Wingman: generate_knowledge_suggestion(context_messages)
|
|
|
|
|
|
Wingman->>Dify: 调用 Dify API
|
|
|
|
|
|
Dify-->>Wingman: ai_result
|
|
|
|
|
|
Wingman-->>Svc: ai_result
|
|
|
|
|
|
Svc->>Svc: 置信门控 + audience 标注
|
|
|
|
|
|
Svc->>DB: INSERT knowledge_suggestion
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Svc-->>API: {annotations_analyzed, conversations_analyzed, suggestions_generated}
|
|
|
|
|
|
API-->>ADM: {code:0, data: result}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### audience 自动标注规则(D8)
|
|
|
|
|
|
|
|
|
|
|
|
| source_type | 判定逻辑 | audience |
|
|
|
|
|
|
|-------------|---------|----------|
|
|
|
|
|
|
| manual | 直接判定 | engineer_workguide |
|
|
|
|
|
|
| document_ragflow | 直接判定 | engineer_workguide |
|
|
|
|
|
|
| annotation | 查 Conversation → 默认 | employee_quick_reply |
|
|
|
|
|
|
| conversation | 查 Conversation → 默认 | employee_quick_reply |
|
|
|
|
|
|
| ai_uncertain | 查 Conversation → 默认 | employee_quick_reply |
|
|
|
|
|
|
| 其他/未知 | 保守默认 | employee_quick_reply |
|
|
|
|
|
|
|
|
|
|
|
|
#### 置信门控逻辑(D3)
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 置信门控:confidence < 0.7 → source_failed=True
|
|
|
|
|
|
if not source_failed and confidence < self.confidence_gate_threshold:
|
|
|
|
|
|
source_failed = True
|
|
|
|
|
|
logger.info(f"置信度 {confidence} 低于门控阈值 {self.confidence_gate_threshold},标记 source_failed")
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**门控效果**:
|
|
|
|
|
|
- `source_failed=True` 的建议标题为 `[生成失败] 新FAQ建议` 或 `[生成失败] 优化建议`
|
|
|
|
|
|
- 前端卡片样式变红(`approval-inline-card--failed`)
|
|
|
|
|
|
- 不影响审批流程,训练师仍可手动改写后采纳
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
**页面文件**:`frontend-admin/src/views/KnowledgeIteration.vue`
|
|
|
|
|
|
|
|
|
|
|
|
| 页面区域 | 功能 |
|
|
|
|
|
|
|---------|------|
|
|
|
|
|
|
| 页面标题 | "📚 知识迭代管理" |
|
|
|
|
|
|
| 视图切换 | 列表 / 图谱(el-button-group) |
|
|
|
|
|
|
| 操作按钮 | 手动录入(通道 B)/ 触发分析 |
|
|
|
|
|
|
| 统计概要 | 待审核 / 队列中 / 已通过 / 已应用 / 已同步 |
|
|
|
|
|
|
| 筛选栏 | 状态 / 受众 / 置信度下限 / 置信度上限 |
|
|
|
|
|
|
| 提案表格 | 标题 / 类型 / 状态 / 置信度 / 受众 / 来源 / 创建时间 / 操作 |
|
|
|
|
|
|
| 操作按钮 | 采纳 / 驳回 / 详情 |
|
|
|
|
|
|
| 分页 | el-pagination |
|
|
|
|
|
|
| 详情弹窗 | 标题/内容/分类/受众编辑 + 图字段编辑(Issue/Action/关系类型/父Issue) |
|
|
|
|
|
|
| 重复检查 | 检查重复按钮 → 重复结果弹窗 |
|
|
|
|
|
|
| 手动录入 | 标题/内容/分类/受众/图字段 → 提交(confidence=1.0, source_type=manual) |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — 后端 12 条 API 路由已注册,47KB 服务文件完整实现,前端页面 980 行 Vue3 组件已部署。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.8 图谱可视化
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
管理后台使用 ECharts 力导向图可视化 Neo4j 知识图谱,支持全图查询和按 Issue 名称的子图查询。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:Neo4j 运行中,ECharts 可视化已部署。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class IssueNode {
|
|
|
|
|
|
+String uuid
|
|
|
|
|
|
+String name
|
|
|
|
|
|
+String category
|
|
|
|
|
|
+DateTime created_at
|
|
|
|
|
|
+DateTime updated_at
|
|
|
|
|
|
+String source_suggestion_id
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ActionNode {
|
|
|
|
|
|
+String uuid
|
|
|
|
|
|
+String name
|
|
|
|
|
|
+String description
|
|
|
|
|
|
+DateTime created_at
|
|
|
|
|
|
+String source_suggestion_id
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class RelationEdge {
|
|
|
|
|
|
+String from_uuid
|
|
|
|
|
|
+String to_uuid
|
|
|
|
|
|
+String type : "LEADS_TO"|"RELATES_TO"|"CAN_JUMP_TO"
|
|
|
|
|
|
+Integer order
|
|
|
|
|
|
+Float weight
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Neo4jClient {
|
|
|
|
|
|
+String uri
|
|
|
|
|
|
+String user
|
|
|
|
|
|
+String password
|
|
|
|
|
|
+String database
|
|
|
|
|
|
+AsyncDriver _driver
|
|
|
|
|
|
+initialize()
|
|
|
|
|
|
+close()
|
|
|
|
|
|
+health_check() Boolean
|
|
|
|
|
|
+execute_write_query(cypher, params)
|
|
|
|
|
|
+execute_read_query(cypher, params)
|
|
|
|
|
|
+merge_issue(name, category, props) IssueNode
|
|
|
|
|
|
+merge_action(name, props) ActionNode
|
|
|
|
|
|
+find_issue_by_name(name) IssueNode
|
|
|
|
|
|
+create_relation(from_uuid, to_uuid, rel) Boolean
|
|
|
|
|
|
+query_full_graph(limit) Dict
|
|
|
|
|
|
+query_issue_subgraph(issue_name, depth) Dict
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Neo4jClient --> IssueNode : manages
|
|
|
|
|
|
Neo4jClient --> ActionNode : manages
|
|
|
|
|
|
Neo4jClient --> RelationEdge : manages
|
|
|
|
|
|
IssueNode --> RelationEdge : from
|
|
|
|
|
|
ActionNode --> RelationEdge : to
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Neo4j 图 Schema
|
|
|
|
|
|
|
|
|
|
|
|
**约束**:
|
|
|
|
|
|
```cypher
|
|
|
|
|
|
CREATE CONSTRAINT issue_uuid IF NOT EXISTS FOR (i:Issue) REQUIRE i.uuid IS UNIQUE
|
|
|
|
|
|
CREATE CONSTRAINT action_uuid IF NOT EXISTS FOR (a:Action) REQUIRE a.uuid IS UNIQUE
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**索引**:
|
|
|
|
|
|
```cypher
|
|
|
|
|
|
CREATE INDEX issue_category IF NOT EXISTS FOR (i:Issue) ON (i.category)
|
|
|
|
|
|
CREATE INDEX issue_name IF NOT EXISTS FOR (i:Issue) ON (i.name)
|
|
|
|
|
|
CREATE INDEX action_name IF NOT EXISTS FOR (a:Action) ON (a.name)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求参数 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|---------|------|------|
|
|
|
|
|
|
| GET | `/api/admin/knowledge-iteration/graph` | `?limit=100&issue_name=` | `{code:0, data:{nodes:[], links:[]}}` | 获取知识图谱数据 |
|
|
|
|
|
|
|
|
|
|
|
|
**响应数据格式**(ECharts 力导向图兼容):
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"code": 0,
|
|
|
|
|
|
"data": {
|
|
|
|
|
|
"nodes": [
|
|
|
|
|
|
{"id": "uuid", "name": "VPN问题", "category": "网络", "label": "VPN问题", "type": "issue"},
|
|
|
|
|
|
{"id": "uuid", "name": "个人VPN开通", "category": "", "label": "个人VPN开通", "type": "action"}
|
|
|
|
|
|
],
|
|
|
|
|
|
"links": [
|
|
|
|
|
|
{"source": "issue_uuid", "target": "action_uuid", "type": "LEADS_TO", "weight": 1.0}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant ADM as 管理后台
|
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
|
participant Client as Neo4jClient
|
|
|
|
|
|
participant Neo4j as Neo4j
|
|
|
|
|
|
|
|
|
|
|
|
ADM->>API: GET /graph?limit=200
|
|
|
|
|
|
API->>Client: get_neo4j_client()
|
|
|
|
|
|
|
|
|
|
|
|
alt Neo4j 不可用
|
|
|
|
|
|
Client-->>API: None
|
|
|
|
|
|
API-->>ADM: {code:0, data:{nodes:[], links:[]}, message:"Neo4j 不可用"}
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
alt 全图查询(无 issue_name)
|
|
|
|
|
|
Client->>Neo4j: MATCH (i:Issue) RETURN ... LIMIT $limit
|
|
|
|
|
|
Neo4j-->>Client: issue_nodes[]
|
|
|
|
|
|
Client->>Neo4j: MATCH (a:Action) RETURN ... LIMIT $limit
|
|
|
|
|
|
Neo4j-->>Client: action_nodes[]
|
|
|
|
|
|
Client->>Neo4j: MATCH (n)-[r]->(m) WHERE ... LIMIT $limit*3
|
|
|
|
|
|
Neo4j-->>Client: relations[]
|
|
|
|
|
|
else 子图查询(有 issue_name)
|
|
|
|
|
|
Client->>Neo4j: MATCH path = (center:Issue {name: $name})-[*0..1]-(neighbor) ...
|
|
|
|
|
|
Neo4j-->>Client: subgraph_nodes[]
|
|
|
|
|
|
Client->>Neo4j: MATCH (center:Issue {name: $name})-[r*1..1]-(neighbor) ...
|
|
|
|
|
|
Neo4j-->>Client: subgraph_links[]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Client-->>API: {nodes, links}
|
|
|
|
|
|
API-->>ADM: {code:0, data: graph_data}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
| 配置项 | 值 | 说明 |
|
|
|
|
|
|
|--------|-----|------|
|
|
|
|
|
|
| 图表类型 | `graph` (force layout) | ECharts 力导向图 |
|
|
|
|
|
|
| Issue 节点 | 绿色 `#67c23a`, symbolSize=28 | 问题节点 |
|
|
|
|
|
|
| Action 节点 | 橙色 `#e6a23c`, symbolSize=22 | 动作节点 |
|
|
|
|
|
|
| 连线颜色 | `#c0c4cc`, curveness=0.3 | 曲线连线 |
|
|
|
|
|
|
| 连线宽度 | `max(0.5, weight * 1.5)` | 按 weight 粗细 |
|
|
|
|
|
|
| 排斥力 | repulsion=300 | 力导向参数 |
|
|
|
|
|
|
| 重力 | gravity=0.1 | 力导向参数 |
|
|
|
|
|
|
| 边长度 | [100, 250] | 边长度范围 |
|
|
|
|
|
|
| 缩放 | roam=true | 支持鼠标缩放平移 |
|
|
|
|
|
|
| 高亮 | focus='adjacency' | 悬停高亮相邻节点 |
|
|
|
|
|
|
| 筛选 | 按 Issue 名称筛选子图 | 留空查全图 |
|
|
|
|
|
|
| 节点/关系计数 | 实时显示 | "节点: X | 关系: Y" |
|
|
|
|
|
|
| 响应式 | ResizeObserver | 自动 resize |
|
|
|
|
|
|
|
|
|
|
|
|
#### Neo4j 连接配置
|
|
|
|
|
|
|
|
|
|
|
|
| 配置项 | 默认值 | 环境变量 |
|
|
|
|
|
|
|--------|--------|---------|
|
|
|
|
|
|
| neo4j_uri | `bolt://localhost:7687` | `NEO4J_URI` |
|
|
|
|
|
|
| neo4j_user | `neo4j` | `NEO4J_USER` |
|
|
|
|
|
|
| neo4j_password | (无默认值) | `NEO4J_PASSWORD` |
|
|
|
|
|
|
| neo4j_database | `neo4j` | `NEO4J_DATABASE` |
|
|
|
|
|
|
| neo4j_max_connection_lifetime | 3600(秒) | — |
|
|
|
|
|
|
| neo4j_max_connection_pool_size | 50 | — |
|
|
|
|
|
|
| neo4j_connection_acquisition_timeout | 30(秒) | — |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — Neo4j 容器 `wecom_it_neo4j` 运行中,Neo4j 6.2.0 驱动已安装,API 路由已注册,ECharts 可视化已部署。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.9 合并去重
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
将重复的知识建议合并到主建议中,标签和元数据合并,重复建议标记为 rejected(合并归入)。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:生产在线。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据模型
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
classDiagram
|
|
|
|
|
|
class MergeRequest {
|
|
|
|
|
|
+String primary_id
|
|
|
|
|
|
+String duplicate_id
|
|
|
|
|
|
+String reviewer_id
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class MergeResult {
|
|
|
|
|
|
+KnowledgeSuggestion primary
|
|
|
|
|
|
+KnowledgeSuggestion duplicate
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class KnowledgeIterationService {
|
|
|
|
|
|
+merge_suggestions(db, primary_id, duplicate_id, reviewer_id) KnowledgeSuggestion
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MergeRequest --> KnowledgeIterationService : input
|
|
|
|
|
|
KnowledgeIterationService --> MergeResult : output
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### API 接口设计
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 路径 | 请求体 | 响应 | 说明 |
|
|
|
|
|
|
|------|------|--------|------|------|
|
|
|
|
|
|
| POST | `/api/admin/knowledge-iteration/suggestions/{id}/merge` | `{duplicate_id: string}` | `{code:0, data: KnowledgeSuggestionResponse}` | 合并重复建议 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心流程
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant ADM as 管理后台
|
|
|
|
|
|
participant API as FastAPI
|
|
|
|
|
|
participant Svc as KnowledgeIterationService
|
|
|
|
|
|
participant DB as PostgreSQL
|
|
|
|
|
|
|
|
|
|
|
|
ADM->>API: POST /suggestions/{primary_id}/merge {duplicate_id}
|
|
|
|
|
|
API->>Svc: merge_suggestions(db, primary_id, duplicate_id, reviewer_id)
|
|
|
|
|
|
|
|
|
|
|
|
Svc->>DB: SELECT * FROM knowledge_suggestions WHERE id = primary_id
|
|
|
|
|
|
DB-->>Svc: primary (主建议)
|
|
|
|
|
|
|
|
|
|
|
|
alt 主建议不存在
|
|
|
|
|
|
Svc-->>API: None
|
|
|
|
|
|
API-->>ADM: {code:404, message:"主建议不存在"}
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Svc->>DB: SELECT * FROM knowledge_suggestions WHERE id = duplicate_id
|
|
|
|
|
|
DB-->>Svc: duplicate (重复建议)
|
|
|
|
|
|
|
|
|
|
|
|
alt 重复建议存在
|
|
|
|
|
|
Svc->>Svc: 合并标签: merged_tags = set(primary.tags + duplicate.tags)
|
|
|
|
|
|
Svc->>Svc: 合并 graph_meta: primary.graph_meta.update(duplicate.graph_meta)
|
|
|
|
|
|
Svc->>DB: UPDATE duplicate SET status='rejected', reject_reason='已合并至建议 {primary_id}(去重)', reviewer_id, reviewed_at
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Svc->>DB: COMMIT
|
|
|
|
|
|
Svc->>DB: REFRESH primary
|
|
|
|
|
|
Svc-->>API: primary (合并后)
|
|
|
|
|
|
API-->>ADM: {code:0, message:"建议合并完成,重复建议已标记为已驳回(合并归入)", data: primary}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 合并规则
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 合并策略 |
|
|
|
|
|
|
|------|---------|
|
|
|
|
|
|
| tags | 并集去重:`set(primary.tags + duplicate.tags)` |
|
|
|
|
|
|
| graph_meta | 深度合并:`primary.graph_meta.update(duplicate.graph_meta)` |
|
|
|
|
|
|
| status (duplicate) | → `rejected` |
|
|
|
|
|
|
| reject_reason (duplicate) | → `已合并至建议 {primary_id}(去重)` |
|
|
|
|
|
|
| reviewer_id (duplicate) | → 当前审核人 |
|
|
|
|
|
|
| reviewed_at (duplicate) | → 当前时间 |
|
|
|
|
|
|
| primary 其他字段 | 保持不变 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 前端交互设计
|
|
|
|
|
|
|
|
|
|
|
|
| 交互 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| 触发入口 | 重复检测结果弹窗中每行的"合并"按钮 |
|
|
|
|
|
|
| 请求参数 | `suggestion_id`(主建议,URL 路径参数)+ `duplicate_id`(重复建议,请求体) |
|
|
|
|
|
|
| 成功反馈 | 关闭重复弹窗 + 刷新列表 + 刷新统计 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — 后端 `merge_suggestions` 方法 + API 路由 + 前端合并操作均已部署。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 3.10 会话关闭→建议→审核→写图
|
|
|
|
|
|
|
|
|
|
|
|
#### 功能描述
|
|
|
|
|
|
|
|
|
|
|
|
全链路闭环:坐席结单 → 异步触发 AI 生成知识建议 → 训练师审核 → KB 落库 → Neo4j 写图。
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**:生产在线。全链路打通。
|
|
|
|
|
|
|
|
|
|
|
|
#### 全链路数据流
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
A[坐席结单] --> B[异步触发\n知识建议生成]
|
|
|
|
|
|
B --> C{Dify 可用?}
|
|
|
|
|
|
C -->|是| D[调用 Wingman AI\n生成结构化建议]
|
|
|
|
|
|
C -->|否| E[source_failed=True\n标题=生成失败]
|
|
|
|
|
|
D --> F{confidence ≥ 0.7?}
|
|
|
|
|
|
F -->|是| G[创建 KnowledgeSuggestion\nstatus=pending]
|
|
|
|
|
|
F -->|否| H[source_failed=True\n标记低置信]
|
|
|
|
|
|
E --> G
|
|
|
|
|
|
H --> G
|
|
|
|
|
|
G --> I{训练师审核}
|
|
|
|
|
|
I -->|采纳| J[status=approved]
|
|
|
|
|
|
I -->|驳回| K[status=rejected\n终态]
|
|
|
|
|
|
I -->|改写| L[重置 status=pending\n重新审核]
|
|
|
|
|
|
I -->|入队| M[status=queued\n独立队列]
|
|
|
|
|
|
M --> N[队列审批\n→ approved]
|
|
|
|
|
|
J --> O[创建 KnowledgeBase 条目\nstatus=applied]
|
|
|
|
|
|
N --> O
|
|
|
|
|
|
O --> P{Neo4j 写图}
|
|
|
|
|
|
P -->|成功| Q[status=graph_synced\ngraph_sync_status=synced\n回填 kb.graph_node_uuid]
|
|
|
|
|
|
P -->|失败| R[graph_sync_status=failed\n可重试]
|
|
|
|
|
|
Q --> S[终态:知识图谱更新]
|
|
|
|
|
|
R --> T[后续优化:\n重试队列]
|
|
|
|
|
|
|
|
|
|
|
|
style A fill:#e3f2fd
|
|
|
|
|
|
style Q fill:#e8f5e9
|
|
|
|
|
|
style S fill:#c8e6c9
|
|
|
|
|
|
style K fill:#ffebee
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 详细时序图
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant AG as 坐席端
|
|
|
|
|
|
participant API_Conv as 会话 API
|
|
|
|
|
|
participant Svc_KI as 知识迭代服务
|
|
|
|
|
|
participant Wingman as Wingman AI
|
|
|
|
|
|
participant Dify as Dify
|
|
|
|
|
|
participant DB as PostgreSQL
|
|
|
|
|
|
participant Neo4j as Neo4j
|
|
|
|
|
|
participant ADM as 管理后台
|
|
|
|
|
|
|
|
|
|
|
|
%% 阶段1:会话关闭 → 异步生成建议
|
|
|
|
|
|
rect rgb(227, 242, 253)
|
|
|
|
|
|
Note over AG,DB: 阶段1:会话关闭 → 异步生成建议
|
|
|
|
|
|
AG->>API_Conv: POST /api/conversations/{id}/resolve (结单)
|
|
|
|
|
|
API_Conv->>DB: 会话状态 → resolved/closed
|
|
|
|
|
|
API_Conv-->>AG: 结单成功(不阻塞)
|
|
|
|
|
|
|
|
|
|
|
|
API_Conv->>API_Conv: asyncio.ensure_future(_trigger_knowledge_suggestion())
|
|
|
|
|
|
|
|
|
|
|
|
Note over API_Conv: 独立 db session 后台任务
|
|
|
|
|
|
API_Conv->>Svc_KI: generate_knowledge_suggestion(db, "conversation", [conv_id], reason)
|
|
|
|
|
|
Svc_KI->>Svc_KI: _check_existing_suggestion() — 避免重复
|
|
|
|
|
|
Svc_KI->>Svc_KI: _build_context_from_source() — 获取消息历史
|
|
|
|
|
|
Svc_KI->>Wingman: generate_knowledge_suggestion(context_messages)
|
|
|
|
|
|
Wingman->>Dify: 调用 Dify API
|
|
|
|
|
|
Dify-->>Wingman: {title, content, confidence, issue, action, ...}
|
|
|
|
|
|
Wingman-->>Svc_KI: ai_result
|
|
|
|
|
|
|
|
|
|
|
|
Svc_KI->>Svc_KI: 置信门控: confidence < 0.7 → source_failed
|
|
|
|
|
|
Svc_KI->>Svc_KI: audience 自动标注
|
|
|
|
|
|
Svc_KI->>DB: INSERT knowledge_suggestion (status=pending)
|
|
|
|
|
|
Svc_KI-->>API_Conv: suggestion
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
%% 阶段2:训练师审核
|
|
|
|
|
|
rect rgb(255, 243, 224)
|
|
|
|
|
|
Note over ADM,DB: 阶段2:训练师审核
|
|
|
|
|
|
ADM->>Svc_KI: GET /suggestions (查看待审核列表)
|
|
|
|
|
|
Svc_KI->>DB: SELECT * FROM knowledge_suggestions WHERE status='pending'
|
|
|
|
|
|
DB-->>ADM: suggestions[]
|
|
|
|
|
|
|
|
|
|
|
|
ADM->>ADM: 训练师查看详情,编辑图字段
|
|
|
|
|
|
|
|
|
|
|
|
alt 采纳
|
|
|
|
|
|
ADM->>Svc_KI: POST /suggestions/{id}/approve
|
|
|
|
|
|
Svc_KI->>Svc_KI: 校验 pending → approved (状态机)
|
|
|
|
|
|
Svc_KI->>DB: UPDATE status=approved, reviewer_id, reviewed_at
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
%% 阶段3:KB 落库 + Neo4j 写图
|
|
|
|
|
|
rect rgb(232, 245, 233)
|
|
|
|
|
|
Note over Svc_KI,Neo4j: 阶段3:KB 落库 + Neo4j 写图
|
|
|
|
|
|
Svc_KI->>DB: INSERT knowledge_base (title, content, category, tags)
|
|
|
|
|
|
Svc_KI->>DB: UPDATE suggestion status=applied, applied_at
|
|
|
|
|
|
|
|
|
|
|
|
Svc_KI->>Svc_KI: sync_to_neo4j(neo4j_client, suggestion)
|
|
|
|
|
|
|
|
|
|
|
|
rect rgb(232, 234, 246)
|
|
|
|
|
|
Note over Svc_KI,Neo4j: Neo4j 写图步骤
|
|
|
|
|
|
Svc_KI->>Neo4j: merge_issue(issue, category, props) — MERGE 幂等
|
|
|
|
|
|
Neo4j-->>Svc_KI: IssueNode (uuid)
|
|
|
|
|
|
|
|
|
|
|
|
opt 有父 Issue
|
|
|
|
|
|
Svc_KI->>Neo4j: merge_issue(parent_issue, ...)
|
|
|
|
|
|
Neo4j-->>Svc_KI: parent_node
|
|
|
|
|
|
Svc_KI->>Neo4j: create_relation(parent → issue, type, weight)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
opt 有 Action
|
|
|
|
|
|
Svc_KI->>Neo4j: merge_action(action, props)
|
|
|
|
|
|
Neo4j-->>Svc_KI: ActionNode (uuid)
|
|
|
|
|
|
Svc_KI->>Neo4j: create_relation(issue → action, type, weight=confidence)
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
alt 写图成功
|
|
|
|
|
|
Svc_KI->>DB: UPDATE suggestion status=graph_synced, graph_sync_status=synced
|
|
|
|
|
|
Svc_KI->>DB: UPDATE kb graph_sync_status=synced, graph_node_uuid=issue_node.uuid
|
|
|
|
|
|
else 写图失败
|
|
|
|
|
|
Svc_KI->>DB: UPDATE suggestion graph_sync_status=failed
|
|
|
|
|
|
Svc_KI->>DB: UPDATE kb graph_sync_status=failed
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
Svc_KI->>DB: COMMIT
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
ADM->>Svc_KI: 响应 {code:0, data: suggestion (graph_synced)}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 会话关闭触发点
|
|
|
|
|
|
|
|
|
|
|
|
**文件**:`backend/app/api/conversations.py`,`resolve_conversation` 函数
|
|
|
|
|
|
|
|
|
|
|
|
**关键代码**:
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 会话结单后异步触发知识建议生成
|
|
|
|
|
|
async def _trigger_knowledge_suggestion():
|
|
|
|
|
|
"""异步生成知识建议的后台任务(独立 db session)。"""
|
|
|
|
|
|
from app.database import _get_session_factory
|
|
|
|
|
|
from app.services.knowledge_iteration_service import KnowledgeIterationService
|
|
|
|
|
|
|
|
|
|
|
|
factory = _get_session_factory()
|
|
|
|
|
|
async with factory() as bg_db:
|
|
|
|
|
|
knowledge_service = KnowledgeIterationService()
|
|
|
|
|
|
suggestion = await knowledge_service.generate_knowledge_suggestion(
|
|
|
|
|
|
db=bg_db,
|
|
|
|
|
|
source_type="conversation",
|
|
|
|
|
|
source_data=[str(conversation_id)],
|
|
|
|
|
|
reason=f"会话'{conversation_id}'已结单,自动生成知识迭代建议",
|
|
|
|
|
|
)
|
|
|
|
|
|
if suggestion:
|
|
|
|
|
|
bg_db.add(suggestion)
|
|
|
|
|
|
await bg_db.commit()
|
|
|
|
|
|
|
|
|
|
|
|
# 创建后台任务(不阻塞结单响应)
|
|
|
|
|
|
_asyncio.ensure_future(_trigger_knowledge_suggestion())
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**设计要点**:
|
|
|
|
|
|
1. **不阻塞结单**:使用 `asyncio.ensure_future` 异步执行,结单响应立即返回
|
|
|
|
|
|
2. **独立 db session**:后台任务使用独立的 `_get_session_factory()` 创建新 session,避免与主请求 session 冲突
|
|
|
|
|
|
3. **失败不影响主流程**:知识建议生成失败时仅记录日志,不影响结单
|
|
|
|
|
|
4. **避免重复**:`_check_existing_suggestion` 检查是否已有 pending 建议
|
|
|
|
|
|
|
|
|
|
|
|
#### Neo4j 写图逻辑(sync_to_neo4j)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart TD
|
|
|
|
|
|
A[approve_suggestion 触发] --> B{suggestion.issue 存在?}
|
|
|
|
|
|
B -->|否| C[return True\n无图字段不视为失败]
|
|
|
|
|
|
B -->|是| D[merge_issue\nMERGE Issue 节点]
|
|
|
|
|
|
|
|
|
|
|
|
D --> E{suggestion.parent_issue 存在?}
|
|
|
|
|
|
E -->|是| F[merge_issue\nMERGE 父 Issue 节点]
|
|
|
|
|
|
F --> G[create_relation\n父Issue → 当前Issue]
|
|
|
|
|
|
E -->|否| H{suggestion.action 存在?}
|
|
|
|
|
|
|
|
|
|
|
|
G --> H
|
|
|
|
|
|
H -->|是| I[merge_action\nMERGE Action 节点]
|
|
|
|
|
|
I --> J[create_relation\nIssue → Action\nweight=confidence]
|
|
|
|
|
|
H -->|否| K[return True]
|
|
|
|
|
|
|
|
|
|
|
|
J --> K
|
|
|
|
|
|
K --> L[写图成功]
|
|
|
|
|
|
|
|
|
|
|
|
style L fill:#c8e6c9
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**MERGE 幂等写入**:
|
|
|
|
|
|
- Issue 节点按 `name` MERGE(同名不重复创建)
|
|
|
|
|
|
- Action 节点按 `name` MERGE
|
|
|
|
|
|
- 关系通过 `MATCH + CREATE` 创建
|
|
|
|
|
|
|
|
|
|
|
|
#### 部署状态
|
|
|
|
|
|
|
|
|
|
|
|
**生产在线** — 全链路已打通,从会话结单到 Neo4j 写图完整闭环。测试通过率 89/89。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 功能依赖关系图
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
graph TB
|
|
|
|
|
|
subgraph "H5 员工端功能"
|
|
|
|
|
|
F1[1.分诊交互]
|
|
|
|
|
|
F2[2.置信门控]
|
|
|
|
|
|
F6[6.代答排除]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "坐席端功能"
|
|
|
|
|
|
F3[3.内联审批卡片]
|
|
|
|
|
|
F4[4.拓扑预览]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "管理后台功能"
|
|
|
|
|
|
F5[5.重复检测]
|
|
|
|
|
|
F7[7.知识迭代管理]
|
|
|
|
|
|
F8[8.图谱可视化]
|
|
|
|
|
|
F9[9.合并去重]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "全链路功能"
|
|
|
|
|
|
F10[10.会话关闭→建议→审核→写图]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "基础设施"
|
|
|
|
|
|
NEO4J[Neo4j 图数据库]
|
|
|
|
|
|
DIFY[Dify AI 平台]
|
|
|
|
|
|
PG[(PostgreSQL)]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
%% 依赖关系
|
|
|
|
|
|
F2 -->|confidence < 0.7 触发| F10
|
|
|
|
|
|
F1 -->|分诊上下文转人工| F10
|
|
|
|
|
|
F6 -->|排除选项影响| F1
|
|
|
|
|
|
|
|
|
|
|
|
F10 -->|生成 KnowledgeSuggestion| F3
|
|
|
|
|
|
F10 -->|生成 KnowledgeSuggestion| F7
|
|
|
|
|
|
|
|
|
|
|
|
F3 -->|展示拓扑| F4
|
|
|
|
|
|
F3 -->|检查重复| F5
|
|
|
|
|
|
F5 -->|发现重复| F9
|
|
|
|
|
|
|
|
|
|
|
|
F7 -->|管理审核| F3
|
|
|
|
|
|
F7 -->|查看图谱| F8
|
|
|
|
|
|
F7 -->|检查重复| F5
|
|
|
|
|
|
F7 -->|合并去重| F9
|
|
|
|
|
|
|
|
|
|
|
|
%% 基础设施依赖
|
|
|
|
|
|
F2 --> DIFY
|
|
|
|
|
|
F10 --> DIFY
|
|
|
|
|
|
F10 --> PG
|
|
|
|
|
|
F3 --> PG
|
|
|
|
|
|
F5 --> NEO4J
|
|
|
|
|
|
F5 --> PG
|
|
|
|
|
|
F7 --> PG
|
|
|
|
|
|
F8 --> NEO4J
|
|
|
|
|
|
F9 --> PG
|
|
|
|
|
|
F10 --> NEO4J
|
|
|
|
|
|
F4 --> NEO4J
|
|
|
|
|
|
|
|
|
|
|
|
%% 样式
|
|
|
|
|
|
style F1 fill:#fff3e0,stroke:#ff9800,stroke-dasharray: 5 5
|
|
|
|
|
|
style F4 fill:#fff3e0,stroke:#ff9800,stroke-dasharray: 5 5
|
|
|
|
|
|
style F6 fill:#fff3e0,stroke:#ff9800,stroke-dasharray: 5 5
|
|
|
|
|
|
style F2 fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style F3 fill:#e3f2fd,stroke:#2196f3
|
|
|
|
|
|
style F5 fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style F7 fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style F8 fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style F9 fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style F10 fill:#e8f5e9,stroke:#4caf50
|
|
|
|
|
|
style NEO4J fill:#e8eaf6,stroke:#3f51b5
|
|
|
|
|
|
style DIFY fill:#fce4ec,stroke:#e91e63
|
|
|
|
|
|
style PG fill:#e8eaf6,stroke:#3f51b5
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**图例**:
|
|
|
|
|
|
- 🟢 绿色边框:生产在线
|
|
|
|
|
|
- 🟠 橙色虚线边框:未实现/仅前端组件
|
|
|
|
|
|
- 🔵 蓝色:基础设施
|
|
|
|
|
|
|
|
|
|
|
|
**核心依赖链**:
|
|
|
|
|
|
```
|
|
|
|
|
|
置信门控 → 会话关闭→建议→审核→写图 → 内联审批卡片 → 重复检测 → 合并去重
|
|
|
|
|
|
↓
|
|
|
|
|
|
拓扑预览
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 全链路数据流图
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 通道 A:会话自动生成(全链路闭环)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart TD
|
|
|
|
|
|
Start([员工提问]) --> AI_Reply[AI 回复]
|
|
|
|
|
|
AI_Reply --> ConfCheck{confidence ≥ 0.7?}
|
|
|
|
|
|
|
|
|
|
|
|
ConfCheck -->|是| Normal[正常回复]
|
|
|
|
|
|
ConfCheck -->|否| GateBanner[置信门控横幅<br/>展示转人工入口]
|
|
|
|
|
|
|
|
|
|
|
|
GateBanner --> Transfer{员工选择}
|
|
|
|
|
|
Transfer -->|转人工| WaitingAgent[会话 → waiting_agent]
|
|
|
|
|
|
Transfer -->|继续 AI| Normal
|
|
|
|
|
|
|
|
|
|
|
|
Normal --> Resolved{问题解决?}
|
|
|
|
|
|
Resolved -->|是| Close1[员工关闭]
|
|
|
|
|
|
Resolved -->|否| WaitingAgent
|
|
|
|
|
|
|
|
|
|
|
|
WaitingAgent --> AgentServe[坐席接管]
|
|
|
|
|
|
AgentServe --> Close2[坐席结单]
|
|
|
|
|
|
|
|
|
|
|
|
Close1 --> AsyncGen[异步触发<br/>知识建议生成]
|
|
|
|
|
|
Close2 --> AsyncGen
|
|
|
|
|
|
|
|
|
|
|
|
AsyncGen --> BuildCtx[构建对话上下文<br/>获取消息历史]
|
|
|
|
|
|
BuildCtx --> CallAI[调用 Dify Wingman<br/>生成结构化建议]
|
|
|
|
|
|
|
|
|
|
|
|
CallAI --> ConfGate{confidence ≥ 0.7?}
|
|
|
|
|
|
ConfGate -->|是| CreateSuggestion[创建 KnowledgeSuggestion<br/>status=pending]
|
|
|
|
|
|
ConfGate -->|否| MarkFailed[source_failed=True<br/>标题=生成失败]
|
|
|
|
|
|
MarkFailed --> CreateSuggestion
|
|
|
|
|
|
|
|
|
|
|
|
CreateSuggestion --> NotifyAgent[通知坐席<br/>内联审批卡片]
|
|
|
|
|
|
CreateSuggestion --> NotifyAdmin[通知训练师<br/>管理后台列表]
|
|
|
|
|
|
|
|
|
|
|
|
NotifyAgent --> Review{审核决策}
|
|
|
|
|
|
NotifyAdmin --> Review
|
|
|
|
|
|
|
|
|
|
|
|
Review -->|采纳| Approve[status=approved]
|
|
|
|
|
|
Review -->|驳回| Reject[status=rejected 终态]
|
|
|
|
|
|
Review -->|改写| Rewrite[修改字段<br/>重置 pending]
|
|
|
|
|
|
Review -->|入队| Queue[status=queued<br/>独立队列]
|
|
|
|
|
|
|
|
|
|
|
|
Queue --> QueueReview[队列审批]
|
|
|
|
|
|
QueueReview -->|通过| Approve
|
|
|
|
|
|
QueueReview -->|驳回| Reject
|
|
|
|
|
|
|
|
|
|
|
|
Rewrite --> Review
|
|
|
|
|
|
|
|
|
|
|
|
Approve --> CreateKB[创建 KnowledgeBase 条目<br/>status=applied]
|
|
|
|
|
|
CreateKB --> WriteNeo4j[Neo4j 写图<br/>merge_issue + merge_action]
|
|
|
|
|
|
|
|
|
|
|
|
WriteNeo4j --> SyncCheck{写图成功?}
|
|
|
|
|
|
SyncCheck -->|是| GraphSynced[status=graph_synced<br/>回填 kb.graph_node_uuid]
|
|
|
|
|
|
SyncCheck -->|否| SyncFailed[graph_sync_status=failed<br/>待重试]
|
|
|
|
|
|
|
|
|
|
|
|
GraphSynced --> Done([知识图谱更新完成])
|
|
|
|
|
|
|
|
|
|
|
|
style GateBanner fill:#fff3e0
|
|
|
|
|
|
style AsyncGen fill:#e3f2fd
|
|
|
|
|
|
style CreateSuggestion fill:#e8f5e9
|
|
|
|
|
|
GraphSynced fill:#c8e6c9
|
|
|
|
|
|
style Reject fill:#ffebee
|
|
|
|
|
|
style Done fill:#c8e6c9
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 通道 B:训练师手动录入
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
A[训练师点击<br/>手动录入] --> B[填写表单<br/>标题/内容/分类/受众/图字段]
|
|
|
|
|
|
B --> C[提交<br/>source_type=manual<br/>confidence=1.0]
|
|
|
|
|
|
C --> D[创建 KnowledgeSuggestion<br/>status=pending]
|
|
|
|
|
|
D --> E[审核流程<br/>同通道 A]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 通道 C:RAGFlow 文档 ETL(预留未实现)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
A[RAGFlow 文档上传] --> B[ETL 处理<br/>文档→FAQ]
|
|
|
|
|
|
B --> C[source_type=document_ragflow<br/>audience=engineer_workguide]
|
|
|
|
|
|
C --> D[创建 KnowledgeSuggestion<br/>status=pending]
|
|
|
|
|
|
D --> E[审核流程<br/>同通道 A]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5.4 三通道汇总
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
graph TB
|
|
|
|
|
|
subgraph "通道 A:会话自动生成"
|
|
|
|
|
|
A1[会话关闭] --> A2[Dify AI 生成] --> A3[KnowledgeSuggestion]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "通道 B:手动录入"
|
|
|
|
|
|
B1[训练师录入] --> B2[confidence=1.0] --> B3[KnowledgeSuggestion]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph "通道 C:RAGFlow(预留)"
|
|
|
|
|
|
C1[文档 ETL] --> C2[自动提取] --> C3[KnowledgeSuggestion]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
A3 --> S[统一审核队列<br/>status=pending]
|
|
|
|
|
|
B3 --> S
|
|
|
|
|
|
C3 --> S
|
|
|
|
|
|
|
|
|
|
|
|
S --> R{审核}
|
|
|
|
|
|
R -->|采纳| AP[approved → applied → graph_synced]
|
|
|
|
|
|
R -->|驳回| RJ[rejected]
|
|
|
|
|
|
R -->|改写| RW[重置 pending]
|
|
|
|
|
|
R -->|入队| Q[queued → 队列审批]
|
|
|
|
|
|
|
|
|
|
|
|
style S fill:#e3f2fd
|
|
|
|
|
|
style AP fill:#e8f5e9
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 未实现功能设计
|
|
|
|
|
|
|
|
|
|
|
|
### 6.1 分诊交互 — 前瞻设计
|
|
|
|
|
|
|
|
|
|
|
|
#### 当前状态
|
|
|
|
|
|
|
|
|
|
|
|
前端组件 `TriageCard.vue` 已完成(530 行),包含完整的 UI 交互:步骤进度、选项列表、概率展示、专家模式、折叠/展开、跳过/确认。但后端 API 未实现,Dify 分诊 prompt 未配置。
|
|
|
|
|
|
|
|
|
|
|
|
#### 建议实现方案
|
|
|
|
|
|
|
|
|
|
|
|
**后端新增**:
|
|
|
|
|
|
|
|
|
|
|
|
1. **新增 API 文件**:`backend/app/api/triage.py`
|
|
|
|
|
|
- `POST /api/h5/triage/start` — 发起分诊
|
|
|
|
|
|
- `POST /api/h5/triage/step` — 提交步骤选择
|
|
|
|
|
|
- `POST /api/h5/triage/skip` — 跳过步骤
|
|
|
|
|
|
- `POST /api/h5/triage/transfer` — 转人工
|
|
|
|
|
|
|
|
|
|
|
|
2. **Dify Prompt 设计**:
|
|
|
|
|
|
- 输入:员工问题文本
|
|
|
|
|
|
- 输出:分步选择题数组 `[{question, options: [{label, probability}], total_steps}]`
|
|
|
|
|
|
- 复杂度自适应:简单问题 1-2 步,复杂问题 3-5 步
|
|
|
|
|
|
|
|
|
|
|
|
3. **数据模型**:
|
|
|
|
|
|
- 复用 `Conversation` 表,增加 `triage_steps` JSON 字段存储分诊过程
|
|
|
|
|
|
- 或新建 `triage_sessions` 表
|
|
|
|
|
|
|
|
|
|
|
|
4. **集成点**:
|
|
|
|
|
|
- H5 对话页面在 AI 回复前调用分诊 API
|
|
|
|
|
|
- 分诊完成后将收集的上下文传入 Dify 生成最终回复
|
|
|
|
|
|
|
|
|
|
|
|
#### 预估工作量
|
|
|
|
|
|
|
|
|
|
|
|
| 任务 | 工作量 |
|
|
|
|
|
|
|------|--------|
|
|
|
|
|
|
| 后端 API + 服务 | 2 人日 |
|
|
|
|
|
|
| Dify Prompt 调试 | 3 人日 |
|
|
|
|
|
|
| H5 前端对接 | 1 人日 |
|
|
|
|
|
|
| 测试 | 1 人日 |
|
|
|
|
|
|
| **合计** | **7 人日** |
|
|
|
|
|
|
|
|
|
|
|
|
### 6.2 拓扑预览 — 前瞻设计
|
|
|
|
|
|
|
|
|
|
|
|
#### 当前状态
|
|
|
|
|
|
|
|
|
|
|
|
前端 SVG 缩略图已实现(基于 suggestion 的 issue/parent_issue/action 字段静态渲染),后端 `query_issue_subgraph` 方法已实现但未通过 API 暴露。
|
|
|
|
|
|
|
|
|
|
|
|
#### 建议实现方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **新增 API 端点**:
|
|
|
|
|
|
```python
|
|
|
|
|
|
@router.get("/suggestions/{suggestion_id}/topology")
|
|
|
|
|
|
@require_admin
|
|
|
|
|
|
async def get_suggestion_topology(suggestion_id: str, ...):
|
|
|
|
|
|
# 查询 suggestion 获取 issue 名称
|
|
|
|
|
|
# 调用 neo4j_client.query_issue_subgraph(issue_name, depth=1)
|
|
|
|
|
|
# 返回 {nodes, links}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. **前端增强**:
|
|
|
|
|
|
- SVG 缩略图保留为快速预览
|
|
|
|
|
|
- 点击缩略图弹出 ECharts mini graph modal 展示完整子图
|
|
|
|
|
|
- 子图支持节点点击跳转到图谱可视化页面
|
|
|
|
|
|
|
|
|
|
|
|
3. **降级处理**:
|
|
|
|
|
|
- Neo4j 不可用时回退到当前 SVG 静态渲染
|
|
|
|
|
|
- suggestion 无 issue 字段时不展示拓扑
|
|
|
|
|
|
|
|
|
|
|
|
#### 预估工作量
|
|
|
|
|
|
|
|
|
|
|
|
| 任务 | 工作量 |
|
|
|
|
|
|
|------|--------|
|
|
|
|
|
|
| 后端 API 端点 | 0.5 人日 |
|
|
|
|
|
|
| 前端 ECharts modal | 1 人日 |
|
|
|
|
|
|
| 测试 | 0.5 人日 |
|
|
|
|
|
|
| **合计** | **2 人日** |
|
|
|
|
|
|
|
|
|
|
|
|
### 6.3 代答排除 — 前瞻设计
|
|
|
|
|
|
|
|
|
|
|
|
#### 当前状态
|
|
|
|
|
|
|
|
|
|
|
|
前端 `TriageCard.vue` 中 `setExcludedOptions` / `setRecommendedOption` 方法定义完成,但无后端 API 对接,无 WS 推送机制。
|
|
|
|
|
|
|
|
|
|
|
|
#### 建议实现方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **后端新增**:
|
|
|
|
|
|
- `POST /api/agent/triage/exclude` — 坐席排除选项
|
|
|
|
|
|
- `POST /api/agent/triage/recommend` — 坐席推荐选项
|
|
|
|
|
|
|
|
|
|
|
|
2. **WebSocket 推送**:
|
|
|
|
|
|
- 坐席排除/推荐操作后,通过 WS 实时推送到 H5 员工端
|
|
|
|
|
|
- H5 端接收后调用 `TriageCard.setExcludedOptions()` / `setRecommendedOption()`
|
|
|
|
|
|
|
|
|
|
|
|
3. **Dify Prompt 增强**:
|
|
|
|
|
|
- 将排除的选项作为上下文传入 Dify,影响后续步骤生成
|
|
|
|
|
|
- 避免 AI 在后续步骤中再次推荐已排除的选项
|
|
|
|
|
|
|
|
|
|
|
|
4. **审计日志**:
|
|
|
|
|
|
- 记录坐席排除/推荐操作(操作人、时间、排除的选项、原因)
|
|
|
|
|
|
|
|
|
|
|
|
#### 预估工作量
|
|
|
|
|
|
|
|
|
|
|
|
| 任务 | 工作量 |
|
|
|
|
|
|
|------|--------|
|
|
|
|
|
|
| 后端 API + WS 推送 | 1.5 人日 |
|
|
|
|
|
|
| 坐席端前端对接 | 1 人日 |
|
|
|
|
|
|
| H5 前端对接 | 0.5 人日 |
|
|
|
|
|
|
| 测试 | 1 人日 |
|
|
|
|
|
|
| **合计** | **4 人日** |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 已知问题与后续优化方向
|
|
|
|
|
|
|
|
|
|
|
|
### 7.1 已知问题
|
|
|
|
|
|
|
|
|
|
|
|
| # | 问题 | 影响 | 严重程度 | 当前处理 |
|
|
|
|
|
|
|---|------|------|---------|---------|
|
|
|
|
|
|
| 1 | Neo4j 写图失败后无自动重试 | `graph_sync_status=failed` 的建议停留在 applied 状态,图数据不完整 | P1 | 人工触发重新审批 |
|
|
|
|
|
|
| 2 | `_analyze_conversation_data` 采样限制 20 条 | 分析超过 20 条会话时仅采样前 20 条,可能遗漏 | P2 | 可接受,后续调大采样 |
|
|
|
|
|
|
| 3 | audience 自动标注默认 employee_quick_reply | Conversation 模型无 session_type 字段,无法精确区分员工/工程师会话 | P2 | 保守默认,训练师可手动修改 |
|
|
|
|
|
|
| 4 | 相似度计算为简单前缀匹配 | 无法检测语义相似但文字不同的重复 Issue | P2 | 后续可引入向量相似度 |
|
|
|
|
|
|
| 5 | 会话关闭异步任务无重试机制 | Dify 不可用时建议生成失败,无自动重试 | P2 | source_failed 标记,训练师可手动改写 |
|
|
|
|
|
|
| 6 | 过期状态 expired 无定时任务 | 设计中有 expired 状态(72h 超时),但无定时任务自动触发 | P3 | 待实现定时任务 |
|
|
|
|
|
|
| 7 | `create_relation` 使用 CREATE 而非 MERGE | 重复审批同一建议可能创建重复关系边 | P2 | 后续改为 MERGE |
|
|
|
|
|
|
| 8 | 前端 `createSuggestion` 直接调用 POST /suggestions | API 路由中无 POST /suggestions 创建端点(仅列表 GET) | P1 | 需补充创建 API 或使用其他路径 |
|
|
|
|
|
|
|
|
|
|
|
|
### 7.2 后续优化方向
|
|
|
|
|
|
|
|
|
|
|
|
#### 短期(P0-P1)
|
|
|
|
|
|
|
|
|
|
|
|
1. **Neo4j 写图重试队列**
|
|
|
|
|
|
- 新增定时任务扫描 `graph_sync_status=failed` 的建议
|
|
|
|
|
|
- 自动重试写图,最多 3 次
|
|
|
|
|
|
- 超过重试次数通知管理员
|
|
|
|
|
|
|
|
|
|
|
|
2. **补充手动创建建议 API**
|
|
|
|
|
|
- 前端 `createSuggestion` 调用的 POST /suggestions 端点需补充
|
|
|
|
|
|
- 或确认是否通过其他路由处理
|
|
|
|
|
|
|
|
|
|
|
|
3. **关系边 MERGE 幂等**
|
|
|
|
|
|
- `create_relation` 改用 MERGE 替代 CREATE
|
|
|
|
|
|
- 避免重复审批产生重复关系
|
|
|
|
|
|
|
|
|
|
|
|
#### 中期(P2)
|
|
|
|
|
|
|
|
|
|
|
|
4. **向量相似度去重**
|
|
|
|
|
|
- 引入 embedding 模型计算 Issue 名称的语义相似度
|
|
|
|
|
|
- 替代当前的前缀匹配算法
|
|
|
|
|
|
- 提高重复检测准确率
|
|
|
|
|
|
|
|
|
|
|
|
5. **过期定时任务**
|
|
|
|
|
|
- 实现 72h 超时自动 expired 的定时任务
|
|
|
|
|
|
- 使用 APScheduler 或 Celery beat
|
|
|
|
|
|
|
|
|
|
|
|
6. **分诊交互后端实现**
|
|
|
|
|
|
- 实现分诊 API + Dify Prompt
|
|
|
|
|
|
- 打通 TriageCard 前后端
|
|
|
|
|
|
|
|
|
|
|
|
7. **拓扑预览 API 对接**
|
|
|
|
|
|
- 暴露 `query_issue_subgraph` 为 API
|
|
|
|
|
|
- 前端 ECharts mini graph 展示
|
|
|
|
|
|
|
|
|
|
|
|
#### 长期(P3)
|
|
|
|
|
|
|
|
|
|
|
|
8. **RAGFlow 通道 C 实现**
|
|
|
|
|
|
- 部署 RAGFlow 服务
|
|
|
|
|
|
- 实现文档 ETL → KnowledgeSuggestion 自动生成
|
|
|
|
|
|
- `ragflow_ingestion_enabled` 配置开关已预留
|
|
|
|
|
|
|
|
|
|
|
|
9. **知识图谱推理**
|
|
|
|
|
|
- 基于 Neo4j 图结构进行路径推荐
|
|
|
|
|
|
- 员工提问时推荐相关 Issue→Action 路径
|
|
|
|
|
|
|
|
|
|
|
|
10. **全链路监控看板**
|
|
|
|
|
|
- 建议生成→审核→写图各阶段耗时统计
|
|
|
|
|
|
- 转化漏斗:生成数 → 采纳数 → 写图成功数
|
|
|
|
|
|
- Dify 调用成功率监控
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附录
|
|
|
|
|
|
|
|
|
|
|
|
### A. 数据库迁移
|
|
|
|
|
|
|
|
|
|
|
|
| 迁移版本 | 说明 |
|
|
|
|
|
|
|---------|------|
|
|
|
|
|
|
| 043_knowledge_iteration | 创建 knowledge_suggestions 表 + conversation_annotations 表 |
|
|
|
|
|
|
| 044_automation | 自动化相关表(后续迁移) |
|
|
|
|
|
|
|
|
|
|
|
|
### B. 测试覆盖
|
|
|
|
|
|
|
|
|
|
|
|
| 测试层级 | 测试数 | 通过率 | 报告 |
|
|
|
|
|
|
|---------|--------|--------|------|
|
2026-08-07 22:31:32 +08:00
|
|
|
|
| Tier0 基础测试 | 41 | 100% | `docs/03-测试文档/Tier0-测试报告-20260708.md` |
|
2026-07-11 23:13:10 +08:00
|
|
|
|
| Tier1 API 测试 | 34 | 100% | 同上 |
|
|
|
|
|
|
| CSV 验证 | 14 | 100% | 同上 |
|
2026-08-07 22:31:32 +08:00
|
|
|
|
| P2 可视化测试 | — | — | `docs/03-测试文档/P0串联+P2可视化-测试报告-20260708.md` |
|
2026-07-11 23:13:10 +08:00
|
|
|
|
| **合计** | **89** | **100%** | — |
|
|
|
|
|
|
|
|
|
|
|
|
### C. 关键文件索引
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 行数 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| `backend/app/api/knowledge_iteration.py` | 568 | 12 条 API 路由 |
|
|
|
|
|
|
| `backend/app/api/approval_queue.py` | 208 | 3 条队列 API 路由 |
|
|
|
|
|
|
| `backend/app/services/knowledge_iteration_service.py` | 1197 | 核心服务 |
|
|
|
|
|
|
| `backend/app/services/neo4j_client.py` | 759 | Neo4j 异步客户端 |
|
|
|
|
|
|
| `backend/app/models/knowledge_suggestion.py` | 260 | 数据模型 |
|
|
|
|
|
|
| `backend/app/models/knowledge_base.py` | 143 | 数据模型 |
|
|
|
|
|
|
| `backend/app/models/neo4j_schema.py` | 115 | 图节点 Pydantic 模型 |
|
|
|
|
|
|
| `backend/app/schemas/enums.py` | 159 | 枚举 + 状态机 |
|
|
|
|
|
|
| `backend/app/schemas/knowledge_suggestion.py` | 208 | 请求/响应 Schema |
|
|
|
|
|
|
| `backend/app/config.py` | 469 | 配置项 |
|
|
|
|
|
|
| `backend/app/api/conversations.py` | ~400+ | 会话关闭触发点 |
|
|
|
|
|
|
| `frontend-admin/src/views/KnowledgeIteration.vue` | 982 | 管理后台页面 |
|
|
|
|
|
|
| `frontend-agent/src/components/chat/ApprovalInlineCard.vue` | 695 | 内联审批卡片 |
|
|
|
|
|
|
| `frontend-h5/src/components/TriageCard.vue` | 530 | 分诊卡片 |
|
|
|
|
|
|
| `frontend-h5/src/components/ConfidenceGateBanner.vue` | 332 | 置信门控横幅 |
|
|
|
|
|
|
| `frontend-h5/src/composables/useConfidenceGate.ts` | 181 | 置信门控逻辑 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
> **文档结束**
|
|
|
|
|
|
> 本文档基于代码分析生成,已部署功能为回溯文档,未实现功能为前瞻设计。
|
|
|
|
|
|
> 如有疑问请联系架构组。
|