# diagnosis_record - 旧诊断记录表 > 归档说明:`diagnosis_record` 已在 `V007__drop_diagnosis_record.sql` 中删除,当前主模型是 `diagnosis_session + agent_step + tool_invocation`。本文只用于追溯早期设计。 ## 表定位 **核心业务表**:存储每次诊断任务的完整记录 ## 设计理念 ### 兼容多种故障类型 **问题背景**: - 初始设计过于聚焦"外部接口故障" - 实际故障类型更丰富:空指针异常、数据库死锁、缓存穿透、线程池耗尽等 **解决方案**: - 字段泛化: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 | 字段泛化,支持多种故障类型 |