From 9b52afce07a81e2895f6ba5e43ddbcbea5d92ae3 Mon Sep 17 00:00:00 2001 From: zhuyongxin Date: Fri, 26 Jun 2026 17:29:27 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=90=88=E5=B9=B6=20.docs/mvp=20?= =?UTF-8?q?=E5=88=B0=E6=A0=B9=20mvp=20=E7=9B=AE=E5=BD=95=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 .docs/mvp 目录,内容合并到根目录 mvp/ - 更新 session-storage-design.md 实现变更记录 - 修复引用路径 --- ...24-ai-ops-prompt-config-and-lookup-tool.md | 2 +- .../knowledge-retrieval-architecture.md | 421 ------------------ .docs/mvp/plan/session-storage-design.md | 266 ----------- bash.exe.stackdump | 2 +- mvp/plan/session-storage-design.md | 32 +- 5 files changed, 33 insertions(+), 690 deletions(-) delete mode 100644 .docs/mvp/architecture/knowledge-retrieval-architecture.md delete mode 100644 .docs/mvp/plan/session-storage-design.md diff --git a/.docs/2026-06-24-ai-ops-prompt-config-and-lookup-tool.md b/.docs/2026-06-24-ai-ops-prompt-config-and-lookup-tool.md index 38c0b5b..39d6371 100644 --- a/.docs/2026-06-24-ai-ops-prompt-config-and-lookup-tool.md +++ b/.docs/2026-06-24-ai-ops-prompt-config-and-lookup-tool.md @@ -229,5 +229,5 @@ category: api ## 八、参考文档 -- [知识库检索架构说明](./mvp/architecture/knowledge-retrieval-architecture.md) +- [知识库检索架构说明](../mvp/architecture/knowledge-retrieval-architecture.md) - [AI Ops 核心设计 Essence 报告](../docs/learning/01-AI-Ops-核心设计-Essence报告.md) diff --git a/.docs/mvp/architecture/knowledge-retrieval-architecture.md b/.docs/mvp/architecture/knowledge-retrieval-architecture.md deleted file mode 100644 index f9bbc54..0000000 --- a/.docs/mvp/architecture/knowledge-retrieval-architecture.md +++ /dev/null @@ -1,421 +0,0 @@ -# 知识库检索架构(L0 + L1) - -**更新日期**: 2026-06-25 - ---- - -## 一、概述 - -`LookupKnowledgeTool` 实现两阶段混合检索: - -- **L0 精确匹配**:基于内存索引的关键词匹配(< 10ms),索引从数据库加载 -- **L1 语义检索**:基于 Milvus 向量数据库的相似度搜索(200-500ms) - ---- - -## 二、完整流程 - -``` -用户查询 - │ - ▼ -┌─────────────────────────────┐ -│ L0: 关键词精确匹配 │ (< 10ms) -│ • 从内存索引做关键词匹配 │ -│ • 索引来源: ApiDocument DB│ -└──────────┬──────────────────┘ - │ - ▼ - ┌──────┴──────┐ - │ matches=1 │ ← 唯一匹配(高置信度) - └──────┬──────┘ - │ - ▼ - ┌──────────────┐ ┌──────────────────┐ - │ 跳过 L1 │ │ L0 返回正文摘要 │ - │ 置信度: high │ │ buildCompactSummary│ - └──────────────┘ └──────────────────┘ - - - ┌──────┴──────┐ - │ matches=0 │ ← 无匹配 - └──────┬──────┘ - │ - ▼ - ┌──────────────┐ ┌──────────────────┐ - │ 触发 L1 │ │ L0 无结果 │ - │ L1 语义检索 │ │ 仅有 L1 补充结果 │ - └──────────────┘ └──────────────────┘ - - - ┌──────┴──────┐ - │ matches>=2 │ ← 多匹配 - └──────┬──────┘ - │ - ▼ - ┌──────────────┐ - │ 触发 L1 │ - │ L1 语义检索 │ - └──────┬──────┘ - │ - ┌─────┴─────┐ - │ ║ │ - ▼ ▼ - L1 有结果 L1 无结果 - │ │ - ▼ ▼ - 元数据摘要 正文摘要 - (不读文件) (读文件) -``` - ---- - -## 三、L0 返回内容策略 - -根据匹配场景决定 L0 返回给 LLM 的上下文内容量。 - -### 3.1 唯一匹配(高置信度,matches=1) - -**策略**: `buildCompactSummary()` - -L1 被跳过,LLM 只有 L0 信息来源,需要提供足够的正文内容。 - -``` -文档: 支付网关错误码定义 -摘要: 记录了支付网关所有核心错误码的含义及排查方向 -章节: - - 超时类错误 - - 业务类错误 - - 签名类错误 ---- -**含义**:支付网关请求超时 -**常见原因**:网络延迟、第三方服务响应慢 -... -``` - -| 组成部分 | 说明 | 大小 | -|---------|------|------| -| title + summary | 从内存索引获取 | ~50-100 字符 | -| 章节标题列表 | 从文件解析 `##` 标题 | ~50-200 字符 | -| 正文片段 | 去 frontmatter/标题行/空行,短文档 800/长文档 500 字符截断 | ~300-800 字符 | -| **总计** | | **~400-1000 字符** | - -### 3.2 多匹配 + L1 有结果 - -**策略**: `buildMetadataOnlySummary()` - -L1 已有语义内容片段,L0 仅需告知 LLM 命中了哪些文档。**不读文件**,仅用内存索引。 - -``` -文档: 支付网关错误码定义 -摘要: 记录了支付网关所有核心错误码的含义及排查方向 -关键词: ERR_TIMEOUT, 超时, 支付网关 -来源: api/payment-errors.md -``` - -| 组成部分 | 说明 | 大小 | -|---------|------|------| -| title + summary + keywords | 全部从内存索引获取 | ~100-200 字符 | -| **总计** | | **~100-200 字符** | - -### 3.3 多匹配 + L1 无结果 - -**策略**: `buildCompactSummary()`(同 3.1) - -L1 未返回结果, L0 作为兜底提供正文内容。 - ---- - -## 四、决策矩阵 - -``` -needFullContent = highConfidence || !hasL1 -``` - -| 场景 | matches | L1 结果 | needFullContent | L0 策略 | 是否读文件 | 上下文大小 | -|------|:-------:|:--------:|:---------------:|---------|:---------:|:--------:| -| 唯一匹配 | 1 | 未执行 | true | `buildCompactSummary` | 是 | ~600 字符 | -| 多匹配 + L1 有结果 | 2+ | 有 | false | `buildMetadataOnlySummary` | **否** | ~150 字符 | -| 多匹配 + L1 无结果 | 2+ | 无 | true | `buildCompactSummary` | 是 | ~600 字符 | -| 无匹配 | 0 | 有 | — | 无 L0,仅 L1 | 否 | 0 | - ---- - -## 五、代码结构 - -``` -LookupKnowledgeTool - ├── lookupKnowledge(query) # 入口:编排 L0 + L1 - ├── buildResult(l0, l1, confidence) # 组装结果,选择摘要策略 - ├── buildCompactSummary(entry) # 元数据 + 章节 + 正文片段(读文件) - ├── buildMetadataOnlySummary(entry) # 仅元数据(不读文件) - ├── countMdHeadings(content) # 统计章节数(日志用) - └── extractFirstMeaningfulLine(...) # 提取首个有意义文本行(日志用) -``` - -### 关键逻辑(buildResult) - -```java -boolean needFullContent = highConfidence || !hasL1; -String content = needFullContent - ? buildCompactSummary(first) - : buildMetadataOnlySummary(first); -``` - ---- - -## 六、日志输出示例 - -### 多匹配场景(matches=2, L1 有结果) - -``` -[L0 精确匹配] 完成: matches=2, time=3ms -[置信度判断] highConfidence=false, reason=多个或零个匹配 -[L1 语义检索] L0非唯一匹配,触发L1语义检索... -[L1 语义检索] 完成: matches=1, time=245ms ----------------------------------------- -<<< [工具返回] lookup_knowledge -<<< [L0 主结果] 标题: 支付网关错误码定义 -<<< [L0 主结果] 摘要: 记录了支付网关所有核心错误码的含义及排查方向 ← 仅元数据 -<<< [L0 主结果] 内容: 126 字符, 0 个章节 ← 约150字符 -<<< [L1 补充] 相似度: 0.8234 -<<< [L1 补充] 内容片段: 支付网关请求超时... ← L1 提供具体内容 -``` - -### 唯一匹配场景(matches=1, 跳过 L1) - -``` -[L0 精确匹配] 完成: matches=1, time=2ms -[置信度判断] highConfidence=true, reason=唯一匹配 -[L1 语义检索] L0唯一匹配,跳过L1检索 ----------------------------------------- -<<< [工具返回] lookup_knowledge -<<< [L0 主结果] 标题: 支付网关错误码定义 -<<< [L0 主结果] 摘要: 记录了支付网关所有核心错误码的含义及排查方向 -<<< [L0 主结果] 内容: 725 字符, 3 个章节 ← 约700字符 -``` - ---- - -## 七、MVP 效率评估 & 改进方向 - -### 7.1 当前效率评估 - -| 维度 | 评分 | 说明 | -|------|:----:|------| -| L0 匹配速度 | ★★★★★ | 内存索引,< 10ms,几乎没有优化空间 | -| L1 检索速度 | ★★★★☆ | Milvus 向量检索,200-500ms,取决于数据量 | -| L0 匹配准确率 | ★★☆☆☆ | 子串匹配,无排序无评分,匹配即返回 | -| L1 检索准确率 | ★★★☆☆ | 语义相似度,但分块缺少上下文信息 | -| 召回率(查全) | ★★★☆☆ | L0+L1 两阶段覆盖大多数场景,但缺乏融合重排 | -| 上下文利用率 | ★★★★☆ | 根据场景动态控制 L0 内容量,已优化 | -| **综合** | **★★★☆☆** | **MVP 可用,但检索质量有提升空间** | - -### 7.2 关键瓶颈 - -#### 瓶颈 1:分块丢失上下文(✅ 已修复—见下方 7.5) - -当前每个 Chunk 只记录最近的 `##` 标题: - -```json -{ - "content": "**含义**:支付网关请求超时\n**常见原因**:网络延迟", - "title": "超时类错误", - "chunkIndex": 2 -} -``` - -LLM 收到这个片段时**不知道**它属于"支付网关错误码定义"这个文档,也不知道具体错误码名称是 ERR_TIMEOUT。如果同时检索了多个文档的片段,LLM 容易混淆。 - -#### 瓶颈 2:L0 关键词匹配过于简单 - -当前 `KnowledgeIndexService.matchesKeywords()` 只做子串包含匹配,没有: -- 排序/评分(多个匹配时按什么顺序?) -- 权重(标题匹配 > 正文匹配) -- 部分匹配("timeout" 匹配 "ERR_TIMEOUT") - -#### 瓶颈 3:L0 和 L1 无交叉融合 - -两阶段检索结果只是简单的"1位L0 + 1位L1"拼接,没有: -- RRF 或加权融合重排 -- 重复内容去重 -- 根据相关性选择 top-K - ---- - -### 7.3 改进方向分析 - -#### 方向 A:面包屑导航(Chunk 携带层级上下文) - -**做法**:分块时记录完整的标题层级路径作为 `breadcrumb`。 - -当前分块 metadata: -```json -{ "title": "超时类错误" } -``` - -改进后: -```json -{ - "title": "超时类错误", - "breadcrumb": "支付网关错误码定义 > 超时类错误 > ERR_TIMEOUT", - "heading_h1": "支付网关错误码定义", - "heading_h2": "超时类错误", - "heading_h3": "ERR_TIMEOUT" -} -``` - -**收益评估**: - -| 场景 | 无面包屑的问题 | 有面包屑的改善 | 提升幅度 | -|------|---------------|---------------|:--------:| -| 单文档多分块 | LLM 知道标题但不知道层级关系 | 清楚"文档>章节>条目"归属 | 中等 | -| 跨文档混合结果 | 分块看不出源文档 | breadcrumb 第一段就是文档标题 | 大 | -| 深层嵌套文档(3+ 级) | 分块内容难以定位 | 完整路径一目了然 | 显著 | -| 向量检索相关性 | 只对 chunk content 做 embedding | breadcrumb 可拼入 content 做 embedding 或单独索引 | 中等 | - -**MVP 阶段价值**:当前文档结构较浅(2-3级),breadcrumb 对 LLM 理解帮助中等。但如果后续文档层级加深(像你提到的"排障指南 > 支付网关 > 502错误处理"),价值会显著提升。 - -**实现成本**:低。修改 `DocumentChunkService` 的分块逻辑,积累当前标题栈,写入 `DocumentChunk` 和 Milvus metadata。 - -#### 方向 B:混合检索 + RRF 重排 - -**做法**:L0 关键词和 L1 向量检索并行执行 → 结果用 Reciprocal Rank Fusion 统一排序 → 取 top-K。 - -``` -用户查询 → 并行的: - ├── L0 关键词匹配 → 得分向量 S₀ - └── L1 向量检索 → 得分向量 S₁ - ↓ - RRF 融合重排 - ↓ - top-K 统一结果 -``` - -RRF 公式:对每个文档 d,`score(d) = Σ 1/(k + rank_r(d))`,其中 k=60(常数)。 - -**收益评估**: - -| 场景 | 当前的问题 | 混合 + RRF | 提升幅度 | -|------|-----------|-----------|:--------:| -| 精确关键词("ERR_TIMEOUT") | L0 匹配但不排序,L1 可能不匹配 | L0 高排名 → RRF 拉到顶部 | 大 | -| 语义查询("支付超时如何处理") | L0 可能不匹配,全靠 L1 | L1 兜底不受影响 | 无变化 | -| 混合查询("ERR_TIMEOUT 支付网关超时") | L0 匹配一个、L1 匹配一个,无融合 | RRF 统一排序,更合理 | 中等 | -| 多文档匹配 | L0 返回无序列表 + L1 独立结果 | 统一排序、去重 | 大 | - -**MVP 阶段价值**:RRF 的实现成本和维护成本较高,而当前 MVP 数据量小(6 个文档),人工检查即可确定哪些匹配是好的。**建议数据量 > 50 个文档时引入**。 - -#### 方向 C:Breadcrumb + Embedding 增强 - -**做法**:将 breadcrumb 拼入 chunk content 后再做 embedding,让向量包含层级语义。 - -```java -// 当前 -embeddingService.generateEmbedding(chunk.getContent()) - -// 改进 -String augmentedContent = chunk.getBreadcrumb() + "\n" + chunk.getContent(); -embeddingService.generateEmbedding(augmentedContent); -``` - -这样搜索"ERR_TIMEOUT"时,"支付网关错误码定义 > 超时类错误 > ERR_TIMEOUT" 也会匹配到,而不只是 chunk 正文。 - -| 场景 | 当前 | Breadcrumb + Embedding | 提升 | -|------|------|------------------------|:----:| -| 搜索"支付网关超时" | 匹配到正文含"超时"和"支付网关"的 chunk | breadcrumb 直接含"支付网关",匹配更准 | 中等 | -| 搜索"错误码定义" | 可能匹配不到具体错误内容的 chunk | breadcrumb 含"错误码定义",相关性更高 | 大 | - ---- - -### 7.4 实施优先级建议 - -| 优先级 | 改进项 | 复杂度 | 收益 | 状态 | -|:------:|--------|:------:|:----:|:----:| -| P0 | **Breadcrumb 上下文**(方向 A) | 低 | 中 | **✅ 已实现 (2026-06-26)** | -| P1 | 下个版本 | 低 | 中-大 | 待定 | -| P1 | L0 排序(匹配评分 + 排序) | 低 | 中 | 待定 | -| P2 | 混合检索 + RRF 重排 | 高 | 大 | 数据量 > 50 文档时引入 | - -### 7.5 Breadcrumb 实现说明 - -已于 2026-06-26 实现。改动范围: - -| 文件 | 改动 | -|------|------| -| `DocumentChunk.java` | 新增 `breadcrumb` 字段 | -| `DocumentChunkService.java` | `splitByHeadings()` 维护标题层级栈,`Section` 新增 `level`/`breadcrumb`,`chunkSection()` 和 `saveChunkAndGetNextStart()` 透传 Breadcrumb | -| `VectorIndexService.java` | `buildMetadata()` 和 `buildDocumentMetadata()` 将 breadcrumb 写入 Milvus metadata | - -#### 层级栈算法 - -```java -// 在 splitByHeadings() 中,每次匹配到标题时: -while (!headingStack.isEmpty() && headingStack.size() >= level) { - headingStack.remove(headingStack.size() - 1); // 弹出同级或更高级 -} -headingStack.add(title); // 追加当前标题 -currentBreadcrumb = String.join(" > ", headingStack); -``` - -示例:处理 `fault-diagnosis-process.md` 的完整面包屑路径── - -```json -// 分块 "应急响应流程 > 1. 初步评估" -{ "breadcrumb": "故障诊断流程规范 > 应急响应流程 > 1. 初步评估" } - -// 分块 "根因分析方法 > 5-Why 分析法" -{ "breadcrumb": "故障诊断流程规范 > 根因分析方法 > 5-Why 分析法" } -``` - -#### 当前 metadata 结构(Milvus) - -```json -{ - "_source": "knowledge_base/api/payment-errors.md", - "_file_name": "payment-errors.md", - "category": "api", - "chunkIndex": 2, - "totalChunks": 5, - "title": "超时类错误", - "breadcrumb": "支付网关错误码定义 > 超时类错误 > ERR_TIMEOUT" -} -``` - -以 `fault-diagnosis-process.md` 为例: - -```markdown -# 故障诊断流程规范 ← heading_h1 - -## 应急响应流程 ← heading_h2 - -### 1. 初步评估 ← heading_h3(分块1) -内容... - -### 2. 快速止血 ← heading_h3(分块2) -内容... - -## 根因分析方法 ← heading_h2 - -### 5-Why 分析法 ← heading_h3(分块3) -内容... -``` - -改造后每个分块的 metadata: - -``` -分块1: breadcrumb = "故障诊断流程规范 > 应急响应流程 > 1. 初步评估" -分块2: breadcrumb = "故障诊断流程规范 > 应急响应流程 > 2. 快速止血" -分块3: breadcrumb = "故障诊断流程规范 > 根因分析方法 > 5-Why 分析法" -``` - -LLM 视角受益:当检索到 "2. 快速止血" 时,LLM 立刻知道它属于"故障诊断流程规范 > 应急响应流程"体系,不需要额外读取其他分块来推断上下文。 - -| 文件 | 说明 | -|------|------| -| `LookupKnowledgeTool.java` | 检索工具入口 | -| `KnowledgeIndexService.java` | L0 内存索引管理 | -| `VectorSearchService.java` | L1 向量检索(Milvus) | -| `KnowledgeEntry.java` | 索引条目 DTO(含 title, summary, keywords) | -| `LookupResult.java` | 查询结果 DTO | -| `PrimaryResult.java` | L0 结果 DTO | -| `SupplementResult.java` | L1 结果 DTO | diff --git a/.docs/mvp/plan/session-storage-design.md b/.docs/mvp/plan/session-storage-design.md deleted file mode 100644 index c0bdda5..0000000 --- a/.docs/mvp/plan/session-storage-design.md +++ /dev/null @@ -1,266 +0,0 @@ -# 会话存储方案设计 - -**日期**: 2026-06-26 -**类型**: 架构设计 -**状态**: 待评审 - ---- - -## 一、背景与目标 - -### 1.1 现状问题 - -当前仅有一张 `diagnosis_record` 表,存在以下问题: - -| 问题 | 说明 | -|------|------| -| **语义耦合** | `fault_category`、`error_code`、`root_cause`、`solution` 等字段耦合在"告警分析"领域语义,ChatService 通用问答场景用不上 | -| **Agent 维度缺失** | 只有一个 `tool_calls` JSON 字段,存不下两个 Agent 的多轮决策链 | -| **检索质量不可追溯** | 没有记录 L0/L1 命中层、截断信息、召回内容长度 | -| **指标不完整** | 有 `duration` 和 `confidence`,但缺 token 用量、自评信号、采纳率 | - -### 1.2 存储范围 - -需要覆盖四个层面的数据: - -``` -诊断级元数据 - ├── 单次诊断的唯一 ID、查询问题、状态 - ├── 会话级决策链 - │ ├── agent_step:每个 Agent 的每一步(输入、输出、延迟、Token) - │ └── tool_invocation:每次工具调用(参数、结果、耗时) - ├── 检索质量明细 - │ └── 每次 lookup_knowledge 的命中层(L0/L1)、内容长度、是否截断 - └── 自评估信号 - └── LLM 对结论的置信度自评 -``` - -### 1.3 设计目标 - -- **可观测**:Debug 时能回溯完整决策链 -- **可评估**:能统计 L0/L1 命中率、平均 Token 消耗、工具采纳率等指标 -- **可演进**:覆盖当前两个 Agent(ChatService / AiOpsService),未来新增 Agent 也能接入 - ---- - -## 二、存储选型分析 - -### 2.1 方案对比 - -| 维度 | SQL + JSON 列 | NoSQL 文档库 | -|------|:------------:|:-----------:| -| 基础设施 | 已有的 MySQL,零新增 | 需新部署 MongoDB 等 | -| 层级查询 | `WHERE session_id=? AND agent_name=?` 高效 | 需二级索引 | -| 指标聚合 | `AVG(token_count) GROUP BY agent_name` 原生支持 | 聚合管道,学习成本 | -| 非结构化内容 | JSON 列(MySQL 8+ 支持良好) | 天然支持 | -| MVP 迭代速度 | JPA Entity + Flyway 快速迭代 | 新 ORM 学习成本 | - -### 2.2 结论 - -**采用 MySQL + JSON 列**。结构化字段做查询和聚合,JSON 列存非结构化载荷。MVP 阶段数据量可控,等后续 > 百万级或需要更灵活 schema 时再评估 NoSQL。 - ---- - -## 三、存储模型 - -### 3.1 整体关系 - -``` -diagnosis_session (1) - │ - └── agent_step (0:N) —— 单次诊断的每一步 Agent 决策 - │ - └── tool_invocation (0:N) —— 每步中的工具调用 -``` - -### 3.2 表设计 - -#### 表 1:diagnosis_session(诊断会话) - -```sql -CREATE TABLE diagnosis_session ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - session_id VARCHAR(64) UNIQUE NOT NULL COMMENT '会话唯一 ID', - - -- 请求 - query TEXT NOT NULL COMMENT '用户原始问题', - status VARCHAR(16) DEFAULT 'PENDING' COMMENT 'PENDING / RUNNING / SUCCESS / FAILED', - agent_flow VARCHAR(32) COMMENT 'CHAT / AI_OPS', - - -- 汇总指标 - total_duration_ms INT COMMENT '总耗时(毫秒)', - total_token_count INT COMMENT '总 Token 消耗', - step_count INT COMMENT 'Agent 步数', - tool_call_count INT COMMENT '工具调用次数', - - -- 自评估信号(模型对结论的置信度自评) - self_evaluation JSON COMMENT '{"confidence": 0-100, "reasoning": "...", "evidence_count": 3}', - - -- 用户反馈 - feedback VARCHAR(16) COMMENT 'useful / not_useful / null', - - -- 元数据 - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - INDEX idx_created_at (created_at), - INDEX idx_status (status), - INDEX idx_agent_flow (agent_flow) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='诊断会话表'; -``` - -#### 表 2:agent_step(Agent 决策步骤) - -```sql -CREATE TABLE agent_step ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - session_id VARCHAR(64) NOT NULL COMMENT '关联 diagnosis_session', - - step_index INT NOT NULL COMMENT '当前 Agent 的第几步(从0开始)', - agent_name VARCHAR(32) NOT NULL COMMENT 'intelligent_assistant / planner / executor / supervisor', - - -- 模型调用(输入输出摘要,非完整消息体) - model_input JSON COMMENT '模型输入摘要 [{role, content_truncated}, ...]', - model_output JSON COMMENT '模型输出摘要 {text, tool_calls, ...}', - thought TEXT COMMENT 'Agent 思考过程文本', - has_tool_call BOOLEAN DEFAULT FALSE COMMENT '本轮是否调用了工具', - - -- 性能指标 - duration_ms INT COMMENT '本轮耗时', - token_count INT COMMENT '本轮 Token 消耗', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - - INDEX idx_session_step (session_id, step_index), - INDEX idx_agent_name (agent_name) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Agent 决策步骤表'; -``` - -#### 表 3:tool_invocation(工具调用明细) - -```sql -CREATE TABLE tool_invocation ( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - session_id VARCHAR(64) NOT NULL COMMENT '关联 diagnosis_session', - step_id BIGINT COMMENT '关联 agent_step.id(可为空,不强制外键)', - - tool_name VARCHAR(64) NOT NULL COMMENT 'lookup_knowledge / queryPrometheusAlerts / 等', - - -- 调用信息 - input_params JSON NOT NULL COMMENT '工具入参', - output_preview TEXT COMMENT '输出前500字符(可观测用,不存完整输出)', - output_length INT COMMENT '输出总字符数', - - -- 检索质量(仅 lookup_knowledge 时有意义) - retrieval_layer VARCHAR(8) COMMENT 'L0 / L1 / L0+L1', - l0_match_count INT COMMENT 'L0 匹配数', - l1_match_count INT COMMENT 'L1 匹配数', - is_truncated BOOLEAN DEFAULT FALSE COMMENT '返回内容是否被截断', - retrieval_details JSON COMMENT '{"l0_titles":[], "l1_scores":[], "has_supplement": true}', - - -- 性能 & 状态 - duration_ms INT COMMENT '工具执行耗时', - success BOOLEAN DEFAULT TRUE COMMENT '是否成功', - error_message TEXT COMMENT '失败原因', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - - INDEX idx_session_id (session_id), - INDEX idx_tool_name (tool_name), - INDEX idx_retrieval_layer (retrieval_layer) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工具调用明细表'; -``` - ---- - -## 四、数据流设计 - -### 4.1 完整链路 - -``` -用户请求 - │ - ▼ -1. 创建 diagnosis_session(status=RUNNING) - │ - ▼ -2. Agent Loop(可能多轮) - │ - ├── beforeModel() - │ └── AgentLoggingHook 记录 model_input + 开始时间 → 写入 agent_step(先创建,duration 待填) - │ - ├── afterModel() - │ └── AgentLoggingHook 记录 model_output + token_count + 工具调用决策 → 更新 agent_step - │ - ├── 工具执行(如 lookup_knowledge) - │ └── LookupKnowledgeTool 记录 tool_invocation(L0/L1 明细、耗时、是否截断) - │ - └── 循环直到模型不再调用工具 - │ - ▼ -3. 诊断完成 → 更新 diagnosis_session - ├── status = SUCCESS / FAILED - ├── 汇总指标:total_duration_ms / total_token_count / step_count / tool_call_count - └── self_evaluation(可选,由 LLM 自评) -``` - -### 4.2 变更点 - -| 模块 | 当前行为 | 改造后 | -|------|---------|--------| -| `AgentLoggingHook` | 只打日志到 stdout | 同时写入 `agent_step` 表 | -| `LookupKnowledgeTool` | 只打日志到 stdout | 同时写入 `tool_invocation` 表 | -| `ChatService` / `AiOpsService` | 执行前后无持久化 | 创建 + 更新 `diagnosis_session` | - ---- - -## 五、可观测能力 - -### 5.1 查询场景 - -| 需求 | SQL | 说明 | -|------|-----|------| -| 某次诊断用了哪些工具 | `SELECT * FROM tool_invocation WHERE session_id=?` | 按 session 关联 | -| lookup_knowledge 的 L0/L1 命中率 | `SELECT retrieval_layer, COUNT(*) FROM tool_invocation WHERE tool_name='lookup_knowledge' GROUP BY retrieval_layer` | 聚合检索层分布 | -| 某个 Agent 的平均思考耗时 | `SELECT AVG(duration_ms) FROM agent_step WHERE agent_name=?` | 按 Agent 分组 | -| 某次诊断的完整决策链 | `SELECT * FROM agent_step WHERE session_id=? ORDER BY step_index` | 按步骤号排序 | -| 被截断的检索占比 | `SELECT COUNT(*) FROM tool_invocation WHERE is_truncated=true AND tool_name='lookup_knowledge'` | 条件计数 | -| 高置信度但用户反馈 negative | `SELECT * FROM diagnosis_session WHERE JSON_EXTRACT(self_evaluation, '$.confidence') > 80 AND feedback='not_useful'` | JSON 条件查询 | - -### 5.2 评估指标 - -| 指标 | 计算方式 | 数据来源 | -|------|---------|---------| -| 平均诊断耗时 | `AVG(total_duration_ms)` | diagnosis_session | -| 平均 Token 消耗 | `AVG(total_token_count)` | diagnosis_session | -| 工具采纳率 | `tools_accepted / tools_proposed` | self_evaluation | -| L0 命中率 | `l0_match_count > 0 的比例` | tool_invocation | -| 截断率 | `is_truncated=true 的比例` | tool_invocation | -| 用户满意度 | `feedback='useful' 的比例` | diagnosis_session | - ---- - -## 六、与现有表的关系 - -### 6.1 diagnosis_session vs 现有 diagnosis_record - -- **`diagnosis_record`** 保持不动,继续用于"告警分析"场景的领域字段(root_cause、solution 等) -- **`diagnosis_session`** 是通用会话存储,覆盖 ChatService 和 AiOpsService -- 两者通过 `session_id` 可关联 - -### 6.2 迁移策略 - -| 阶段 | 动作 | -|:----:|------| -| MVP | 新建三张表,新代码写入新表 | -| V1.1 | 评估是否将 diagnosis_record 合并回 diagnosis_session(加 fault 相关字段到 JSON) | -| V1.2 | 数据量 > 10 万时评估是否需要归档或迁移 | - ---- - -## 七、未完成事项 - -- [ ] AI Ops Supervisor 的 Agent 执行步骤如何对应 agent_step 表(Supervisor 内嵌的子 Agent 步骤归到同一个 session 还是独立) -- [ ] self_evaluation 的 confidence 自评通过什么方式获取(单独的 LLM 调用还是在 prompt 中要求输出) -- [ ] feedback 字段和前端的交互方式 -- [ ] Tool_invocation 的 output_preview 截断策略(当前建议 500 字符) diff --git a/bash.exe.stackdump b/bash.exe.stackdump index 314e21a..76862b8 100644 --- a/bash.exe.stackdump +++ b/bash.exe.stackdump @@ -17,8 +17,8 @@ Loaded modules: 7FF9B84F0000 GDI32.dll 7FF9B6CD0000 gdi32full.dll 7FF9B6790000 msvcp_win.dll -7FF9B7000000 ucrtbase.dll 000210040000 msys-2.0.dll +7FF9B7000000 ucrtbase.dll 7FF9B7370000 advapi32.dll 7FF9B8E40000 msvcrt.dll 7FF9B85B0000 sechost.dll diff --git a/mvp/plan/session-storage-design.md b/mvp/plan/session-storage-design.md index c0bdda5..518b485 100644 --- a/mvp/plan/session-storage-design.md +++ b/mvp/plan/session-storage-design.md @@ -2,7 +2,7 @@ **日期**: 2026-06-26 **类型**: 架构设计 -**状态**: 待评审 +**状态**: 已实现 (2026-06-26) --- @@ -264,3 +264,33 @@ CREATE TABLE tool_invocation ( - [ ] self_evaluation 的 confidence 自评通过什么方式获取(单独的 LLM 调用还是在 prompt 中要求输出) - [ ] feedback 字段和前端的交互方式 - [ ] Tool_invocation 的 output_preview 截断策略(当前建议 500 字符) + +--- + +## 八、实现变更记录 + +### 8.1 与设计文档的差异 + +| 设计 | 实现 | 原因 | +|------|------|------| +| AgentLoggingHook 为 @Component | 改为 POJO(构造注入 Repository + agentName) | 需要为 ChatService / AiOpsService 创建多个 Hook 实例(不同 agentName) | +| sessionId 通过 RunnableConfig 的 metadata 携带 | 通过 `RunnableConfig.builder().addMetadata("sessionId", id)` 构建 | 确认框架 API 原生支持,线程安全 | +| Token 从 ChatResponse 获取 | 增加了 `TokenTrackingChatModel` 包装器拦截 ChatModel.call() | 框架的 `_TOKEN_USAGE_` 仅在 stream 路径可用,call 路径需自行拦截 | +| sessionId 汇总后回填 | `backfillSessionMetrics()` 从 agent_step 表统计 | 避免在 Hook 中维护累加状态 | + +### 8.2 新增文件(超出原设计) + +| 文件 | 用途 | +|------|------| +| `TokenTrackingChatModel.java` | ChatModel 包装器,拦截 call() 获取实际 token 用量 | +| `TokenUsageHolder.java` | ThreadLocal 传递 token 数给 Hook | +| `QuestionComplexity.java` | 问题复杂度判断,路由单 Agent / 多 Agent | +| `SessionContextHolder.java` | ThreadLocal 传递 sessionId(同步路径兜底) | + +### 8.3 删除文件 + +| 文件 | 原因 | +|------|------| +| `DiagnosisRecord.java` / `DiagnosisRecordRepository.java` / `DiagnosisStatus.java` | 被新三表替代,V007 Flyway 迁移删除 | +| `.docs/mvp/` | 内容合并到根目录 `mvp/` | +