Files
wecom_it_smart_desk/docs/02-技术文档/技术架构/增量设计-知识库迭代与痛点缓解-20260711.md
T
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交
(5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。

一、docs 结构整改(整改 #14)
根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入,
随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录
树并存于 docs/,共 791 文件、双分类体系冲突。

修复动作:
- b2 同名异主题文件改名迁移保全 9 个
- C 类 39 个孤立文件按主题正确归类
- A/B1 类 222 个重复文件删除(新结构已有内容副本)
- 9 个旧独有空目录删除
- 270 处内部引用按 verified 映射改写
- 整改记录 #14 登记于 04-运维文档/部署运维

结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。
残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。

二、compose 双目录对齐(消除踩坑 A)
- docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist
  改为 src/frontend-*/dist(h5 / agent / admin / terminal)
- docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/
- 效果:本地 docker compose up 不再把根目录 stale dist 挂回,
  与线上一致,分叉隐患消除(已 docker compose config 校验通过)

防复发铁律:
- 重构须提交;仓库修复须 git stash -u 或先 commit
- 新结构须 git add 并提交,避免再次 untracked 复活
- H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2026-08-07 22:31:32 +08:00

2082 lines
72 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 增量设计:知识库迭代与痛点缓解
> **文档版本**v1.0
> **创建日期**2026-07-11
> **文档类型**:回溯文档(已部署功能)+ 前瞻设计(未实现功能)
> **测试报告引用**`docs/03-测试文档/Tier0-测试报告-20260708.md`89/89 通过)
> **技术栈**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) | 异步 ORMAsyncSession |
| 关系数据库 | 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 | 移动端 UIvan-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
%% 阶段3KB 落库 + Neo4j 写图
rect rgb(232, 245, 233)
Note over Svc_KI,Neo4j: 阶段3KB 落库 + 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 通道 CRAGFlow 文档 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 "通道 CRAGFlow(预留)"
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. 测试覆盖
| 测试层级 | 测试数 | 通过率 | 报告 |
|---------|--------|--------|------|
| Tier0 基础测试 | 41 | 100% | `docs/03-测试文档/Tier0-测试报告-20260708.md` |
| Tier1 API 测试 | 34 | 100% | 同上 |
| CSV 验证 | 14 | 100% | 同上 |
| P2 可视化测试 | — | — | `docs/03-测试文档/P0串联+P2可视化-测试报告-20260708.md` |
| **合计** | **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 | 置信门控逻辑 |
---
> **文档结束**
> 本文档基于代码分析生成,已部署功能为回溯文档,未实现功能为前瞻设计。
> 如有疑问请联系架构组。