13 KiB
SPEC: Markdown-First 物理落盘与来源分级架构
版本: v1.0
前置依赖:
- SPEC_deepview_metadata_scoping_v3.md (Prosumer-First 沙箱隔离)
- SPEC_tri_domain_knowledge_architecture.md (三元知识域)
- DESIGN_PHILOSOPHY_AI_NATIVE.md (AI-Native 产品心法)
状态: 草案 (Proposal)
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.md,response 仅 401 字符 |
1.2 幻觉复利效应
当前 profile.md 既是 Agent 的输入素材(读取既往档案),又是 Agent 的输出目标(生成新档案后覆盖写入)。文件系统中没有任何标记区分:
asr.md(L0 原始转写,可信度最高)profile.md(L2 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 1:Agent 通过
read_file自主读取asr.md(及其他素材) - Stage 1 → Stage 2:管线代码从 Agent 写入的物理文件读取内容,传入 Stage 2
- Stage 2 → DB:JSON 写入数据库(已实现,无变更)
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_response(Ghost 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 产出必须标注来源级别,原始素材不可变。 审阅确认后,将指导两条管线的统一改造。