# SPEC: Markdown-First 物理落盘与来源分级架构 > **版本**: v1.0 > **前置依赖**: > - [SPEC_deepview_metadata_scoping_v3.md](./SPEC_deepview_metadata_scoping_v3.md) (Prosumer-First 沙箱隔离) > - [SPEC_tri_domain_knowledge_architecture.md](./SPEC_tri_domain_knowledge_architecture.md) (三元知识域) > - [DESIGN_PHILOSOPHY_AI_NATIVE.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 后,从该路径读取内容。 ```python # ✅ 正确:明确输出路径,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 注释形式嵌入来源元数据: ```markdown # 面诊沟通X光片深度分析报告 ... ``` ```markdown # 👤 客户全景档案:测女士 ... ``` L0 文件(asr.md)**不需要**标注——没有标注即为 L0。这是"无标记即原始"的默认原则。 ### 3.3 Agent 行为约束(注入 SKILL.md) 在 Agent 的 SKILL 指令中,追加来源分级感知规则: ```markdown ## 📋 来源分级阅读规则 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 中要求写入 `` 标注 | ### 5.2 客户档案管线 (`_generateClientProfile`) | 步骤 | 现状 | 改造 | |------|------|------| | Agent user_message | 含 `profileMdPath` 路径 | 保持(Agent 已自然写入此路径) | | Stage 1 取值 | ~~`result.get("final_response")`~~ **已修复** → 读取 `profile.md` | ✅ 已完成 | | 文件头标注 | 无 | 需追加 `` | ### 5.3 SKILL.md 追加 | 文件 | 变更 | |------|------| | `skills/deepview_assistant/SKILL.md` | 追加"来源分级阅读规则"章节 | | `skills/deepview_profile/PROMPT_stage1.md` | 要求输出文件头带 `` 标注 | --- ## 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 的关系 ```mermaid graph TB A["DESIGN_PHILOSOPHY_AI_NATIVE
先有价值,后有治理"] --> B["SPEC_metadata_scoping_v3
Prosumer-First 沙箱隔离"] B --> C["SPEC_tri_domain_knowledge
三元知识域"] B --> D["SPEC_md_first_persistence
📄 本规范"] D --> E["来源分级标记"] D --> F["管线物理接口"] D --> G["Agent 分层阅读策略"] ``` - **V3 SPEC** 定义了"数据在哪"(`users/{userId}/` 沙箱) - **三元域 SPEC** 定义了"知识从哪来"(平台/机构/个人三级注入) - **本 SPEC** 定义了"文件怎么流"(物理落盘、来源标记、Agent 感知证据层级) 三者合力构成了完整的数据治理体系:**沙箱隔离 × 知识分域 × 来源追溯**。 --- ## 8. 验证计划 ### 8.1 自动化测试 ```bash # 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 产出必须标注来源级别,原始素材不可变。* > *审阅确认后,将指导两条管线的统一改造。*