doctorAI/docs/SPEC_md_first_persistence_v1.md

13 KiB
Raw Blame History

SPEC: Markdown-First 物理落盘与来源分级架构

版本: v1.0
前置依赖:


1. 问题陈述

当前管线中存在三个结构性隐患,它们共享同一根源——AI 产出物与原始素材在文件系统中无法区分

1.1 Ghost Response 问题

Hermes Agent 在执行"分析素材并生成报告"类任务时,天然地会通过 write_file 工具将分析结果写入物理文件,而 final_response 仅返回"操作完成"的告知性消息。如果管线代码从 final_response 取值,拿到的是一段无意义的摘要而非真正的分析内容。

这不是 Agent 的 bug——这是 Agent 作为自主工作者的正确行为。人类分析师也不会口述 2000 字报告给你,他会"写完放这里,告诉你一声"。

管线 当前取值方式 风险
录音笔记 Stage 1 result.get("final_response") 碰巧可靠Agent 恰好未写文件),但不稳定
客户档案 Stage 1 result.get("final_response") 已验证失效 — Agent 将内容写入 profile.mdresponse 仅 401 字符

1.2 幻觉复利效应

当前 profile.md 既是 Agent 的输入素材(读取既往档案),又是 Agent 的输出目标(生成新档案后覆盖写入)。文件系统中没有任何标记区分:

  • asr.mdL0 原始转写,可信度最高)
  • profile.mdL2 AI 聚合产出,可能包含错误推断)

当 Agent 下次执行时,它 read_file("profile.md")——无法判断这是人类录入的事实,还是上一轮 AI 的推测。如果上一次的 profile.md 含有错误推断(如"客户属于价格不敏感型"Agent 会将其当作已有事实继续叠加推理。

错误被放大而非纠正——这是幻觉的复利。

1.3 Token 消耗悖论

一位客户积累 50 次面诊后:

  • 暴力拼接所有 asr.md(每条 1-3 万字)→ 100 万字 → 上下文直接爆炸
  • 只读 report.md 摘要(每条 3000 字)→ 15 万字 → 可控

但前提是:Agent 必须知道 report.md 是 AI 生成的一阶摘要有损asr.md 才是无损证据。当需要考据时,应回溯 asr.md 原文,而非引用 report.md 中的话当作原声。

可靠的中间产出物反而减少 Token 消耗;不可靠的中间产出物则制造幻觉。


2. 核心原则Markdown-First 物理落盘

2.1 总则

管线各阶段之间的接口契约,必须是物理文件,不是内存态变量。

接口方式 韧性 可审计性 Agent 兼容性
final_response(内存态) 进程崩溃即丢 需翻 session 日志 与 Agent 的 write_file 行为冲突
物理 .md 文件 落盘即不丢 cat 即可审 顺应 Agent 自然行为

2.2 两段式管线的物理接口

Stage 0 (ASR/上传)      Stage 1 (Hermes Agent)       Stage 2 (Qwen JSON)
     │                        │                            │
     ▼                        ▼                            ▼
  asr.md ──read───► Agent ──write──► report_draft.md ──read──► LLM ──► DB JSON
  (L0 原始)                          (L1 AI 产出)
  • Stage 0 → Stage 1Agent 通过 read_file 自主读取 asr.md(及其他素材)
  • Stage 1 → Stage 2:管线代码从 Agent 写入的物理文件读取内容,传入 Stage 2
  • Stage 2 → DBJSON 写入数据库(已实现,无变更)

2.3 Agent 指令约定

Agent 的 user_message 必须明确指定输出目标路径,让 Agent 将分析结果写入该路径。管线代码执行完 Agent 后,从该路径读取内容。

# ✅ 正确明确输出路径Agent 写入后管线读取
result = agent.run_conversation(
    user_message=f"分析 {historyDir}/ 下的素材,将全景档案写入 {outputPath}",
    system_message=systemPrompt,
)
with open(outputPath, "r") as f:
    mdReport = f.read()

# ❌ 错误:依赖 final_responseGhost Response 风险)
mdReport = result.get("final_response", "")

3. 来源分级标记 (Provenance Levels)

3.1 三级分类

级别 标识 含义 可信度 文件命名约定 示例
L0 source: human 物理世界直接采集的原始素材 最高——可回溯到原声/原件 asr.md, asr_raw.m4a, 用户上传照片 录音转写文本ASR 原始输出)
L1 source: ai-single AI 基于单个 L0 素材生成的一阶分析 高——有损摘要,但来源明确 report_draft.md 单条录音的面诊 X 光片报告
L2 source: ai-aggregate AI 基于多个 L0/L1 素材聚合生成的产物 中——叠加推理,幻觉风险最大 profile.md 客户全景档案(跨录音合成)

