# Diagnosis Knowledge Orchestration — 诊断知识编排框架设计

> **Status**: Research / Proposal
> **Author**: Investibook Team
> **Date**: 2026-04-21
> **Scope**: Agent context management, knowledge ingestion pipeline, diagnostic workflow runtime

---

## 目录

- [1. 问题定义](#1-问题定义)
- [2. 现状分析](#2-现状分析)
- [3. 核心矛盾](#3-核心矛盾)
- [4. 类比研究](#4-类比研究)
- [5. 架构设计](#5-架构设计)
- [6. 详细设计](#6-详细设计)
- [7. 实施路径](#7-实施路径)
- [8. 风险与未解决问题](#8-风险与未解决问题)

---

## 1. 问题定义

### 1.1 Investibook 的本质

Investibook 是一个 **让 LLM 成为 TiDB 故障诊断专家** 的系统。它的核心价值循环是：

```
故障发生 → agent 诊断 → 人 review → 发现 agent 错了/漏了
   ^                                        |
   └──────── 把教训沉淀回系统 ←──────────────┘
```

这个循环意味着系统会持续吸收新的输入：

| 输入类型 | 增长速度 | 例子 |
|---|---|---|
| 新 SOP / 诊断流程 | 每月 2-5 个 | TiFlash OOM 流程、BR 恢复流程 |
| 错题 / 纠偏规则 | 每周 1-3 条 | "ANALYZE 不是主因"、"statement_count 要配合 affected_rows" |
| 领域知识 | 持续 | 新版本 panel 变化、新 metric、架构变更 |
| 用户业务知识 | 每个 case 独立 | "这个客户凌晨有批量导入" |
| 新工具 / 数据源 | 每 1-2 月 | 新 MCP server、新 API endpoint |

### 1.2 核心挑战

**系统能否以可预测的方式吸收持续增长的知识，而不退化？**

具体而言：
- 新知识加入后，不应该影响无关场景的诊断质量
- 知识总量增长不应该导致 agent context 线性膨胀
- 每条知识应该在正确的时刻、以正确的方式投递给 agent
- 知识之间的冲突应该可以被检测

### 1.3 为什么现在就需要考虑这个问题

项目处于早期启动阶段，后续会快速叠加大量新 SOP 和输入。如果架构不支持可预测的知识增长，以下退化路径会很快出现：

```
月份 1-2:  10 个 SOP，agent 表现良好
月份 3-4:  25 个 SOP + 30 条规则，context 开始紧张
月份 5-6:  50 个 SOP + 80 条规则，agent 开始"忘记"规则、混淆流程
月份 7+:   每加一条新规则都需要重新调整已有规则的措辞和位置
```

这不是假设——当前的 `tidb-clinic-diagnosis/SKILL.md` 已经膨胀到 36KB 且在多处重复强调同一条规则，就是这个退化路径的早期信号。

---

## 2. 现状分析

### 2.1 当前架构

系统将所有诊断能力通过 **Skills (SKILL.md 文本文件)** 承载，通过 OpenCode 的 skill 加载机制投递给 agent。

**默认 active 的 9 个 Skills：**

| # | Skill | SKILL.md 大小 | 按需 Knowledge / References | 角色 |
|---|---|---|---|---|
| 1 | tidb-clinic-diagnosis | 36KB (~9K tokens) | scripts 261KB | 核心诊断 SOP |
| 2 | grafana-panel-finder | 20KB (~5K tokens) | — | PromQL 查询辅助 |
| 3 | tidb-query-tuning | 10KB (~2.5K tokens) | references 742KB | 慢查询优化 |
| 4 | clinic-api | 9KB (~2.3K tokens) | scripts 53KB | 数据接入层 |
| 5 | tidb-knowledge-base | 8KB (~2K tokens) | knowledge JSON 39KB | 错题集 + tier 路由 |
| 6 | github-issue-search | 5KB (~1.3K tokens) | — | GitHub 搜索 |
| 7 | jira | 4KB (~1K tokens) | — | Jira 查询 |
| 8 | evidence-report | 3KB (~0.8K tokens) | — | 报告写入协议 |
| 9 | time-conversion | 2KB (~0.6K tokens) | scripts | 时间转换 |

**所有 SKILL.md 合计**: ~98KB (~24.5K tokens)

### 2.2 Context 注入链路

```
Session 启动:
  (1) OpenCode 自动扫描 .opencode/skills/ 目录
      → 读取所有 9 个 SKILL.md 的 frontmatter (description)
      → 注入 agent system context (~1-2K tokens)

  (2) build_system_prompt() 通过 ACP prompt 注入
      → Core rules + workspace metadata + metric routing
        + timestamp rules + MCP guidance + Jira guidance
      → ~3-4K tokens (无 cluster) / ~5-6K tokens (有 cluster)

Agent 运行时:
  (3) Agent 自行决定 read("skills/xxx/SKILL.md")
      → 一次性加载整个 SKILL.md 全文
      → tidb-clinic-diagnosis: 一次 read = 9K tokens

  (4) Agent 按 SKILL.md 指令 read knowledge/references
      → tier-architecture.json: ~3K tokens
      → incorrect-conclusions.json: ~1.5K tokens
      → tikv-details-dedicated.json: ~78K tokens

  (5) 每次用户 prompt 追加 build_mcp_guidance_prompt()
      → ~1.5K tokens 重复注入
```

### 2.3 知识的四种能力维度

所有注入 agent 的内容可以归类为四种能力：

| 能力维度 | 当前载体 | 例子 |
|---|---|---|
| **方法论** (What to do) | SKILL.md workflow/SOP | Node C→D→E 分析流程、database time model |
| **工具使用** (How to do) | SKILL.md 中的 CLI 指令 + scripts | collect_evidence.py, clinic-api shell |
| **经验纠偏** (Don't mess up) | incorrect-conclusions.json + REASONING GUARDs + system prompt | "ANALYZE 不是主因" |
| **领域知识** (Reference) | knowledge/*.json, references/*.md | tikv-details panel 定义、oncall 案例 |

**核心发现：四种本质不同的能力全部塞进同一载体（SKILL.md 文本文件），靠"agent read 进 context window"这一个机制投递。**

---

## 3. 核心矛盾

### 3.1 SKILL.md 是不可分割的原子单位

OpenCode 的 skills 加载机制：description 做匹配，`read()` 加载全文。Agent 一旦 read `tidb-clinic-diagnosis/SKILL.md`，36KB 全部进入 context。

但诊断是分阶段的——Step 0 的证据收集指令、Node D 的组件分析方法、Node E 的结论检查清单，在任何一个时刻 agent 只需要其中一个阶段的内容。

### 3.2 System Prompt 重复 SKILL 内容

以 "Step A then Step B before evidence" 为例，当前在三个位置重复定义：

| 位置 | 重复内容 |
|---|---|
| `system_prompt.py` DIAGNOSIS_KB_AND_METRIC_ROUTING | 完整描述 Step A/B + metric routing |
| `tidb-knowledge-base/SKILL.md` | 完整 Step A/B/C/D 流程定义 |
| `tidb-clinic-diagnosis/SKILL.md` | 重述 Step A/B checkpoints + blocking rules |

三处重复 ≈ 额外 ~3K tokens 的 context 浪费，且维护时容易遗漏某处的更新。

### 3.3 经验纠偏靠"反复说"来保证遵守

`incorrect-conclusions.json` 的使用要求在 system prompt、tidb-knowledge-base SKILL.md、tidb-clinic-diagnosis SKILL.md 三处反复强调。

这是一个信号：**当前框架缺少结构化的约束执行机制，只能靠自然语言的重复来弥补。** 当规则数量从 2 条增长到 50 条时，这种模式不可持续。

### 3.4 知识增长 = Context 增长 = 退化

当前模式下，新知识的唯一入口是编辑 SKILL.md / system_prompt.py / JSON 文件：

```
新教训进来
  → 编辑某个文件，加几行/几段
  → 所有 session 的 context 变大
  → agent 表现开始不稳定（因为注意力被稀释）
  → 发现问题，手动调整措辞/顺序
  → 重复
```

每条新规则都增加全局 context 负担。第 10 条规则和第 100 条规则的边际 cost 一样（都占 context），但边际 value 在下降（第 100 条规则大概率与当前 case 无关）。

### 3.5 没有反馈闭环

加了一条新规则后：
- 无法知道它是否生效了
- 无法知道它是否和其他规则冲突
- 无法知道它是否让某些本来正确的 case 反而出错了
- 唯一的验证方式是等下一个类似 case 出现

---

## 4. 类比研究

### 4.1 Clinical Decision Support Systems (CDSS)

**最精确的类比。** 医疗临床决策支持系统解决的问题和 Investibook 几乎完全对称：

```
医疗诊断                         TiDB 故障诊断
─────────                       ─────────────
患者症状 + 检查结果               cluster metrics + logs + slow queries
临床指南 (CPG)                   诊断 SOP (workflow)
药物禁忌 / 交叉反应规则           错题集 / reasoning guards
检验项目手册                     panel / PromQL 参考知识
过往病例库                       oncall 案例库
医生的临床经验                   agent 的推理能力
```

**CDSS 遇到并解决了的同样问题：**

1. **临床指南越来越多**（cf. SOP 越来越多）→ 不能全部背下来
2. **禁忌规则要在正确的时刻触发**（cf. guard rails）→ 不能开药时忘记过敏
3. **不同科室知识不能混淆**（cf. cluster_type routing）→ 心脏科和骨科的规则不同
4. **新的循证医学证据要持续灌入**（cf. case feedback）→ 知识库要可迭代

**CDSS 在几十年演进中收敛到的架构：**

```
┌──────────────────┐
│  Knowledge Base  │  ← 结构化的规则/指南/事实（Arden Syntax 标准）
│                  │     每条规则有：触发条件、适用场景、执行逻辑
└────────┬─────────┘
         │ 触发
         ▼
┌──────────────────┐
│  Rule Engine     │  ← 根据当前患者数据，匹配规则，按时序触发
│  (Inference)     │     不是一次性全部展示给医生
└────────┬─────────┘
         │ 推送
         ▼
┌──────────────────┐
│  Point-of-Care   │  ← 在医生做决策的那个时刻，推送相关提醒
│  Alert           │     "此患者有青霉素过敏，确定开这个药？"
└──────────────────┘
```

**关键标准：CDS Hooks**

HL7 CDS Hooks 标准定义了一种"在工作流特定节点触发规则推送"的机制。规则不是文档，是 **hook**——在特定事件（打开病历、开药、签医嘱、出院）发生时，系统自动将匹配的规则推送到医生面前。

CDS Hooks 和 Investibook 诊断流程的对应关系：

| CDS Hook | 触发时机 | Investibook 对应 | 触发时机 |
|---|---|---|---|
| patient-view | 打开患者病历 | session-start | 打开 workspace |
| order-select | 医生选择药品 | pre-evidence | 开始收集证据前 |
| order-sign | 医生签署医嘱 | pre-conclusion | agent 准备写结论前 |
| encounter-discharge | 患者出院 | post-analysis | 分析完成后验证 |

**CDSS 的核心洞察**：

> 知识的价值不在于被"知道"，而在于在正确的决策点被"想起来"。
> CDSS 不是把药典塞给医生背，而是在医生开处方的那一刻弹出相关的禁忌提醒。

这正是 Investibook 当前缺少的——不缺知识，缺的是"在正确时刻投递正确知识"的机制。

### 4.2 CI/CD Pipeline (GitHub Actions / Tekton)

诊断流程本质上是一个 **有状态的 pipeline**，每个阶段有输入、输出、前置条件（gate）：

```yaml
# 概念模型，非真实代码
diagnosis_pipeline:
  stages:
    - name: tier_routing
      trigger: on_diagnosis_start
      inject: tier-architecture.json
      gate: cluster_type must be resolved

    - name: pitfall_preload
      trigger: after tier_routing
      inject: matched guards from guard_rules where phase=pre-analysis
      gate: at least 1 guard acknowledged

    - name: evidence_collection
      trigger: after pitfall_preload
      tools: [collect_evidence.py]
      gate: evidence_summary_for_agent.txt exists

    - name: app_triage
      trigger: after evidence_collection
      inject: node-c-app-triage.md + matched guards for phase=node-c
      output: bottleneck_component

    - name: component_dive
      trigger: after app_triage
      inject: node-d-{bottleneck_component}.md + matched guards
      conditional_inject:
        - if bottleneck_component == "tikv": tikv-details/{section}.json
        - if bottleneck_component == "tidb": tidb.json
      output: root_cause_candidates

    - name: conclusion
      trigger: after component_dive
      inject: node-e-crosscheck.md + ALL guards for phase=node-e
      validation: run guard_check(analysis_patch) before emit
```

CI Pipeline 的关键特性与 Investibook 的对应：

| Pipeline 特性 | Investibook 需求 |
|---|---|
| 阶段是声明式的 | 诊断 SOP 应该是声明式的阶段定义，不是一个大文档 |
| 每个阶段有明确的 input/output/gate | 每个诊断阶段有明确的前置条件和产出 |
| 条件注入 (if/matrix) | 根据 cluster_type / symptom 注入不同知识 |
| Gate 是阻塞的 | Step A 没完成不能进入 Step B |
| Actions 可复用 | 知识单元可以被多个 pipeline 阶段复用 |

### 4.3 Claude Code 的做法

Claude Code 的架构相对简单：

```
System prompt (固定身份 + 规则)
  + Tools (结构化能力接口: Read, Edit, Grep, Bash...)
  + CLAUDE.md (项目级指令)
  + 用户消息
```

Claude Code 做对的事情：

1. **Tool-based architecture**：不把"怎么搜索代码"写成文档让 agent 记住，而是提供工具让 agent 按需调用。知识在工具执行时实时获取，不预先注入 context。
2. **CLAUDE.md 极简**：只放不变的项目级约束，不放操作手册。
3. **Agent 自主探索**：通过 Glob/Grep/Read 实时了解代码库，而不是预先灌入代码结构知识。

**但 Claude Code 不适用于 Investibook 的地方**：

- Claude Code 的知识主要来自模型预训练（编程语言、框架），不需要持续灌入领域知识
- 编程场景没有"必须按 Step A → B → C 顺序执行"的刚性流程约束
- 不需要"错题集"机制——编程错误的模式相对稳定且被预训练覆盖

**Investibook 可以从 Claude Code 借鉴的**：

- System prompt 应该极简（身份 + 不变规则），所有可变内容通过其他机制投递
- 能用 tool 实时获取的知识，不要预先注入 context
- 让 agent 有自主探索的能力，而不是预先灌入所有可能需要的信息

### 4.4 类比总结

| 维度 | CDSS | CI Pipeline | Claude Code | Investibook 应取 |
|---|---|---|---|---|
| 知识表示 | 结构化规则 (Arden) | 声明式 YAML | 工具接口 + 代码 | 结构化知识单元 |
| 投递时机 | Point-of-Care Hook | Stage trigger | 工具调用时 | 诊断阶段 Hook |
| 约束执行 | 强制弹窗确认 | Gate 阻塞 | 无（靠预训练） | Gate + 后验证 |
| 知识增长 | 规则库独立增长 | Action marketplace | 预训练覆盖 | 知识库独立增长 |
| 运行时 context | 只推送匹配的规则 | 只加载当前 stage | 只 read 需要的文件 | 只注入当前阶段+匹配的知识 |

---

## 5. 架构设计

### 5.1 目标架构

```
┌─────────────────────────────────────────────────────┐
│              Knowledge Ingestion Layer               │
│              (知识录入 — 人写的)                        │
│                                                     │
│   结构化模板录入，每条知识带:                            │
│   type, phase, triggers, cluster_types, content      │
└──────────────────┬──────────────────────────────────┘
                   │ 编译 (build script)
                   ▼
┌─────────────────────────────────────────────────────┐
│           Knowledge Organization Layer               │
│           (知识编排 — 自动化)                           │
│                                                     │
│   - 按 phase + type 聚合为阶段文件                     │
│   - 按 triggers 建立症状索引                           │
│   - 冲突检测 + 覆盖分析                               │
│   - 生成 pipeline 定义                               │
└──────────────────┬──────────────────────────────────┘
                   │ 运行时投递
                   ▼
┌─────────────────────────────────────────────────────┐
│            Runtime Delivery Layer                     │
│            (运行时 — 给 agent)                         │
│                                                     │
│   根据: 当前诊断阶段 + 症状 + cluster_type              │
│   只投递: 此时此刻需要的知识子集                         │
│   方式: 阶段文件 read + guard 注入 + knowledge 检索     │
└─────────────────────────────────────────────────────┘
```

### 5.2 四种能力的正确载体

诊断能力被分离到各自最适合的机制：

```
┌──────────┐  ┌──────────┐  ┌───────────────────┐
│ Workflow  │  │ Toolbox  │  │   Guard Rails     │
│ Engine    │  │          │  │   (约束层)         │
│           │  │          │  │                   │
│ 方法论    │  │ 工具使用  │  │  经验纠偏          │
│ SOP 流程  │  │ scripts  │  │  错题集            │
│ 分析框架  │  │ CLI 指令  │  │  reasoning guards │
└────┬─────┘  └────┬─────┘  └────────┬──────────┘
     │             │                  │
┌────▼─────────────▼──────────────────▼──────────┐
│              Knowledge Store                    │
│  (按需检索，不全量注入)                             │
│  tier-architecture, panel definitions,          │
│  oncall cases, official docs                    │
└────────────────────────────────────────────────┘
```

| 能力维度 | 载体 | 投递方式 | 增长策略 |
|---|---|---|---|
| **方法论** | Workflow sections (分阶段 .md 文件) | Agent 在当前阶段 read 对应 section | 新 SOP = 新 section 文件，不影响其他阶段 |
| **工具使用** | Skills (不变) + scripts | Agent read skill doc → 调用 script | 和当前模式一致 |
| **经验纠偏** | Guard rules (结构化单元) | 融入阶段文件 + post-analysis validation | 新规则 = 新 unit，编排脚本自动归入对应阶段 |
| **领域知识** | Knowledge store (分片 + 索引) | 按症状/组件索引后按需 read | 新知识 = 新分片，不增加全局 context |

### 5.3 核心设计原则

**原则 1：知识增长与 context 消耗解耦**

```
当前: 知识是文档 → 文档是 context → context 有限 → 知识增长 = 退化
目标: 知识是结构化单元 → 按需编译为 context → 运行时 context 只取决于"当前阶段需要多少"
```

无论系统总共有 50 条 guard rules 还是 500 条，运行时只投递与当前阶段 + 症状匹配的 3-5 条。

**原则 2：Single Source of Truth**

每条知识只在一个地方完整定义。System prompt 不重复 SKILL.md 的内容，SKILL.md 不重复 knowledge 文件的内容。其他位置通过 ID / 引用触发。

**原则 3：Progressive Disclosure**

Agent 先看索引/摘要（低 token cost），根据当前需求深入加载细节（按需 cost）。不一次性灌入所有可能需要的信息。

**原则 4：约束是结构化执行的，不靠自然语言重复**

Guard rules 通过两种机制生效：
- **Inline**：融入 workflow 阶段文件，在 agent 做判断的时刻出现
- **Validation**：在 agent 输出结论后，用确定性逻辑检查是否违反规则

不再靠在多个文件中反复写"你必须先读 incorrect-conclusions.json"。

**原则 5：声明式阶段定义**

诊断流程是声明式的 pipeline，每个阶段有明确的 input/output/gate/inject。不是一个 36KB 的叙事性文档。

---

## 6. 详细设计

### 6.1 Knowledge Unit — 结构化知识单元

每条新知识使用结构化模板录入，取代"编辑一个大 markdown"：

```yaml
# 文件: knowledge-units/guards/guard-analyze-not-primary.yaml
id: guard-analyze-not-primary
type: guard_rule                       # guard_rule | sop_step | knowledge_fact | tool_usage
title: "ANALYZE 不能作为 primary root cause"

# 何时生效
phase: [node-d, node-e]                # 在哪个诊断阶段
triggers:                              # 什么条件下需要这条知识
  symptoms:
    - "TopSQL contains ANALYZE"
    - "SlowQuery top by count is ANALYZE"
  keywords: [analyze, topsql, slow-query, cpu]

# 适用范围
cluster_types: [all]                   # all | dedicated | premium | starter | essential
components: [tidb, tikv]               # 相关组件

# 知识内容
content: |
  ANALYZE is NOT the primary root cause unless it dominates
  TopSQL CPU vs non-ANALYZE digests. When analyzing TopSQL
  and Slow Query, deprioritize ANALYZE rows first.

corrective_checks:
  - "Verify primary cause is not ANALYZE unless it dominates hotspot CPU"
  - "Use TopSQL cpu_pct for attribution, not SlowQuery count"
  - "Deprioritize ANALYZE rows when scanning TopSQL/SlowQuery"

conclusion_rule: |
  Final root-cause must not name ANALYZE as primary unless
  evidence shows it dominates TiKV/TiDB hotspot CPU.

# 溯源
source_cases: [O11Y-2328599]
created: 2026-04-01
updated: 2026-04-15
```

```yaml
# 文件: knowledge-units/sop/sop-tikv-cpu-hotspot.yaml
id: sop-tikv-cpu-hotspot
type: sop_step
title: "TiKV CPU hotspot 分析步骤"

phase: [node-d]
triggers:
  symptoms:
    - "TiKV CPU high"
    - "TiKV hotspot instance"
  keywords: [tikv, cpu, hotspot, thread]

cluster_types: [all]
components: [tikv]

content: |
  ## TiKV CPU Hotspot — Resource-first Layered Diagnosis

  1. **CPU saturation check (absolute threshold — MUST check first)**:
     Gate check reports `cpu_saturation` when peak CPU > 80% of quota.
     Instance at >80% IS a hotspot signal even if ratio to peers < 2x.

  2. **Instance identification (relative threshold)**:
     Identify outlier TiKV instance(s): CPU/memory/IOPS >2x peers.

  3. **Thread-level classification**:
     Query `tikv_thread_cpu_seconds_total` on hotspot instance:
     - grpc threads hot → gRPC hotspot
     - cop/coprocessor hot → read hotspot
     - raftstore hot → write hotspot
     - sched hot → transaction contention

  4. **TopSQL attribution**:
     Highest cpu_pct on hotspot instance = primary candidate.
     cpu_pct < 5% on hot instance → NOT a contributor.

depends_on: [guard-analyze-not-primary]  # 执行此 SOP 时同时加载此 guard
```

```yaml
# 文件: knowledge-units/knowledge/fact-premium-metric-routing.yaml
id: fact-premium-metric-routing
type: knowledge_fact
title: "Premium 集群 metric routing 规则"

phase: [tier-routing]
triggers:
  symptoms: []
  keywords: [premium, parent_id, metric, routing]

cluster_types: [premium]
components: [tikv, pd, tiflash, node]

content: |
  Premium clusters (cluster_type == "premium", has parent_id):
  - TiDB metrics → use cluster_id (the premium cluster itself)
  - All other components (TiKV, PD, TiFlash, Node) → use parent_id

source_cases: []
created: 2026-03-01
```

### 6.2 Knowledge Unit 类型体系

```
knowledge_unit_types:
  guard_rule:      # 约束规则 — "不要做什么" / "做之前必须检查什么"
    必填: corrective_checks, conclusion_rule
    投递方式: 融入阶段文件 + post-analysis validation

  sop_step:        # 操作步骤 — "怎么分析某个组件/症状"
    必填: content (步骤说明)
    可选: depends_on (依赖的 guard rules)
    投递方式: agent read 阶段文件

  knowledge_fact:  # 领域事实 — "某个概念的定义/规则"
    必填: content
    投递方式: 索引后按需 read

  tool_usage:      # 工具手册 — "怎么调用某个 API/脚本"
    必填: content (命令说明)
    投递方式: 保持现有 SKILL.md 模式
```

### 6.3 编排脚本 — 从 Knowledge Units 生成运行时文件

```
knowledge-units/              # 人写的，结构化知识单元
├── guards/
│   ├── guard-analyze-not-primary.yaml
│   ├── guard-statement-count-affected-rows.yaml
│   ├── guard-same-node-comparison.yaml
│   └── ...
├── sop/
│   ├── sop-tikv-cpu-hotspot.yaml
│   ├── sop-tidb-gc-check.yaml
│   ├── sop-premium-worker-check.yaml
│   └── ...
├── knowledge/
│   ├── fact-premium-metric-routing.yaml
│   ├── fact-starter-essential-rcu.yaml
│   └── ...
└── tools/
    └── (保持现有 SKILL.md 不变)

      │
      │ build_knowledge.py (编排脚本)
      ▼

generated/                    # 自动生成的，给 agent 消费
├── pipeline.yaml             # 诊断 pipeline 定义
├── stages/
│   ├── tier-routing.md       # 聚合 phase=tier-routing 的所有 units
│   ├── pre-analysis.md       # 聚合 phase=pre-analysis 的 guards
│   ├── evidence-collection.md
│   ├── node-c-app-triage.md
│   ├── node-d-tikv.md        # 聚合 phase=node-d + component=tikv
│   ├── node-d-tidb.md        # 聚合 phase=node-d + component=tidb
│   ├── node-e-crosscheck.md
│   └── ...
├── indexes/
│   ├── symptom-index.json    # 症状 → 相关 knowledge unit IDs
│   ├── component-index.json  # 组件 → 相关 knowledge unit IDs
│   └── guard-index.json      # 阶段 → 应用的 guard rule IDs + 摘要
└── validation/
    └── guard-rules.json      # 所有 guard rules 的结构化表示，供 validation 用
```

**编排脚本的核心逻辑**：

```python
# build_knowledge.py (概念伪代码)

def build():
    units = load_all_knowledge_units("knowledge-units/")

    # 1. 冲突检测
    conflicts = detect_conflicts(units)
    if conflicts:
        report_conflicts(conflicts)

    # 2. 覆盖分析
    coverage = analyze_coverage(units)
    report_uncovered_phases(coverage)

    # 3. 按 phase + component 聚合生成阶段文件
    for phase in ALL_PHASES:
        phase_units = [u for u in units if phase in u.phase]
        for component in extract_components(phase_units):
            stage_file = generate_stage_file(phase, component, phase_units)
            write("generated/stages/{phase}-{component}.md", stage_file)

    # 4. 生成索引
    write("generated/indexes/symptom-index.json", build_symptom_index(units))
    write("generated/indexes/guard-index.json", build_guard_index(units))

    # 5. 生成 validation rules
    guard_units = [u for u in units if u.type == "guard_rule"]
    write("generated/validation/guard-rules.json", export_guard_rules(guard_units))

    # 6. 生成 pipeline 定义
    write("generated/pipeline.yaml", generate_pipeline_definition(units))
```

### 6.4 生成的阶段文件示例

`generated/stages/node-d-tikv.md`（由编排脚本自动生成）：

```markdown
<!-- Auto-generated from knowledge units. Do not edit directly. -->
<!-- Sources: sop-tikv-cpu-hotspot, sop-tikv-write-pipeline, guard-analyze-not-primary, ... -->

# Node D: TiKV Component Deep-dive

## Analysis Steps

### CPU Hotspot (sop-tikv-cpu-hotspot)
1. CPU saturation check: peak CPU > 80% of quota = hotspot signal
2. Instance identification: CPU/memory/IOPS >2x peers = outlier
3. Thread-level classification: grpc/cop/raftstore/sched
4. TopSQL attribution: highest cpu_pct on hotspot instance

### Write Pipeline (sop-tikv-write-pipeline)
...

## Guard Rules (MUST check during this phase)

### [guard-analyze-not-primary]
ANALYZE is NOT the primary root cause unless it dominates TopSQL CPU.
Corrective checks:
- [ ] Verify primary cause is not ANALYZE unless it dominates hotspot CPU
- [ ] Use TopSQL cpu_pct for attribution, not SlowQuery count

### [guard-statement-count-affected-rows]
statement_count must be paired with affected_rows for DML.
Corrective checks:
- [ ] If statement_count rises but affected_rows flat → "execution overhead", NOT "traffic increased"

## Knowledge References
- For TiKV panel PromQL: read knowledge/tikv-details/{section}.json
- For thread CPU details: query tikv_thread_cpu_seconds_total
```

**关键特征**：
- 方法论 (SOP steps) 和约束 (guard rules) 在同一个文件中，出现在 agent 需要它们的时刻
- 每个 guard rule 以 checklist 形式呈现，agent 可以逐条检查
- Knowledge references 是索引引用，不是全文嵌入
- 文件头注明来源 units，方便溯源和调试

### 6.5 Runtime Delivery — 运行时投递

**精简后的 System Prompt（~2K tokens）：**

```python
def build_system_prompt(cluster_meta, active_mcp_servers):
    # Core: ~800 tokens (永远注入)
    prompt = CORE_RULES
    # 语言规则、输出风格、"plan first"、"no links in text"
    # 不包含任何诊断逻辑

    # Workspace context: ~500 tokens (有 cluster 时)
    if cluster_meta:
        prompt += build_workspace_context(cluster_meta)
        # 只含 IDs, version, type, time range
        # 不含 metric routing 细节 (已在 knowledge unit 中)

    # Diagnosis routing: ~300 tokens (永远注入，作为 trigger)
    prompt += """
    ## Diagnosis Routing
    For performance diagnosis / root cause analysis:
      → Start with generated/stages/ pipeline
      → Read stage file for current phase
    For ticket-only requests (status, comments, alerts):
      → Use jira skill directly
    """

    # Active tools: ~200 tokens
    if active_mcp_servers:
        prompt += build_active_tools_table(active_mcp_servers)

    return prompt
```

**精简后的目录页 SKILL.md（~800 tokens）：**

```markdown
---
name: tidb-clinic-diagnosis
description: TiDB Cloud performance diagnosis...
---
# TiDB Clinic Diagnosis

## Prerequisites
MUST pair with tidb-knowledge-base. Complete Step A (tier routing)
and Step B (pitfall preload) before evidence collection.

## Pipeline Stages
| Phase | File | When |
|---|---|---|
| Tier routing | generated/stages/tier-routing.md | On diagnosis start |
| Pre-analysis guards | generated/stages/pre-analysis.md | After tier routing |
| Evidence collection | generated/stages/evidence-collection.md | After pre-analysis |
| App triage | generated/stages/node-c-app-triage.md | After evidence |
| Component dive | generated/stages/node-d-{component}.md | After Node C |
| Cross-check | generated/stages/node-e-crosscheck.md | Before conclusion |

## Skill Routing
| Symptom | Route to |
|---|---|
| TiCDC replication | ticdc-health-inspection |
| Transaction / lock | transaction-oncall-handbook |
| Specific slow query | tidb-query-tuning |
```

**运行时 context 预算对比：**

```
当前模式 (agent read tidb-clinic-diagnosis/SKILL.md):
  System prompt:        ~5K tokens
  SKILL.md 全文:        ~9K tokens
  tidb-knowledge-base:  ~2K tokens
  Total at diagnosis:   ~16K tokens (且大部分与当前阶段无关)

新模式 (agent read 阶段文件):
  System prompt:        ~2K tokens
  目录页 SKILL.md:      ~0.8K tokens
  当前阶段 section:     ~1.5-2K tokens
  本阶段 guards:        ~0.5-1K tokens
  Total at any stage:   ~5-6K tokens (全部与当前阶段相关)
```

### 6.6 Guard Rail 执行机制

Guard rules 通过两层机制生效：

**Layer 1: Inline (融入阶段文件)**

Guard rules 被编排脚本自动嵌入到对应 phase 的阶段文件中。Agent 在做分析时自然会看到它们——和方法论步骤在同一个文件里，不需要额外 read 操作。

这解决了"agent 不去 read 错题集文件"的问题：规则出现在 agent 做判断的时刻，不是提前灌入让它"记住"。

**Layer 2: Post-analysis Validation (确定性检查)**

在 agent 写完 `analysis_patch.json` 后，服务端运行 validation：

```python
# backend/investibook/core/guard_validation.py

def validate_analysis(analysis_patch: dict, evidence_summary: dict, guard_rules: list) -> list[str]:
    """检查 agent 结论是否违反 guard rules。"""
    violations = []

    for rule in guard_rules:
        if rule["id"] == "guard-analyze-not-primary":
            root_cause = analysis_patch.get("root_cause", "")
            if "ANALYZE" in root_cause.upper():
                # 检查 evidence 中 ANALYZE 是否真的 dominate CPU
                if not analyze_dominates_cpu(evidence_summary):
                    violations.append({
                        "rule_id": rule["id"],
                        "message": "ANALYZE attributed as primary without TopSQL dominance proof",
                        "corrective_action": rule["corrective_checks"][0],
                    })

        if rule["id"] == "guard-statement-count-affected-rows":
            if mentions_traffic_increase(analysis_patch):
                if not mentions_affected_rows(analysis_patch):
                    violations.append({
                        "rule_id": rule["id"],
                        "message": "Traffic increase claimed without affected_rows evidence",
                    })

    return violations
```

如果 validation 发现违规，将 violations 反馈给 agent 要求修正：

```python
if violations:
    feedback = "Your analysis violates the following guard rules:\n"
    for v in violations:
        feedback += f"- [{v['rule_id']}] {v['message']}\n"
    feedback += "\nPlease revise your conclusion."
    await session.prompt(feedback)
```

**两层机制的分工**：

| 机制 | 覆盖范围 | 强度 | 适用场景 |
|---|---|---|---|
| Inline (阶段文件) | 软性约束 | 依赖 agent 遵守 | 复杂推理约束（"优先考虑 X 而非 Y"） |
| Post-validation | 硬性约束 | 确定性检查 | 可以程序化判断的约束（"结论包含 X 但缺少 Y"） |

长期演进：随着错题集增长，越来越多的 guard rules 可以被实现为 post-validation 的确定性检查，减少对"agent 记住并遵守"的依赖。

### 6.7 Knowledge Store — 大文件分片与索引

针对大型 knowledge 文件（如 tikv-details-dedicated.json 313KB）：

```
knowledge/
├── knowledge-index.json              # 全局索引 (~2K tokens)
│   {
│     "tikv-details-dedicated": {
│       "total_panels": 180,
│       "sections": {
│         "grpc": { "panels": "1-15", "keywords": ["grpc", "message", "duration"] },
│         "raft": { "panels": "16-45", "keywords": ["raft", "propose", "apply", "commit"] },
│         "rocksdb": { "panels": "46-90", "keywords": ["rocksdb", "compaction", "write_stall"] },
│         "coprocessor": { "panels": "91-120", "keywords": ["cop", "coprocessor", "scan"] },
│         ...
│       }
│     }
│   }
│
├── tikv-details-dedicated/           # 按 section 拆分
│   ├── grpc.json                     # ~30KB
│   ├── raft.json                     # ~40KB
│   ├── rocksdb.json                  # ~50KB
│   ├── coprocessor.json              # ~30KB
│   └── ...
│
├── tikv-details-dedicated.json       # 保留完整文件（向后兼容）
└── ...
```

Agent 的 knowledge 加载路径：

```
1. read("knowledge/knowledge-index.json")     → 500 tokens
2. 根据诊断方向匹配 section
3. read("knowledge/tikv-details-dedicated/grpc.json")  → 7K tokens
   （而非 read 整个 tikv-details-dedicated.json 的 78K tokens）
```

---

## 7. 实施路径

### Phase 0: 最小结构化改造 (1-2 周)

**目标**：缓解当前 context 问题，建立文件层面的分阶段结构。

**改动**：
1. **拆分 `tidb-clinic-diagnosis/SKILL.md`** 为目录页 + 阶段文件（手动拆分）
   - SKILL.md → 精简为 ~3KB 目录页
   - Step 0 → `workflow/evidence-collection.md`
   - Node C → `workflow/node-c-app-triage.md`
   - Node D → `workflow/node-d-component-dive.md`
   - Node E → `workflow/node-e-crosscheck.md`
   - REASONING GUARDs → 融入对应 Node 的文件末尾

2. **System prompt 去重**
   - 删除 `DIAGNOSIS_KB_AND_METRIC_ROUTING` 中与 SKILL.md 重复的内容
   - 删除 `build_system_prompt()` 中重复的 Step A/B 描述
   - 保留精简的诊断路由触发器

3. **错题集引用去重**
   - System prompt 只保留一句话引用
   - SKILL.md 只在目录页列出前置条件
   - Guard 内容融入 Node D/E 阶段文件

**不改的**：
- OpenCode skills 加载机制不变
- Knowledge JSON 文件不变
- 其他 8 个 skill 不变

**预期效果**：
- System prompt: ~5K → ~2K tokens
- 单次 SKILL.md read: ~9K → ~0.8K tokens
- 新规则有明确的归属位置（哪个阶段文件）

### Phase 1: Knowledge Unit 模板 (1-2 月)

**目标**：新知识录入有标准化流程，编排可自动化。

**改动**：
1. 定义 Knowledge Unit YAML schema
2. 将现有 guard rules / SOP steps 迁移为 knowledge units
3. 实现 `build_knowledge.py` 编排脚本
4. 生成阶段文件替代手动维护的 workflow 文件

**预期效果**：
- 新知识录入: 填 YAML 模板 → 运行脚本 → 自动生成阶段文件
- 冲突检测: 脚本自动报告规则冲突
- 覆盖分析: 脚本报告哪些阶段缺少 guard rules

### Phase 2: Pipeline Runtime (3-6 月)

**目标**：运行时按阶段 + 症状动态投递知识。

**改动**：
1. 实现 pipeline stage 状态跟踪（session 级别）
2. 实现条件注入（根据 cluster_type / bottleneck_component 选择 knowledge）
3. 实现 post-analysis guard validation
4. Knowledge 文件分片 + 索引层

**预期效果**：
- Context 消耗与知识总量解耦
- Guard rules 有确定性执行保障
- 系统可以承载 50+ SOP + 100+ guard rules 而不退化

### Phase 3: 反馈闭环 (6+ 月)

**目标**：知识效果可度量、可迭代。

**改动**：
1. 跟踪每条 guard rule 的触发率和违规率
2. 跟踪每个 SOP 的使用频率和诊断成功率
3. 基于 case outcome 自动建议新的 guard rules
4. Oncall 案例库 embedding 索引（可选 RAG）

---

## 8. 风险与未解决问题

### 8.1 Agent 对分片文件的路由准确性

风险：Agent 可能选错阶段文件（比如在 Node D 阶段 read 了 Node C 的文件）。

缓解：目录页 SKILL.md 的路由表要足够清晰，每个阶段文件开头声明 "This file is for Node D: Component Deep-dive. Prerequisites: Node C completed."

### 8.2 编排脚本的维护成本

风险：`build_knowledge.py` 本身成为需要维护的基础设施。

缓解：Phase 0 不需要编排脚本（手动拆分），Phase 1 的脚本应该极简（<500 行 Python），不引入复杂依赖。

### 8.3 OpenCode Skills 加载机制的限制

风险：OpenCode 的 skill 匹配基于 frontmatter description，分片后目录页的 description 是否还能准确匹配。

缓解：目录页 SKILL.md 的 description 保持原样（甚至更丰富），确保匹配不受影响。阶段文件作为 skill 内部的子文件 read，不依赖 skill 匹配。

### 8.4 Post-validation 的规则表达力

风险：某些 guard rules 很难用程序逻辑判断（如"论证逻辑是否自洽"），post-validation 的覆盖范围有限。

缓解：不追求 100% 覆盖。可以程序化判断的规则用 post-validation（Layer 2），复杂推理约束靠 inline 融入阶段文件（Layer 1）。两层互补。

### 8.5 向后兼容

风险：Phase 0 的分片改造可能破坏现有的 agent 行为（agent 之前习惯 read 完整的 SKILL.md）。

缓解：保留原始 SKILL.md 作为 fallback，但在 description 中引导 agent 优先使用阶段文件。逐步验证后再完全切换。

### 8.6 是否需要 RAG

**短期结论：不需要。**

当前最大的 knowledge 文件（tikv-details JSON）是结构化的 panel 定义，分片 + 关键词索引比 embedding 检索更精确。

**中期可能需要的场景**：oncall 案例库增长到数百个 case 后，按症状匹配相关历史案例适合 embedding 检索。但这不是当前瓶颈。

### 8.7 是否需要跨 Session 记忆系统

**结论：当前不需要。**

Investibook 的场景是"一个 workspace 一个故障诊断"，workspace 本身就是记忆（cluster_meta, evidence files, diagnosis_report）。

跨 workspace 的学习通过更新 Knowledge Units 实现——这比让 agent 自己维护记忆更可靠、更可审计。

---

## 附录 A: 迭代模型对比

```
当前模式:
  新 case feedback → 编辑 SKILL.md/system_prompt → 全局 context 膨胀
                   → 无法知道是否生效
                   → 无法知道是否与其他规则冲突
                   → 等下一个 case 验证

目标模式:
  新 case feedback → 填 knowledge unit YAML (30 秒)
                   → 运行编排脚本
                   → 自动归入对应阶段文件
                   → 只在相关场景的 context 中出现
                   → 冲突检测自动报告
                   → post-validation 可确定性验证
```

## 附录 B: Context Budget 估算

基于 200K token context window:

```
固定开销:
  System prompt (精简后):           ~2K tokens
  Skill descriptions (9 skills):   ~1.5K tokens
  Workspace metadata:              ~0.5K tokens
                                   ─────────
  小计:                             ~4K tokens

诊断过程可变开销 (每阶段):
  当前阶段 workflow section:        ~2K tokens
  当前阶段 guard rules:             ~0.5-1K tokens
  按需 knowledge 分片:              ~5-8K tokens
                                   ─────────
  小计:                             ~8-11K tokens/阶段

对话历史 + 工具输出:
  多轮对话:                          ~50-80K tokens
  tool call inputs/outputs:         ~10-20K tokens
                                   ─────────
  小计:                             ~60-100K tokens

总计:  ~72-115K tokens (留有 85-128K tokens 余量)
```

对比当前模式：一次 read tidb-clinic-diagnosis SKILL.md 就消耗 9K tokens，且大部分与当前阶段无关。

## 附录 C: 与现有系统的关系

| 现有组件 | Phase 0 | Phase 1 | Phase 2 |
|---|---|---|---|
| `system_prompt.py` | 去重精简 | 进一步精简 | 动态化 |
| `tidb-clinic-diagnosis/SKILL.md` | 拆分为目录页+阶段文件 | 由编排脚本生成 | Pipeline runtime 消费 |
| `incorrect-conclusions.json` | 规则融入阶段文件 | 迁移为 guard_rule units | Post-validation 规则源 |
| `tidb-knowledge-base/SKILL.md` | 精简引用 | 目录页化 | 自动生成 |
| `tikv-details-*.json` | 不变 | 不变 | 分片+索引 |
| OpenCode skills 机制 | 不变 | 不变 | 不变（仅消费层改变） |
| ACP session / acp.py | 不变 | 不变 | 增加 stage 状态跟踪 |
