diff --git a/docs/INDEX.md b/docs/INDEX.md new file mode 100644 index 0000000..00fb75f --- /dev/null +++ b/docs/INDEX.md @@ -0,0 +1,81 @@ +# 数据库设计文档索引 + +## 📂 文档结构 + +``` +docs/ +├── README.md # 总览(推荐从这里开始) +├── database-design.md # 总览(同 README.md) +│ +├── tables/ # 表设计详细文档 +│ ├── diagnosis_record.md # 诊断记录表(核心) +│ ├── case_library.md # 案例库表 +│ └── api_document.md # 文档元数据表 +│ +└── architecture/ # 架构设计文档 + ├── agent-architecture-mvp.md # ⭐ Agent 架构 MVP 精简版 + ├── agent-architecture.md # Agent 架构完整版(含生产级扩展) + ├── session-management.md # 会话管理设计 + └── implementation-plan.md # 实施规划 +``` + +--- + +## 🚀 快速导航 + +### 我是开发者 +1. [总览](README.md) - 了解整体设计 +2. [diagnosis_record](tables/diagnosis_record.md) - 核心业务表 +3. [实施规划](architecture/implementation-plan.md) - 开发计划 + +### 我是运维 +1. [总览](README.md) - 了解表结构 +2. [实施规划](architecture/implementation-plan.md) - 部署检查清单 + +### 我是产品 +1. [总览](README.md) - 了解系统定位 +2. [会话管理](architecture/session-management.md) - 了解用户交互流程 + +--- + +## 📋 表清单 + +| 表名 | 优先级 | 文档 | 说明 | +|------|--------|------|------| +| diagnosis_record | P0 | [查看](tables/diagnosis_record.md) | 诊断记录(核心) | +| case_library | P0 | [查看](tables/case_library.md) | 案例库 | +| api_document | P0 | [查看](tables/api_document.md) | 文档元数据 | + +--- + +## 📖 阅读建议 + +### 第一次阅读 +``` +1. README.md(10分钟) + - 了解设计原则 + - 了解表关系 + +2. diagnosis_record.md(15分钟) + - 核心表设计 + - 字段泛化设计 + +3. implementation-plan.md(5分钟) + - 分阶段实施计划 +``` + +### 深入理解 +``` +- case_library.md - 案例推荐机制 +- api_document.md - 文档管理设计 +- session-management.md - 会话管理机制 +``` + +--- + +## 🔄 文档维护 + +- 原完整文档已备份:`database-design-backup-20240622.md` +- 每个表的详细设计在 `tables/` 目录 +- 架构设计在 `architecture/` 目录 +- 修改表结构时,同步更新对应 Markdown diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..4b59445 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,155 @@ +# 数据库设计文档 + +## 📚 文档导航 + +### 核心表设计 +- [diagnosis_record](tables/diagnosis_record.md) - 诊断记录表(核心) +- [case_library](tables/case_library.md) - 案例库表 +- [api_document](tables/api_document.md) - 文档元数据表 + +### 架构设计 +- [Agent 架构设计](architecture/agent-architecture.md) - Agent 协作 + Skill + Harness +- [会话管理](architecture/session-management.md) - Redis + MySQL 会话管理 +- [实施规划](architecture/implementation-plan.md) - 分阶段实施计划 + +--- + +## 一、设计原则 + +### 1.1 核心原则 +- ✅ **简单优先**:满足诊断流程需要,避免过度设计 +- ✅ **渐进增强**:先实现核心功能,再逐步扩展 +- ✅ **数据分离**:诊断结果持久化(MySQL),会话上下文临时化(Redis) +- ✅ **适度冗余**:避免过度范式化,适当冗余提升查询性能 + +### 1.2 系统定位 +**自动化诊断系统** +- 核心:一键诊断 → 返回完整报告 +- 辅助:支持追问,但不是主要场景 +- 特点:大部分用户单次诊断即结束,少数用户会追问细节 + +--- + +## 二、表结构总览 + +### 2.1 核心表关系 + +``` +┌─────────────────────┐ +│ diagnosis_record │ 诊断记录(核心) +│ - 每次诊断一条 │ +└──────────┬──────────┘ + │ 1:1 + ↓ +┌─────────────────────┐ +│ case_library │ 案例库(知识沉淀) +│ - 诊断成功→案例 │ +└─────────────────────┘ + +┌─────────────────────┐ +│ api_document │ 文档元数据(管理层) +│ - 状态追踪/去重 │ +└──────────┬──────────┘ + │ doc_id + ↓ +┌─────────────────────┐ +│ Milvus │ 文档内容(检索层) +│ - 向量检索 │ +└─────────────────────┘ + +┌─────────────────────┐ +│ Redis Session │ 会话管理(临时) +│ - 30分钟过期 │ +│ - 支持追问 │ +└─────────────────────┘ +``` + +### 2.2 表统计 + +| 表名 | 类型 | 预估数据量 | 用途 | +|------|------|-----------|------| +| diagnosis_record | 核心 | 3.6万/年 | 诊断记录 | +| case_library | 核心 | 500-1000 | 案例库 | +| api_document | 核心 | 100-200 | 文档管理 | + +--- + +## 三、技术栈 + +### 3.1 数据存储 +``` +MySQL 8.0+ +├─ 元数据管理 +├─ 事务支持 +└─ JSON 字段支持 + +Redis 6.0+ +├─ 会话存储 +├─ 缓存 +└─ TTL 自动过期 + +Milvus 2.6+ +├─ 向量存储 +├─ 语义检索 +└─ 混合检索 +``` + +### 3.2 开发框架 +``` +Spring Boot 3.2 +Spring AI Alibaba 1.1.0 +Milvus SDK Java 2.6.10 +DashScope SDK +``` + +--- + +## 四、快速开始 + +### 4.1 创建数据库 + +```sql +-- 1. 创建数据库 +CREATE DATABASE diagnosis_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 2. 执行建表脚本(按顺序) +SOURCE tables/diagnosis_record.sql; +SOURCE tables/case_library.sql; +SOURCE tables/api_document.sql; +``` + +### 4.2 初始化 Milvus + +```java +// 创建 Collection +MilvusClientFactory.createCollection(); +``` + +### 4.3 配置 Redis + +```yaml +spring: + redis: + host: localhost + port: 6379 + database: 0 +``` + +--- + +## 五、版本历史 + +| 版本 | 日期 | 变更内容 | +|------|------|---------| +| v1.0 | 2024-06-15 | 初版,定义核心表结构 | +| v2.0 | 2024-06-15 | diagnosis_record 字段泛化,支持多种故障类型 | +| v2.1 | 2024-06-22 | 文档拆分,增加 api_document 表 | + +--- + +## 六、维护说明 + +- 每个表的详细设计在 `tables/` 目录下 +- 架构设计文档在 `architecture/` 目录下 +- 修改表结构时,同步更新对应的 Markdown 文档 +- 重大变更需记录在版本历史中 diff --git a/docs/architecture/agent-architecture-mvp.md b/docs/architecture/agent-architecture-mvp.md new file mode 100644 index 0000000..6f03db2 --- /dev/null +++ b/docs/architecture/agent-architecture-mvp.md @@ -0,0 +1,529 @@ +# Agent 架构设计(MVP 版) + +## 一、MVP 全景 + +``` +用户输入 + ↓ +┌──────────────────────────────────────────┐ +│ 意图识别(Intent Recognition) 🆕 │ +│ "用户想干什么?" │ +│ │ +│ 诊断意图 → 路由到诊断 Skill │ +│ 文档意图 → 路由到文档问答 │ +│ 案例意图 → 路由到案例查询 │ +│ 闲聊 → 快速响应(不启动 Agent) │ +│ 模糊/无关 → 提示用户,直接中断 │ +└──────────────┬───────────────────────────┘ + │ 诊断意图 + ↓ +┌──────────────────────────────────────────┐ +│ Supervisor Agent(调度者) │ +│ "谁来干?什么时候停?" │ +└──────────────┬───────────────────────────┘ + ↓ +┌──────────────────────────────────────────┐ +│ Planner Agent(规划者) │ +│ 分析问题 → 制定策略 → 生成报告 │ +└──────────────┬───────────────────────────┘ + ↓ +┌──────────────────────────────────────────┐ +│ Executor Agent(执行者) │ +│ 调用工具收集证据 │ +└──────────────┬───────────────────────────┘ + ↓ +┌──────────────────────────────────────────┐ +│ Verifier Agent(验证者) │ +│ 事实核查 → 判定通过/修正/驳回 │ +└──────────────┬───────────────────────────┘ + ↓ + 诊断报告输出 + ↓ + 用户反馈(有用/无用) + ↓ + 案例沉淀 + BadCase 优化 +``` + +--- + +## 二、意图识别(入口层)🆕 + +### 2.1 设计理念 + +``` +定位:独立模块,不嵌入任何单一 Agent + +分层策略(不是二选一,而是组合): + +L0: 正则规则 —— 0 成本,毫秒级 ✅ MVP +├─ 处理 80%+ 的结构化查询 +├─ 正则匹配订单号/traceId/错误码格式 +└─ 关键词匹配("报错"/"异常"/"失败") + +L1: 小模型 Agent —— 低成本,百毫秒级 ✅ MVP +├─ L0 未命中时触发 +├─ 处理灵活的模糊表达("系统有点慢"、"怎么查不到了") +├─ 不启动全链路 Agent,只做意图分类 +└─ 判断为诊断意图 → 路由到诊断 Skill + +L2: 兜底策略 —— 极少使用 +├─ L0+L1 都无法判断 → 意图不明 → 中断 +└─ Phase 2 增强 +``` + +### 2.2 意图分类与路由 + +``` +┌────────────────────────────────────────────────────┐ +│ 意图 │ 说明 │ 路由 │ +├────────────────────────────────────────────────────┤ +│ 诊断意图 │ 包含结构化标识或错误描述 │ → 诊断Skill│ +│ 文档问答 │ "XX接口的参数有哪些" │ → 直接RAG │ +│ 案例查询 │ "之前有类似的问题吗" │ → 案例检索 │ +│ 闲聊 │ "你好"/"谢谢" │ → 快速响应 │ +│ 意图不明 │ 无法识别 │ → 中断+提示 │ +└────────────────────────────────────────────────────┘ + +关键原则: +- 只有诊断意图才启动 Agent 全链路 +- 非诊断意图走轻量路径或直接中断 +``` + +### 2.3 L0:正则规则(MVP,处理 80%) + +``` +为什么先做 L0? +→ 0 成本(不调 LLM),毫秒级响应 +→ 结构化查询占比最大(订单号、traceId、错误码、关键词) +→ L0 命中直接路由,不需要走后续逻辑 + +规则配置(可扩展): +┌────────────────────────────────────────────────┐ +│ 规则 │ 意图 │ 方式 │ +├────────────────────────────────────────────────┤ +│ 匹配 \d{12,} │ 诊断 │ 正则 │ +│ 匹配 trace[-_]?\w{8,} │ 诊断 │ 正则 │ +│ 包含"报错‖失败‖异常‖挂了‖超时" │ 诊断 │ 关键词│ +│ 包含"文档‖接口‖参数‖字段‖API" │ 文档 │ 关键词│ +│ 包含"案例‖之前‖类似‖历史" │ 案例 │ 关键词│ +│ 长度 <= 5 字符 │ 闲聊 │ 规则 │ +└────────────────────────────────────────────────┘ + +命中 → 直接路由,不调 L1 +未命中 → 进入 L1 +``` + +### 2.4 L1:小模型 Agent(MVP,处理剩余 20%) + +``` +为什么用小模型 Agent 而非嵌入到 Supervisor? +→ 意图识别是独立职责,不应耦合到任何业务 Agent +→ 轻量 Agent:单一职责,只分类不执行 +→ 成本低(~50 token),延迟低(~200ms) + +何时触发:L0 规则未命中 + +System Prompt: +"你是意图分类器,判断用户想做什么。 + 只返回一个词:[诊断 / 文档查询 / 案例查询 / 闲聊 / 意图不明] + + 诊断:用户描述了故障、报错、异常 + 文档查询:用户询问接口文档、字段含义 + 案例查询:用户询问历史案例、类似问题 + 闲聊:简单的问候、感谢 + 意图不明:无法判断用户意图" + +输入:用户原始输入 +输出:意图类型 + 置信度 +``` + +### 2.5 L2:兜底策略 + +``` +L0+L1 都无法判断 → L2 兜底 + +中断规则: +├─ 意图不明 → 提示用户 + 中断 +│ "无法判断您的意图,请提供订单号或错误码" +├─ 闲聊 → 快速响应 + 中断 +│ "我是故障诊断助手,请描述您遇到的问题" +└─ 不启动 Agent,直接返回 + +路由规则: +├─ 诊断意图 → 启动 Supervisor + 4 Agent 全链路 +├─ 文档意图 → 不启动 Agent,直接 RAG 检索 +└─ 案例意图 → 不启动 Agent,直接查询 case_library +``` + +### 2.5 架构位置 + +``` +用户输入 + ↓ +┌──────────────────────────────────────────┐ +│ 意图识别模块(独立) │ +│ │ +│ L1: 小模型 Agent ─→ 诊断意图? │ +│ │ 文档意图? │ +│ │ 案例意图? │ +│ │ 闲聊? │ +│ ↓ │ +│ L2: 兜底 ─────────→ 意图不明 → 中断 │ +│ 闲聊 → 快速响应 │ +└───────────────┬──────────────────────────┘ + │ 诊断意图 + ↓ + Supervisor → Planner → Executor → Verifier +``` + +### 2.6 MVP vs Phase 2 + +``` +MVP L0(正则)+ L1(小模型Agent) 覆盖 95%+ 场景 +Phase 2 L2(兜底增强) 细化中断提示,支持多轮澄清 +``` + +--- + +## 三、4 个 Agent 设计 + +### 2.1 Supervisor Agent(调度者) + +**职责**:总指挥,协调工作流 + +``` +调度规则: +├─ 接收任务 → 发给 Planner 分析 +├─ Planner 完成 → 发给 Executor 执行 +├─ Executor 完成 → 发给 Verifier 校验 +└─ Verifier PASS → 输出报告 / REJECT → 返回 Planner 重新规划 + +不做: +- 不直接调用工具 +- 不直接生成报告 +``` + +### 2.2 Planner Agent(规划者 + 分诊) + +**职责**:分析问题、制定策略、生成报告草稿 + +``` +分析规则: +├─ 有 errorCode + 接口 URL → EXTERNAL_API(外部接口故障) +├─ 有堆栈信息 → INTERNAL_ERROR(系统内部错误) +├─ 有数据库错误码(如 1213)→ DATABASE(数据库问题) +└─ 其他 → 通用排查 + +规划流程: +1. 确定 fault_category +2. 制定排查步骤(每步:工具名 + 参数 + 预期) +3. 生成决策:EXECUTE(继续执行)| FINISH(生成报告) + +Replanner 职责: +├─ Executor 每次返回结果后 → 评估证据是否充分 +├─ 需要补充?→ 调整步骤,继续执行 +├─ 证据齐全?→ FINISH,生成报告草稿 +└─ 连续 3 次失败?→ 降级 + +禁止: +- 编造数据 +- 引用未经工具返回的内容 +``` + +### 2.3 Executor Agent(执行者) + +**职责**:调用工具收集证据 + +``` +工具清单: +├─ queryOrder:查询订单/业务数据(MySQL 只读) +├─ searchDoc:检索接口文档(混合检索 Milvus + MySQL) +├─ recommendCase:推荐相似案例(精确匹配 + 语义检索) +└─ getCurrentTime:获取当前时间 + +执行规则: +├─ 每次只执行 Planner 指定的一个步骤 +├─ 返回结构化的执行结果 +├─ 失败时返回错误详情(便于 Planner 调整) +└─ 禁止编造结果 + +扩展预留: +// 代码中 Executor 是接口,后续可扩展为 SubAgent +public interface Executor { + ExecutionResult execute(Step step); +} +``` + +### 2.4 Verifier Agent(验证者) + +**职责**:验证诊断报告,防止编造 + +``` +验证流程: + +1️⃣ 事实核查(最重要) +├─ 报告中的错误码 → 在 tool_calls 中存在? +├─ 根因结论 → 有日志/文档证据支撑? +├─ 修复方案 → 引用了文档或案例? +└─ 发现编造数据 → 直接 REJECT + +2️⃣ 完整性检查 +├─ 根因分析章节不能为空 +├─ 证据链章节不能为空 +└─ 修复方案章节不能为空 + +判决结果: +├─ PASS:报告成立,直接输出 +├─ REVISE:小问题可修正,返回 Planner 微调 +└─ REJECT:编造数据或严重错误,返回 Planner 重新分析 +``` + +--- + +## 四、RAG 两层加载策略 + +### 4.1 设计理念 + +``` +问题: +❌ 全前置:启动时把所有文档塞给 Agent → 信息过载,推理变慢 +❌ 纯被动:等到需要才查 → Planner 没有全局视野,可能跑偏 +❌ 固定步骤:每次都调 → 内部错误查接口文档浪费 + +正确做法:两层互补 + +L1 预加载(Planner 启动时) +→ 通用领域知识:系统架构、通用错误码、业务流程 +→ 给 Planner 全局视野,避免方向性错误 + +L2 按需加载(Executor 执行中) +→ 具体接口文档:字段定义、错误码含义、调用规范 +→ 给 Executor 精准证据,定位具体问题 +``` + +### 4.2 两层对比 + +| | L1 预加载 | L2 按需加载 | +|------|---------|-----------| +| 触发时机 | 意图识别后,Planner 启动前 | Executor 拿到具体信息后 | +| 内容 | 通用知识(架构、流程、高频错误码) | 具体接口文档(字段、错误码含义) | +| 目的 | 让 Planner 有全局视野 | 让 Executor 有精准证据 | +| 成本 | 固定,每次诊断 1 次 | 按需,最多 2-3 次 | +| 谁负责 | Supervisor 注入 | Executor 自主调用 | + +### 4.3 实现方式 + +``` +L1 预加载: +Supervisor 在启动 Planner 前: + searchDoc(keyword="系统架构 通用错误码 业务流程") + → 注入到 Planner 的 System Prompt 中 + → Planner 拥有"领域背景知识" + +L2 按需加载: +Executor 执行 Step 2 时: + 拿到 errorCode=40003, faultSource="广东" + → 自主调用 searchDoc(errorCode="40003", faultSource="广东") + → 获取该接口的具体字段定义和错误码说明 + → 作为证据写入诊断报告 +``` + +--- + +## 五、Skill 设计(1 个) + +### /diagnose-by-orderid(按订单号诊断) + +``` +输入:orderId + +工作流(6 步): + +Step 1: 查询订单信息 + 工具:queryOrder + 失败:ABORT(订单不存在则终止) + +Step 2: 检索接口文档 + 工具:searchDoc + 参数:errorCode + faultSource + 失败:SKIP(标注"文档缺失") + +Step 3: 查询日志 + 工具:queryLogs(Mock) + 参数:traceId + 失败:SKIP(标注"日志缺失") + +Step 4: 检索相似案例 + 工具:recommendCase + 参数:errorCode + faultCategory + 失败:SKIP(标注"无相似案例") + +Step 5: 生成诊断报告 + 汇总所有证据,按模板生成报告 + +Step 6: Verifier 验证 + 事实核查 → 判决 + +门禁规则: +├─ Step 1 失败 → 终止,返回"订单不存在" +├─ Step 2-4 失败 → 跳过,标注缺失信息 +├─ 任意步骤超时 30s → 终止 +└─ Verifier REJECT → 返回 Planner 重新规划 +``` + +--- + +## 六、Harness 控制层(精简版) + +### 4.1 5 个 Quality Gates + +``` +输入门禁(2 个): +├─ Gate 1: 输入参数非空校验 +└─ Gate 2: 5 分钟内同一订单 → 返回缓存 + +执行门禁(1 个): +└─ Gate 3: 工具调用超时(10 秒) + +输出门禁(2 个): +├─ Gate 4: 报告章节完整性(3 章节不全 → 不通过) +└─ Gate 5: 置信度阈值(< 60 → 标记"低置信度") +``` + +### 4.2 中断规则 + +``` +自动中断: +├─ 工具连续失败 3 次 → 终止,降级输出 +└─ 全局超时 30 秒 → 终止 + +条件降级: +├─ 文档检索为空 → 跳过继续 +├─ 案例推荐为空 → 跳过继续 +└─ 日志查询失败 → 跳过继续 + +降级输出: +"无法自动诊断,请人工介入" ++ 已收集的证据(订单信息 + 部分日志 + 已知错误码) +``` + +--- + +## 七、技术实现 + +### 5.1 基于 Spring AI Alibaba + +```java +// Supervisor - 框架提供 +SupervisorAgent supervisor = SupervisorAgent.builder() + .name("diagnosis_supervisor") + .model(chatModel) + .subAgents(List.of(planner, executor, verifier)) + .build(); + +// Planner +ReactAgent planner = ReactAgent.builder() + .name("planner_agent") + .model(chatModel) + .systemPrompt(plannerPrompt) + .outputKey("planner_plan") + .build(); + +// Executor(代码中预留 SubAgent 扩展接口) +ReactAgent executor = ReactAgent.builder() + .name("executor_agent") + .model(chatModel) + .systemPrompt(executorPrompt) + .methodTools(diagnosisTools) + .tools(new ToolCallback[]{queryOrder, searchDoc, recommendCase, getCurrentTime}) + .build(); + +// Verifier +ReactAgent verifier = ReactAgent.builder() + .name("verifier_agent") + .model(chatModel) + .systemPrompt(verifierPrompt) + .outputKey("verifier_result") + .build(); +``` + +### 5.2 工具注册 + +```java +@Component +public class DiagnosisTools { + + @Tool(description = "查询订单/业务数据(只读)") + public OrderInfo queryOrder(@ToolParam(description = "订单号") String orderId) { + // MySQL 只读 + SQL 注入防护 + } + + @Tool(description = "检索接口文档") + public List searchDoc( + @ToolParam(description = "错误码") String errorCode, + @ToolParam(description = "省份/服务名") String faultSource + ) { + // 混合检索:精确匹配 + 向量检索 + } + + @Tool(description = "推荐相似历史案例") + public List recommendCase( + @ToolParam(description = "错误码") String errorCode, + @ToolParam(description = "故障类别") String faultCategory + ) { + // 精确匹配 MySQL + 语义检索 Milvus + } +} +``` + +--- + +## 八、闭环机制 + +``` +诊断报告输出 + ↓ +用户反馈(useful / not_useful) + ↓ +├─ useful → 自动生成 case_library +└─ not_useful → 记录 BadCase + ↓ +每周 BadCase 分析 + ↓ +Prompt / Skill 优化 + ↓ +准确率验证(测试集重跑) +``` + +--- + +## 九、MVP vs 扩展方向 + +| 维度 | MVP | 扩展方向 | +|------|-----|---------| +| Agent | 4 个 Agent | SubAgent 模式(专科医生) | +| Skill | 1 个 | 渐进式披露(3 层知识) | +| 工具 | @Tool 注解 | MCP 独立 Server | +| 回退 | 2 级(失败→降级) | 4 级路由 | +| Gates | 5 个 | 15 个全流程门禁 | +| 隔离 | 单 JVM | K8s Pod 进程隔离 | +| 进化 | 案例自动生成 | 模式识别 + Prompt 自优化 | + +--- + +## 十、面试话术(精简版) + +> "我用 Spring AI Alibaba 实现了一个故障诊断 Agent 系统。 +> +> 入口层是**意图识别**:先判断用户想干什么——诊断故障、查文档、查案例还是闲聊。 +> 非诊断意图直接走轻量路径,只有诊断意图才启动 Agent 全链路,节省资源。 +> +> 4 Agent 协作:Supervisor 调度、Planner 制定策略、 +> Executor 调用工具收集证据、Verifier 验证报告防止编造。 +> +> 诊断流程封装成了 Skill,标准化 6 个步骤和异常处理。 +> Harness 层 5 个门禁保证质量——最关键的是输出门禁, +> Verifier 会对比报告数据和工具返回数据,发现编造就驳回。 +> +> 闭环机制:用户反馈 → BadCase 分析 → Prompt 优化。 +> 案例自动沉淀,系统越用越智能。" diff --git a/docs/architecture/agent-architecture.md b/docs/architecture/agent-architecture.md new file mode 100644 index 0000000..f4c876f --- /dev/null +++ b/docs/architecture/agent-architecture.md @@ -0,0 +1,1519 @@ +# Agent 架构设计 + +## 一、总体架构 + +### 1.1 核心理念 + +``` +不是一个人干所有活,而是团队协作 + +类比:医院会诊 +- Supervisor = 院长(调度资源) +- Planner = 分诊台(判断病情,分配合适科室) +- SubAgent = 专科医生(各有所长,精准诊断) +- Verifier = 质检员(验证诊断,防止误诊) +``` + +### 1.2 Agent 全景图 + +``` +用户输入 + ↓ +┌──────────────────────────────────────────────────────────┐ +│ Supervisor Agent(调度者) │ +│ "谁来干?什么时候干?结果给谁看?" │ +└──────┬───────────────────────────────────────────────────┘ + │ + ↓ +┌──────────────────────────────────────────────────────────┐ +│ Planner Agent(规划者 + 分诊) │ +│ │ +│ 职责1:分析问题类型,确定 fault_category │ +│ 职责2:制定排查策略,拆解执行步骤 │ +│ 职责3:根据 fault_category 选择合适的 SubAgent │ +│ 职责4:根据 Executor 反馈动态调整(Replanner) │ +│ 职责5:最终生成诊断报告草稿 │ +└──────┬───────────────────────────────────────────────────┘ + │ + ↓ fault_category = EXTERNAL_API +┌──────────────────────────────────────────────────────────┐ +│ SubAgent 执行层 │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────┐ ┌─────────────────────────────┐ │ +│ │ ExternalApiSubAgent │ │ InternalErrorSubAgent │ │ +│ │ "接口专家" │ │ "代码专家" │ │ +│ │ │ │ │ │ +│ │ 工具: │ │ 工具: │ │ +│ │ - searchDoc │ │ - queryLogs │ │ +│ │ - queryLogs │ │ - queryTrace │ │ +│ │ - queryTrace │ │ - queryOrder │ │ +│ │ - queryOrder │ │ │ │ +│ │ │ │ Prompt:堆栈分析、代码定位 │ │ +│ │ Prompt:文档对比、 │ │ │ │ +│ │ 参数校验、签名检查 │ │ │ │ +│ └─────────────────────┘ └─────────────────────────────┘ │ +│ │ +│ ┌─────────────────────┐ │ +│ │ DatabaseSubAgent │ Phase 2 扩展... │ +│ │ "数据库专家" │ ┌─────────────────────────┐ │ +│ │ │ │ CacheSubAgent │ │ +│ │ 工具: │ │ "缓存专家" │ │ +│ │ - queryLogs │ └─────────────────────────┘ │ +│ │ - queryTrace │ ┌─────────────────────────┐ │ +│ │ - queryOrder │ │ NetworkSubAgent │ │ +│ │ │ │ "网络专家" │ │ +│ │ Prompt:死锁分析、 │ └─────────────────────────┘ │ +│ │ 慢查询优化、索引建议 │ │ +│ └─────────────────────┘ │ +│ │ +└───────────────────┬───────────────────────────────────────┘ + │ 执行结果 + 证据 + ↓ +┌──────────────────────────────────────────────────────────┐ +│ Verifier Agent(验证者) │ +│ "诊断报告是否成立?证据是否充分?" │ +│ │ +│ 第一轮:事实核查 ──→ 第二轮:逻辑验证 ──→ 第三轮:完整性检查│ +│ │ +│ 判决:PASS ──→ 直接输出报告 │ +│ REVISE ──→ 有问题需修正,返回 Planner │ +│ REJECT ──→ 诊断不成立,返回 Planner 重新分析 │ +└──────────────────────┬───────────────────────────────────┘ + │ + ↓ + 诊断报告输出 +``` + +--- + +## 二、Agent 详细设计 + +### 2.1 Supervisor Agent(调度者) + +**职责**:总指挥,协调所有 Agent 的工作流程 + +**System Prompt 核心**: +``` +你是 AI Ops Supervisor,负责调度 Agent 协作。 + +调度规则: +1. 接收用户任务 → 先调用 Planner 分析 +2. Planner 完成规划后 → 调用合适的 SubAgent 执行 +3. SubAgent 执行完成后 → 决定: + - 继续执行下一步 + - 返回给 Planner 重新规划 + - 调用 Verifier 校验 +4. Verifier 校验完成后 → 决定: + - PASS → 输出报告给用户 + - REVISE → 返回 Planner 修正 + - REJECT → 返回 Planner 重新分析 + +你只做调度,不直接执行工具,不生成报告。 +``` + +--- + +### 2.2 Planner Agent(规划者 + 分诊 + Replanner) + +**职责**:分析问题、制定策略、选择 SubAgent、动态调整 + +**System Prompt 核心**: +``` +你是 Planner Agent,同时承担 Replanner 角色。 + +职责 1:分析问题类型(分诊) +- 有错误码 + 接口URL → EXTERNAL_API +- 有堆栈信息 → INTERNAL_ERROR +- 有数据库错误码(如1213)→ DATABASE +- 有缓存相关关键词 → CACHE + +职责 2:制定排查策略 +- 确定 fault_category 后,选择对应的 SubAgent +- 制定执行步骤(每步包含:工具名、参数、预期输出) + +职责 3:动态调整(Replanner) +- 每次 Executor 返回结果后,评估: + - 证据是否充分? + - 需要补充什么信息? + - 是否需要更换 SubAgent? +- Decision: EXECUTE(继续执行)| FINISH(生成报告) + +职责 4:生成诊断报告草稿 +- 当 decision=FINISH 时,汇总所有证据 +- 按照报告模板生成草稿 +- 交给 Verifier 验证 + +输出格式: +{ + "decision": "EXECUTE|FINISH", + "fault_category": "EXTERNAL_API|INTERNAL_ERROR|DATABASE|...", + "sub_agent": "ExternalApiSubAgent|InternalErrorSubAgent|...", + "steps": [ + { + "tool": "queryOrder", + "params": {"orderId": "xxx"}, + "expect": "订单详情和错误信息" + } + ] +} + +约束: +- 禁止编造数据,只能引用工具返回的真实内容 +- 如果连续 3 次调用同一工具仍失败,停止该方向 +- 如果所有方向都无进展,在报告结论部分诚实说明"无法完成" +``` + +--- + +### 2.3 SubAgent 执行层(专科医生) + +#### 2.3.1 SubAgent 设计原则 + +``` +每个 SubAgent 的差异化要素: +1. 专属 System Prompt(不同的分析思路) +2. 专属工具集(不是所有工具都给) +3. 专属 Skill(不同故障类型走不同诊断流程) +4. 专属 Few-shot 示例(减少推理错误) +``` + +#### 2.3.2 MVP 版本 SubAgent 清单 + +**ExternalApiSubAgent(外部接口专家)** + +``` +System Prompt 核心: +- 对比请求报文 vs 接口文档的必填字段 +- 检查签名算法、加密方式是否正确 +- 解读第三方返回的错误码(查接口文档) +- 检查省份差异(不同省份的字段要求可能不同) +- 检查 HTTP 状态码(4xx/5xx 的含义) + +专属工具: +- searchDoc(检索接口文档,必须) +- queryLogs(查网关/第三方日志) +- queryTrace(看调用链耗时分布) +- queryOrder(查订单基本信息和请求参数) + +专属 Skill: +- /diagnose-by-orderid(按订单号诊断) +- /diagnose-by-errorcode(按错误码诊断) +``` + +**InternalErrorSubAgent(内部错误专家)** + +``` +System Prompt 核心: +- 分析堆栈信息:定位异常类、方法、行号 +- 分析空指针:哪个对象为 null?为什么? +- 分析类型转换、数组越界、参数格式 +- 分析异常传播路径(哪个方法抛出的,谁调用的) +- 建议具体的代码修改位置和修改方式 + +专属工具: +- queryLogs(查错误堆栈,必须) +- queryTrace(查调用链,定位是哪个服务出错) +- queryOrder(查触发错误的请求上下文) + +专属 Skill: +- /diagnose-by-stacktrace(堆栈分析诊断) +``` + +**DatabaseSubAgent(数据库专家)** + +``` +System Prompt 核心: +- 分析死锁日志:事务A等什么锁?事务B持什么锁? +- 分析慢查询:全表扫描?没走索引?JOIN 太多? +- 分析连接池:活跃/空闲/等待数,是否耗尽? +- 建议索引优化、SQL 改写、连接池参数调整 + +专属工具: +- queryLogs(查数据库错误日志,必须) +- queryTrace(查数据库调用耗时) +- queryOrder(查触发 SQL 的业务请求) + +专属 Skill: +- /quick-check(快速检查,只做 SQL 分析和连接池检查) +``` + +--- + +### 2.4 Verifier Agent(验证者) + +**职责**:验证诊断报告的准确性和完整性 + +**System Prompt 核心**: + +``` +你是 Verifier Agent(验证者),负责验证诊断报告的准确性和完整性。 + +## 验证流程 + +### 第一轮:事实核查(Fact Check) +- 报告中引用的错误码:是否在工具返回结果中存在? +- 根因结论:是否有日志/报文/文档证据支撑? +- 修复方案:是否引用了文档或案例中的标准方案? +- 数据准确性:引用的数值(耗时、错误率)是否与工具返回一致? + +### 第二轮:逻辑验证(Logic Check) +- 根因 → 症状的因果关系是否成立? +- 是否存在其他可能的根因(根因是否唯一)? +- 修复方案是否能真正解决根因? +- 修复方案是否会引入新问题? + +### 第三轮:完整性检查(Completeness Check) +- 根因分析章节不能为空 +- 证据链章节必须有具体引用(标注来源) +- 修复方案章节必须可执行(不是空话) +- 不确定的结论必须标注"低置信度" + +## 判决结果 + +{ + "verdict": "PASS|REVISE|REJECT", + "score": 0-100, + "issues": [ + { + "type": "fact_check|logic_check|completeness", + "severity": "error|warning", + "detail": "具体问题描述", + "evidence": "与哪个工具返回数据矛盾" + } + ], + "suggestion": "如果 REVISE,给出具体的修正建议" +} + +判决规则: +- PASS:无 error 级别问题,score >= 70 +- REVISE:有 error 级别问题但可修正,score 40-69 +- REJECT:证据严重不足或逻辑矛盾,score < 40 +- 如果发现疑似编造数据 → 直接 REJECT +``` + +--- + +## 三、Skill 体系设计 + +### 3.1 设计理念 + +``` +Skill = 标准化的诊断流程 + +为什么需要 Skill? +- 没有 Skill:Agent 自由发挥,流程不可控,质量不稳定 +- 有 Skill:固定步骤、明确输入输出、异常处理标准化 + +类比:医生看病的 SOP +- 不同症状走不同 SOP +- 每个 SOP 有固定检查项目 +- 异常情况有预案 +``` + +### 3.2 MVP 版本 Skill 清单 + +``` +/diagnose-by-orderid 按订单号一键诊断(最常用) +/diagnose-by-errorcode 按错误码分类诊断 +/diagnose-by-stacktrace 堆栈分析诊断(内部错误) +/quick-check 快速检查(只做基础排查) +``` + +### 3.3 Skill 定义结构 + +```yaml +skill: + name: diagnose-by-orderid + description: 根据订单号一键诊断故障 + applicable_fault_types: [EXTERNAL_API, INTERNAL_ERROR, DATABASE] + + input: + order_id: + required: true + description: 订单号 + validation: 格式校验 + + workflow: + - step: 1 + name: 查询订单信息 + tool: queryOrder + input_from: user_input + on_failure: abort + on_failure_message: "订单不存在或查询失败" + + - step: 2 + name: 获取链路追踪 + tool: queryTrace + input_from: step1.traceId + on_failure: skip + on_failure_message: "链路追踪数据缺失,继续排查" + + - step: 3 + name: 查询错误日志 + tool: queryLogs + input_from: step1.traceId + on_failure: skip + on_failure_message: "日志查询失败,继续排查" + + - step: 4 + name: 检索接口文档 + tool: searchDoc + input_from: step1.errorCode + step1.province + on_failure: skip + on_failure_message: "文档检索失败,使用已知信息" + + - step: 5 + name: 检索相似案例 + tool: recommendCase + input_from: step1.errorCode + step1.faultCategory + on_failure: skip + on_failure_message: "无相似案例" + + - step: 6 + name: 生成诊断报告 + action: generate_report + + guardrails: + - step1_failure: 终止执行,返回错误 + - step2_5_failure: 跳过继续,最终报告中标注缺失信息 + - any_step_timeout_30s: 超时终止 + - verifier_reject: 返回 planner 重新分析 + + output: + format: Markdown + sections: + - 基本信息 + - 根因分析 + - 证据链 + - 修复方案 + - 相似案例 +``` + +### 3.4 Skill 与 SubAgent 的映射 + +``` +/diagnose-by-orderid +├─ fault_category=EXTERNAL_API → ExternalApiSubAgent +├─ fault_category=INTERNAL_ERROR → InternalErrorSubAgent +└─ fault_category=DATABASE → DatabaseSubAgent + +/diagnose-by-errorcode +└─ fault_category=EXTERNAL_API → ExternalApiSubAgent + +/diagnose-by-stacktrace +└─ fault_category=INTERNAL_ERROR → InternalErrorSubAgent + +/quick-check +└─ fault_category=DATABASE → DatabaseSubAgent +``` + +--- + +## 四、Harness 控制层设计 + +### 4.1 三层架构 + +``` +┌──────────────────────────────────────────────────────────┐ +│ Harness 控制层 │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ 第一层:Prompt Engineering(提示词工程) │ +│ ├─ 系统提示词模板化 │ +│ ├─ 动态上下文注入(历史对话、诊断记录) │ +│ ├─ Few-shot 示例管理(不同故障类型的标准案例) │ +│ └─ 输出格式约束(JSON Schema / Markdown 模板) │ +│ │ +│ 第二层:Quality Gates(质量门禁) │ +│ ├─ 输入门禁:校验请求合法性 │ +│ ├─ 执行门禁:监控工具调用质量 │ +│ ├─ 输出门禁:校验报告质量 │ +│ └─ 安全门禁:禁止编造、SQL注入防护 │ +│ │ +│ 第三层:Interrupt(中断机制) │ +│ ├─ 自动中断:连续失败、超时、置信度过低 │ +│ ├─ 人工确认:高危建议、敏感操作 │ +│ └─ 条件降级:部分失败时跳过继续 │ +│ │ +└──────────────────────────────────────────────────────────┘ +``` + +--- + +### 4.2 Prompt Engineering(提示词工程) + +#### 4.2.1 提示词文件结构 + +``` +src/main/resources/prompts/ +├── system/ +│ ├── supervisor-system.md # Supervisor Agent 提示词 +│ ├── planner-system.md # Planner Agent 提示词 +│ ├── executor-external-api.md # ExternalApiSubAgent 提示词 +│ ├── executor-internal-error.md # InternalErrorSubAgent 提示词 +│ ├── executor-database.md # DatabaseSubAgent 提示词 +│ └── verifier-system.md # Verifier Agent 提示词 +│ +├── few-shot/ +│ ├── external-api-case1.md # 外部接口故障示例1 +│ ├── internal-error-case1.md # 内部错误示例1 +│ └── database-case1.md # 数据库问题示例1 +│ +├── templates/ +│ └── diagnosis-report.md # 报告模板 +│ +└── rules/ + ├── output-rules.md # 输出格式规则 + └── safety-rules.md # 安全规则 +``` + +#### 4.2.2 动态上下文注入 + +``` +每次 Prompt 构建时,动态注入: + +1. 用户输入(orderId / traceId / errorDescription) +2. 历史对话上下文(Redis 中的最近 3 轮对话) +3. 当前诊断记录(diagnosis_record 的已有信息) +4. 相似案例(case_library 中的 Top 3 案例) +5. Few-shot 示例(根据 fault_category 选择) +``` + +--- + +### 4.3 Quality Gates(质量门禁) + +#### 4.3.1 门禁清单 + +``` +输入门禁(诊断前): +├─ Gate 1: order_id / trace_id 格式校验 +├─ Gate 2: 输入参数不能为空 +├─ Gate 3: 5分钟内同一订单 → 返回缓存结果 +├─ Gate 4: SQL 注入检测(queryOrder 工具) +└─ Gate 5: 敏感信息脱敏检查 + +执行门禁(诊断中): +├─ Gate 6: 工具参数合法性校验 +├─ Gate 7: 工具返回结果非空校验 +├─ Gate 8: 工具调用超时检查(10 秒) +├─ Gate 9: 脱敏校验(返回内容中的手机号、身份证) +└─ Gate 10: 工具调用次数限制(同一工具最多 5 次) + +输出门禁(诊断后): +├─ Gate 11: 报告章节完整性(4 章节不全 → 不通过) +├─ Gate 12: 置信度阈值检查(< 60 → 标记"低置信度") +├─ Gate 13: 数据真实性校验(引用的错误码是否真实存在于 Milvus) +├─ Gate 14: 禁止编造检测(报告中的数据 vs 工具返回数据对比) +└─ Gate 15: 报告长度检查(不能太短,"无法分析"之类的不通过) +``` + +#### 4.3.2 门禁实现结构 + +``` +src/main/java/com/superbiz/agent/ +├── harness/ +│ ├── gate/ +│ │ ├── GateResult.java # 门禁结果 +│ │ ├── InputGates.java # 输入门禁 +│ │ ├── ExecutionGates.java # 执行门禁 +│ │ ├── OutputGates.java # 输出门禁 +│ │ └── SecurityGates.java # 安全门禁 +│ │ +│ ├── interrupt/ +│ │ ├── InterruptDecision.java # 中断决策 +│ │ ├── InterruptService.java # 中断服务 +│ │ └── InterruptStrategy.java # 中断策略 +│ │ +│ └── prompt/ +│ ├── PromptTemplate.java # Prompt 模板 +│ ├── PromptBuilder.java # Prompt 构建器 +│ └── ContextInjector.java # 上下文注入器 +``` + +--- + +### 4.4 Interrupt(中断机制) + +#### 4.4.1 中断分类 + +``` +自动中断(无需人工): +├─ 工具连续失败 3 次 → 终止,标记状态 +├─ 工具调用超时 10 秒 → 终止,记录超时 +├─ 全局执行超时 30 秒 → 终止,返回中间结果 +├─ 置信度 < 60 → 终止,标记"需要人工审核" +└─ SQL 注入风险 → 紧急终止,记录安全事件 + +条件降级(继续执行): +├─ 文档检索为空 → 跳过,标注"文档缺失" +├─ 案例推荐为空 → 跳过,标注"无相似案例" +├─ 链路追踪数据缺失 → 跳过,基于日志继续 +└─ 日志查询返回空 → 跳过,提示用户补充信息 + +人工确认(弹窗等待): +├─ 删除文档操作 → 二次确认 +├─ 置信度 < 60 的报告 → 人工审核后发布 +├─ 高危修复建议(如重启服务)→ 二次确认 +└─ 重新索引操作 → 确认对话框 +``` + +#### 4.4.2 中断处理流程 + +``` +工具调用 + ↓ +中断检查 + ↓ +├─ 连续失败 3 次? → 自动终止,返回部分结果 + 错误说明 +├─ 超时? → 自动终止,返回中间状态 + 耗时信息 +├─ 置信度低? → 发起人工确认(标记状态,等待审核) +├─ 高危操作? → 弹窗确认 +└─ 正常 → 继续执行 +``` + +--- + +## 五、技术实现(基于 Spring AI Alibaba) + +### 5.1 框架能力复用 + +```java +// 框架已提供,直接使用 +✅ DashScopeChatModel // 大模型调用 +✅ DashScopeEmbeddingModel // 向量化 +✅ ReactAgent // Agent 基类 +✅ SupervisorAgent // 多 Agent 调度 +✅ @Tool 注解 // 工具注册 +✅ ToolCallbackProvider // 工具发现 +``` + +### 5.2 Agent 实现方式 + +```java +// Supervisor Agent(框架提供) +SupervisorAgent supervisor = SupervisorAgent.builder() + .name("diagnosis_supervisor") + .description("负责调度 Planner / SubAgent / Verifier") + .model(chatModel) + .systemPrompt(supervisorPrompt) + .subAgents(List.of(plannerAgent, verifierAgent, + externalApiSubAgent, internalErrorSubAgent, databaseSubAgent)) + .build(); + +// Planner Agent +ReactAgent planner = ReactAgent.builder() + .name("planner_agent") + .description("负责分析问题、制定策略、选择 SubAgent") + .model(chatModel) + .systemPrompt(plannerPrompt) + .outputKey("planner_plan") + .build(); + +// SubAgent 示例(ExternalApiSubAgent) +ReactAgent externalApiSubAgent = ReactAgent.builder() + .name("external_api_sub_agent") + .description("外部接口故障专家") + .model(chatModel) + .systemPrompt(externalApiPrompt) + .methodTools(externalApiTools) // 专属工具集 + .tools(new ToolCallback[]{searchDoc, queryLogs, queryTrace, queryOrder}) + .build(); + +// Verifier Agent +ReactAgent verifier = ReactAgent.builder() + .name("verifier_agent") + .description("负责验证诊断报告的准确性") + .model(chatModel) + .systemPrompt(verifierPrompt) + .outputKey("verifier_result") + .build(); +``` + +### 5.3 Skill 实现方式 + +```java +// Skill 定义接口 +public interface SkillDefinition { + String getName(); + String getDescription(); + List getWorkflow(); + List getGuardrails(); + SkillOutput execute(SkillInput input); +} + +// Skill 注册中心 +@Component +public class SkillRegistry { + private final Map skills = new HashMap<>(); + + public void register(SkillDefinition skill) { + skills.put(skill.getName(), skill); + } + + public SkillDefinition get(String name) { + return skills.get(name); + } + + public List getByFaultType(String faultCategory) { + // 根据故障类型推荐合适的 Skill + } +} + +// Skill 示例 +@Component +public class DiagnoseByOrderIdSkill implements SkillDefinition { + @Override + public String getName() { return "diagnose-by-orderid"; } + + @Override + public List getWorkflow() { + return Arrays.asList( + new SkillStep(1, "查询订单", "queryOrder", FailStrategy.ABORT), + new SkillStep(2, "查询链路", "queryTrace", FailStrategy.SKIP), + new SkillStep(3, "查询日志", "queryLogs", FailStrategy.SKIP), + new SkillStep(4, "检索文档", "searchDoc", FailStrategy.SKIP), + new SkillStep(5, "推荐案例", "recommendCase", FailStrategy.SKIP), + new SkillStep(6, "生成报告", null, FailStrategy.NONE) + ); + } + + // ... +} +``` + +--- + +## 六、面试话术 + +### 6.1 Agent 架构 + +> "这个系统的核心是 5 个 Agent 协作: +> +> - **Supervisor** 是总指挥,负责调度 +> - **Planner** 是分诊台 + 军师,分析问题类型,制定策略,选择合适的 SubAgent +> - **3 个 SubAgent** 是专科医生,各有专长 +> - **Verifier** 是质检员,验证诊断报告的准确性 +> +> 不是一个人干所有活,而是团队协作, +> 类比医院的会诊制度。" + +### 6.2 Skill 体系 + +> "诊断流程太复杂,不能让 Agent 自由发挥。我设计了 Skill 体系: +> +> 每个 Skill 固定了 6 个步骤,每步调用哪个工具、传什么参数、失败怎么处理, +> 都定义清楚了。 +> +> 不同故障类型走不同 Skill: +> - 外部接口故障走 /diagnose-by-orderid +> - 内部错误走 /diagnose-by-stacktrace +> +> 就像医生看病的 SOP,流程标准化后,质量才能稳定。" + +### 6.3 Harness 控制 + +> "Harness 是 Agent 的安全带,三层控制: +> +> **Prompt Engineering**:不是写死一个 Prompt,而是模板化 + 动态注入。 +> 不同 SubAgent 有专属 Prompt,不同阶段注入不同上下文。 +> +> **Quality Gates**:15 个门禁点覆盖输入→执行→输出全流程。 +> 最关键的是输出门禁——报告必须通过事实核查才能发布。 +> +> **Interrupt**:分级中断策略。自动中断(连续失败、超时)、 +> 条件降级(跳过非关键步骤)、人工确认(高危操作)。 +> +> 这三层保证 Agent 不会胡说八道,出了问题有据可查。" + +--- + +## 七、MVP 版本总结 + +### 7.1 Agent 清单 + +| Agent | 角色 | 实现方式 | +|-------|------|---------| +| SupervisorAgent | 总指挥 | Spring AI Alibaba SupervisorAgent | +| PlannerAgent | 军师+分诊 | ReactAgent | +| ExternalApiSubAgent | 接口专家 | ReactAgent + 专属工具 | +| InternalErrorSubAgent | 代码专家 | ReactAgent + 专属工具 | +| DatabaseSubAgent | 数据库专家 | ReactAgent + 专属工具 | +| VerifierAgent | 质检员 | ReactAgent | + +### 7.2 Skill 清单 + +| Skill | 适用场景 | 对应 SubAgent | +|-------|---------|---------------| +| /diagnose-by-orderid | 按订单号诊断 | 自动选择 | +| /diagnose-by-errorcode | 按错误码诊断 | ExternalApiSubAgent | +| /diagnose-by-stacktrace | 堆栈分析 | InternalErrorSubAgent | +| /quick-check | 快速检查 | DatabaseSubAgent | + +### 7.3 Harness 清单 + +| 层 | 数量 | 说明 | +|----|------|------| +| Prompt 模板 | 6 个系统提示词 + 3 个 Few-shot | 每个 Agent 一个 | +| Quality Gates | 15 个门禁 | 输入5 + 执行5 + 输出5 | +| Interrupt | 4 自动 + 4 降级 + 3 人确 | 分级中断 | + +--- + +## 八、与框架的关系 + +``` +Spring AI Alibaba 提供: +✅ DashScope 大模型调用 +✅ ReactAgent 基类 +✅ SupervisorAgent 多 Agent 调度 +✅ @Tool 注解工具注册 +✅ 向量化(Embedding) + +我们在此基础上增强: +🆕 SubAgent 模式(专科医生分工) +🆕 Verifier Agent(独立验证角色) +🆕 Skill 体系(标准化诊断流程) +🆕 Harness 三层控制(安全+质量) +🆕 混合 RAG 检索(提升准确率) + +不是重复造轮子,是对框架的增强和工程化! +``` + +--- + +## 九、Skills 知识底座(渐进式披露) + +### 9.1 设计理念 + +``` +问题: +把全部 Skill 一次性加载给 Agent +→ Agent 信息过载,决策变慢,容易选错流程 + +解决方案:渐进式披露 +→ 根据诊断进度,逐步释放需要的知识 +→ 就像你不会给实习生看所有 SOP, + 而是根据他当前的任务,逐步放出需要的知识 +``` + +### 9.2 三层知识结构 + +``` +┌──────────────────────────────────────────────────────────┐ +│ Skill 知识底座(三层渐进式) │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ L1:通用诊断 Skill(所有 Agent 始终可见) │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ /quick-check 快速检查(首个诊断步骤) │ │ +│ │ /safety-rules 安全规则(禁止编造、脱敏) │ │ +│ │ /output-format 输出格式要求(Markdown 模板) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ↓ Planner 分析 fault_category │ +│ L2:领域 Skill(按故障类别加载) │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ EXTERNAL_API → /diagnose-by-orderid │ │ +│ │ → /diagnose-by-errorcode │ │ +│ │ INTERNAL_ERROR→ /diagnose-by-stacktrace │ │ +│ │ DATABASE → /diagnose-sql-analysis │ │ +│ │ → /diagnose-deadlock │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ↓ 执行中触发具体模式 │ +│ L3:专家 Skill(按识别到的模式触发) │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ NPE 模式触发 → /diagnose-npe-pattern │ │ +│ │ 死锁模式触发 → /diagnose-deadlock-pattern │ │ +│ │ 广东社保模式触发 → /diagnose-guangdong-social-sec │ │ +│ │ 签名失败模式触发 → /diagnose-signature-failure │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +└──────────────────────────────────────────────────────────┘ +``` + +### 9.3 加载逻辑 + +``` +Planner 启动时: + ✅ L1 始终加载(4 个通用 Skill) + +Planner 分析 fault_category=EXTERNAL_API 时: + ✅ 额外加载 L2 中 EXTERNAL_API 相关的 2 个 Skill + +Executor 执行中发现 NPE 异常模式时: + ✅ 触发加载 L3 中 /diagnose-npe-pattern + ✅ 该 Skill 会指导如何分析堆栈、定位代码行 + +Executor 执行中发现广东社保 40003 错误时: + ✅ 触发加载 L3 中 /diagnose-guangdong-social-sec + ✅ 该 Skill 包含广东省社保接口的特有字段和常见错误 +``` + +### 9.4 面试话术 + +> "Skill 不是一次性全给 Agent,而是渐进式披露。 +> +> L1 通用 Skill 始终可见,保证基础安全规则和输出规范。 +> L2 领域 Skill 按故障类别按需加载,比如外部接口故障时 +> 才加载接口文档对比相关的 Skill。 +> L3 专家 Skill 是最精密的,只有 Agent 识别到特定模式时才触发, +> 比如检测到 NPE 模式,自动加载空指针分析专家 Skill。 +> +> 这样做的好处是:Agent 不会被信息淹没, +> 每个阶段只看到该阶段需要的知识,决策更精准。" + +--- + +## 十、SubAgent 进程隔离(防止故障扩散) + +### 10.1 设计理念 + +``` +问题: +所有 SubAgent 在同一个 JVM 进程中 +→ 一个 SubAgent OOM,所有诊断都挂了 +→ 一个 SubAgent 死循环,整个系统卡死 +→ CPU/内存竞争,互相影响 + +解决方案:每个 SubAgent 独立进程,K8s Pod 隔离 +``` + +### 10.2 隔离架构 + +``` +┌──────────────────────────────────────────────────────────┐ +│ Kubernetes 集群 │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ Supervisor Pod(调度器) replicas: 1 │ │ +│ │ resources: 256Mi / 0.5 CPU │ │ +│ └──────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ Planner Pod(规划器) replicas: 1 │ │ +│ │ resources: 256Mi / 0.5 CPU │ │ +│ └──────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ SubAgent 容器组(独立 Pod,独立扩缩) │ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │ │ +│ │ │External API │ │Internal Err │ │ Database │ │ │ +│ │ │SubAgent Pod │ │SubAgent Pod │ │SubAgent Pod│ │ │ +│ │ ├─────────────┤ ├─────────────┤ ├────────────┤ │ │ +│ │ │ replicas: 3 │ │ replicas: 2 │ │ replicas: 2│ │ │ +│ │ │ 512Mi/1 CPU │ │ 512Mi/1 CPU │ │ 512Mi/1 CPU│ │ │ +│ │ │ 故障不扩散 │ │ 故障不扩散 │ │ 故障不扩散 │ │ │ +│ │ │ 独立扩缩 │ │ 独立扩缩 │ │ 独立扩缩 │ │ │ +│ │ └─────────────┘ └─────────────┘ └────────────┘ │ │ +│ │ │ │ +│ └──────────────────────────────────────────────────┘ │ +│ ↓ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ Verifier Pod(验证器) replicas: 1 │ │ +│ │ resources: 256Mi / 1 CPU │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ MCP Tool Server 容器组(独立服务) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │ DB Svr │ │Log Svr │ │Doc Svr │ ... │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +└──────────────────────────────────────────────────────────┘ +``` + +### 10.3 隔离级别 + +``` +资源隔离: +├─ 每个 SubAgent 独立 CPU/Memory Request & Limit +├─ ExternalAPI SubAgent:流量高 → replicas=3, 1CPU +├─ InternalError SubAgent:流量低 → replicas=2, 0.5CPU +└─ 不会互相抢占资源 + +故障隔离: +├─ DatabaseSubAgent OOM → K8s 自动重启该 Pod +├─ 其他两个 SubAgent 不受影响 +├─ Supervisor 检测到 Pod 重启 → 自动切换请求到新 Pod +└─ 故障半径:1 个 Pod(而非整个系统) + +部署隔离: +├─ 更新 ExternalApiSubAgent → 滚动更新,不中断服务 +├─ 不影响其他 SubAgent +└─ 金丝雀发布:10% 流量 → 验证 → 100% + +安全隔离: +├─ DatabaseSubAgent 可以访问 DB 网络 +├─ ExternalApiSubAgent 不能访问 DB 网络 +└─ Network Policy 精细化控制 +``` + +### 10.4 MVP 实现方式 + +``` +Phase 1(当前): +- 所有 SubAgent 在同一 JVM,但代码层面做了接口隔离 +- 预留 K8s 部署配置模板 + +Phase 2(生产化): +- 独立 Pod 部署 +- Helm Chart 管理 +- HPA 自动扩缩 + +面试时可以说: +"当前 MVP 版本在代码层面做了接口隔离, +生产环境可以通过 K8s Pod 实现进程级隔离。 +部署配置已经预留好,切换只需修改 Helm values。" +``` + +### 10.5 面试话术 + +> "SubAgent 之间进程隔离,就像微服务架构。 +> +> 一个 DatabaseSubAgent 如果因为慢查询导致 OOM, +> K8s 会自动重启它,而 ExternalApiSubAgent 和 +> InternalErrorSubAgent 完全不受影响。 +> +> 每个 SubAgent 可以独立扩缩: +> 外部接口故障高峰期,ExternalApiSubAgent 扩容到 5 个副本, +> 其他 SubAgent 保持 2 个副本。资源利用更精准。 +> +> 更新一个 SubAgent 也不需要重启整个系统, +> 滚动更新 + 金丝雀发布,0 停机。" + +--- + +## 十一、回退路由(不让一次失败摧毁整个诊断) + +### 11.1 设计理念 + +``` +问题: +专项 SubAgent 失败 → 诊断终止 → 返回"系统错误" +用户得到的是一个无法使用的错误信息 + +解决方案:多级回退路由 +→ 永远不会返回"系统错误" +→ 最差给用户"请人工介入" + 已有证据 +→ 每级回退都有价值 +``` + +### 11.2 四级回退路由 + +``` +用户输入:orderId=202406150001 + +┌──────────────────────────────────────────────────────────┐ +│ Planner 选择 SubAgent │ +└──────┬───────────────────────────────────────────────────┘ + │ fault_category=EXTERNAL_API + ↓ +┌──────────────────────────────────────────────────────────┐ +│ L0:首选路由 │ +│ ExternalApiSubAgent(接口专家) │ +│ 预期:对比文档 → 检查参数 → 定位根因 │ +└──────┬───────────────────────────────────────────────────┘ + │ ❌ 执行失败(工具连续失败/超时) + ↓ +┌──────────────────────────────────────────────────────────┐ +│ L1:第1级回退 │ +│ InternalErrorSubAgent(换个角度) │ +│ 也许"外部接口故障"的表象下是内部空指针 │ +│ 重新诊断:查日志 → 分析堆栈 │ +└──────┬───────────────────────────────────────────────────┘ + │ ❌ 仍然失败 + ↓ +┌──────────────────────────────────────────────────────────┐ +│ L2:第2级回退 │ +│ GenericDiagnosisSubAgent(通用诊断) │ +│ 不做专项分析,基于已有证据给出推断性结论 │ +│ 标注"低置信度" │ +└──────┬───────────────────────────────────────────────────┘ + │ ❌ 仍然失败 + ↓ +┌──────────────────────────────────────────────────────────┐ +│ L3:第3级回退 │ +│ 基于缓存的快速响应 │ +│ 查询相似订单的历史诊断结果 │ +│ "订单 202406150001 的错误码 40003,类似订单 xxx 的根因是…" │ +│ 标注"缓存推断,置信度低" │ +└──────┬───────────────────────────────────────────────────┘ + │ ❌ 仍然失败 + ↓ +┌──────────────────────────────────────────────────────────┐ +│ L4:降级报告 │ +│ 返回: │ +│ "无法自动诊断,请人工介入" │ +│ + 已收集的证据(订单信息、部分日志、已知错误码) │ +│ + 建议人工排查方向 │ +│ │ +│ 永不返回"系统错误"! │ +└──────────────────────────────────────────────────────────┘ +``` + +### 11.3 回退决策规则 + +``` +触发回退的条件: +├─ SubAgent 连续 3 次工具调用失败 → L1 回退 +├─ SubAgent 执行超时 30 秒 → L1 回退 +├─ Verifier 判定 REJECT → L1 回退 +├─ L1 回退后仍然失败 → L2 回退 +├─ L2 回退后仍然失败 → L3 回退 +└─ L3 回退后仍然失败 → L4 降级 + +不触发回退的条件: +├─ 只是文档检索为空 → 跳过该步骤,继续执行 +├─ 只是案例推荐为空 → 标注"无相似案例",继续执行 +└─ Verifier 判定 REVISE → Planner 修正,不换 SubAgent +``` + +### 11.4 面试话术 + +> "诊断系统最重要的不是'多准确',而是'多可靠'。 +> +> 我设计了 4 级回退路由: +> +> 第一级,换 SubAgent。外部接口专家不行,换内部错误专家试试, +> 也许故障表象是外部 API 错误,根因其实是内部空指针。 +> +> 第二级,换通用模式。不做专项分析,基于已有证据给推断结论。 +> +> 第三级,换历史经验。查相似订单的已有诊断结果。 +> +> 第四级,降级服务。返回'请人工介入',但附带已收集的所有证据, +> 让运维人员不需要从零开始排查。 +> +> 核心原则:永不返回'系统错误',每级回退都有价值输出。" + +--- + +## 十二、进化引擎(从每次诊断中学习) + +### 12.1 设计理念 + +``` +问题: +系统只是"被使用",不会"变聪明" +每次诊断都从零开始,历史经验只有案例推荐 + +解决方案:全自动进化引擎 +→ 高频模式 → 自动创建 Skill +→ 低效 Prompt → 自动优化 +→ 低质量案例 → 自动降权 +→ 过时文档 → 自动提醒更新 +``` + +### 12.2 四大进化模块 + +``` +┌──────────────────────────────────────────────────────────┐ +│ 进化引擎 │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ 模块1:模式识别引擎 │ │ +│ │ │ │ +│ │ 输入:过去 30 天的 diagnosis_record │ │ +│ │ 规则: │ │ +│ │ ├─ 同一 error_code 出现 > 50 次 → 高优先级模式 │ │ +│ │ ├─ 同一 fault_target 出现 > 30 次 → 热点接口 │ │ +│ │ ├─ 新出现的 error_code 组合 → 新故障模式 │ │ +│ │ └─ 聚类相似根因的案例 → 生成通用解决方案 │ │ +│ │ │ │ +│ │ 输出: │ │ +│ │ ├─ 自动创建 L3 专家 Skill │ │ +│ │ ├─ 自动归类新 fault_category │ │ +│ │ └─ 自动生成 Few-shot 示例 │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ 模块2:Prompt 自优化 │ │ +│ │ │ │ +│ │ 输入:每个 Prompt 变体的诊断准确率 │ │ +│ │ 规则: │ │ +│ │ ├─ A/B 测试:10% 流量用 Prompt A,10% 用 Prompt B │ │ +│ │ ├─ 统计 7 天内的准确率差异 │ │ +│ │ ├─ 显著提升(>5%)→ 全量切换 │ │ +│ │ └─ 无显著差异 → 保留当前版本 │ │ +│ │ │ │ +│ │ 输出: │ │ +│ │ ├─ 自动切换到最优 Prompt │ │ +│ │ ├─ 记录 Prompt 变更历史(可回退) │ │ +│ │ └─ 生成优化报告 │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ 模块3:案例质量自动评估 │ │ +│ │ │ │ +│ │ 输入:case_library 的引用和反馈数据 │ │ +│ │ 规则: │ │ +│ │ ├─ reference_count 高 + 关联诊断 feedback=useful │ │ +│ │ │ → 提升权重(score +10) │ │ +│ │ ├─ reference_count 高 + 关联诊断 feedback=not_useful │ │ +│ │ │ → 降低权重(score -20),标记人工审核 │ │ +│ │ ├─ 创建 > 90 天的案例无引用 → 降低权重(时间衰减) │ │ +│ │ └─ 创建 > 180 天的案例无引用 → 自动归档 │ │ +│ │ │ │ +│ │ 输出: │ │ +│ │ ├─ 案例权重自动调整 │ │ +│ │ ├─ 低质量案例自动归档 │ │ +│ │ └─ 高质量案例置顶 │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ 模块4:知识自动更新 │ │ +│ │ │ │ +│ │ 规则: │ │ +│ │ ├─ 文档 30 天未更新 + 引用率下降 → 提醒更新 │ │ +│ │ ├─ 新接口上线 + 文档缺失 → 提醒导入 │ │ +│ │ ├─ 错误码模式变更 → 提醒复查文档 │ │ +│ │ └─ 案例老化 → 自动归档,释放存储 │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +└──────────────────────────────────────────────────────────┘ +``` + +### 12.3 MVP 实现方式 + +``` +Phase 1(当前): +✅ 案例自动生成(diagnosis_record → case_library) +✅ reference_count 简单排序 +✅ 用户 feedback 字段 + +Phase 2(进化): +❌ 模式识别引擎(定时任务,每周执行) +❌ Prompt A/B 测试框架 +❌ 案例自动升降权 +❌ 文档过期检测 + +面试时可以说: +"当前 MVP 已实现案例自动生成和反馈收集, +为进化引擎储备了数据基础。 +Phase 2 会增加模式识别和 Prompt 自优化, +这些是自动化运行的,不需要人工干预。" +``` + +### 12.4 面试话术 + +> "系统不只是'被使用',而是'在进化'。每次诊断都是一次学习。 +> +> **模式识别**:如果同一个错误码出现了 50 次以上, +> 系统自动创建一个 L3 专家 Skill,包含处理这类问题的标准流程。 +> +> **Prompt 自优化**:A/B 测试不同 Prompt 变体, +> 自动统计哪个准确率更高,7 天后自动切换到最优版本。 +> 不需要人工分析"哪个 Prompt 更好"。 +> +> **案例自评估**:引用率高 + 反馈好的案例自动提权排在前面, +> 长期无人引用的案例自动归档。质量越高越靠前,劣质案例自然淘汰。 +> +> **知识更新提醒**:文档 30 天没更新?引用率下降? +> 自动提醒运维复查。新接口上线没文档?自动提醒导入。 +> +> 最重要的是,这些都是自动化的,系统越运行越聪明。" + +--- + +## 十三、MCP 协议化工具(标准化连接) + +### 13.1 设计理念 + +``` +问题: +工具写在 Java 代码里(@Tool 注解) +→ 工具和 Agent 紧耦合 +→ 换工具需要改 Agent 代码 +→ 新工具需要重新部署 Agent + +解决方案:MCP 协议标准化 +→ 工具作为独立 MCP Server 运行 +→ Agent 通过 MCP Client 发现和调用工具 +→ 类似 USB:换工具不需要改 Agent +``` + +### 13.2 MCP 架构 + +``` +┌──────────────────────────────────────────────────────────┐ +│ Agent 层(MCP Client) │ +│ Supervisor / Planner / SubAgent / Verifier │ +│ │ +│ 通过 MCP 协议发现和调用工具 │ +│ 不关心工具的实现细节 │ +└──────┬───────────────────────────────────────────────────┘ + │ MCP 协议(标准 JSON-RPC) + ↓ +┌──────────────────────────────────────────────────────────┐ +│ MCP Tool Server 层(独立服务) │ +├──────────────────────────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ Database MCP Server │ │ +│ │ ├─ queryOrder:查询订单 │ │ +│ │ ├─ queryUser:查询用户 │ │ +│ │ ├─ queryConfig:查询配置 │ │ +│ │ └─ 安全:只读 + SQL注入防护 + 超时控制 │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ Log MCP Server │ │ +│ │ ├─ queryLogsByTraceId:按链路查日志 │ │ +│ │ ├─ queryLogsByKeyword:按关键词查日志 │ │ +│ │ └─ 后端可切换:ES / Loki / SLS │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ Document MCP Server │ │ +│ │ ├─ searchDoc:检索接口文档 │ │ +│ │ ├─ indexDoc:索引新文档 │ │ +│ │ └─ 后端:Milvus + api_document │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ Trace MCP Server │ │ +│ │ ├─ queryTrace:查询调用链 │ │ +│ │ └─ 后端:Jaeger / SkyWalking(可切换) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ Case MCP Server │ │ +│ │ ├─ recommendCase:推荐相似案例 │ │ +│ │ └─ 后端:MySQL + Milvus(混合检索) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ │ +└──────────────────────────────────────────────────────────┘ +``` + +### 13.3 MCP 协议化的优势 + +``` +优势1:工具可发现 +├─ Agent 启动时自动扫描所有 MCP Server +├─ 通过 mcp.listTools() 获取所有可用工具 +└─ 新工具上线 → Agent 自动发现,无需重启 + +优势2:工具可替换 +├─ 换 ES 为 Loki → 只改 Log MCP Server 实现 +├─ 换 Jaeger 为 SkyWalking → 只改 Trace MCP Server 实现 +└─ Agent 代码完全不变 + +优势3:工具可组合 +├─ 不同 SubAgent 使用不同的工具子集 +├─ ExternalApiSubAgent:Document + Log + Trace Server +├─ DatabaseSubAgent:Database + Log + Trace Server +└─ 权限隔离:不同 SubAgent 只能调用授权的 Server + +优势4:工具可独立部署 +├─ Document MCP Server 流量大 → 独立扩容 5 个副本 +├─ 不影响其他 Server +└─ 每个 Server 独立版本管理和灰度发布 + +优势5:跨语言支持 +├─ Agent 用 Java(Spring AI Alibaba) +├─ Log MCP Server 可以用 Go(性能更好) +├─ Document MCP Server 可以用 Python(ML 生态好) +└─ MCP 协议统一 JSON-RPC,不限制语言 +``` + +### 13.4 MVP 实现方式 + +``` +Phase 1(当前): +✅ @Tool 注解直接在 Java 代码中 +✅ 工具接口抽象(预留 MCP 切换能力) +✅ Spring AI MCP Client 已集成(pom.xml 已有依赖) + +Phase 2(生产化): +✅ 每个 MCP Server 独立 Spring Boot 应用 +✅ 独立 Docker 镜像 +✅ K8s 独立部署和扩缩 + +面试时可以说: +"当前 MVP 用 @Tool 注解快速实现, +但工具接口层已经做了抽象。 +生产化时每个 Server 独立部署, +Agent 通过 MCP 协议发现和调用。Agent 代码完全不变。" +``` + +### 13.5 面试话术 + +> "工具不是写死在 Agent 代码里的,而是通过 MCP 协议标准化暴露。 +> +> 就像 USB 接口:你换一个鼠标,不需要改装电脑。 +> 我换 ES 为 Loki,只需要改 Log MCP Server 的实现, +> Agent 代码完全不动。 +> +> 每个 MCP Server 是独立的服务: +> - 可以独立扩缩(文档检索流量大,Document Server 扩到 5 个副本) +> - 可以独立部署(更新 Log Server 不需要重启 Agent) +> - 可以用不同语言写(Python 写文档解析,Go 写日志查询,Java 写 Agent) +> +> 新工具上线也是即插即用:部署一个新的 MCP Server, +> Agent 通过协议自动发现,零代码变更。" + +--- + +## 十四、生产级全景图 + +### 14.1 最终架构总览 + +``` + ┌──────────────┐ + │ 用户输入 │ + └──────┬───────┘ + │ + ┌──────────────────────┴──────────────────────────────┐ + │ K8s 集群 │ + ├──────────────────────────────────────────────────────┤ + │ │ + │ ┌─────────────────────────────────────────────────┐ │ + │ │ Supervisor Pod(调度者) │ │ + │ │ + 回退路由控制 │ │ + │ └───────────────┬─────────────────────────────────┘ │ + │ │ │ + │ ┌───────────────┴─────────────────────────────────┐ │ + │ │ Planner Pod(规划者 + 分诊) │ │ + │ │ + Skill 渐进式加载 │ │ + │ └───────────────┬─────────────────────────────────┘ │ + │ │ │ + │ ┌───────────────┴─────────────────────────────────┐ │ + │ │ SubAgent 容器组(进程隔离,独立扩缩) │ │ + │ │ │ │ + │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ + │ │ │External │ │Internal │ │Database │ │ │ + │ │ │API Pod │ │Error Pod │ │Pod │ │ │ + │ │ │×3 reps │ │×2 reps │ │×2 reps │ │ │ + │ │ └──────────┘ └──────────┘ └──────────┘ │ │ + │ │ │ │ + │ │ ┌──────────────────────────────────┐ │ │ + │ │ │ GenericSubAgent(回退路由L2) │ │ │ + │ │ └──────────────────────────────────┘ │ │ + │ └───────────────┬─────────────────────────────────┘ │ + │ │ │ + │ ┌───────────────┴─────────────────────────────────┐ │ + │ │ Verifier Pod(验证者 + 质量门禁) │ │ + │ └───────────────┬─────────────────────────────────┘ │ + │ │ │ + │ ┌───────────────┴─────────────────────────────────┐ │ + │ │ MCP Tool Server 层(独立服务,独立扩缩) │ │ + │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ │ + │ │ │ DB │ │ Log │ │ Doc │ │Trace │ │ Case ││ │ + │ │ │Server│ │Server│ │Server│ │Server│ │Server││ │ + │ │ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘│ │ + │ └──────────────────────────────────────────────────┘ │ + │ │ + │ ┌──────────────────────────────────────────────────┐ │ + │ │ 进化引擎(后台任务) │ │ + │ │ ├─ 模式识别(每周) │ │ + │ │ ├─ Prompt 自优化(AB 测试) │ │ + │ │ ├─ 案例质量评估(每天) │ │ + │ │ └─ 知识更新提醒(每周) │ │ + │ └──────────────────────────────────────────────────┘ │ + │ │ + └──────────────────────────────────────────────────────┘ +``` + +### 14.2 技术栈全景 + +``` +应用框架: +├─ Spring Boot 3.2 +├─ Spring AI Alibaba 1.1.0(Agent 框架) +└─ DashScope(大模型 + 向量化) + +数据存储: +├─ MySQL 8.0+(元数据 + 业务数据) +├─ Redis 6.0+(会话 + 缓存) +└─ Milvus 2.6+(向量检索) + +基础设施: +├─ Kubernetes(容器编排 + 进程隔离) +├─ Helm(部署管理) +└─ Prometheus + Grafana(监控) + +协议标准: +├─ MCP(工具协议层) +└─ REST + SSE(API 层) +``` + +--- + +## 十五、更新面试话术 + +### 15.1 完整架构描述(2 分钟版) + +> "这是一个**生产级的、可持续进化的线上诊断 Agent 系统**,包含 6 层设计: +> +> **第一层,Agent 协作**:5 个 Agent——Supervisor 调度、Planner 分诊、 +> 3 个 SubAgent 专科诊断、Verifier 验证。SubAgent 进程隔离, +> 一个挂掉不影响其他的,K8s 自动拉起。 +> +> **第二层,Skill 知识底座**:渐进式披露,三层知识结构。 +> 通用 Skill 始终可见,领域 Skill 按故障类别加载, +> 专家 Skill 按识别到的模式触发。Agent 不会被信息淹没。 +> +> **第三层,回退路由**:4 级回退——专项 SubAgent → 通用 SubAgent → +> 缓存历史 → 降级报告。永不返回'系统错误',最差给用户'请人工介入'加证据。 +> +> **第四层,Harness 安全带**:Prompt Engineering + 15 个 Quality Gates + +> 分级中断。保证 Agent 不会胡说八道。 +> +> **第五层,MCP 协议化工具**:工具作为独立服务运行,像 USB 一样即插即用。 +> 换工具不改 Agent 代码,新工具上线自动发现。 +> +> **第六层,进化引擎**:模式识别 → 自动创建 Skill,Prompt A/B 测试自动选优, +> 案例自动升降权。系统越运行越聪明。" +``` + +### 15.2 面试追问应对 + +| 追问 | 回答要点 | +|------|---------| +| "Agent 怎么保证不编造数据?" | Verifier 事实核查 + Output Gate 数据真实性校验 | +| "一个 SubAgent 挂了怎么办?" | 进程隔离 + K8s 自动重启 + 回退路由切换到其他 SubAgent | +| "工具换了怎么改代码?" | MCP 协议化,换工具只改 Server 实现,Agent 代码不动 | +| "系统怎么越来越准?" | 进化引擎:模式识别创建 Skill + Prompt A/B 测试自动选优 | +| "准确率能提升多少?" | 混合 RAG 62%→85%,闭环优化每月 +1%,目标 90% | +| "和直接用 ChatGPT 有什么区别?" | 专业诊断 Skill + 领域文档 RAG + 案例库 + 质量门禁 + 进化引擎 | + +--- + +## 十六、MVP vs 生产级对比 + +| 维度 | MVP(Phase 1) | 生产级(Phase 2-4) | +|------|---------------|-------------------| +| Agent | 5 Agent 同一 JVM | 独立 Pod,进程隔离 | +| Skill | 4 个固定 Skill | 3 层渐进式,50+ Skill | +| 回退 | 3 次失败终止 | 4 级回退路由 | +| 工具 | @Tool 注解 | MCP 独立 Server | +| 进化 | 案例自动生成 | 模式识别 + Prompt 自优化 + 案例自评估 | +| 部署 | 单实例 | K8s 集群 + HPA 扩缩 | +| 准确率 | 85%(目标) | 90%+(持续进化) | + +--- + +## 十七、面试核心金句 + +``` +"不是一个人干所有活,而是 5 个 Agent 团队协作。" + +"Skill 不是一次性全给,而是渐进式披露,Agent 不被信息淹没。" + +"SubAgent 进程隔离,一个挂了不影响其他的,就像微服务。" + +"4 级回退路由,永不返回'系统错误',最差给'人工介入'加证据。" + +"Harness 是安全带,15 个门禁保证 Agent 不胡说八道。" + +"MCP 协议化就像 USB,换工具不需要改 Agent。" + +"进化引擎让系统越运行越聪明,不只是被使用,而是在进化。" + +"不是重复造轮子,是对 Spring AI Alibaba 框架的增强和工程化。" +``` diff --git a/docs/architecture/implementation-plan.md b/docs/architecture/implementation-plan.md new file mode 100644 index 0000000..7a3b929 --- /dev/null +++ b/docs/architecture/implementation-plan.md @@ -0,0 +1,211 @@ +# 实施规划 + +## Phase 1:核心功能(第1周) + +### 实现内容 +``` +✅ diagnosis_record 表 +✅ case_library 表 +✅ api_document 表 +✅ Redis 会话管理 +✅ 单次诊断流程 +``` + +### 不实现 +``` +❌ conversation_history 表(先不加) +❌ 会话同步(先不做) +❌ 追问功能(先不支持) +``` + +### 验收标准 +``` +- 用户输入订单号 → 返回诊断报告 +- 诊断记录持久化到 MySQL +- 可以查询历史诊断 +- 可以统计诊断成功率 +- 文档可以导入、查询、删除 +- 案例可以推荐 +``` + +--- + +## Phase 2:追问功能(第2周) + +### 实现内容 +``` +✅ 支持多轮对话(基于 Redis 上下文) +✅ conversation_history 表(可选) +✅ 会话上下文管理 +``` + +### 验收标准 +``` +- 用户可以追问细节 +- Agent 能基于上下文回答 +- 追问不创建新的诊断记录 +``` + +--- + +## Phase 3:优化分析(第3周) + +### 实现内容 +``` +✅ 会话同步(Redis → MySQL) +✅ BadCase 分析 +✅ 追问频率统计 +✅ 案例质量评分 +``` + +### 验收标准 +``` +- 重要会话自动同步到 MySQL +- 可以分析用户追问模式 +- 可以优化 Prompt 和功能 +``` + +--- + +## 技术债务清单 + +### 待优化项(Phase 4+) + +``` +1. api_document 增强 + - 软删除(archived_at) + - 启用开关(enabled) + - 批次管理(batch_id) + - 状态细化(PARSING/SPLITTING/INDEXING...) + +2. case_library 增强 + - 复杂评分(useful_count + score) + - 标签分类(tags) + - 版本管理 + - 案例合并 + +3. 性能优化 + - Redis 缓存有效文档列表 + - 分页查询优化 + - 索引优化 + +4. 监控告警 + - 诊断成功率监控 + - 诊断耗时监控 + - 文档索引状态监控 +``` + +--- + +## 数据迁移计划 + +### 如果已有旧数据 + +``` +1. diagnosis_record 迁移 + - 旧字段 → 新字段映射 + - order_id → business_id + - province → fault_source + - api_url → fault_target + +2. 执行迁移脚本 + UPDATE diagnosis_record SET + business_id = order_id, + fault_category = 'EXTERNAL_API', + fault_source = province, + fault_target = api_url + WHERE fault_category IS NULL; + +3. 验证数据一致性 +``` + +--- + +## 部署检查清单 + +### Phase 1 部署前 + +``` +□ MySQL 数据库已创建 +□ 三张核心表已创建(diagnosis_record/case_library/api_document) +□ Redis 已配置并可连接 +□ Milvus Collection 已创建 +□ 向量化服务(DashScope)配置正确 +□ 文件上传目录已创建并有写权限 +□ 应用配置文件检查完成 +``` + +### 配置文件示例 + +```yaml +# application.yml +spring: + datasource: + url: jdbc:mysql://localhost:3306/diagnosis_system + username: root + password: xxx + + redis: + host: localhost + port: 6379 + database: 0 + +milvus: + host: localhost + port: 19530 + collection-name: api_doc_collection + +dashscope: + api-key: sk-xxx + +file: + upload: + path: /data/uploads +``` + +--- + +## 回滚方案 + +### 数据库回滚 + +```sql +-- 保留旧表备份 +CREATE TABLE diagnosis_record_backup_20240622 AS SELECT * FROM diagnosis_record; + +-- 回滚时恢复 +DROP TABLE diagnosis_record; +RENAME TABLE diagnosis_record_backup_20240622 TO diagnosis_record; +``` + +### Milvus 回滚 + +``` +- Milvus 数据无法回滚 +- 建议:重要操作前先备份 Collection +- 或者:保留原始文件,可重新索引 +``` + +--- + +## 监控指标 + +### 核心指标 + +``` +1. 诊断成功率 + - 目标:> 85% + - 告警:< 80% + +2. 诊断耗时 + - 目标:P95 < 10s + - 告警:P95 > 15s + +3. 文档索引成功率 + - 目标:> 95% + - 告警:< 90% + +4. 案例推荐准确率 + - 目标:> 70% + - 评估:用户反馈 +``` diff --git a/docs/architecture/session-management.md b/docs/architecture/session-management.md new file mode 100644 index 0000000..8882bf6 --- /dev/null +++ b/docs/architecture/session-management.md @@ -0,0 +1,210 @@ +# 会话管理设计 + +## 会话存储策略 + +### Redis(主) + +**数据结构**: +``` +key: session:{session_id} +value: { + "sessionId": "sess-abc", + "userId": "user-123", + "currentDiagnosisId": "diag-001", + "messages": [ + {"role": "user", "content": "诊断订单 A"}, + {"role": "assistant", "content": "完整报告..."} + ], + "context": { + "province": "广东", + "apiName": "社保查询", + "errorCode": "40003" + }, + "createdAt": "2024-06-15T14:30:00Z", + "lastActiveAt": "2024-06-15T14:35:00Z" +} +ttl: 1800秒(30分钟) +``` + +**优势**: +- ✅ 快速读写 +- ✅ 自动过期 +- ✅ 支持追问(保存上下文) + +--- + +### MySQL(辅助,可选) + +**同步策略**: +1. 重要会话同步 + - 有用户反馈的会话 + - 诊断失败的会话(BadCase) + - 多轮对话 > 3 轮的会话 + +2. 同步时机 + - 会话结束时(30分钟过期) + - 用户反馈时(实时) + - 定时任务(每小时,可选) + +3. 同步目标 + - conversation_history 表 + - 用于长期分析和审计 + +--- + +## 数据流设计 + +### 场景1:单次诊断(主流 80%) + +``` +1. 用户发起诊断 + POST /api/diagnosis/start + { + "orderId": "202406150001" + } + +2. 创建会话(Redis) + key: session:sess-abc + ttl: 1800秒 + +3. 创建诊断记录(MySQL) + INSERT INTO diagnosis_record + - diagnosis_id: diag-001 + - session_id: sess-abc + - status: RUNNING + +4. Agent 执行诊断 + - 调用工具(queryOrder, queryLogs, searchDoc...) + - 生成报告 + +5. 更新诊断记录(MySQL) + UPDATE diagnosis_record + - status: SUCCESS + - root_cause: "idCard字段缺失" + - report_markdown: "完整报告..." + +6. 返回报告 + → 大部分用户到此结束 +``` + +--- + +### 场景2:追问(少数 20%) + +``` +1. 用户追问 + POST /api/chat + { + "sessionId": "sess-abc", + "message": "为什么会缺失字段?" + } + +2. 从 Redis 获取上下文 + GET session:sess-abc + - 有之前的诊断结果 + - 有对话历史 + +3. Agent 基于上下文回答 + - 不创建新的 diagnosis_record + - 只是普通对话 + +4. 更新 Redis 会话 + - 追加对话历史 + - 刷新 TTL(重新计时30分钟) + +5. 可选:保存到 conversation_history(MySQL) + - 如果需要长期分析 + - 异步存储 +``` + +--- + +### 场景3:同一会话多次诊断 + +``` +1. 用户第一次诊断 + "诊断订单 A" + → diagnosis_record(diag-001, session_id=sess-abc) + +2. 用户第二次诊断 + "再诊断订单 B" + → diagnosis_record(diag-002, session_id=sess-abc) + +3. 会话关联 + - 同一个 session_id + - 两条 diagnosis_record + - Redis 中保存完整对话历史 +``` + +--- + +## 会话生命周期 + +``` +创建 + ↓ +活跃(每次交互刷新TTL) + ↓ +30分钟无活动 + ↓ +自动过期 + ↓ +可选:同步到 MySQL(重要会话) +``` + +--- + +## 实现示例 + +### Java 代码 + +```java +@Service +public class SessionService { + + @Autowired + private RedisTemplate redisTemplate; + + private static final String SESSION_PREFIX = "session:"; + private static final Duration SESSION_TTL = Duration.ofMinutes(30); + + // 创建会话 + public String createSession(String userId) { + String sessionId = UUID.randomUUID().toString(); + + SessionData session = SessionData.builder() + .sessionId(sessionId) + .userId(userId) + .messages(new ArrayList<>()) + .context(new HashMap<>()) + .createdAt(LocalDateTime.now()) + .lastActiveAt(LocalDateTime.now()) + .build(); + + String key = SESSION_PREFIX + sessionId; + redisTemplate.opsForValue().set(key, toJson(session), SESSION_TTL); + + return sessionId; + } + + // 获取会话 + public SessionData getSession(String sessionId) { + String key = SESSION_PREFIX + sessionId; + String json = redisTemplate.opsForValue().get(key); + return json != null ? fromJson(json) : null; + } + + // 更新会话(刷新TTL) + public void updateSession(SessionData session) { + session.setLastActiveAt(LocalDateTime.now()); + String key = SESSION_PREFIX + session.getSessionId(); + redisTemplate.opsForValue().set(key, toJson(session), SESSION_TTL); + } + + // 删除会话 + public void deleteSession(String sessionId) { + String key = SESSION_PREFIX + sessionId; + redisTemplate.delete(key); + } +} +``` diff --git a/docs/database-design-backup-20240622.md b/docs/database-design-backup-20240622.md new file mode 100644 index 0000000..714f753 --- /dev/null +++ b/docs/database-design-backup-20240622.md @@ -0,0 +1,1711 @@ +# 数据库设计文档 + +## 一、设计原则 + +### 1.1 核心原则 +- ✅ **简单优先**:满足诊断流程需要,避免过度设计 +- ✅ **渐进增强**:先实现核心功能,再逐步扩展 +- ✅ **数据分离**:诊断结果持久化(MySQL),会话上下文临时化(Redis) +- ✅ **适度冗余**:避免过度范式化,适当冗余提升查询性能 + +### 1.2 系统定位 +**自动化诊断系统** +- 核心:一键诊断 → 返回完整报告 +- 辅助:支持追问,但不是主要场景 +- 特点:大部分用户单次诊断即结束,少数用户会追问细节 + +--- + +## 二、核心表设计 + +### 2.1 diagnosis_record(诊断记录表) + +#### 设计理念:兼容多种故障类型 + +**问题背景**: +- 初始设计过于聚焦"外部接口故障"(省份、接口URL、业务错误码) +- 实际故障类型更丰富:空指针异常、数据库死锁、缓存穿透、线程池耗尽等 +- 需要字段泛化,支持**外部接口故障 + 系统内部错误** + +**解决方案**: +- 字段泛化:business_id 替代 order_id,fault_source 替代 province +- 增加分类:fault_category 显式区分故障类别 +- 增强错误信息:error_message、stack_trace 支持内部错误 + +--- + +#### 表结构(v2.0 泛化版) + +```sql +CREATE TABLE diagnosis_record ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + diagnosis_id VARCHAR(64) UNIQUE NOT NULL COMMENT '诊断唯一ID(UUID)', + + -- 关联信息 + session_id VARCHAR(64) COMMENT '会话ID(关联Redis)', + business_id VARCHAR(128) COMMENT '业务标识(订单号/请求ID/线程ID/任务ID...)', + trace_id VARCHAR(64) COMMENT '链路追踪ID', + + -- 故障分类(泛化设计) + fault_category VARCHAR(32) COMMENT '故障类别(EXTERNAL_API/INTERNAL_ERROR/DATABASE/CACHE/NETWORK/THREAD/MEMORY/CONFIG)', + fault_source VARCHAR(128) COMMENT '故障源(省份/服务名/类名/数据库实例/Redis集群...)', + fault_target VARCHAR(256) COMMENT '故障目标(接口URL/方法名/SQL语句/缓存键...)', + + -- 错误信息(通用) + error_code VARCHAR(64) COMMENT '错误码(业务错误码/HTTP状态码/异常类名/数据库错误码)', + error_message TEXT COMMENT '错误消息', + stack_trace TEXT COMMENT '堆栈信息(内部错误时记录)', + + -- 诊断结果 + problem_type VARCHAR(32) COMMENT '问题类型(参数/网络/权限/逻辑/空指针/死锁/缓存穿透/线程池满...)', + root_cause TEXT COMMENT '根因分析', + solution TEXT COMMENT '修复方案', + report_markdown TEXT COMMENT '完整诊断报告(Markdown格式)', + + -- 评估指标 + status VARCHAR(16) DEFAULT 'PENDING' COMMENT '诊断状态(PENDING/RUNNING/SUCCESS/FAILED)', + confidence INT COMMENT '诊断置信度(0-100)', + duration INT COMMENT '诊断耗时(毫秒)', + + -- 调试字段(可选) + tool_calls JSON COMMENT '工具调用记录', + + -- 元数据 + created_by VARCHAR(64) COMMENT '创建人', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + -- 索引 + INDEX idx_business_id (business_id), + INDEX idx_trace_id (trace_id), + INDEX idx_session_id (session_id), + INDEX idx_fault_category (fault_category), + INDEX idx_fault_source_target (fault_source, fault_target(100)), + INDEX idx_error_code (error_code), + INDEX idx_created_at (created_at), + INDEX idx_status (status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='诊断记录表(v2.0 泛化版)'; +``` + +#### 字段说明(泛化后) + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| diagnosis_id | VARCHAR(64) | 是 | 诊断唯一标识(UUID) | +| session_id | VARCHAR(64) | 否 | 会话ID,关联Redis会话上下文 | +| business_id | VARCHAR(128) | 否 | **泛化**:业务标识(订单号/请求ID/线程ID/任务ID),根据故障类型灵活填写 | +| trace_id | VARCHAR(64) | 否 | 链路追踪ID,用于串联日志 | +| fault_category | VARCHAR(32) | 否 | **新增**:故障类别(EXTERNAL_API/INTERNAL_ERROR/DATABASE/CACHE/NETWORK/THREAD/MEMORY/CONFIG) | +| fault_source | VARCHAR(128) | 否 | **泛化**:故障源(省份/服务名/类名/数据库实例),根据故障类别填写 | +| fault_target | VARCHAR(256) | 否 | **泛化**:故障目标(接口URL/方法名/SQL语句/缓存键),描述具体位置 | +| error_code | VARCHAR(64) | 否 | **扩展**:错误码(业务错误码/HTTP状态码/异常类名/数据库错误码) | +| error_message | TEXT | 否 | **新增**:错误消息,通用描述 | +| stack_trace | TEXT | 否 | **新增**:堆栈信息,内部错误时记录 | +| problem_type | VARCHAR(32) | 否 | 问题类型(参数/网络/权限/逻辑/空指针/死锁/缓存穿透/线程池满...) | +| root_cause | TEXT | 否 | 根因分析 | +| solution | TEXT | 否 | 修复方案 | +| report_markdown | TEXT | 否 | 完整诊断报告(Markdown格式) | +| status | VARCHAR(16) | 是 | 诊断状态(PENDING/RUNNING/SUCCESS/FAILED) | +| confidence | INT | 否 | 置信度(0-100) | +| duration | INT | 否 | 诊断耗时(毫秒) | +| tool_calls | JSON | 否 | 工具调用记录 | + +#### 核心设计决策 + +**1. 字段泛化:支持多种故障类型** + +**泛化前 → 泛化后**: +``` +order_id (订单号) → business_id (业务标识) +province (省份) → fault_source (故障源) +api_name (接口名称) → 移除(信息合并到 fault_target) +api_url (接口URL) → fault_target (故障目标) +error_code (业务错误码) → error_code (通用错误码,扩展支持) +新增 fault_category (故障类别) +新增 error_message (错误消息) +新增 stack_trace (堆栈信息) +``` + +**设计理由**: +- 原设计假设"故障 = 外部接口调用失败",但实际故障类型更多样 +- 泛化后支持:外部接口故障、内部异常、数据库问题、缓存问题、线程问题等 +- 字段语义更通用,根据故障类型灵活填写 + +--- + +**2. fault_category 枚举值** + +``` +故障类别分类: +├─ EXTERNAL_API:外部接口调用失败(第三方API、政府接口) +├─ INTERNAL_ERROR:系统内部错误(空指针、NPE、业务异常) +├─ DATABASE:数据库问题(死锁、慢查询、连接池耗尽) +├─ CACHE:缓存问题(穿透、雪崩、击穿) +├─ NETWORK:网络问题(超时、连接失败、DNS解析失败) +├─ THREAD:线程问题(线程池满、死锁) +├─ MEMORY:内存问题(OOM、内存泄漏) +└─ CONFIG:配置问题(配置错误、配置缺失) + +用途: +- 统计不同类别故障的分布 +- 路由不同的诊断策略(不同类别使用不同工具) +- 支持按类别过滤查询 +``` + +--- + +**3. 字段映射示例** + +**示例1:外部接口故障(原场景)** +``` +business_id: "202406150001" (订单号) +fault_category: "EXTERNAL_API" +fault_source: "广东" (省份) +fault_target: "/api/v1/guangdong/social-security" (接口URL) +error_code: "40003" (业务错误码) +error_message: "参数缺失:idCard" +stack_trace: NULL (无堆栈) +``` + +**示例2:空指针异常(内部错误)** +``` +business_id: "req-xyz789" (请求ID) +fault_category: "INTERNAL_ERROR" +fault_source: "order-service" (服务名) +fault_target: "OrderController.createOrder()" (方法名) +error_code: "NullPointerException" (异常类名) +error_message: "Cannot invoke 'User.getName()' because 'user' is null" +stack_trace: "java.lang.NullPointerException: ...\n at OrderController.java:45\n ..." (完整堆栈) +``` + +**示例3:数据库死锁** +``` +business_id: "txn-20240615-001" (事务ID) +fault_category: "DATABASE" +fault_source: "mysql-master-01" (数据库实例) +fault_target: "UPDATE orders SET status=? WHERE order_id=?" (SQL) +error_code: "1213" (MySQL死锁错误码) +error_message: "Deadlock found when trying to get lock" +stack_trace: NULL (数据库错误无堆栈) +``` + +**示例4:缓存穿透** +``` +business_id: "cache-key-user:99999" (缓存键) +fault_category: "CACHE" +fault_source: "redis-cluster" (Redis集群) +fault_target: "user:99999" (缓存键) +error_code: "CACHE_MISS" (自定义) +error_message: "恶意查询不存在的用户ID,导致缓存穿透" +stack_trace: NULL +``` + +**示例5:线程池耗尽** +``` +business_id: "pool-async-executor" (线程池名称) +fault_category: "THREAD" +fault_source: "order-service" (服务名) +fault_target: "asyncExecutor ThreadPool" (线程池) +error_code: "RejectedExecutionException" (异常类名) +error_message: "Task rejected from ThreadPoolExecutor" +stack_trace: "java.util.concurrent.RejectedExecutionException: ...\n at ThreadPoolExecutor.java:2063\n ..." +``` + +--- + +**4. 向下兼容策略** + +如果已有数据使用旧字段(order_id、province、api_url),可以通过以下方式迁移: + +```sql +-- 数据迁移脚本 +UPDATE diagnosis_record SET + business_id = order_id, + fault_category = 'EXTERNAL_API', + fault_source = province, + fault_target = api_url, + error_message = CONCAT('错误码: ', error_code) +WHERE fault_category IS NULL; +``` + +应用层可以同时支持新旧字段: +``` +读取时:优先使用新字段,兼容旧字段 +写入时:只写新字段 +``` + +--- + +**5. 一次诊断 = 一条记录** +``` +特点: +- 用户发起一次诊断任务,创建一条记录 +- 不是聊天记录(不存多轮对话) +- 追问对话存在 conversation_history 表(可选) + +示例: +用户:"诊断订单 202406150001" +→ 创建 diagnosis_record(status=RUNNING) +→ Agent 执行 +→ 更新 diagnosis_record(status=SUCCESS) +→ 返回报告 +``` + +--- + +**6. report_markdown 字段的必要性** +``` +为什么要存储完整报告? +- 固化结果:Prompt变化不影响历史报告 +- 快速展示:不需要重新生成 +- 历史审计:可以看到当时的诊断结果 + +成本: +- 字段较大(TEXT类型) +- 有一定冗余 + +结论:存储,因为报告是最终产物 +``` + +--- + +**7. session_id 的作用** +``` +用途: +- 关联 Redis 会话(支持追问) +- 同一会话可能有多次诊断 +- 用于会话级别的数据分析 + +场景: +用户:"诊断订单 A"(session_id=sess-001, diagnosis_id=diag-001) +用户:"再诊断订单 B"(session_id=sess-001, diagnosis_id=diag-002) +→ 同一会话,两次诊断 +``` + +#### 典型查询场景 + +**1. 查询历史诊断** +```sql +-- 按业务标识查询(兼容订单号、请求ID等) +SELECT * FROM diagnosis_record +WHERE business_id = '202406150001' +ORDER BY created_at DESC; + +-- 按链路ID查询 +SELECT * FROM diagnosis_record +WHERE trace_id = 'trace-abc-123' +ORDER BY created_at DESC; +``` + +**2. 按故障类别统计** +```sql +-- 统计最近7天各类别故障分布 +SELECT + fault_category, + COUNT(*) as count, + ROUND(AVG(duration), 2) as avg_duration_ms, + ROUND(AVG(confidence), 2) as avg_confidence +FROM diagnosis_record +WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) +GROUP BY fault_category +ORDER BY count DESC; + +-- 结果示例: +-- +------------------+-------+-----------------+----------------+ +-- | fault_category | count | avg_duration_ms | avg_confidence | +-- +------------------+-------+-----------------+----------------+ +-- | EXTERNAL_API | 120 | 5234.5 | 85.3 | +-- | INTERNAL_ERROR | 45 | 3456.2 | 90.1 | +-- | DATABASE | 20 | 4567.8 | 88.5 | +-- | CACHE | 15 | 2345.1 | 82.0 | +-- | THREAD | 5 | 6789.3 | 87.2 | +-- +------------------+-------+-----------------+----------------+ +``` + +**3. 内部错误Top异常统计** +```sql +-- 统计内部错误中最频繁的异常 +SELECT + error_code, + fault_target, + COUNT(*) as count, + AVG(duration) as avg_duration +FROM diagnosis_record +WHERE fault_category = 'INTERNAL_ERROR' + AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) +GROUP BY error_code, fault_target +ORDER BY count DESC +LIMIT 10; + +-- 结果示例: +-- +---------------------------+--------------------------------+-------+--------------+ +-- | error_code | fault_target | count | avg_duration | +-- +---------------------------+--------------------------------+-------+--------------+ +-- | NullPointerException | OrderController.createOrder() | 15 | 3245.2 | +-- | IllegalArgumentException | UserService.validateUser() | 10 | 2567.8 | +-- | NullPointerException | PaymentService.processPayment()| 8 | 4123.5 | +-- +---------------------------+--------------------------------+-------+--------------+ +``` + +**4. 外部接口故障统计(按省份)** +```sql +-- 统计外部接口故障(按省份) +SELECT + fault_source as province, + COUNT(*) as count +FROM diagnosis_record +WHERE fault_category = 'EXTERNAL_API' + AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) +GROUP BY fault_source +ORDER BY count DESC; + +-- 结果示例: +-- +----------+-------+ +-- | province | count | +-- +----------+-------+ +-- | 广东 | 45 | +-- | 江苏 | 32 | +-- | 浙江 | 28 | +-- +----------+-------+ +``` + +**5. 数据库问题分析** +```sql +-- 统计数据库问题(按错误码) +SELECT + error_code, + COUNT(*) as count, + fault_target as example_sql +FROM diagnosis_record +WHERE fault_category = 'DATABASE' + AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) +GROUP BY error_code, fault_target +ORDER BY count DESC +LIMIT 5; + +-- 结果示例: +-- +------------+-------+---------------------------------------------+ +-- | error_code | count | example_sql | +-- +------------+-------+---------------------------------------------+ +-- | 1213 | 12 | UPDATE orders SET status=? WHERE order_id=? | +-- | 1205 | 8 | SELECT * FROM orders WHERE user_id=? | +-- +------------+-------+---------------------------------------------+ +``` + +**6. 诊断成功率统计** +```sql +-- 统计最近7天的诊断成功率 +SELECT + COUNT(*) as total, + SUM(CASE WHEN status = 'SUCCESS' THEN 1 ELSE 0 END) as success, + ROUND(SUM(CASE WHEN status = 'SUCCESS' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as success_rate +FROM diagnosis_record +WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY); +``` + +**7. 性能监控(P50/P90/P95)** +```sql +-- MySQL 8.0+ 使用 PERCENTILE_CONT +SELECT + 'P50' as metric, + PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY duration) as value_ms +FROM diagnosis_record +WHERE status = 'SUCCESS' + AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) +UNION ALL +SELECT 'P90', PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY duration) +FROM diagnosis_record +WHERE status = 'SUCCESS' + AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) +UNION ALL +SELECT 'P95', PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY duration) +FROM diagnosis_record +WHERE status = 'SUCCESS' + AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY); + +-- 或使用近似方式(兼容旧版本MySQL) +SELECT + 'P50' as metric, + duration as value_ms +FROM ( + SELECT duration, ROW_NUMBER() OVER (ORDER BY duration) as rn, + COUNT(*) OVER() as total + FROM diagnosis_record + WHERE status = 'SUCCESS' + AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) +) t +WHERE rn = FLOOR(total * 0.5); +``` + +--- + +### 2.2 case_library(案例库表) + +#### 设计理念:知识沉淀,系统越用越智能 + +**核心价值**: +- 质量过滤:只存储高质量案例(成功诊断 + 用户反馈有用) +- 知识沉淀:历史诊断经验可复用 +- 提升准确率:相似问题提供历史参考 +- 加速诊断:快速推荐相似案例 + +**MVP版本设计原则**: +- ✅ 能用:满足基本案例推荐功能 +- ✅ 简单:字段不多,逻辑清晰 +- ✅ 可扩展:后续可增加字段 +- ❌ 不做(Phase 2):复杂评分、版本管理、标签分类 + +--- + +#### 表结构(MVP版) + +```sql +CREATE TABLE case_library ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + case_id VARCHAR(64) UNIQUE NOT NULL COMMENT '案例唯一ID(UUID)', + + -- 来源关联 + diagnosis_id VARCHAR(64) COMMENT '关联诊断记录(可选,人工录入时为空)', + source_type VARCHAR(16) DEFAULT 'AUTO' COMMENT '来源类型(AUTO:自动生成/MANUAL:人工录入)', + + -- 案例分类(复用 diagnosis_record 的分类字段) + fault_category VARCHAR(32) COMMENT '故障类别(EXTERNAL_API/INTERNAL_ERROR/DATABASE/CACHE/NETWORK/THREAD/MEMORY/CONFIG)', + fault_source VARCHAR(128) COMMENT '故障源(省份/服务名/类名/数据库实例...)', + error_code VARCHAR(64) COMMENT '错误码(业务错误码/HTTP状态码/异常类名)', + + -- 案例内容 + title VARCHAR(256) NOT NULL COMMENT '案例标题(简短描述,如"广东社保查询idCard字段缺失")', + root_cause TEXT NOT NULL COMMENT '根因分析', + solution TEXT NOT NULL COMMENT '解决方案', + + -- 简单统计 + reference_count INT DEFAULT 0 COMMENT '引用次数(被推荐的次数,用于排序)', + + -- 元数据 + created_by VARCHAR(64) COMMENT '创建人', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + -- 索引 + INDEX idx_fault_category (fault_category), + INDEX idx_error_code (error_code), + INDEX idx_fault_source (fault_source), + INDEX idx_diagnosis_id (diagnosis_id), + INDEX idx_reference_count (reference_count), + INDEX idx_created_at (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='案例库表(MVP版)'; +``` + +#### 字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| case_id | VARCHAR(64) | 是 | 案例唯一标识(UUID) | +| diagnosis_id | VARCHAR(64) | 否 | 关联诊断记录,追溯案例来源(人工录入时为空)| +| source_type | VARCHAR(16) | 是 | 来源类型:AUTO(自动生成)/MANUAL(人工录入)| +| fault_category | VARCHAR(32) | 否 | 故障类别,与 diagnosis_record 一致 | +| fault_source | VARCHAR(128) | 否 | 故障源,按省份/服务检索 | +| error_code | VARCHAR(64) | 否 | 错误码,精确匹配检索 | +| title | VARCHAR(256) | 是 | 案例标题,快速浏览 | +| root_cause | TEXT | 是 | 根因分析,核心内容 | +| solution | TEXT | 是 | 解决方案,核心内容 | +| reference_count | INT | 是 | 引用次数,用于简单排序(引用多的排前面)| + +#### 核心设计决策 + +**1. 案例来源** + +``` +来源1:自动生成(source_type=AUTO) +├─ 触发条件:诊断成功 + 用户反馈"有用" +├─ 关联诊断:diagnosis_id 不为空 +└─ 质量保证:用户验证过 + +来源2:人工录入(source_type=MANUAL) +├─ 运维团队总结的经典案例 +├─ diagnosis_id 为空 +└─ 质量最高 + +注意:诊断失败或用户反馈"无用"的不自动生成案例 +``` + +**2. 简化的评分机制(MVP)** + +``` +MVP版本:只按 reference_count 排序 +- 引用次数多的排前面 +- 简单有效 + +Phase 2 可增强: +- 增加 useful_count(用户反馈有用次数) +- 增加 score(综合评分:引用加分 + 有用率加分 - 时间衰减) +- 增加 is_featured(人工标记的经典案例) +``` + +**3. 不做版本管理(MVP)** + +``` +当前:直接更新案例 +UPDATE case_library +SET root_cause = '修正后的根因', + solution = '修正后的方案' +WHERE case_id = 'xxx'; + +优点:简单,保持单一案例 +缺点:历史版本丢失 + +Phase 2 如需版本管理: +- 方案A:增加 version 字段 +- 方案B:建 case_history 表 +``` + +**4. 与 diagnosis_record 的关系** + +``` +关系:一对一(可选) +- 一次诊断 → 可以生成一个案例 +- 通过 diagnosis_id 关联 +- diagnosis_id 可为空(人工录入案例) + +流程: +diagnosis_record(成功) + ↓ +用户反馈"有用" + ↓ +自动生成 case_library + ↓ +后续可人工修正、合并相似案例 +``` + +#### 数据流 + +**场景1:自动生成案例** +``` +诊断完成 + 用户反馈"有用" + ↓ +INSERT INTO case_library +- diagnosis_id: diag-001 +- source_type: AUTO +- fault_category: INTERNAL_ERROR +- error_code: NullPointerException +- title: "订单服务创建订单空指针异常" +- root_cause: "OrderController.createOrder()方法中user对象为null,未做空判断" +- solution: "在第45行添加空判断:if (user == null) throw new BizException(...)" +- reference_count: 0 +``` + +**场景2:人工录入案例** +``` +运维团队总结经验 + ↓ +INSERT INTO case_library +- diagnosis_id: NULL +- source_type: MANUAL +- fault_category: EXTERNAL_API +- error_code: 40003 +- title: "广东省社保接口参数缺失通用处理" +- root_cause: "前端表单未做必填校验,导致请求报文缺少关键参数" +- solution: "前端增加必填校验;后端返回明确的字段缺失提示" +- reference_count: 0 +``` + +**场景3:推荐案例并更新引用次数** +``` +诊断时查询相似案例 + ↓ +SELECT * FROM case_library +WHERE error_code = '40003' + AND fault_category = 'EXTERNAL_API' +ORDER BY reference_count DESC +LIMIT 3; + ↓ +返回 Top 3 案例 + ↓ +UPDATE case_library +SET reference_count = reference_count + 1 +WHERE case_id IN ('case-001', 'case-005', 'case-012'); +``` + +#### 典型查询场景 + +**1. 精确匹配查询(优先)** +```sql +-- 按错误码查询 +SELECT * FROM case_library +WHERE error_code = '40003' +ORDER BY reference_count DESC +LIMIT 5; + +-- 按故障类别 + 错误码查询 +SELECT * FROM case_library +WHERE fault_category = 'INTERNAL_ERROR' + AND error_code = 'NullPointerException' +ORDER BY reference_count DESC +LIMIT 5; + +-- 按故障源查询(如省份、服务名) +SELECT * FROM case_library +WHERE fault_source = '广东' + AND fault_category = 'EXTERNAL_API' +ORDER BY reference_count DESC +LIMIT 5; +``` + +**2. 统计分析** +```sql +-- 统计案例分布 +SELECT + fault_category, + COUNT(*) as count, + AVG(reference_count) as avg_reference +FROM case_library +GROUP BY fault_category +ORDER BY count DESC; + +-- Top 引用案例 +SELECT title, reference_count, created_at +FROM case_library +ORDER BY reference_count DESC +LIMIT 10; + +-- 人工录入的案例 +SELECT * FROM case_library +WHERE source_type = 'MANUAL' +ORDER BY created_at DESC; +``` + +**3. 案例查重(避免重复)** +```sql +-- 检查是否已有相同错误码的案例 +SELECT * FROM case_library +WHERE error_code = '40003' + AND fault_source = '广东' + AND fault_category = 'EXTERNAL_API'; +``` + +#### 数据示例 + +```sql +-- 外部接口故障案例 +INSERT INTO case_library VALUES +(1, 'case-001', 'diag-001', 'AUTO', 'EXTERNAL_API', '广东', '40003', + '广东社保查询idCard字段缺失', + '请求报文中未传入idCard字段,导致参数校验失败', + '前端表单增加idCard必填校验;后端增加参数校验提示', + 15, 'system', NOW(), NOW()); + +-- 内部错误案例 +INSERT INTO case_library VALUES +(2, 'case-002', 'diag-045', 'AUTO', 'INTERNAL_ERROR', 'order-service', 'NullPointerException', + '订单服务创建订单空指针异常', + 'OrderController.createOrder()方法中user对象为null,未做空判断', + '在第45行添加空判断:if (user == null) throw new BizException("用户信息不存在")', + 8, 'system', NOW(), NOW()); + +-- 人工录入的经典案例 +INSERT INTO case_library VALUES +(3, 'case-003', NULL, 'MANUAL', 'DATABASE', 'mysql-master-01', '1213', + '订单库存更新死锁通用处理', + '两个事务互相等待对方释放锁:事务A持有订单锁等待库存锁,事务B持有库存锁等待订单锁', + '调整事务加锁顺序:统一先锁订单,再锁库存;或使用乐观锁方案', + 3, 'admin', NOW(), NOW()); + +-- 缓存问题案例 +INSERT INTO case_library VALUES +(4, 'case-004', 'diag-078', 'AUTO', 'CACHE', 'redis-cluster', 'CACHE_MISS', + '用户信息缓存穿透', + '恶意查询不存在的用户ID,缓存未命中,每次都打到数据库', + '使用布隆过滤器拦截无效查询;或缓存空结果(TTL 5分钟)', + 5, 'system', NOW(), NOW()); +``` + +#### 与 Milvus 向量库的配合 + +``` +案例检索策略(混合检索): + +1. 精确匹配(MySQL) + - 按 error_code 精确查询 + - 按 fault_category + fault_source 组合查询 + - 优点:快速、准确 + - 缺点:只能匹配相同错误码 + +2. 语义检索(Milvus) + - 将案例内容(title + root_cause + solution)向量化 + - 存储到 Milvus 的 case_library_collection + - 按语义相似度查询 + - 优点:能找到相似但不同错误码的案例 + - 缺点:召回可能不精确 + +3. 混合策略(推荐) + Step 1: 先精确匹配(MySQL) + Step 2: 如果结果 < 3 个,补充语义检索(Milvus) + Step 3: 合并去重,按 reference_count 排序 + Step 4: 返回 Top 5 + +Milvus Collection 设计: +{ + "collection_name": "case_library_collection", + "fields": [ + {"name": "case_id", "type": "VARCHAR"}, + {"name": "embedding", "type": "FLOAT_VECTOR", "dim": 1536}, + {"name": "reference_count", "type": "INT32"} + ], + "metric_type": "COSINE" +} +``` + +#### MVP 版本的简化 + +``` +Phase 1(当前): +✅ 基础字段和表结构 +✅ 自动生成案例(诊断成功 + 用户反馈) +✅ 人工录入案例 +✅ 按 reference_count 简单排序 +✅ 精确匹配查询 + +Phase 2(未来增强): +❌ 复杂评分机制(useful_count + score) +❌ 版本管理(case_history 表) +❌ 标签分类(tags 字段) +❌ 案例合并功能(多个相似案例 → 1个综合案例) +❌ 人工标注(is_featured 字段) +❌ 时间衰减(score 计算中考虑时间因素) +``` + +--- + +### 2.4 api_document(文档元数据表) + +#### 设计理念:文档管理,不是文档检索 + +**核心定位**: +- MySQL 负责文档元数据管理(状态、版本、去重) +- Milvus 负责文档内容存储和检索 +- 通过 doc_id 关联两者 + +**MVP版本原则**: +- ✅ 最简字段,满足基本管理需求 +- ✅ 文件去重(基于 file_hash) +- ✅ 状态追踪(索引进度) +- ✅ 硬删除(同步删除 Milvus 数据) +- ❌ 暂不支持:软删除、启用开关、版本管理(Phase 2) + +--- + +#### 表结构(MVP版) + +```sql +CREATE TABLE api_document ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + doc_id VARCHAR(64) UNIQUE NOT NULL COMMENT '文档唯一ID(UUID),关联Milvus', + + -- 文档分类 + fault_category VARCHAR(32) DEFAULT 'EXTERNAL_API' COMMENT '文档类别(EXTERNAL_API/INTERNAL_ERROR...)', + fault_source VARCHAR(128) COMMENT '文档归属(省份/服务名,如"广东"/"order-service")', + api_name VARCHAR(128) COMMENT '接口名称(如"社保查询")', + version VARCHAR(32) DEFAULT 'v1.0' COMMENT '文档版本', + + -- 文件信息 + file_name VARCHAR(256) NOT NULL COMMENT '原始文件名', + file_path VARCHAR(512) COMMENT '文件存储路径', + file_hash VARCHAR(64) COMMENT '文件MD5 hash(用于去重)', + file_size BIGINT COMMENT '文件大小(字节)', + + -- 索引状态 + status VARCHAR(16) DEFAULT 'PENDING' COMMENT '索引状态(PENDING/PROCESSING/INDEXED/FAILED)', + chunk_count INT DEFAULT 0 COMMENT '分块数量', + error_message TEXT COMMENT '失败原因', + + -- 时间字段 + indexed_at DATETIME COMMENT '索引完成时间', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- 索引 + UNIQUE INDEX uk_file_hash (file_hash), + INDEX idx_doc_id (doc_id), + INDEX idx_fault_source (fault_source), + INDEX idx_status (status), + INDEX idx_created_at (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文档元数据表(MVP版)'; +``` + +#### 字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| doc_id | VARCHAR(64) | 是 | **核心**:文档唯一ID,关联 Milvus 中的所有分块 | +| fault_category | VARCHAR(32) | 否 | 文档类别,与 diagnosis_record 一致 | +| fault_source | VARCHAR(128) | 否 | 文档归属(省份/服务名)| +| api_name | VARCHAR(128) | 否 | 接口名称 | +| version | VARCHAR(32) | 否 | 文档版本 | +| file_name | VARCHAR(256) | 是 | 原始文件名 | +| file_path | VARCHAR(512) | 否 | 文件存储路径 | +| file_hash | VARCHAR(64) | 否 | **去重关键**:文件MD5,唯一约束 | +| file_size | BIGINT | 否 | 文件大小 | +| status | VARCHAR(16) | 是 | **状态追踪**:PENDING/PROCESSING/INDEXED/FAILED | +| chunk_count | INT | 否 | 分块数量 | +| error_message | TEXT | 否 | 失败原因 | +| indexed_at | DATETIME | 否 | 索引完成时间 | + +#### 核心设计决策 + +**1. doc_id:MySQL 与 Milvus 的桥梁** + +``` +作用: +- MySQL:通过 doc_id 管理文档元数据 +- Milvus:每个 chunk 的 metadata 中携带 doc_id + +关联关系: +api_document (MySQL) + doc_id: doc-001 + ↓ 1:N +Milvus chunks + chunk_1: {doc_id: 'doc-001', text: '...', vector: [...]} + chunk_2: {doc_id: 'doc-001', text: '...', vector: [...]} + +管理操作: +- 删除文档: + DELETE FROM milvus_collection WHERE metadata["doc_id"] == 'doc-001'; + DELETE FROM api_document WHERE doc_id = 'doc-001'; + +- 重新索引: + 先删除旧数据,再重新导入 +``` + +--- + +**2. file_hash:文件去重** + +``` +去重流程: +1. 用户上传文件 + ↓ +2. 计算文件 MD5 + file_hash = md5(file_content) + ↓ +3. 检查是否已存在 + SELECT * FROM api_document WHERE file_hash = 'abc123...'; + ↓ +4a. 如果存在 → 提示"文档已存在" +4b. 如果不存在 → 继续导入 + +唯一约束: +UNIQUE INDEX uk_file_hash (file_hash) +``` + +--- + +**3. status:状态追踪** + +``` +状态流转: +PENDING (待处理) + ↓ +PROCESSING (处理中) + ↓ 成功 +INDEXED (已索引) + + ↓ 失败 +FAILED (失败) + +用途: +- 批量导入时监控进度 +- 失败重试 +- 统计索引成功率 +``` + +--- + +**4. 硬删除策略(MVP)** + +``` +删除文档时: +1. 删除 Milvus 中的所有分块 + DELETE FROM milvus_collection WHERE metadata["doc_id"] == 'xxx'; + +2. 删除 MySQL 元数据 + DELETE FROM api_document WHERE doc_id = 'xxx'; + +3. 可选:删除原始文件 + Files.delete(file_path); + +特点: +- 简单直接 +- 数据彻底删除 +- 不可恢复(需谨慎) + +Phase 2 可增强: +- 软删除(archived_at) +- 启用开关(enabled) +``` + +--- + +#### 数据流 + +**场景1:导入新文档** + +``` +1. 用户上传文件 + file: "广东社保查询v2.1.docx" + ↓ +2. 计算 hash + file_hash = md5(file) + ↓ +3. 检查去重(MySQL) + SELECT * FROM api_document WHERE file_hash = 'abc123'; + → 不存在 + ↓ +4. 插入元数据(MySQL) + INSERT INTO api_document VALUES ( + NULL, 'doc-001', 'EXTERNAL_API', '广东', '社保查询', 'v2.1', + '广东社保查询v2.1.docx', '/docs/guangdong/social-v2.1.docx', + 'abc123...', 1048576, + 'PROCESSING', 0, NULL, NULL, NOW(), NOW() + ); + ↓ +5. 后台任务处理 + - 解析 → Markdown + - 分块(15个chunk) + - 向量化 + - 存入 Milvus(每个chunk的metadata中携带doc_id='doc-001') + ↓ +6. 更新状态(MySQL) + UPDATE api_document + SET status = 'INDEXED', + chunk_count = 15, + indexed_at = NOW() + WHERE doc_id = 'doc-001'; +``` + +--- + +**场景2:删除文档** + +``` +1. 用户删除文档 + doc_id = 'doc-001' + ↓ +2. 删除 Milvus 中的所有分块 + DELETE FROM milvus_collection + WHERE metadata["doc_id"] == 'doc-001'; + ↓ +3. 删除 MySQL 元数据 + DELETE FROM api_document WHERE doc_id = 'doc-001'; + ↓ +4. 可选:删除原始文件 + rm /docs/guangdong/social-v2.1.docx +``` + +--- + +**场景3:重新索引文档** + +``` +1. 文档内容更新,需要重新索引 + doc_id = 'doc-001' + ↓ +2. 删除旧数据 + - Milvus: DELETE WHERE metadata["doc_id"] == 'doc-001' + - MySQL: DELETE FROM api_document WHERE doc_id = 'doc-001' + ↓ +3. 重新导入(同场景1) +``` + +--- + +#### 典型查询 + +**1. 查看文档列表** +```sql +-- 按省份查询 +SELECT doc_id, file_name, version, status, chunk_count, indexed_at +FROM api_document +WHERE fault_source = '广东' + AND status = 'INDEXED' +ORDER BY indexed_at DESC; + +-- 查询失败的文档 +SELECT doc_id, file_name, error_message +FROM api_document +WHERE status = 'FAILED'; +``` + +**2. 文档去重检查** +```sql +-- 导入前检查 +SELECT doc_id, file_name +FROM api_document +WHERE file_hash = 'abc123...'; +``` + +**3. 统计分析** +```sql +-- 统计各状态文档数量 +SELECT status, COUNT(*) as count +FROM api_document +GROUP BY status; + +-- 统计各省份文档数量 +SELECT fault_source, COUNT(*) as count +FROM api_document +WHERE status = 'INDEXED' +GROUP BY fault_source +ORDER BY count DESC; +``` + +--- + +#### 与 Milvus 的协作 + +**Milvus Collection Schema** + +```python +{ + "collection_name": "api_doc_collection", + "fields": [ + {"name": "id", "type": "VARCHAR", "max_length": 64, "is_primary": true}, + {"name": "content", "type": "VARCHAR", "max_length": 2000}, + {"name": "vector", "type": "FLOAT_VECTOR", "dim": 1536}, + {"name": "metadata", "type": "JSON"} + ] +} + +# metadata 结构 +{ + "doc_id": "doc-001", # 关联 MySQL + "_source": "/path/to/file", + "_file_name": "xxx.docx", + "chunkIndex": 0, + "totalChunks": 15, + "fault_category": "EXTERNAL_API", + "fault_source": "广东", + "error_code": "40003" +} +``` + +**Java 代码示例** + +```java +// 插入时携带 doc_id +Map metadata = new HashMap<>(); +metadata.put("doc_id", docId); // 关联 MySQL +metadata.put("_source", filePath); +metadata.put("chunkIndex", chunkIndex); +metadata.put("fault_source", province); + +// 删除文档的所有分块 +String expr = String.format("metadata[\"doc_id\"] == \"%s\"", docId); +DeleteParam deleteParam = DeleteParam.newBuilder() + .withCollectionName(COLLECTION_NAME) + .withExpr(expr) + .build(); +milvusClient.delete(deleteParam); +``` + +--- + +#### 数据示例 + +```sql +-- 外部接口文档 +INSERT INTO api_document VALUES +(1, 'doc-001', 'EXTERNAL_API', '广东', '社保查询', 'v2.1', + '广东社保查询v2.1.docx', '/docs/guangdong/social-v2.1.docx', + 'abc123...', 1048576, + 'INDEXED', 15, NULL, '2024-06-15 10:30:00', NOW(), NOW()); + +-- 内部服务文档 +INSERT INTO api_document VALUES +(2, 'doc-002', 'INTERNAL_ERROR', 'order-service', '订单服务API', 'v1.0', + '订单服务API文档.pdf', '/docs/internal/order-service-api.pdf', + 'def456...', 2097152, + 'INDEXED', 20, NULL, '2024-06-14 15:20:00', NOW(), NOW()); + +-- 处理失败的文档 +INSERT INTO api_document VALUES +(3, 'doc-003', 'EXTERNAL_API', '江苏', '公积金查询', 'v1.5', + '江苏公积金查询.html', '/docs/jiangsu/fund-v1.5.html', + 'ghi789...', 512000, + 'FAILED', 0, '不支持HTML格式,请转换为Word或PDF', NULL, NOW(), NOW()); +``` + +--- + +#### MVP 版本的简化 + +``` +Phase 1(当前): +✅ 基础字段和表结构 +✅ 文件去重(file_hash) +✅ 状态追踪(status) +✅ 硬删除(彻底删除) +✅ 通过 doc_id 关联 Milvus + +Phase 2(未来增强): +❌ enabled(启用开关) +❌ archived_at(软删除) +❌ batch_id(批次管理) +❌ status 细化(PARSING/SPLITTING/INDEXING...) +❌ tags(标签分类) +❌ is_latest(版本标记) +``` + +--- + +## 三、会话管理设计 + +#### 表结构 + +```sql +CREATE TABLE conversation_history ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + conversation_id VARCHAR(64) NOT NULL COMMENT '对话ID(UUID)', + + -- 关联信息 + session_id VARCHAR(64) NOT NULL COMMENT '会话ID', + diagnosis_id VARCHAR(64) COMMENT '关联诊断ID(追问时可为空)', + + -- 对话内容 + round_number INT NOT NULL COMMENT '对话轮次(1, 2, 3...)', + role VARCHAR(16) NOT NULL COMMENT '角色(user/assistant)', + content TEXT NOT NULL COMMENT '对话内容', + + -- 调试字段(可选) + tool_calls JSON COMMENT '工具调用记录', + + -- 元数据 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + + -- 索引 + INDEX idx_session_id (session_id), + INDEX idx_diagnosis_id (diagnosis_id), + INDEX idx_created_at (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='对话历史表(可选,用于分析)'; +``` + +#### 字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| conversation_id | VARCHAR(64) | 是 | 对话唯一标识 | +| session_id | VARCHAR(64) | 是 | 会话ID,关联多轮对话 | +| diagnosis_id | VARCHAR(64) | 否 | 关联诊断ID,初次诊断时填写,追问时为空 | +| round_number | INT | 是 | 对话轮次,从1开始递增 | +| role | VARCHAR(16) | 是 | 角色:user(用户)/assistant(AI) | +| content | TEXT | 是 | 对话内容 | + +#### 核心设计决策 + +**1. 用途定位** +``` +主要用途: +- BadCase分析(用户追问什么?) +- 功能优化(哪些问题常被追问?) +- 审计追溯(完整对话记录) + +不是: +- 主要业务表(诊断记录才是) +- 实时查询(对话上下文在Redis) + +结论:辅助表,Phase 2 再加 +``` + +**2. diagnosis_id 可为空** +``` +场景1:初次诊断 +- diagnosis_id: diag-001 +- round 1: user → "诊断订单 A" +- round 2: assistant → "完整报告..." + +场景2:追问(不创建新诊断) +- diagnosis_id: NULL +- round 3: user → "为什么会缺失字段?" +- round 4: assistant → "因为前端表单未校验..." + +场景3:新诊断 +- diagnosis_id: diag-002 +- round 5: user → "诊断订单 B" +- round 6: assistant → "完整报告..." +``` + +#### 典型查询场景 + +**1. 查询会话的所有对话** +```sql +-- 按轮次排序 +SELECT * FROM conversation_history +WHERE session_id = 'sess-abc' +ORDER BY round_number; +``` + +**2. 查询某次诊断的对话** +```sql +-- 包括诊断前后的追问 +SELECT * FROM conversation_history +WHERE diagnosis_id = 'diag-001' + OR (session_id IN ( + SELECT session_id FROM conversation_history WHERE diagnosis_id = 'diag-001' + )) +ORDER BY round_number; +``` + +**3. 统计追问频率** +```sql +-- 统计有多少诊断被追问 +SELECT + COUNT(DISTINCT diagnosis_id) as total_diagnosis, + COUNT(DISTINCT CASE WHEN round_number > 2 THEN diagnosis_id END) as with_followup, + ROUND(COUNT(DISTINCT CASE WHEN round_number > 2 THEN diagnosis_id END) * 100.0 / COUNT(DISTINCT diagnosis_id), 2) as followup_rate +FROM conversation_history +WHERE diagnosis_id IS NOT NULL; +``` + +--- + +## 三、会话管理设计 + +### 3.1 会话存储策略 + +#### Redis(主) +``` +数据结构: +key: session:{session_id} +value: { + "sessionId": "sess-abc", + "userId": "user-123", + "currentDiagnosisId": "diag-001", + "messages": [ + {"role": "user", "content": "诊断订单 A"}, + {"role": "assistant", "content": "完整报告..."} + ], + "context": { + "province": "广东", + "apiName": "社保查询", + "errorCode": "40003" + }, + "createdAt": "2024-06-15T14:30:00Z", + "lastActiveAt": "2024-06-15T14:35:00Z" +} +ttl: 1800秒(30分钟) + +优势: +- 快速读写 +- 自动过期 +- 支持追问(保存上下文) +``` + +#### MySQL(辅助,可选) +``` +同步策略: +1. 重要会话同步 + - 有用户反馈的会话 + - 诊断失败的会话(BadCase) + - 多轮对话 > 3 轮的会话 + +2. 同步时机 + - 会话结束时(30分钟过期) + - 用户反馈时(实时) + - 定时任务(每小时,可选) + +3. 同步目标 + - conversation_history 表 + - 用于长期分析和审计 +``` + +### 3.2 数据流设计 + +#### 场景1:单次诊断(主流 80%) + +``` +1. 用户发起诊断 + POST /api/diagnosis/start + { + "orderId": "202406150001" + } + +2. 创建会话(Redis) + key: session:sess-abc + ttl: 1800秒 + +3. 创建诊断记录(MySQL) + INSERT INTO diagnosis_record + - diagnosis_id: diag-001 + - session_id: sess-abc + - status: RUNNING + +4. Agent 执行诊断 + - 调用工具(queryOrder, queryLogs, searchDoc...) + - 生成报告 + +5. 更新诊断记录(MySQL) + UPDATE diagnosis_record + - status: SUCCESS + - root_cause: "idCard字段缺失" + - report_markdown: "完整报告..." + +6. 返回报告 + → 大部分用户到此结束 +``` + +#### 场景2:追问(少数 20%) + +``` +1. 用户追问 + POST /api/chat + { + "sessionId": "sess-abc", + "message": "为什么会缺失字段?" + } + +2. 从 Redis 获取上下文 + GET session:sess-abc + - 有之前的诊断结果 + - 有对话历史 + +3. Agent 基于上下文回答 + - 不创建新的 diagnosis_record + - 只是普通对话 + +4. 更新 Redis 会话 + - 追加对话历史 + - 刷新 TTL(重新计时30分钟) + +5. 可选:保存到 conversation_history(MySQL) + - 如果需要长期分析 + - 异步存储 +``` + +#### 场景3:同一会话多次诊断 + +``` +1. 用户第一次诊断 + "诊断订单 A" + → diagnosis_record(diag-001, session_id=sess-abc) + +2. 用户第二次诊断 + "再诊断订单 B" + → diagnosis_record(diag-002, session_id=sess-abc) + +3. 会话关联 + - 同一个 session_id + - 两条 diagnosis_record + - Redis 中保存完整对话历史 +``` + +--- + +## 四、实施规划 + +### 4.1 Phase 1:核心功能(第1周) + +**实现内容**: +``` +✅ diagnosis_record 表 +✅ Redis 会话管理 +✅ 单次诊断流程 + +不实现: +❌ conversation_history 表(先不加) +❌ 会话同步(先不做) +❌ 追问功能(先不支持) +``` + +**验收标准**: +``` +- 用户输入订单号 → 返回诊断报告 +- 诊断记录持久化到 MySQL +- 可以查询历史诊断 +- 可以统计诊断成功率 +``` + +### 4.2 Phase 2:追问功能(第2周) + +**实现内容**: +``` +✅ 支持多轮对话(基于 Redis 上下文) +✅ conversation_history 表(可选) +✅ 会话上下文管理 +``` + +**验收标准**: +``` +- 用户可以追问细节 +- Agent 能基于上下文回答 +- 追问不创建新的诊断记录 +``` + +### 4.3 Phase 3:优化分析(第3周) + +**实现内容**: +``` +✅ 会话同步(Redis → MySQL) +✅ BadCase 分析 +✅ 追问频率统计 +``` + +**验收标准**: +``` +- 重要会话自动同步到 MySQL +- 可以分析用户追问模式 +- 可以优化 Prompt 和功能 +``` + +--- + +## 五、关键设计决策总结 + +### 5.1 单次诊断 vs 多轮对话 + +**决策**:主要是单次诊断,辅助支持追问 + +**理由**: +- 系统定位是"自动化诊断",不是聊天机器人 +- 大部分用户需求:输入 → 报告 → 结束 +- 追问是少数场景,不应主导设计 + +**实现**: +- diagnosis_record 只记录诊断任务 +- conversation_history 记录追问对话(可选) + +### 5.2 会话存储:Redis vs MySQL + +**决策**:Redis 主存储,MySQL 辅助备份 + +**理由**: +- 会话是临时数据,30分钟过期 +- Redis 读写快,适合实时交互 +- MySQL 用于长期分析,不是主路径 + +**实现**: +- Redis 存所有会话(自动过期) +- MySQL 只存重要会话(按需同步) + +### 5.3 report_markdown 是否存储 + +**决策**:存储完整报告 + +**理由**: +- 报告是最终产物,需要固化 +- Prompt 可能变化,历史报告不应变 +- 查询历史时直接展示,不重新生成 + +**成本**: +- TEXT 字段较大 +- 适度冗余可接受 + +### 5.4 conversation_history 是否必需 + +**决策**:Phase 2 再加,不是必需 + +**理由**: +- 核心功能不依赖对话历史 +- 主要用于分析和优化 +- 可以后期扩展 + +--- + +## 六、数据量预估 + +### 6.1 diagnosis_record + +``` +场景:中型企业运维团队 +- 日均诊断:100 次 +- 月均诊断:3000 次 +- 年均诊断:36000 次 + +存储预估: +- 单条记录:约 5KB(含报告) +- 年存储量:36000 × 5KB = 180MB +- 三年存储:540MB + +结论:数据量不大,可以全量保留 +``` + +### 6.2 conversation_history + +``` +场景:20% 用户会追问 +- 日均追问:20 次 +- 平均追问轮次:3 轮 +- 日均对话记录:20 × 3 × 2(user+assistant)= 120 条 + +存储预估: +- 单条记录:约 1KB +- 年存储量:120 × 365 × 1KB = 44MB + +结论:数据量很小,可以全量保留 +``` + +--- + +## 七、索引设计说明 + +### 7.1 diagnosis_record 索引 + +```sql +-- 业务查询索引 +INDEX idx_business_id (business_id) -- 按业务标识查询(订单号/请求ID/线程ID) +INDEX idx_trace_id (trace_id) -- 按链路ID查询 +INDEX idx_session_id (session_id) -- 按会话查询 + +-- 故障分类索引 +INDEX idx_fault_category (fault_category) -- 按故障类别过滤 +INDEX idx_fault_source_target (fault_source, fault_target(100)) -- 按故障源+目标统计 +INDEX idx_error_code (error_code) -- 按错误码统计 + +-- 通用索引 +INDEX idx_created_at (created_at) -- 时间范围查询 +INDEX idx_status (status) -- 状态过滤 +``` + +### 7.2 索引使用场景 + +```sql +-- 场景1:查询业务标识历史(使用 idx_business_id) +SELECT * FROM diagnosis_record +WHERE business_id = '202406150001'; + +-- 场景2:统计故障类别(使用 idx_fault_category) +SELECT fault_category, COUNT(*) +FROM diagnosis_record +WHERE fault_category = 'INTERNAL_ERROR' +GROUP BY fault_category; + +-- 场景3:统计特定服务的异常(使用 idx_fault_source_target) +SELECT fault_target, COUNT(*) +FROM diagnosis_record +WHERE fault_source = 'order-service' + AND fault_category = 'INTERNAL_ERROR' +GROUP BY fault_target; + +-- 场景4:时间范围统计(使用 idx_created_at) +SELECT DATE(created_at) as date, COUNT(*) +FROM diagnosis_record +WHERE created_at >= '2024-06-01' +GROUP BY DATE(created_at); +``` + +--- + +## 八、数据安全考虑 + +### 8.1 敏感数据处理 + +``` +敏感字段: +- 请求报文中的手机号、身份证 +- 响应报文中的个人信息 + +脱敏策略: +- 存储时脱敏(在 tool_calls JSON 中) +- 手机号:138****5678 +- 身份证:110101********1234 + +实现: +- 报文查询工具自动脱敏 +- 存入数据库前已脱敏 +- 降低泄露风险 +``` + +### 8.2 数据保留策略 + +``` +diagnosis_record: +- 保留周期:3 年 +- 清理策略:定时任务(每月) +- 归档:超过 3 年的数据导出后删除 + +conversation_history: +- 保留周期:1 年 +- 清理策略:定时任务(每月) +- 可选:关联诊断被删除时级联删除 +``` + +--- + +## 九、扩展性考虑 + +### 9.1 预留扩展字段 + +```sql +-- diagnosis_record 可选扩展字段 +├─ tags VARCHAR(256) -- 标签(用于分类) +├─ severity VARCHAR(16) -- 严重级别(LOW/MEDIUM/HIGH/CRITICAL) +├─ affected_users INT -- 影响用户数 +├─ resolved_at DATETIME -- 解决时间 +└─ resolver VARCHAR(64) -- 解决人 + +-- 添加方式(不影响现有功能) +ALTER TABLE diagnosis_record ADD COLUMN tags VARCHAR(256); +``` + +### 9.2 分表策略(未来) + +``` +场景:数据量达到千万级别 + +方案1:按时间分表 +- diagnosis_record_2024_06 +- diagnosis_record_2024_07 +- ... + +方案2:按省份分表 +- diagnosis_record_guangdong +- diagnosis_record_jiangsu +- ... + +当前:不分表,单表够用(年均 36000 条) +``` + +--- + +## 十、变更日志 + +| 版本 | 日期 | 变更内容 | 变更人 | +|------|------|---------|--------| +| v1.0 | 2024-06-15 | 初版,定义核心表结构 | - | +| v1.1 | 2024-06-15 | 添加会话管理设计 | - | +| v1.2 | 2024-06-15 | 补充实施规划和数据流 | - | +| v2.0 | 2024-06-15 | **重大更新**:字段泛化,支持多种故障类型(外部接口+内部错误) | - | + +### v2.0 主要变更 + +**字段泛化**: +- `order_id` → `business_id`(订单号→业务标识) +- `province` → `fault_source`(省份→故障源) +- `api_name` → 移除(信息合并到fault_target) +- `api_url` → `fault_target`(接口URL→故障目标) +- `error_code`:扩展支持(业务错误码→通用错误码) + +**新增字段**: +- `fault_category`:故障类别(EXTERNAL_API/INTERNAL_ERROR/DATABASE/CACHE/NETWORK/THREAD/MEMORY/CONFIG) +- `error_message`:错误消息(通用描述) +- `stack_trace`:堆栈信息(内部错误专用) + +**设计理念**: +- 从"只支持外部接口故障"扩展到"支持所有故障类型" +- 字段语义更通用,根据故障类型灵活填写 +- 保持向下兼容,可通过数据迁移支持旧数据 + +**影响范围**: +- SQL建表语句 +- 索引设计 +- 查询示例 +- 数据示例 + +--- + +**文档维护说明**: +- 本文档随系统演进持续更新 +- 任何表结构变更需同步更新此文档 +- 重大设计调整需记录决策理由 diff --git a/docs/database-design.md b/docs/database-design.md new file mode 100644 index 0000000..4b59445 --- /dev/null +++ b/docs/database-design.md @@ -0,0 +1,155 @@ +# 数据库设计文档 + +## 📚 文档导航 + +### 核心表设计 +- [diagnosis_record](tables/diagnosis_record.md) - 诊断记录表(核心) +- [case_library](tables/case_library.md) - 案例库表 +- [api_document](tables/api_document.md) - 文档元数据表 + +### 架构设计 +- [Agent 架构设计](architecture/agent-architecture.md) - Agent 协作 + Skill + Harness +- [会话管理](architecture/session-management.md) - Redis + MySQL 会话管理 +- [实施规划](architecture/implementation-plan.md) - 分阶段实施计划 + +--- + +## 一、设计原则 + +### 1.1 核心原则 +- ✅ **简单优先**:满足诊断流程需要,避免过度设计 +- ✅ **渐进增强**:先实现核心功能,再逐步扩展 +- ✅ **数据分离**:诊断结果持久化(MySQL),会话上下文临时化(Redis) +- ✅ **适度冗余**:避免过度范式化,适当冗余提升查询性能 + +### 1.2 系统定位 +**自动化诊断系统** +- 核心:一键诊断 → 返回完整报告 +- 辅助:支持追问,但不是主要场景 +- 特点:大部分用户单次诊断即结束,少数用户会追问细节 + +--- + +## 二、表结构总览 + +### 2.1 核心表关系 + +``` +┌─────────────────────┐ +│ diagnosis_record │ 诊断记录(核心) +│ - 每次诊断一条 │ +└──────────┬──────────┘ + │ 1:1 + ↓ +┌─────────────────────┐ +│ case_library │ 案例库(知识沉淀) +│ - 诊断成功→案例 │ +└─────────────────────┘ + +┌─────────────────────┐ +│ api_document │ 文档元数据(管理层) +│ - 状态追踪/去重 │ +└──────────┬──────────┘ + │ doc_id + ↓ +┌─────────────────────┐ +│ Milvus │ 文档内容(检索层) +│ - 向量检索 │ +└─────────────────────┘ + +┌─────────────────────┐ +│ Redis Session │ 会话管理(临时) +│ - 30分钟过期 │ +│ - 支持追问 │ +└─────────────────────┘ +``` + +### 2.2 表统计 + +| 表名 | 类型 | 预估数据量 | 用途 | +|------|------|-----------|------| +| diagnosis_record | 核心 | 3.6万/年 | 诊断记录 | +| case_library | 核心 | 500-1000 | 案例库 | +| api_document | 核心 | 100-200 | 文档管理 | + +--- + +## 三、技术栈 + +### 3.1 数据存储 +``` +MySQL 8.0+ +├─ 元数据管理 +├─ 事务支持 +└─ JSON 字段支持 + +Redis 6.0+ +├─ 会话存储 +├─ 缓存 +└─ TTL 自动过期 + +Milvus 2.6+ +├─ 向量存储 +├─ 语义检索 +└─ 混合检索 +``` + +### 3.2 开发框架 +``` +Spring Boot 3.2 +Spring AI Alibaba 1.1.0 +Milvus SDK Java 2.6.10 +DashScope SDK +``` + +--- + +## 四、快速开始 + +### 4.1 创建数据库 + +```sql +-- 1. 创建数据库 +CREATE DATABASE diagnosis_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 2. 执行建表脚本(按顺序) +SOURCE tables/diagnosis_record.sql; +SOURCE tables/case_library.sql; +SOURCE tables/api_document.sql; +``` + +### 4.2 初始化 Milvus + +```java +// 创建 Collection +MilvusClientFactory.createCollection(); +``` + +### 4.3 配置 Redis + +```yaml +spring: + redis: + host: localhost + port: 6379 + database: 0 +``` + +--- + +## 五、版本历史 + +| 版本 | 日期 | 变更内容 | +|------|------|---------| +| v1.0 | 2024-06-15 | 初版,定义核心表结构 | +| v2.0 | 2024-06-15 | diagnosis_record 字段泛化,支持多种故障类型 | +| v2.1 | 2024-06-22 | 文档拆分,增加 api_document 表 | + +--- + +## 六、维护说明 + +- 每个表的详细设计在 `tables/` 目录下 +- 架构设计文档在 `architecture/` 目录下 +- 修改表结构时,同步更新对应的 Markdown 文档 +- 重大变更需记录在版本历史中 diff --git a/docs/tables/api_document.md b/docs/tables/api_document.md new file mode 100644 index 0000000..2669213 --- /dev/null +++ b/docs/tables/api_document.md @@ -0,0 +1,332 @@ +# api_document - 文档元数据表 + +## 表定位 + +**文档管理表**:管理接口文档的元信息,不负责文档检索(检索由 Milvus 负责) + +## 设计理念 + +### 文档管理,不是文档检索 + +**核心定位**: +- MySQL 负责文档元数据管理(状态、版本、去重) +- Milvus 负责文档内容存储和检索 +- 通过 doc_id 关联两者 + +**MVP版本原则**: +- ✅ 最简字段,满足基本管理需求 +- ✅ 文件去重(基于 file_hash) +- ✅ 状态追踪(索引进度) +- ✅ 硬删除(同步删除 Milvus 数据) +- ❌ 暂不支持:软删除、启用开关、版本管理(Phase 2) + +--- + +## 表结构(MVP版) + +```sql +CREATE TABLE api_document ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + doc_id VARCHAR(64) UNIQUE NOT NULL COMMENT '文档唯一ID(UUID),关联Milvus', + + -- 文档分类 + fault_category VARCHAR(32) DEFAULT 'EXTERNAL_API' COMMENT '文档类别', + fault_source VARCHAR(128) COMMENT '文档归属(省份/服务名)', + api_name VARCHAR(128) COMMENT '接口名称', + version VARCHAR(32) DEFAULT 'v1.0' COMMENT '文档版本', + + -- 文件信息 + file_name VARCHAR(256) NOT NULL COMMENT '原始文件名', + file_path VARCHAR(512) COMMENT '文件存储路径', + file_hash VARCHAR(64) COMMENT '文件MD5 hash(用于去重)', + file_size BIGINT COMMENT '文件大小(字节)', + + -- 索引状态 + status VARCHAR(16) DEFAULT 'PENDING' COMMENT '索引状态(PENDING/PROCESSING/INDEXED/FAILED)', + chunk_count INT DEFAULT 0 COMMENT '分块数量', + error_message TEXT COMMENT '失败原因', + + -- 时间字段 + indexed_at DATETIME COMMENT '索引完成时间', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- 索引 + UNIQUE INDEX uk_file_hash (file_hash), + INDEX idx_doc_id (doc_id), + INDEX idx_fault_source (fault_source), + INDEX idx_status (status), + INDEX idx_created_at (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文档元数据表(MVP版)'; +``` + +--- + +## 字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| doc_id | VARCHAR(64) | 是 | **核心**:文档唯一ID,关联 Milvus | +| fault_category | VARCHAR(32) | 否 | 文档类别 | +| fault_source | VARCHAR(128) | 否 | 文档归属(省份/服务名)| +| api_name | VARCHAR(128) | 否 | 接口名称 | +| version | VARCHAR(32) | 否 | 文档版本 | +| file_name | VARCHAR(256) | 是 | 原始文件名 | +| file_path | VARCHAR(512) | 否 | 文件存储路径 | +| file_hash | VARCHAR(64) | 否 | **去重关键**:文件MD5 | +| file_size | BIGINT | 否 | 文件大小 | +| status | VARCHAR(16) | 是 | **状态追踪**:PENDING/PROCESSING/INDEXED/FAILED | +| chunk_count | INT | 否 | 分块数量 | +| error_message | TEXT | 否 | 失败原因 | +| indexed_at | DATETIME | 否 | 索引完成时间 | + +--- + +## 核心设计决策 + +### 1. doc_id:MySQL 与 Milvus 的桥梁 + +``` +作用: +- MySQL:通过 doc_id 管理文档元数据 +- Milvus:每个 chunk 的 metadata 中携带 doc_id + +关联关系: +api_document (MySQL) + doc_id: doc-001 + ↓ 1:N +Milvus chunks + chunk_1: {doc_id: 'doc-001', text: '...', vector: [...]} + chunk_2: {doc_id: 'doc-001', text: '...', vector: [...]} + +管理操作: +- 删除文档: + DELETE FROM milvus_collection WHERE metadata["doc_id"] == 'doc-001'; + DELETE FROM api_document WHERE doc_id = 'doc-001'; +``` + +### 2. file_hash:文件去重 + +``` +去重流程: +1. 用户上传文件 + ↓ +2. 计算文件 MD5 + file_hash = md5(file_content) + ↓ +3. 检查是否已存在 + SELECT * FROM api_document WHERE file_hash = 'abc123...'; + ↓ +4a. 如果存在 → 提示"文档已存在" +4b. 如果不存在 → 继续导入 + +唯一约束:UNIQUE INDEX uk_file_hash (file_hash) +``` + +### 3. status:状态追踪 + +``` +状态流转: +PENDING (待处理) + ↓ +PROCESSING (处理中) + ↓ 成功 +INDEXED (已索引) + ↓ 失败 +FAILED (失败) + +用途: +- 批量导入时监控进度 +- 失败重试 +- 统计索引成功率 +``` + +### 4. 硬删除策略(MVP) + +``` +删除文档时: +1. 删除 Milvus 中的所有分块 +2. 删除 MySQL 元数据 +3. 可选:删除原始文件 + +特点: +- 简单直接 +- 数据彻底删除 +- 不可恢复(需谨慎) + +Phase 2 可增强: +- 软删除(archived_at) +- 启用开关(enabled) +``` + +--- + +## 数据流 + +### 场景1:导入新文档 + +``` +1. 用户上传文件 + ↓ +2. 计算 hash + ↓ +3. 检查去重(MySQL) + ↓ +4. 插入元数据(status=PROCESSING) + ↓ +5. 后台处理:解析 → 分块 → 向量化 → 存入 Milvus + ↓ +6. 更新状态(status=INDEXED, chunk_count=15) +``` + +### 场景2:删除文档 + +``` +1. 用户删除文档 + ↓ +2. 删除 Milvus 数据(WHERE metadata["doc_id"] == 'xxx') + ↓ +3. 删除 MySQL 元数据 + ↓ +4. 可选:删除原始文件 +``` + +### 场景3:重新索引 + +``` +1. 删除旧数据(Milvus + MySQL) + ↓ +2. 重新导入(同场景1) +``` + +--- + +## 典型查询 + +```sql +-- 查看文档列表 +SELECT doc_id, file_name, version, status, chunk_count, indexed_at +FROM api_document +WHERE fault_source = '广东' + AND status = 'INDEXED' +ORDER BY indexed_at DESC; + +-- 查询失败的文档 +SELECT doc_id, file_name, error_message +FROM api_document +WHERE status = 'FAILED'; + +-- 统计各状态文档数量 +SELECT status, COUNT(*) as count +FROM api_document +GROUP BY status; +``` + +--- + +## 与 Milvus 的协作 + +### Milvus Collection Schema + +```python +{ + "collection_name": "api_doc_collection", + "fields": [ + {"name": "id", "type": "VARCHAR", "is_primary": true}, + {"name": "content", "type": "VARCHAR"}, + {"name": "vector", "type": "FLOAT_VECTOR", "dim": 1536}, + {"name": "metadata", "type": "JSON"} + ] +} + +# metadata 结构 +{ + "doc_id": "doc-001", # 关联 MySQL + "_source": "/path/to/file", + "_file_name": "xxx.docx", + "chunkIndex": 0, + "totalChunks": 15 +} +``` + +### Java 代码示例 + +```java +// 插入时携带 doc_id +Map metadata = new HashMap<>(); +metadata.put("doc_id", docId); // 关联 MySQL +metadata.put("_source", filePath); +metadata.put("chunkIndex", chunkIndex); + +// 删除文档的所有分块 +String expr = String.format("metadata[\"doc_id\"] == \"%s\"", docId); +milvusClient.delete(DeleteParam.newBuilder() + .withCollectionName(COLLECTION_NAME) + .withExpr(expr) + .build()); +``` + +--- + +## 数据示例 + +```sql +-- 外部接口文档 +INSERT INTO api_document VALUES +(1, 'doc-001', 'EXTERNAL_API', '广东', '社保查询', 'v2.1', + '广东社保查询v2.1.docx', '/docs/guangdong/social-v2.1.docx', + 'abc123...', 1048576, + 'INDEXED', 15, NULL, '2024-06-15 10:30:00', NOW(), NOW()); + +-- 内部服务文档 +INSERT INTO api_document VALUES +(2, 'doc-002', 'INTERNAL_ERROR', 'order-service', '订单服务API', 'v1.0', + '订单服务API文档.pdf', '/docs/internal/order-service-api.pdf', + 'def456...', 2097152, + 'INDEXED', 20, NULL, '2024-06-14 15:20:00', NOW(), NOW()); + +-- 处理失败的文档 +INSERT INTO api_document VALUES +(3, 'doc-003', 'EXTERNAL_API', '江苏', '公积金查询', 'v1.5', + '江苏公积金查询.html', '/docs/jiangsu/fund-v1.5.html', + 'ghi789...', 512000, + 'FAILED', 0, '不支持HTML格式', NULL, NOW(), NOW()); +``` + +--- + +## 数据量预估 + +``` +预估:100-200 条 +- 外部接口文档:50-100 条 +- 内部服务文档:20-50 条 +- 其他文档:30-50 条 + +存储: +- 单条记录:约 1KB +- 200 条:约 200KB + +结论:数据量很小 +``` + +--- + +## MVP 版本的简化 + +``` +Phase 1(当前): +✅ 基础字段和表结构 +✅ 文件去重(file_hash) +✅ 状态追踪(status) +✅ 硬删除 +✅ 通过 doc_id 关联 Milvus + +Phase 2(未来增强): +❌ enabled(启用开关) +❌ archived_at(软删除) +❌ batch_id(批次管理) +❌ status 细化 +❌ tags(标签分类) +``` diff --git a/docs/tables/case_library.md b/docs/tables/case_library.md new file mode 100644 index 0000000..74c23f9 --- /dev/null +++ b/docs/tables/case_library.md @@ -0,0 +1,265 @@ +# case_library - 案例库表 + +## 表定位 + +**知识沉淀表**:存储高质量诊断案例,支持相似案例推荐 + +## 设计理念 + +### 知识沉淀,系统越用越智能 + +**核心价值**: +- 质量过滤:只存储高质量案例(成功诊断 + 用户反馈有用) +- 知识沉淀:历史诊断经验可复用 +- 提升准确率:相似问题提供历史参考 +- 加速诊断:快速推荐相似案例 + +**MVP版本设计原则**: +- ✅ 能用:满足基本案例推荐功能 +- ✅ 简单:字段不多,逻辑清晰 +- ✅ 可扩展:后续可增加字段 + +--- + +## 表结构(MVP版) + +```sql +CREATE TABLE case_library ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + case_id VARCHAR(64) UNIQUE NOT NULL COMMENT '案例唯一ID(UUID)', + + -- 来源关联 + diagnosis_id VARCHAR(64) COMMENT '关联诊断记录(可选,人工录入时为空)', + source_type VARCHAR(16) DEFAULT 'AUTO' COMMENT '来源类型(AUTO:自动生成/MANUAL:人工录入)', + + -- 案例分类 + fault_category VARCHAR(32) COMMENT '故障类别(EXTERNAL_API/INTERNAL_ERROR/DATABASE...)', + fault_source VARCHAR(128) COMMENT '故障源(省份/服务名/类名...)', + fault_target VARCHAR(256) COMMENT '故障目标(接口URL/方法名/SQL...)', + error_code VARCHAR(64) COMMENT '错误码', + + -- 案例内容 + title VARCHAR(256) NOT NULL COMMENT '案例标题(简短描述)', + root_cause TEXT NOT NULL COMMENT '根因分析', + solution TEXT NOT NULL COMMENT '解决方案', + + -- 简单统计 + reference_count INT DEFAULT 0 COMMENT '引用次数(被推荐的次数)', + + -- 元数据 + created_by VARCHAR(64) COMMENT '创建人', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- 索引 + INDEX idx_fault_category (fault_category), + INDEX idx_error_code (error_code), + INDEX idx_fault_source (fault_source), + INDEX idx_fault_target (fault_target(100)), + INDEX idx_diagnosis_id (diagnosis_id), + INDEX idx_reference_count (reference_count), + INDEX idx_created_at (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='案例库表(MVP版)'; +``` + +--- + +## 字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| case_id | VARCHAR(64) | 是 | 案例唯一标识(UUID)| +| diagnosis_id | VARCHAR(64) | 否 | 关联诊断记录(人工录入时为空)| +| source_type | VARCHAR(16) | 是 | 来源:AUTO(自动)/MANUAL(人工)| +| fault_category | VARCHAR(32) | 否 | 故障类别 | +| fault_source | VARCHAR(128) | 否 | 故障源 | +| fault_target | VARCHAR(256) | 否 | 故障目标(与 diagnosis_record 一致)| +| error_code | VARCHAR(64) | 否 | 错误码 | +| title | VARCHAR(256) | 是 | 案例标题 | +| root_cause | TEXT | 是 | 根因分析(核心内容)| +| solution | TEXT | 是 | 解决方案(核心内容)| +| reference_count | INT | 是 | 引用次数(用于排序)| + +--- + +## 核心设计决策 + +### 1. 案例来源 + +``` +来源1:自动生成(source_type=AUTO) +├─ 触发条件:诊断成功 + 用户反馈"有用" +├─ 关联诊断:diagnosis_id 不为空 +└─ 质量保证:用户验证过 + +来源2:人工录入(source_type=MANUAL) +├─ 运维团队总结的经典案例 +├─ diagnosis_id 为空 +└─ 质量最高 + +注意:诊断失败或用户反馈"无用"的不自动生成案例 +``` + +### 2. 简化的评分机制(MVP) + +``` +MVP版本:只按 reference_count 排序 +- 引用次数多的排前面 +- 简单有效 + +Phase 2 可增强: +- 增加 useful_count(用户反馈有用次数) +- 增加 score(综合评分) +- 增加 is_featured(人工标记的经典案例) +``` + +### 3. 与 diagnosis_record 的关系 + +``` +关系:一对一(可选) +- 一次诊断 → 可以生成一个案例 +- 通过 diagnosis_id 关联 +- diagnosis_id 可为空(人工录入案例) + +流程: +diagnosis_record(成功) + ↓ +用户反馈"有用" + ↓ +自动生成 case_library + ↓ +后续可人工修正、合并相似案例 +``` + +--- + +## 数据示例 + +### 示例1:外部接口故障案例 +```sql +INSERT INTO case_library VALUES +(1, 'case-001', 'diag-001', 'AUTO', 'EXTERNAL_API', '广东', '/api/v1/guangdong/social-security', '40003', + '广东社保查询idCard字段缺失', + '请求报文中未传入idCard字段,导致参数校验失败', + '前端表单增加idCard必填校验;后端增加参数校验提示', + 15, 'system', NOW(), NOW()); +``` + +### 示例2:内部错误案例 +```sql +INSERT INTO case_library VALUES +(2, 'case-002', 'diag-045', 'AUTO', 'INTERNAL_ERROR', 'order-service', 'OrderController.createOrder()', 'NullPointerException', + '订单服务创建订单空指针异常', + 'OrderController.createOrder()方法中user对象为null,未做空判断', + '在第45行添加空判断:if (user == null) throw new BizException("用户信息不存在")', + 8, 'system', NOW(), NOW()); +``` + +### 示例3:人工录入案例 +```sql +INSERT INTO case_library VALUES +(3, 'case-003', NULL, 'MANUAL', 'DATABASE', 'mysql-master-01', 'UPDATE orders SET status=? WHERE order_id=?', '1213', + '订单库存更新死锁通用处理', + '两个事务互相等待对方释放锁', + '调整事务加锁顺序:统一先锁订单,再锁库存;或使用乐观锁', + 3, 'admin', NOW(), NOW()); +``` + +--- + +## 典型查询 + +### 精确匹配查询 +```sql +-- 按错误码查询 +SELECT * FROM case_library +WHERE error_code = '40003' +ORDER BY reference_count DESC +LIMIT 5; + +-- 按故障类别 + 错误码 + 故障目标查询 +SELECT * FROM case_library +WHERE fault_category = 'INTERNAL_ERROR' + AND error_code = 'NullPointerException' + AND fault_target = 'OrderController.createOrder()' +ORDER BY reference_count DESC +LIMIT 5; +``` + +### 统计分析 +```sql +-- 统计案例分布 +SELECT + fault_category, + COUNT(*) as count, + AVG(reference_count) as avg_reference +FROM case_library +GROUP BY fault_category +ORDER BY count DESC; + +-- Top 引用案例 +SELECT title, reference_count, created_at +FROM case_library +ORDER BY reference_count DESC +LIMIT 10; +``` + +--- + +## 与 Milvus 的配合 + +### 混合检索策略 + +``` +1. 精确匹配(MySQL) + - 按 error_code 查询 + - 按 fault_category + fault_source 查询 + - 优点:快速、准确 + +2. 语义检索(Milvus) + - 将案例内容向量化 + - 按语义相似度查询 + - 优点:能找到相似但不同错误码的案例 + +3. 混合策略(推荐) + Step 1: 先精确匹配(MySQL) + Step 2: 如果结果 < 3 个,补充语义检索(Milvus) + Step 3: 合并去重,按 reference_count 排序 + Step 4: 返回 Top 5 +``` + +--- + +## 数据量预估 + +``` +预估:500-1000 条 +- 初期:每月新增 10-20 条 +- 稳定期:每月新增 5-10 条 +- 总量:1-2 年达到稳定 + +存储: +- 单条记录:约 2KB +- 1000 条:约 2MB + +结论:数据量很小 +``` + +--- + +## MVP 版本的简化 + +``` +Phase 1(当前): +✅ 基础字段和表结构 +✅ 自动生成案例 +✅ 人工录入案例 +✅ 按 reference_count 简单排序 + +Phase 2(未来增强): +❌ useful_count + score(复杂评分) +❌ 版本管理 +❌ 标签分类(tags) +❌ 案例合并功能 +``` diff --git a/docs/tables/diagnosis_record.md b/docs/tables/diagnosis_record.md new file mode 100644 index 0000000..db43a9e --- /dev/null +++ b/docs/tables/diagnosis_record.md @@ -0,0 +1,240 @@ +# diagnosis_record - 诊断记录表 + +## 表定位 + +**核心业务表**:存储每次诊断任务的完整记录 + +## 设计理念 + +### 兼容多种故障类型 + +**问题背景**: +- 初始设计过于聚焦"外部接口故障" +- 实际故障类型更丰富:空指针异常、数据库死锁、缓存穿透、线程池耗尽等 + +**解决方案**: +- 字段泛化:business_id 替代 order_id,fault_source 替代 province +- 增加分类:fault_category 显式区分故障类别 +- 增强错误信息:error_message、stack_trace 支持内部错误 + +--- + +## 表结构(v2.0) + +```sql +CREATE TABLE diagnosis_record ( + -- 主键 + id BIGINT PRIMARY KEY AUTO_INCREMENT, + diagnosis_id VARCHAR(64) UNIQUE NOT NULL COMMENT '诊断唯一ID(UUID)', + + -- 关联信息 + session_id VARCHAR(64) COMMENT '会话ID(关联Redis)', + business_id VARCHAR(128) COMMENT '业务标识(订单号/请求ID/线程ID/任务ID...)', + trace_id VARCHAR(64) COMMENT '链路追踪ID', + + -- 故障分类(泛化设计) + fault_category VARCHAR(32) COMMENT '故障类别(EXTERNAL_API/INTERNAL_ERROR/DATABASE/CACHE/NETWORK/THREAD/MEMORY/CONFIG)', + fault_source VARCHAR(128) COMMENT '故障源(省份/服务名/类名/数据库实例...)', + fault_target VARCHAR(256) COMMENT '故障目标(接口URL/方法名/SQL语句/缓存键...)', + + -- 错误信息(通用) + error_code VARCHAR(64) COMMENT '错误码(业务错误码/HTTP状态码/异常类名)', + error_message TEXT COMMENT '错误消息', + stack_trace TEXT COMMENT '堆栈信息(内部错误时记录)', + + -- 诊断结果 + problem_type VARCHAR(32) COMMENT '问题类型(参数/网络/权限/逻辑/空指针/死锁...)', + root_cause TEXT COMMENT '根因分析', + solution TEXT COMMENT '修复方案', + report_markdown TEXT COMMENT '完整诊断报告(Markdown格式)', + + -- 评估指标 + status VARCHAR(16) DEFAULT 'PENDING' COMMENT '诊断状态(PENDING/RUNNING/SUCCESS/FAILED)', + confidence INT COMMENT '诊断置信度(0-100)', + duration INT COMMENT '诊断耗时(毫秒)', + + -- 用户反馈 + feedback VARCHAR(16) COMMENT '用户反馈(useful/not_useful/null)TODO: 后续可拆分为独立反馈表', + + -- 调试字段 + tool_calls JSON COMMENT '工具调用记录', + + -- 元数据 + created_by VARCHAR(64) COMMENT '创建人', + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- 索引 + INDEX idx_business_id (business_id), + INDEX idx_trace_id (trace_id), + INDEX idx_session_id (session_id), + INDEX idx_fault_category (fault_category), + INDEX idx_fault_source_target (fault_source, fault_target(100)), + INDEX idx_error_code (error_code), + INDEX idx_created_at (created_at), + INDEX idx_status (status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='诊断记录表(v2.0 泛化版)'; +``` + +--- + +## 字段说明 + +### 核心字段 + +| 字段 | 说明 | 示例 | +|------|------|------| +| diagnosis_id | 诊断唯一标识 | diag-001 | +| session_id | 会话ID(支持追问) | sess-abc | +| business_id | **泛化**:业务标识 | 订单号/请求ID/线程ID | +| trace_id | 链路追踪ID | trace-xyz | + +### 故障分类字段(泛化设计) + +| 字段 | 说明 | 外部接口示例 | 内部错误示例 | +|------|------|-------------|-------------| +| fault_category | 故障类别 | EXTERNAL_API | INTERNAL_ERROR | +| fault_source | 故障源 | 广东 | order-service | +| fault_target | 故障目标 | /api/v1/social | OrderController.create() | +| error_code | 错误码 | 40003 | NullPointerException | + +### fault_category 枚举值 + +``` +EXTERNAL_API - 外部接口调用失败 +INTERNAL_ERROR - 系统内部错误(空指针、NPE) +DATABASE - 数据库问题(死锁、慢查询) +CACHE - 缓存问题(穿透、雪崩) +NETWORK - 网络问题(超时、连接失败) +THREAD - 线程问题(线程池满、死锁) +MEMORY - 内存问题(OOM、内存泄漏) +CONFIG - 配置问题(配置错误、缺失) +``` + +--- + +## 数据示例 + +### 示例1:外部接口故障 +```sql +INSERT INTO diagnosis_record VALUES ( + NULL, 'diag-001', 'sess-abc', '202406150001', 'trace-001', + 'EXTERNAL_API', '广东', '/api/v1/guangdong/social-security', '40003', + '参数缺失:idCard', NULL, + '参数问题', 'idCard字段缺失', '补充前端校验', '完整报告...', + 'SUCCESS', 85, 5234, NULL, + NULL, NOW(), NOW() +); +``` + +### 示例2:空指针异常 +```sql +INSERT INTO diagnosis_record VALUES ( + NULL, 'diag-002', 'sess-def', 'req-xyz789', NULL, + 'INTERNAL_ERROR', 'order-service', 'OrderController.createOrder()', 'NullPointerException', + 'Cannot invoke "User.getName()" because "user" is null', + 'java.lang.NullPointerException: ...\n at OrderController.java:45\n ...', + '空指针异常', 'createOrder方法中user对象为null', '添加空判断', '完整报告...', + 'SUCCESS', 90, 3456, NULL, + NULL, NOW(), NOW() +); +``` + +### 示例3:数据库死锁 +```sql +INSERT INTO diagnosis_record VALUES ( + NULL, 'diag-003', 'sess-ghi', 'txn-20240615-001', NULL, + 'DATABASE', 'mysql-master-01', 'UPDATE orders SET status=? WHERE order_id=?', '1213', + 'Deadlock found when trying to get lock', NULL, + '数据库死锁', '两个事务互相等待对方释放锁', '调整事务加锁顺序', '完整报告...', + 'SUCCESS', 88, 4567, NULL, + NULL, NOW(), NOW() +); +``` + +--- + +## 典型查询 + +### 按故障类别统计 +```sql +SELECT + fault_category, + COUNT(*) as count, + ROUND(AVG(duration), 2) as avg_duration_ms, + ROUND(AVG(confidence), 2) as avg_confidence +FROM diagnosis_record +WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) +GROUP BY fault_category +ORDER BY count DESC; +``` + +### 内部错误Top异常 +```sql +SELECT + error_code, + fault_target, + COUNT(*) as count +FROM diagnosis_record +WHERE fault_category = 'INTERNAL_ERROR' + AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) +GROUP BY error_code, fault_target +ORDER BY count DESC +LIMIT 10; +``` + +### 诊断成功率 +```sql +SELECT + COUNT(*) as total, + SUM(CASE WHEN status = 'SUCCESS' THEN 1 ELSE 0 END) as success, + ROUND(SUM(CASE WHEN status = 'SUCCESS' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as success_rate +FROM diagnosis_record +WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY); +``` + +--- + +## 核心设计决策 + +### 1. 一次诊断 = 一条记录 +- 用户发起一次诊断任务,创建一条记录 +- 不是聊天记录(不存多轮对话) +- 追问对话上下文暂存 Redis(30分钟过期) + +### 2. report_markdown 字段的必要性 +- 固化结果:Prompt变化不影响历史报告 +- 快速展示:不需要重新生成 +- 历史审计:可以看到当时的诊断结果 + +### 3. 字段泛化的好处 +- 支持多种故障类型(不限于外部接口) +- 灵活填写(根据故障类型选择字段值) +- 易于扩展(新增故障类型只需增加枚举值) + +--- + +## 数据量预估 + +``` +场景:中型企业运维团队 +- 日均诊断:100 次 +- 月均诊断:3000 次 +- 年均诊断:36000 次 + +存储预估: +- 单条记录:约 5KB(含报告) +- 年存储量:36000 × 5KB = 180MB +- 三年存储:540MB + +结论:数据量不大,可以全量保留 +``` + +--- + +## 版本历史 + +| 版本 | 日期 | 变更内容 | +|------|------|---------| +| v1.0 | 2024-06-15 | 初版,基础字段 | +| v2.0 | 2024-06-22 | 字段泛化,支持多种故障类型 |