3.2 文件头元数据标注

所有 AI 生成的 .md 文件,必须在文件头以 HTML 注释形式嵌入来源元数据:

<!-- provenance: ai-single | level: L1 | generated_at: 2026-04-12T19:42:30+08:00 | model: gemini-pro-vertex | sources: [rep_bc439351/asr.md] -->
# 面诊沟通X光片深度分析报告
...
<!-- provenance: ai-aggregate | level: L2 | generated_at: 2026-04-12T19:54:39+08:00 | model: gemini-pro-vertex | sources: [rep_bc439351/asr.md, rep_abc123/asr.md] -->
# 👤 客户全景档案:测女士
...

L0 文件asr.md不需要标注——没有标注即为 L0。这是"无标记即原始"的默认原则。

3.3 Agent 行为约束(注入 SKILL.md

在 Agent 的 SKILL 指令中,追加来源分级感知规则:

## 📋 来源分级阅读规则

1. **L0 文件**asr.md, asr_raw.m4a是不可变的原始证据所有核心论断必须以 L0 文件为最终考据依据。
2. **L1 文件**report_draft.md是单次录音的 AI 摘要,可用于快速浏览历史,但引用原声时必须回溯 L0 验证。
3. **L2 文件**profile.md是跨录音的 AI 聚合分析,优先级最低。如果 L2 中的结论与 L0 原文冲突,以 L0 为准。
4. **引用格式**:所有洞察必须标注来源文件名和大致行号,并注明来源级别。
   -`(来源: rep_bc439351/asr.md L0, 125 行)`
   -`(来源: profile.md)` ← 禁止引用 L2 作为唯一证据

4. 文件系统约定

4.1 录音笔记管线(单条录音 → 报告)

当前:

inbox/{asrId}/
├── asr.md              ← L0 原始转写
└── asr_raw.m4a         ← L0 原始音频

改造后(归档前):

inbox/{asrId}/
├── asr.md              ← L0 原始转写
├── asr_raw.m4a         ← L0 原始音频
└── report_draft.md     ← L1 AI 单次分析Agent 写入,管线读取后传入 Stage 2

改造后(归档后):

clients/{clientId}/history/{reportId}/
├── asr.md              ← L0 不可变
├── asr_raw.m4a         ← L0 不可变
└── report_draft.md     ← L1 随迁(审计留痕)

4.2 客户档案管线(多条录音 → 全景档案)

clients/{clientId}/
├── profile.md          ← L2 AI 聚合产出(每次生成时覆盖)
└── history/
    ├── {reportId_A}/
    │   ├── asr.md              ← L0
    │   ├── asr_raw.m4a         ← L0
    │   └── report_draft.md     ← L1
    ├── {reportId_B}/
    │   ├── asr.md              ← L0
    │   └── report_draft.md     ← L1
    └── ...

4.3 不可变性规则

文件 可读 可写/覆盖 可删除
asr.md (L0) Agent + 管线 上传后不可变
asr_raw.m4a (L0) 审计用
report_draft.md (L1) Agent + 管线 重新生成时覆盖
profile.md (L2) Agent + 管线 每次归档后重新生成

5. 代码改造清单

5.1 录音笔记管线 (_handleReportGenerate)

步骤 现状 改造
Agent user_message 未指定输出路径 新增 report_draft.md 输出路径指令
Stage 1 取值 result.get("final_response") 优先读取 inbox/{asrId}/report_draft.md,兜底 final_response
report_draft.md 写入 Agent 自行写入prompt 引导),或管线兜底写入
文件头标注 Agent prompt 中要求写入 <!-- provenance --> 标注

5.2 客户档案管线 (_generateClientProfile)

步骤 现状 改造
Agent user_message profileMdPath 路径 保持Agent 已自然写入此路径)
Stage 1 取值 result.get("final_response") 已修复 → 读取 profile.md 已完成
文件头标注 需追加 <!-- provenance: ai-aggregate ... -->

5.3 SKILL.md 追加

文件 变更
skills/deepview_assistant/SKILL.md 追加"来源分级阅读规则"章节
skills/deepview_profile/PROMPT_stage1.md 要求输出文件头带 <!-- provenance --> 标注

6. Agent 信息获取策略(规模化场景)

当客户积累大量面诊录音后Agent 应自主规划信息获取策略,而非被管线代码预先读取所有文件:

6.1 分层阅读策略

Agent 收到任务: "生成 p_b1232417 的全景档案"
│
├─ Step 1: search_files → 扫描 history/ 目录结构,确认有 N 条录音
│
├─ Step 2: read_file(profile.md) → 读取 L2 既有档案(如果存在)
│   └── Agent 识别 provenance: ai-aggregate → 知道这是上一轮 AI 自己的产出,仅供参考
│
├─ Step 3: 逐条读取 report_draft.md (L1) → 快速掌握每条录音的核心结论
│   └── Token 消耗: N × ~3000 字(远小于 N × ~20000 字的 asr.md
│
├─ Step 4 (按需): 对关键论断回溯 asr.md (L0) 验证
│   └── 仅在需要考据原声时才读取完整 ASR避免全量加载
│
└─ Step 5: write_file(profile.md) → 生成新的 L2 档案,覆盖旧版

6.2 Token 经济模型

录音数量 暴力全读 (asr.md) 分层阅读 (report_draft.md + 按需 asr.md) 节省比
5 条 ~10 万字 ~1.5 万字 + 按需 ~2 万字 ~65%
20 条 ~40 万字 ~6 万字 + 按需 ~4 万字 ~75%
50 条 ~100 万字 (上下文爆炸) ~15 万字 + 按需 ~6 万字 可行 vs 不可行

7. 与已有 SPEC 的关系

graph TB
    A["DESIGN_PHILOSOPHY_AI_NATIVE<br/>先有价值,后有治理"] --> B["SPEC_metadata_scoping_v3<br/>Prosumer-First 沙箱隔离"]
    B --> C["SPEC_tri_domain_knowledge<br/>三元知识域"]
    B --> D["SPEC_md_first_persistence<br/>📄 本规范"]
    D --> E["来源分级标记"]
    D --> F["管线物理接口"]
    D --> G["Agent 分层阅读策略"]
  • V3 SPEC 定义了"数据在哪"users/{userId}/ 沙箱)
  • 三元域 SPEC 定义了"知识从哪来"(平台/机构/个人三级注入)
  • 本 SPEC 定义了"文件怎么流"物理落盘、来源标记、Agent 感知证据层级)

三者合力构成了完整的数据治理体系:沙箱隔离 × 知识分域 × 来源追溯


8. 验证计划

8.1 自动化测试

# 1. 录音笔记管线:验证 report_draft.md 是否被生成
test -f inbox/{asrId}/report_draft.md && echo "✅ L1 文件存在"
head -1 inbox/{asrId}/report_draft.md | grep "provenance" && echo "✅ 来源标记存在"

# 2. 客户档案管线:验证 profile.md 来源标记
head -1 clients/{clientId}/profile.md | grep "ai-aggregate" && echo "✅ L2 标记正确"

# 3. 归档后文件完整性
ls clients/{clientId}/history/{reportId}/ | grep -c ".md"  # 应 >= 2 (asr.md + report_draft.md)

8.2 人工审计

  • 对比 profile.md 中的引述与 asr.md 原文,确认无二次幻觉放大
  • 检查 Agent session 日志,确认分层阅读行为(先读 L1 摘要,按需回溯 L0

本规范定义了深维面诊助理的 Markdown-First 物理落盘与来源分级架构。 核心信念物理文件是管线各阶段之间的唯一接口契约。AI 产出必须标注来源级别,原始素材不可变。 审阅确认后,将指导两条管线的统一改造。