@a9i5k4/dsh-auto-memory 2.5.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +171 -1
  2. package/README.zh-CN.md +171 -1
  3. package/docs/CONTRIBUTORS.html +471 -0
  4. package/docs/HANDOFF-CRITERIA.md +92 -0
  5. package/docs/INTEGRATION-ANALYSIS.md +350 -348
  6. package/docs/USER-GUIDE.en.md +56 -1
  7. package/docs/USER-GUIDE.zh-CN.md +57 -2
  8. package/docs/internal/ACCEPT-35-LIVE.md +143 -0
  9. package/docs/internal/ACCEPTANCE-20260914.md +90 -0
  10. package/docs/internal/ARCH-REVIEW-BRIEF.md +411 -0
  11. package/docs/internal/ARCH-REVIEW-REQUEST.md +201 -0
  12. package/docs/internal/ARCH-REVIEW-ROUND2.md +169 -0
  13. package/docs/internal/ARCH-REVIEW-ROUND3.md +206 -0
  14. package/docs/internal/AUDIT-WB-GRAPH-FULL-20260916.md +314 -0
  15. package/docs/internal/CONCURRENCY-INVESTIGATION-20260917.md +192 -0
  16. package/docs/internal/CROSS-SESSION-SEARCH-PATH-DECISION.md +72 -0
  17. package/docs/internal/CROSS-SESSION-SEARCH-RESEARCH.md +131 -0
  18. package/docs/internal/DECISIONS-20260914-SESSION.md +269 -0
  19. package/docs/internal/DESIGN-P1-STATE-COMMIT-20260915.md +219 -0
  20. package/docs/internal/DIRECTION-CHECK-WB-GRAPH-20260916.md +132 -0
  21. package/docs/internal/FEEDBACK-TO-DSHAPI-RELAY.md +13 -0
  22. package/docs/internal/GH-DISCUSSION-5732-COMMENT.md +74 -0
  23. package/docs/internal/GPT-ACCEPTANCE-PROMPT-20260916.md +352 -0
  24. package/docs/internal/GPT-REVIEW-PROMPT.md +216 -0
  25. package/docs/internal/GROUP-WEBHOOK-SETUP.md +33 -0
  26. package/docs/internal/KICKOFF-P0.md +254 -0
  27. package/docs/internal/MASTER-PLAN-3.0.md +411 -0
  28. package/docs/internal/MEMORY-MUTATION-AND-INDEX-DESIGN.md +85 -0
  29. package/docs/internal/MERGE-CONFLICT-SCAN-20260914.md +222 -0
  30. package/docs/internal/PENDING-FIXES-20260916.md +289 -0
  31. package/docs/internal/RAG-KARPATHY-PROGRAM.md +229 -0
  32. package/docs/internal/REPORT-P0-NIGHTLY.md +212 -0
  33. package/docs/internal/REPORT-P5-ACCEPTANCE.md +31 -0
  34. package/docs/internal/REPORT-WB-GRAPH-NIGHTLY.md +153 -0
  35. package/docs/internal/REVIEW-WB-GRAPH-SELF.md +81 -0
  36. package/docs/internal/ROADMAP-20260917-WEEK.md +305 -0
  37. package/docs/internal/ROADMAP.md +106 -0
  38. package/docs/internal/RUN-P0-NIGHTLY.md +227 -0
  39. package/docs/internal/S10-CONSTRUCTION-HANDOFF-20260917.md +175 -0
  40. package/docs/internal/S10-GAPS-PLAIN-20260917.md +125 -0
  41. package/docs/internal/SEMANTIC-ARCHITECTURE-SPEC.md +360 -0
  42. package/docs/internal/SESSION-FILE-REPAIR-PROTOCOL.md +90 -0
  43. package/docs/internal/THREE-LAYER-CONTRACT.md +210 -0
  44. package/docs/internal/TODO-BACKLOG.md +263 -142
  45. package/docs/internal/TODO-GRAPH.html +715 -0
  46. package/docs/internal/TODO-GRAPH.html.bak-20260914-v2 +493 -0
  47. package/docs/internal/TODO-GRAPH.html.bak-20260915-alsfix +710 -0
  48. package/docs/internal/TODO-GRAPH.html.bak-20260915-p1 +710 -0
  49. package/docs/internal/TODO-GRAPH.html.bak-20260915-p6a-rev +703 -0
  50. package/docs/internal/TODO-GRAPH.html.bak-20260915-wshint +710 -0
  51. package/docs/internal/TODO-GRAPH.html.bak-20260916-batch +715 -0
  52. package/docs/internal/WB-FORMAT-CONVENTION.md +112 -0
  53. package/docs/internal/WB-GRAPH-DECISIONS-20260914.md +71 -0
  54. package/docs/internal/reviews/CLAIM-VERIFICATION-20260914.md +56 -0
  55. package/docs/internal/reviews/PLAN-gpt6astra-round2-20260914.md +787 -0
  56. package/docs/internal/reviews/REVIEW-gpt6astra-20260914.md +112 -0
  57. package/docs/internal/reviews/ROUND3-REVIEW-INTEGRATION-20260914.md +230 -0
  58. package/docs/prompts/M8-3-enable-verify.md +49 -49
  59. package/lib/acceptance.js +71 -0
  60. package/lib/activation-host.js +90 -9
  61. package/lib/activation-inbox.js +25 -7
  62. package/lib/board-mode.js +30 -0
  63. package/lib/client.js +878 -75
  64. package/lib/context-bridge.js +2 -2
  65. package/lib/context-host.js +70 -6
  66. package/lib/engine-identity.js +149 -0
  67. package/lib/engine-switch.js +247 -0
  68. package/lib/episodic-store.js +11 -10
  69. package/lib/evidence-store.js +2 -2
  70. package/lib/fact-store.js +1 -1
  71. package/lib/fs-retry.js +46 -0
  72. package/lib/index.js +1987 -153
  73. package/lib/intent-clean-safe.js +40 -0
  74. package/lib/intent-clean.js +12 -16
  75. package/lib/l0-extract.js +263 -149
  76. package/lib/l0-index-sync.js +195 -0
  77. package/lib/l0-index.js +349 -239
  78. package/lib/ledger-criteria.js +142 -0
  79. package/lib/m7-index-sync-host.js +65 -4
  80. package/lib/m7-wire.js +3 -3
  81. package/lib/memory-anchor.js +56 -1
  82. package/lib/memory-envelope.js +252 -0
  83. package/lib/memory-hub.js +14 -4
  84. package/lib/memory-mutation.js +246 -0
  85. package/lib/memory-writer.js +204 -24
  86. package/lib/procedure-observation.js +48 -0
  87. package/lib/procedure-store.js +34 -17
  88. package/lib/python-setup.js +1 -1
  89. package/lib/rerank-host.js +160 -0
  90. package/lib/rules-layer.js +261 -0
  91. package/lib/semantic-js.js +15 -0
  92. package/lib/shadow-retrieval.js +3 -3
  93. package/lib/state-commit.js +245 -0
  94. package/lib/subagent-gc.js +4 -8
  95. package/lib/tier-layer-inject.js +650 -0
  96. package/lib/tier0-catalog.js +693 -0
  97. package/lib/water-window.js +263 -186
  98. package/lib/wb-contract.js +495 -0
  99. package/lib/wb-sidecar.js +839 -0
  100. package/lib/ws-overview-rank.js +2 -2
  101. package/package.json +1 -1
  102. package/python/m7_embedding_v1.py +5 -5
  103. package/python/worker_semantic_v1.py +17 -6
  104. package/python/worker_v1.py +38 -4
@@ -0,0 +1,360 @@
1
+ # 语义架构规范 v2(SEMANTIC-ARCHITECTURE-SPEC)
2
+
3
+ > **效力**:本文件是 dsh-auto-memory **语义/检索侧的规范性约束**。此后任何涉及检索、嵌入、分块、融合、重排、注入内容取舍的改动,**必须先在此规范里找到条款依据**;规范没写的做法不得直接进主干(先补条款 → 再施工)。
4
+ > **配套**:三层架构的接口与预算见 `docs/internal/THREE-LAYER-CONTRACT.md`(C1–C7);排期与阶段门见 `docs/internal/TODO-GRAPH.html`、`TODO-BACKLOG.md`。
5
+ > **建立**:2026-09-14。依据 = 用户指定的规范来源(B 站《7 分钟了解 10 种 RAG 策略》BV17J3B6PEGK)+ 通用 advanced-RAG 技术谱系(见附录)。
6
+ > **版本**:**v2**(2026-09-14,条款增删 → 按 §6 第 4 条升版;变更记录见 §0.1)。
7
+
8
+ ---
9
+
10
+ ## 0. 引用纪律(怎么用这份规范)
11
+
12
+ 1. 提改动时**引条款号**(例:"这次改动落在 S2.1 查询改写"),并在卡片/日志里写明。
13
+ 2. 每条条款都有 **判据(能失败的断言)**。没有判据的条款视为未生效,不得作为"已实现"申报。
14
+ 3. 改动**必须带离线对照**(S7):改前基线 / 改后数字 / 样本数 / 判据是否翻过。
15
+ 4. 规范与实现冲突时:**要么改实现,要么走变更程序改规范**(§6),不允许"实现先跑,规范后补"。
16
+
17
+ ### 0.1 变更记录
18
+
19
+ **v2(2026-09-14)** —— **依据「用户 2026-09-14 裁定」**。三处改动:
20
+
21
+ 1. **§7 立场(成本模型)改写为分档表述,并承认此前的定调错误。** 旧 §7 的成本对照表按「轻度用户」写,**并把兼容档的约束(检索路径零 LLM 调用)升格成全项目硬约束(S9 标 MUST)**,等于禁止首要用户(最优档)使用更重的方案。**这是定调错误**:首要用户 = 项目作者本人 = 重度档/最优档,以**最优**为设计目标;兼容档的准确含义是**「降级路径必须存在」**,不是「按最省设计」。
22
+ 2. **S9 由单条 MUST 改为分档条款**:S9.1(兼容档 MUST:检索路径零额外 LLM token + 弱设备可跑)/S9.2(最优档:允许更重方案含 LLM,但每条必须带「成本 + 门控 + 降级路径」三件套)/S9.3(两档共用同一套接口与判据)/S9.4(禁止把"只能跑通兼容档"的设计当目标形态)。旧 S9.1 的"三件套"要求移入新 S9.2;旧 S9.2 的"决策层本地承担"移入新 S9.1;旧 S9.3 的"成本归属"并回 §7。
23
+ 3. **数值口径统一到代码真值**(见 §0.2):消除规范 / 契约 / 代码三方漂移(`B2` 曾 2000 与 2400 并存;`injectBudgetChars` 曾写 4800;`tier0MaxTokens` 的 400 与 `B0`=800 被误当作矛盾)。**自本次起,规范里出现的每个数值都有代码出处,且由一致性守卫测试机械校验**(`tests/smoke/smoke-test-doc-code-consistency-pre.mjs`:代码默认值 ↔ 文档「默认」标注,任一侧漂移即报红)。
24
+
25
+ ### 0.2 数值口径(**代码真值**,与文档不一致时以本节为准;守卫测试按本节模式解析)
26
+
27
+ | 字段 | 代码真值 | 出处(实读) | 口径说明 |
28
+ | --- | --- | --- | --- |
29
+ | `injectBudgetChars` | 默认 **8000** | `lib/index.js:226` | **可配置项**(设置页「记忆窗口 → 注入预算」可调)。沿革:1600 → 2000(2026-09-14 用户裁定,Tier-0 目录要在原预算内"免费"塞入是不可能的)→ **8000**(2026-09-15 用户裁定:实测 2000 下用户级记忆只有约 **9%** 能进注入,"在场但只看到个开头")。**口径(勿用"越大越好"调它)**:本门是「**摘要内联**」额度,全文靠 `memory_recall_pre` / `memory_read_pre` 按需下钻;要装下更多语料应抬 Tier-0 目录配额(`tier0BudgetShare` / `tier0MaxTokens`),而不是把本值推到几万。8000 字符 ≈ 4000 token ≈ 1M 窗口的 0.4%;配合**分级注入**(完整版每 `snapshotMinGapRounds` 轮一次)平均约 1300 token/轮。历史文档里的 `4800` 是更早的旧默认值,已作废。 |
30
+ | `tier0CatalogEnabled` | 默认 **true** | `lib/index.js:220` | C5 Tier-0 常驻目录开关;设 false 回到旧快照。 |
31
+ | `tier0MaxTokens` | 默认 **400**;硬上限 `B0` = 800 | `lib/index.js:224`(默认值)、`lib/tier-layer-inject-pre.js:33`(`B0`) | **400 与 800 不是矛盾,而是「默认值 vs 上限」之别**:800 是硬上限(超设无效),默认取上限的一半(实测 9 条仅 234 token,留余量且不挤证据层)。 |
32
+ | `tier0BudgetShare` | 默认 **0.25** | `lib/index.js:227` | Tier-0 目录最多占「注入预算」的比例;与 `tier0MaxTokens` 取小生效。 |
33
+ | `l0IndexEnabled` | 默认 **true** | `lib/index.js:416` | C3 L0 向量索引接线开关(**2026-09-14 用户裁定改为默认开**);设 false 即回到"零 IO、零嵌入、零目录"。 |
34
+ | `B0`(Tier-0 token 上限) | **800** token | `lib/tier-layer-inject-pre.js:33` | 硬上限(`TIER_BUDGET_PRE_V1.B0`)。 |
35
+ | `B2`(Tier-2 单块字符上限) | **2400** 字符 | `lib/tier-layer-inject-pre.js:36` | `TIER_BUDGET_PRE_V1.B2` = 2400。此前契约 §1.2 / §5 曾写 2000 → **已统一到 2400**(见 §0.1 第 3 条)。 |
36
+
37
+ ---
38
+
39
+ ## 1. 总链与分层(固定骨架)
40
+
41
+ ```
42
+ ①产生 → ②存储 → ③选取 → ④注入 → ⑤晋升 → ⑥呈现
43
+ ```
44
+
45
+ 语义只在前四步产生价值:**②存储**(分块/嵌入/索引)、**③选取**(查询理解 → 召回 → 精排 → 决策)、**④注入**(压缩/预算/降级标注)。①⑤⑥ 不含语义算力(⑥ 只负责把结论显示给人看)。
46
+
47
+ **三层检索(接口已冻结)**:Tier-0 常驻目录(≤ `B0`=800 token,**实际默认 `tier0MaxTokens` = 400**)→ Tier-1 L0 摘要(≤ `L1`=140 字/条,`K`=8)→ Tier-2 原文块(单块 ≤ `B2`=2400 字)。语义算法改造**只允许改层内的算法**,不得改层间的接口形状。
48
+ 数值一律以 §0.2「数值口径(代码真值)」为准(`B2`=2400 出自 `lib/tier-layer-inject-pre.js:36`;历史上出现的 2000 是旧写法,**已统一到 2400**)。
49
+
50
+ ---
51
+
52
+ ## 2. 规范条款
53
+
54
+ ### S1 存储:分块与增量(MUST)
55
+
56
+ - **S1.1** 每个可检索单元必须有**内容寻址的稳定 ID**(块 ID = f(记忆 ID, 记录摘要, 序号)),且**块 ID 必须同时是嵌入缓存键的一部分**。
57
+ - **S1.2** 嵌入缓存键 = **引擎身份**(引擎 + 模型 + 维度 + 归一化方式)+ 块 ID。**换引擎即整库重建**(双引擎是 **OR** 关系:兼容档 = 端侧 JS `multilingual-e5`,最优档 = Python `BGE-M3`;两档共用同一套接口,见 S9.3)。
58
+ - **S1.3** 写一条记忆**不得**引起全库重嵌:只嵌入新增块,删除/修改走 **supersede 声明 + tombstone**(屏蔽必须落在持久层,且检索层与注入层双层生效)。
59
+ - **现状(证据)**:块 ID 已内容寻址(`python/m7_embedding_pre_v1.py:75` `chunk_id_for`)但**未用作缓存键**;索引身份是**整份语料哈希** `memoryIndexVersion`(`lib/index-sync-pre.js:57`),任何细节改动 → miv 变 → 全量重发 + 全量重嵌。
60
+ - **缺口**:S1.2 未落(缓存键无引擎身份);S1.3 未落(现为全量重算,即"草台"根因)。
61
+ - **归属**:阶段 C(P0-④「记忆增删 × 少重建」)。
62
+
63
+ ### S2 选取-查询侧:先理解查询,再检索(SHOULD,本仓最大空白)
64
+
65
+ - **S2.1 查询改写/扩展**:检索前把原始 query(用户消息 / CoT 段 / 助手输出)规范化为**检索式查询**(去指示词、补省略主语、展开本仓专有名词)。
66
+ - **S2.2 多查询(multi-query)**:对复杂 query 生成 2–4 个改写,各自召回后**共同融合**(不是取并集后就地打分)。
67
+ - **S2.3 HyDE 类假设文档**:仅在短查询、零词法命中时启用(成本门控),生成假设答案再嵌入检索。
68
+ - **S2.4 查询侧一切加工必须在 `SHOULD` 预算内**(离线可关、失败即回退原始 query,绝不因改写失败导致检索为空)。
69
+ - **现状**:**三项全无**。现在直接把原始段文本送去检索(`lib/context-host-pre.js:347` 用 `buildObserveWindowText` 的原文)。
70
+ - **缺口**:这是"语义算法底层改进"里**收益最大、风险最低**的一档(不碰索引、不碰接口)。
71
+ - **归属**:阶段 C。
72
+
73
+ ### S3 选取-召回侧:混合臂 + 融合(MUST)
74
+
75
+ - **S3.1** 至少两臂:词法臂 + 稠密语义臂;时间/来源可作软性第三臂(**只提升不硬过滤**)。
76
+ - **S3.2** 融合必须**在排名空间**做(RRF 等,`k`=60 复用 `FUSION_RRF_K_PRE_V1`);**禁止在分数空间加权**(不同臂的分数量纲不可比)。
77
+ - **S3.3** 单臂失败必须**降级可运行**(语义臂不可用 → 纯词法),但**必须显式标注降级**(见 S5.3),不得静默。
78
+ - **S3.4** 语义臂的可用性必须**可被外部观测**(不能只在日志里)。
79
+ - **现状**:✅ 已实现且合规 —— 词法(BM25 式 + 词法包含)+ 稠密(`c3 dense_search` → `_jsSemanticRank`)+ 时间臂;RRF 融合在 `lib/index.js:4068`(`P8`),host 侧 `fuseD6Pre`(`lib/context-host-pre.js:368`);降级链 python → JS → 纯词法。
80
+ - **缺口**:S3.4 部分(本轮 C7 已让 0-1 分与排名进注入文本;仍需一条"引擎/臂身份"标注)。
81
+
82
+ ### S4 选取-精排:召回与打分分离(SHOULD)
83
+
84
+ - **S4.1** 召回与精排分两级:召回要"全"(宽候选),精排要"准"(窄结果)。当前只有一级(融合序直接当最终序)。
85
+ - **S4.2** 精排器可以是 cross-encoder(重)或 LLM 判断(贵),**必须离线可评估**;无资源时允许用"融合序 + fv2 决策"作为近似,但要在规范里标为**近似**。
86
+ - **现状**:❌ 无独立精排级。现有"精排"实际由 fv2 决策(emit/prefetch/suppress)承担**注不注入**的判据,不负责**排序**。
87
+ - **归属**:阶段 C;先做近似(S4.2 后半),有资源再上 cross-encoder。
88
+
89
+ ### S5 注入侧:压缩 + 预算 + 降级(MUST)
90
+
91
+ - **S5.1 上下文压缩**:注入的是"提炼后的结论",不是原文转储(Tier-0 每条 1 行)。
92
+ - **S5.2 预算分层**:Tier-0 ≤ `B0`、Tier-1 ≤ `L1/K`、Tier-2 单块 ≤ `B2`;**per-layer 配额**(project ≤ 60%·`B0`,whiteboard/user 各保底 10%)。
93
+ - **S5.3 不静默降级**:任何一层缺数据都要**显式标注**(I7);索引未就绪**不得静默丢弃**注入。
94
+ - **S5.4 可观测**:注入块必须带 **0-1 相似度 + 批内排名**,且按分值降序。
95
+ - **现状**:S5.1 ✅(C4 Tier-0 生成器,真实语料 788 token ≤ 800);S5.2 部分(配额待 C5 落);S5.3 ❌(07:43–08:35 的 `index-not-ready` 静默丢弃即违规现场);S5.4 ✅(本轮 C7)。
96
+ - **归属**:C5 + P0-④e。
97
+
98
+ ### S6 决策:自适应检索(MUST,本仓强项)
99
+
100
+ - **S6.1** 每次注入前必须有一次显式决策(要不要检索/注入),判据可解释:`lane`(explicit/proactive)+ `intent` 概率 + 融合 `margin` + **echo veto**(防复述用户刚说的话)+ 硬门(有害/纠正/过期/越界)。
101
+ - **S6.2** 决策必须记录**可复算的特征快照**(intent/dense/margin/candN/hit),供离线回放。
102
+ - **S6.3** 冷却与预算门必须与决策同级(防连续唤起烧 token)。
103
+ - **现状**:✅ 已实现(fv2 策略工件 `lib/policies/activation_policy_pre_v2.json`;JS 判定核 `lib/context-host-pre.js:417+`;shadow 日志 `~/.dsh/memory/semantic-pre/activation-shadow.jsonl`)。
104
+ - **注意**:S6 是本仓**领先项**,改造其他条款时**不得削弱**它。
105
+
106
+ ### S7 评估:没有实验就没有资格改算法(MUST)
107
+
108
+ - **S7.1** 任何语义/检索改动必须产出**三策略对照**:A 只给上层目录 / B 上层 + 命中条摘要 / C 上层 + 候选集全灌(上限 `injectBudgetChars`)。
109
+ - **S7.2** 指标固定四项:**命中率**(top-1/top-3/top-5)、**下探后答案可达率**、**注入 token 成本**、**噪声比**。
110
+ - **S7.3** 判据必须**能失败**(能力可达性):判据写成"若实现被改坏则报红",不允许"声明了就算过"。
111
+ - **现状基线(2026-09-14,词法臂,语义臂卡死期间)**:3 条事实 → L0 top-1 命中 **1/3**、top-5 命中 **2/3**;命中原因**全是词法、0 条带语义分**;观察到单字母 token 污染(`词法×3(agent,检索,a)`)。
112
+ - **归属**:E1/E3(P1-⑯)。**语义臂已恢复,可正式跑**。
113
+
114
+ ### S8 观测与再现(SHOULD)
115
+
116
+ - **S8.1** 每条注入/召回都要能回答:**用了哪条记忆、多像(0-1)、为什么选它、来自哪个引擎**。
117
+ - **S8.2** 语料/索引/向量三件套的身份必须能在一次诊断里全部打印(否则无法复现"分数整段消失"这类故障)。
118
+ - **现状**:S8.1 部分(C7 给了相似度与排名;引擎身份未标注);S8.2 部分(`~/.dsh/dsh-auto-memory-pre.json` 诊断 + 向量文件时间戳,本轮排查靠它定位)。
119
+
120
+ ### S9 成本:**分档条款**(兼容档 MUST 零额外 LLM token;最优档允许更重方案,但必须带三件套)
121
+
122
+ > **定调更正(2026-09-14 用户裁定)**:S9 在 v1 里写成**单条 MUST —— "检索路径默认零 LLM 调用"**。那是把**兼容档**的约束升格成了**全项目硬约束**,等于用规范禁止首要用户(最优档)使用更重的方案。**这是定调错误**,v2 改为分档:
123
+
124
+ - **S9.1(兼容档 · MUST)** 兼容档的检索路径(分块 → 嵌入 → 召回 → 融合 → 决策 → 压缩 → 注入)必须**零额外 LLM token**,且必须在**弱设备**(无独显、内存紧张)上跑得动 —— 嵌入走端侧小模型(JS `multilingual-e5` 档)或纯词法,决策层由**本地模型或规则**承担(当前 = fv2 线性分类器,0 token),压缩用本地规则。**"降级路径必须存在"是这一档的唯一硬含义**:任一环节不可用时必须能退到更轻的实现并**显式标注**(S5.3 / I7),而不是整条链路失败。
125
+ - **S9.2(最优档 · 允许更重方案,含 LLM)** 最优档(首要用户 = 项目作者本人)**允许**在检索路径引入 LLM 的方案(如 LLM 查询改写、LLM 精排、LLM 自省、多轮检索),但**每条方案必须同时给出三件套,缺一不可**:
126
+ 1. **成本**:谁付费、按什么计价(每轮 token 数 / 每轮延迟 / 设备算力),必须是可测的数字而不是形容词;
127
+ 2. **门控条件**:什么情况下才启用(查询复杂度阈值、冷却、预算余量、用户开关),以及谁有权把它关掉;
128
+ 3. **无 LLM 时的降级路径**:LLM 不可用 / 超预算 / 报错时退化成什么(规则实现或端侧小模型),且这次退化**必须显式标注**。
129
+ 三件套不齐的方案**不予采纳**(此条沿用 v1 S9.1 的要求,只是作用域从"全项目一律禁止"改为"最优档若要用就必须补齐")。
130
+ - **S9.3(两档共用同一套接口与判据)** 分档**只换引擎与预算,不改契约形状**:Tier-0 / Tier-1 / Tier-2 的接口、字段、注入块的形状、条款判据在两档下完全一致(这正是三层接口已冻结的原因)。**禁止**为某一档设计专用接口、专用字段或专用判据;也**禁止**把两档做成两套代码路径 —— 只有"同一路径 + 不同引擎/预算"。
131
+ - **S9.4(禁止把兼容档形态当目标形态)** **禁止把"只能跑通兼容档"的设计当作目标形态。** 任何在弱档才成立的设计(纯词法、无精排、零端侧模型)都必须标注为**降级形态**,不得写成"目标架构"或据此否决最优档的更强方案;反之,最优档的重方案也必须证明它**不破坏 S9.1 的降级路径**(否则就等于砍掉了第二目标)。
132
+ - **现状**:两档各自合规 —— 兼容档 ✅(决策 = fv2 本地 LR,嵌入 = 端侧 e5,压缩 = 本地规则);最优档 ✅(Python `BGE-M3` 语义引擎在用,属"更重的本地模型",不是 LLM 路径)。⚠️ 风险点仍是 S2 的查询改写:兼容档按 S9.1 必须本地做(规则 + 术语表 + 端侧小模型);最优档若要用 LLM 改写,**按 S9.2 补三件套**,不许一句"效果好"就进主干。
133
+ - **归属**:贯穿阶段 C;审计纳入 P1-⑨(审计对象 = **兼容档是否守住 S9.1 + 最优档每条重方案是否有三件套**,而不是"路径上有没有 LLM"这道一刀切)。
134
+
135
+ ---
136
+
137
+ ## 3. 与三层契约(C1–C7)的关系
138
+
139
+ | 规范条款 | 对应契约项 | 状态 |
140
+ | --- | --- | --- |
141
+ | S5.4(注入可见相似度) | **C7** | ✅ 已落(29 断言) |
142
+ | S5.1/S5.2(压缩 + 配额) | **C4 / C5** | C4 ✅,C5 ✅(套件 83 断言 0 失败;待宿主重启复核) |
143
+ | S1.3(增量/少重建) | P0-④ / P0-④e | 待做(草台根因) |
144
+ | S2/S4(查询侧 + 精排) | 规范新增,无对应 | 待做(本轮立规) |
145
+ | S3/S6(混合臂 + 决策) | 已有实现 | ✅ 合规,改造时不得削弱 |
146
+
147
+ **结论**:本轮之前,检索侧的"算法"只有 S3/S6 是对的;S1/S2/S4/S5 是草台。规范立起来之后,**改造范围就是 S1/S2/S4/S5**。
148
+
149
+ ---
150
+
151
+ ## 4. 阶段门与起点("什么时候开始做语义算法底层改进")
152
+
153
+ **硬约束(用户已定)**:三层架构(Tier-0/L0/原文)必须**先过真实验收**,再进语义算力改造 —— 三层是语义的**接口**,接口没冻结就改算法 = 白改。
154
+
155
+ | 阶段 | 内容 | 起点条件 | 可否并行 |
156
+ | --- | --- | --- | --- |
157
+ | **A · 接口冻结** | C3(接线 L0 向量索引 + 显式落 layer/status)→ C5(Tier-0 常驻 + 闸门 + 配额 + I7 降级标注)→ C6(三层验收套件) | 现在,已开工 | — |
158
+ | **B · 立规与审计**(本轮已启动) | 本规范(**已升至 v2**:§7/S9 分档更正 + 数值口径统一);按 S1–S8 逐条审我方实现;跑 E1/E3 三策略对照,把 S7 基线补齐(**语义臂已恢复**) | 只要不跨界改接口即可开工 | ✅ 与 A 并行 |
159
+ | **C · 算法改造** | 按 §2 的施工清单动算法:S1 增量缓存 → S2 查询侧加工 → S4 精排 → S5.3 降级标注收口 | **A 全绿 + 宿主重启复核注入 Score 钉子** | ❌ 不得与 A 抢同一批文件 |
160
+
161
+ **直接回答**:
162
+ - **语义算法(真改造)的起点 = 阶段 A 通过验收的时刻**(C3/C5/C6 全绿,且注入块里能看到 `Score: 0.xx (rank n/m)`)。按当前进度,A 是**今天到明天**这一档的工作量。
163
+ - **但语义工作今天就已经开始了**,走的是 B 线:立规范(本轮)+ 补实验基线(E1/E3,今天可跑)。B 线不碰接口,不需要等 A。
164
+ - 阶段 C 的施工顺序(按风险/收益比):**S1.3 增量少重建**(止血,草台根因)→ **S5.3 降级标注**(止血,防"分数整段消失"复发)→ **S2 查询侧加工**(收益最大)→ **S4 精排**(最后做,最贵)。
165
+
166
+ ### 4.1 不采纳项(明确写下,免得后面照搬)
167
+
168
+ - **迭代式 RAG(多轮检索/自省循环):不作为默认形态(两档皆然)。** 我们的场景是**每轮自动注入**,多轮检索会把延迟与 token 乘 2 以上;而"要不要检索"已由 S6(fv2 决策 + echo veto + 冷却)承担。迭代式 RAG 适用于"单次检索明显不够 + 允许用户等"的问答场景,不是本仓形态。**最优档若仍想提出**(例如把"自省一轮"作为可选增强),按 **S9.2** 补齐成本 + 门控 + 降级路径三件套后可以讨论 —— 但**兼容档的默认路径不采纳**(S9.1)。
169
+ - **重排(S4):先做近似级,cross-encoder 留给最优档。** 在候选池(`K`=8 / `B0`=800)与 S7 实验判据就绪前直接上 cross-encoder,只会增加延迟而无从证明它比 RRF 融合序更好 —— 所以**先做 S4.2 的近似级,用实验说话**;等判据就绪后,cross-encoder 作为**最优档**的重方案上线(按 S9.2 标注成本),**兼容档保持近似级不变**。
170
+ - **多引擎混排:禁止。** 双引擎是 **OR** 关系(JS `multilingual-e5` 或 Python `BGE-M3`),切换即整库重建;两套向量空间混排即错误结果(S1.2)。切换引擎属**换档**(S9.3 允许换引擎与预算),不属"改契约形状"。
171
+
172
+ ---
173
+
174
+ ## 5. 施工清单(阶段 C,按顺序)
175
+
176
+ 1. **S1.3** 块级增量:块 ID 进缓存键,只嵌新增块;修改走 supersede,屏蔽落持久层(检索+注入双层)。
177
+ 2. **S5.3** 索引未就绪不得静默丢弃:显式降级标注 + 防抖(防"写记忆把索引饿死")。
178
+ 3. **S2.1/S2.2** 查询改写与多查询:**先落 S9.1 的本地实现**(规则 + 术语表 + 端侧小模型,离线可关、失败回退原文);最优档若要升级为 LLM 改写,按 **S9.2** 带三件套另立一条,不覆盖本地路径。
179
+ 4. **S2.3** HyDE(有成本门控时才开 —— 该档的"成本门控"就是 S9.2 的第 2 件套)。
180
+ 5. **S4.2** 精排近似 → cross-encoder(兼容档停在近似级;最优档上 cross-encoder 时按 S9.2 标注成本)。
181
+
182
+ **每条都必须带**:S7 的三策略对照 + 一条能失败的断言 + 引用的条款号。
183
+
184
+ ---
185
+
186
+ ## 6. 变更程序
187
+
188
+ 1. 改实现前,先在 §2 找到/新增条款;新增条款需写明 **判据**。
189
+ 2. 判定标准冲突时以**用户拍板**为准,并把结论写回本规范(标注日期与来源)。
190
+ 3. 每次改完,在 `TODO-GRAPH.html` 对应卡片引用条款号(如「按 S2.1」)。
191
+ 4. 规范版本号只在**条款增删**时递增(v1 → v2);措辞澄清不改版本。
192
+
193
+ ---
194
+
195
+ ## 7. 立场:在「RAG 已死」的语境下,我们为什么仍走检索路线(**分档成本模型**)
196
+
197
+ **判据不是"RAG vs 长上下文",而是"谁付费" —— 而"谁付费"必须分档回答。**
198
+
199
+ ### 7.1 先把定调更正:这是一份**分档**规范,不是"轻量版"规范
200
+
201
+ **首要用户 = 项目作者本人 = 最优档(重度档)**:以**最优**为设计目标 —— 愿意承担更重的算法、更重的本地模型(当前 = Python 语义引擎 `BGE-M3` 档)、更长的注入预算,换检索质量。
202
+
203
+ **第二目标 = 兼容档**:「兼容」的准确含义是 **"降级路径必须存在"**,**不是** "按最省设计"。兼容档存在的意义是让同一套架构在弱设备 / 零额外 token 的普通用户机器上**也能跑通**,而不是给全项目的设计目标定一个最省的下限。
204
+
205
+ > **我们此前把兼容档的约束当成了全项目硬约束,这是定调错误。** 旧 §7 的成本对照表是按"轻度用户"写的,旧 S9 又标 MUST 写"检索路径默认零 LLM 调用"——两者合起来等于:**用规范禁止最优档使用更重的方案**(而最优档才是首要用户)。v2 起:
206
+ > - §7(本节)的成本模型**分档表述**(两档各自的"谁付费"、各自该选什么);
207
+ > - S9 **降级为分档条款**(S9.1 兼容档 MUST / S9.2 最优档带三件套 / S9.3 共用接口与判据 / S9.4 禁止把兼容档形态当目标);
208
+ > - **判定依据**:用户 2026-09-14 裁定。
209
+
210
+ ### 7.2 「RAG 已死」的两个替代方案:成立,但各带隐含前提
211
+
212
+ (均已核验,见附录 F)
213
+
214
+ | 替代方案 | 真实主张 | 隐含前提 | 对最优档 | 对兼容档(轻度用户) |
215
+ | --- | --- | --- | --- | --- |
216
+ | **LLM Wiki**(Karpathy) | 传统 RAG 的病是**没有知识积累**:每次查询都从零重新发现。改为让 LLM 渐进维护一份持久 wiki(实体页/概念页/交叉引用/矛盾标注/综合结论),靠 `index.md` + `log.md` 导航 | 写入侧与维护侧**由 LLM 长期承担**;原文明确说在"约 100 份资料、数百页"规模下**可避开嵌入式 RAG 基础设施** | ✅ 可用:写入侧 token 可接受(我们已模板化),查询侧多花 token 换整合质量,最优档付得起 | ⚠️ 写入侧 token 可接受(可模板化),但查询侧仍要 LLM 读页 —— 只能作为**可选增强**,不能作为这一档的默认路径 |
217
+ | **Grep agentic**(Claude Code) | "早期版本用了 RAG + 本地向量库,很快发现 **agentic search 更好**";"模型驱动的 glob 和 grep 打败了一切";GrepTool 默认只回文件名(控信息量)、`head_limit` 250 防淹没 | **每轮多轮 LLM 工具调用**(token 乘数)+ 语料是**精确 token 可匹配**的(代码/路径/标识符) | ⚠️ 可以做**补充臂**(最优档付得起多轮 token),但我们的语料是自然语言记忆,**没有可 grep 的字面**这一条对它同样成立 | ❌ 多轮即乘数;且自然语言记忆**没有可 grep 的字面** |
218
+
219
+ ### 7.3 两档的成本对照(**各自"谁付费"**)
220
+
221
+ | 路线 | 谁付费 | 最优档(首要用户) | 兼容档(第二目标) |
222
+ | --- | --- | --- | --- |
223
+ | 长上下文 / 全灌 | **贵侧(token)**:每轮 token ∝ 语料规模 | ⚠️ 语料增长 = 成本线性增长;即便最优档,注入预算(`injectBudgetChars` 默认 8000 字符,可配)也是硬约束 | ❌ 最不可取:语料增长即成本增长,而这一档正是 token 敏感 |
224
+ | Grep agentic | **贵侧(token)**:每轮多次 LLM 调用的乘数 | ⚠️ 可作补充臂;探索式检索的收益靠多轮 token 买 | ❌ 最贵的一档 |
225
+ | LLM Wiki | **贵侧(token)**:写入/维护侧 LLM token(查询侧读页也要) | ✅ 可上:整合质量换 token,我们已把写入模板化(自动沉淀 + 结构化日志) | ⚠️ 可用,但必须模板化写入;查询侧读页的 token 只能按需触发 |
226
+ | **本地检索(本仓主线)** | **设备侧(算力)**:一次性索引 + 每轮端侧嵌入,0 token | ✅ 主线;**允许在检索路径叠加 LLM 增强**(按 S9.2 带三件套),因为这是首要用户 | ✅ 唯一完全契合的一档:零额外 LLM token、弱设备可跑 |
227
+
228
+ **两条推出结论(按档读,不要拉平):**
229
+
230
+ 1. **本质规律不变**:把成本从**设备**挪到 **token**,就是"轻档付不起、重档可能付得起"。所以对兼容档这类改动**默认否决**(S9.1);对最优档则是**可选项,按 S9.2 三件套评估**。
231
+ 2. **RAG 没死,死的是两种东西**:① 把检索质量**外包给大模型**的 RAG(LLM 改写 / LLM 重排 / 多轮自省)—— 在**兼容档**它确实"死"了(付不起),在**最优档**它是**可选增强**;② **不分场景**的朴素 RAG。本地检索恰恰是唯一能"**用小模型换大模型 token**"的机制,这在兼容档最不该死,在最优档是**底座**(而不是上限)。
232
+
233
+ ### 7.4 我们的答案:吸收两条路线的优点,按档决定谁付哪部分成本
234
+
235
+ 1. **吸收 LLM Wiki 的"索引即自然语言"**:我们的 Tier-0 目录 + L0 摘要 = Karpathy 的 `index.md`(先读索引、再深入),而**不是**只有向量的黑盒块。层级 = sources(原文)/wiki(笔记、白板、每日日志,LLM 写)/schema(本规范 + 项目笔记)。
236
+ 2. **吸收 agentic 的"要不要搜由智能判断"**:**兼容档**把判断交给**本地线性分类器(fv2,0 token)**,即"零 token 的 agentic 检索";**最优档**允许在判断链上叠加更重的模型(按 S9.2 三件套),但**默认路径仍是 fv2**——因为它是两档共用接口的一部分(S9.3)。
237
+ 3. **按档分配成本**:兼容档拒绝"路径上调用 LLM"(S9.1);最优档不拒绝,但每一条重方案都要付清三件套(S9.2)。
238
+
239
+ ### 7.5 由此推出的工程约束(**已进 S9 与阶段 C**)
240
+
241
+ - 端侧嵌入必须**增量**(S1.3):这是**两档共同**的硬要求,但理由各一条 —— 兼容档:每写一条记忆就全量重嵌 → 弱设备上风扇、电耗、卡顿;最优档:索引永远追不上写节奏 → **静默丢弃注入**(后者在两档都会发生,只是重档机器跑得更快、更晚崩)。
242
+ - 查询侧加工(S2)按档实现:**兼容档必须本地实现**(规则:去指示词、抽实体 + 本仓术语表 + 端侧小模型),**不许**调大模型;**最优档可以引入 LLM 改写/精排**,但按 S9.2 补齐成本 + 门控 + 降级路径,且降级后要退回 S9.1 那条本地路径。
243
+ - **绝不把"只能跑通兼容档"当目标形态**(S9.4):阶段 C 的施工顺序(S1.3 → S5.3 → S2 → S4)是**风险/收益排序**,不是"只做轻档也能做的那些";其中 S4 精排的 cross-encoder 档就是为最优档准备的重方案。
244
+
245
+ ---
246
+
247
+ ## 8. wiki 层(白板)与「记忆涌现」—— 与 Karpathy LLM Wiki 的对应
248
+
249
+ ### 8.1 三条路线的位置(用标准词汇说清我们是什么)
250
+
251
+ | 路线 | 触发方式 | 谁决定"要看什么" | 成本落点 |
252
+ | --- | --- | --- | --- |
253
+ | Karpathy · LLM Wiki | **pull**:LLM 先读 `index.md`,再决定深入哪页 | LLM | 查询侧 token |
254
+ | Claude Code · grep | **pull + 多轮**:LLM 决定搜什么、要不要继续搜 | LLM | 每轮多次 token |
255
+ | **本仓** | **push 主 + pull 辅**:监控 CoT/输入/输出 → 注入 reference;语义端 RAG 供模型主动搜 | **本地 LR(fv2)** | **设备算力** |
256
+
257
+ **"记忆涌现"就是 push。** 两条既有路线**只有 pull**,而 pull 有一个共性的硬伤:**它依赖模型自己意识到"我该去查了"** —— 查不到的东西,模型不知道自己不知道。push 把这个环节从模型手里拿掉,代价是**误注入风险**(见 8.2)。
258
+
259
+ ### 8.2 push 的三条防线(没有观测的涌现 = 幻觉注入)
260
+
261
+ 1. **决策门**:intent LR + 融合 margin + echo veto(禁复述用户刚说的话)+ 硬门(有害/纠正/过期/越界)+ 冷却。**默认路径全部零 token**(S9.1;这是两档共用的默认决策路径,最优档若要叠加 LLM 判断按 S9.2 付三件套)。
262
+ 2. **可观测**:每次涌现必须能回答"哪条、多像(0-1)、为什么、来自哪个引擎"(S8.1;相似度与排名 = C7 已落)。
263
+ 3. **触发源分级**:监控 **CoT** 信息价值最高(模型自己在想什么),但**自我强化风险也最高**;user / tool / assistant 段风险更低。→ **待验证约束**:CoT 段应比其它段用**更严阈值 + 更长冷却**,且需用 S7 实验证明"CoT 触发带来的收益 > 噪声成本",否则不得放宽。
264
+
265
+ ### 8.3 白板 = wiki 层的落地契约(不建状态机,只在写入一个门设防)
266
+
267
+ 对应 Karpathy 的三层与其两个特殊文件:
268
+
269
+ | LLM Wiki 构件 | 本仓对应物 | 状态 |
270
+ | --- | --- | --- |
271
+ | 原始资料(不可变) | 会话记录、外部文档 | ✅ |
272
+ | **Wiki(LLM 拥有)** | 项目笔记 / 白板 PLAN / handoff 账本 / 每日日志 | ✅ 文件已存在 |
273
+ | **Schema** | 本规范 + `THREE-LAYER-CONTRACT.md` + 白板判据约定 | ✅ 文件化(比 Karpathy 更强:有编号与判据) |
274
+ | `index.md`(先读索引再深入) | **Tier-0 目录**(白板是它的可视化视图) | ⏳ C4 已出生成器,C5 待接线 |
275
+ | `log.md`(append-only 前缀可 grep) | 每日日志(`[YYYY-MM-DD] …` + `seq` 纪律) | ✅ |
276
+ | 操作:摄入 / 查询 / **整理(lint)** | 摄入 ✅ / 查询 ✅ / **lint ❌ 缺** | 见 S10.3 |
277
+
278
+ **S10 wiki 层契约(MUST)**
279
+
280
+ - **S10.1 页面即语料**:白板页面/卡片必须带锚点 `<!-- memory:mem_<32hex> -->`(与 L0 抽取同格式)→ **白板内容自动进检索语料**,无需新机制。这条同时解掉"双状态源":白板是**现在时视图**,但它以锚点身份**注册进记忆索引**。
281
+ - **S10.2 索引自动生成,不许手抄**:`index`(Tier-0 目录)由页面**派生**(每条 = 链接 + 一句话 + `layer`/`status`),与白板不得各写一份。
282
+ - **S10.3 lint(整理)必须补上,且尽量零 token**:可零 token 判定的四类 —— ①**孤立条目**(无入站引用/无交叉引用)②**陈旧**(有 `superseded`/`retracted` 标记,或日期超阈)③**被提及却无独立页**的重要概念 ④**缺交叉引用**。**只有"矛盾检测"需要 LLM,必须按需触发(用户点一下),不得进自动路径**(S9.1:兼容档硬要求;最优档若要让它自动跑,按 S9.2 带成本 + 门控 + 降级路径)。
283
+ - **S10.4 不建状态机**(沿用既有拍板):白板是视图层,状态归**记忆条目**(`layer`+`status` 三值)与 sidecar;lint 只做**只读检查 + 留痕**,不新增状态。
284
+ - **S10.5 答案归档回流**(补上"复利"回路):一次检索/分析的结论要能**一键存成白板页面或记忆条目**(现有 `memory_note_pre` / handoff 即为通道);否则知识只在对话里蒸发 —— 这是 Karpathy 方案最核心的收益点,也是我们目前**半闭环**的地方。
285
+ - **S10.6 人机分区**(B4 的工程解法):沿用「模型维护区 / 用户备注区」;Karpathy 的原话是"你(几乎)从不亲自编写 wiki",但他把**原始资料与提问**留给人 —— 与我们 B4 的分区方向一致,外部实践支持此判断。
286
+
287
+ ---
288
+
289
+ ## 附录 · 外部依据
290
+
291
+ ### 附录 A · 视频实际覆盖内容(**已用接口核验**,2026-09-14)
292
+
293
+ 用户指定:《7 分钟了解 10 种 RAG 策略》(B 站 [BV17J3B6PEGK](https://www.bilibili.com/video/BV17J3B6PEGK),UP「Hucci写代码」,时长 451s,aid 116997224472457 / cid 40376927592)。
294
+ **注意口径**:标题里的 **7 是分钟数,策略是 10 种**(章节「RAG 十个策略总览」自证)。
295
+
296
+ `x/player/v2` 返回的 10 段章节要点(= 视频的权威骨架):
297
+
298
+ | # | 章节 | 时间段 |
299
+ | --- | --- | --- |
300
+ | 1 | 引入 RAG 的必要性 | 0:00–0:30 |
301
+ | 2 | RAG 流程概览 | 0:30–1:06 |
302
+ | 3 | **RAG 十个策略总览** | 1:06–1:47 |
303
+ | 4 | **分块策略** | 1:47–2:42 |
304
+ | 5 | **嵌入与索引策略** | 2:42–3:48 |
305
+ | 6 | **查询处理策略** | 3:48–4:21 |
306
+ | 7 | **检索策略** | 4:21–5:03 |
307
+ | 8 | **迭代式 RAG** | 5:03–5:56 |
308
+ | 9 | **自适应路由** | 5:56–6:56 |
309
+ | 10 | 总结与建议 | 6:56–7:31 |
310
+
311
+ **核验边界(不许越界引用)**:字幕列表为空(`subtitle.allow_submit=false`),AI 摘要接口 `x/web-interface/view/conclusion/get` 返回 `-403/-101 账号未登录`,网页端 `-412`。
312
+ → **能核验到"章/组"级,核验不到"条目"级。** 本规范 §2 与本文档其他处对"10 种"的逐条命名属**通用 advanced-RAG 谱系推断**,不得当作该视频的原话引用;需要条目级时,取用户提供的 AI 摘要文本或字幕。
313
+
314
+ ### 附录 B · 我们的条款 ↔ 视频章节(组级对应,可核验)
315
+
316
+ | 视频章节 | 本规范条款 | 我方状态 |
317
+ | --- | --- | --- |
318
+ | 4 分块策略 | S1.1 块 ID 稳定 | 部分(已内容寻址,未进缓存键) |
319
+ | 5 嵌入与索引策略 | S1.2 缓存键含引擎身份 / S1.3 增量 | **缺**(草台根因) |
320
+ | 6 查询处理策略 | S2 改写 / 多查询 / HyDE | **全缺** |
321
+ | 7 检索策略 | S3 混合臂 + 融合、S4 精排 | S3 ✅ / S4 缺 |
322
+ | 8 迭代式 RAG | (**刻意不采纳**,见 §4 结论) | — |
323
+ | 9 自适应路由 | S6 决策 + S5 注入 | ✅ 本仓领先项 |
324
+
325
+ **结论一句话**:我们**最贴近"层次化索引 + 自适应路由"**(视频偏后的高级两章),草台处集中在**上游的分块/嵌入与索引两章**,而非策略选型错误。
326
+
327
+ ### 附录 C · 通用 advanced-RAG 谱系(推断用,非视频原话)
328
+
329
+ - 技术谱系(advanced RAG 技术清单与调优方法):[RAG_Techniques(含 notebook 教程)](https://github.com/hannancheng/RAG_Techniques)、[LlamaIndex 检索调优实战:分块、HyDE、压缩等提效方法](https://developer.aliyun.com/article/1685009)、[Advanced RAG techniques summary](https://github.com/maple3788/RAG_Lab/blob/7516654dbe0c16d110fad95e3de7000b3861e14e/docs/knowledge/advanced-rag-techniques-summary.md)、[关于 RAG 你不得不了解的 17 个技巧](https://cloud.tencent.cn/developer/article/2485763)。
330
+
331
+ ### 附录 D · 本仓内部依据
332
+ - `THREE-LAYER-CONTRACT.md`(接口/预算/不变式 I1–I7、C1–C7)、`MEMORY-MUTATION-AND-INDEX-DESIGN.md`(supersede 与块级缓存)、`ROADMAP.md`(六步链路)、`TODO-GRAPH.html`(排期与阶段门,P1-⑨)。
333
+
334
+ ### 附录 E · 核验用接口(可复现)
335
+
336
+ | 接口 | 结果 |
337
+ | --- | --- |
338
+ | `api.bilibili.com/x/web-interface/view?bvid=` | ✅ 标题/简介/时长/cid/up_mid |
339
+ | `api.bilibili.com/x/player/v2?bvid=&cid=` | ✅ `view_points` = 10 段章节要点(本文档附录 A 来源) |
340
+ | `api.bilibili.com/x/web-interface/view/conclusion/get`(需 wbi 签名 + 登录) | ❌ `-101 账号未登录`(签名算法已本地实现,卡在鉴权) |
341
+ | 网页 `bilibili.com/video/BV...` | ❌ 验证码页 / `-412 request was banned` |
342
+ | 字幕(`player/v2` 的 `subtitle.subtitles`) | ❌ 空列表(UP 未开 CC) |
343
+
344
+ **可复用结论**:无登录凭据时,B 站内容最高只能核验到**章节/结构级**;要条目级需用户提供 AI 摘要文本或字幕,或由用户授权登录态。
345
+
346
+ ### 附录 F · 「RAG 已死」两条替代路线的核验事实(2026-09-14)
347
+
348
+ **① Karpathy · LLM Wiki**([RAG已死!karpathy说:LLM Wiki永生](https://gitcode.csdn.net/69d4e95d0a2f6a37c59d9532.html))
349
+ - 病灶诊断:传统 RAG(NotebookLM / ChatGPT 文件上传)**没有知识积累** —— "LLM 每次回答问题都要从零开始重新发现知识"。
350
+ - 方案:让 LLM **渐进式构建并维护持久 wiki**(markdown 集合),新资料到达时**整合进已有页面**(更新实体页、修订主题摘要、标注与旧说法矛盾处),"编译一次、保持最新"。
351
+ - 三层架构:**原始资料(不可变)/Wiki(LLM 拥有)/Schema**(如 `CLAUDE.md`、`AGENTS.md`,定义结构与工作流)。
352
+ - 操作:摄入 / 查询(**先读 `index.md` 定位,再深入**)/ 整理(lint:矛盾、陈旧、孤立页、缺失交叉引用)。
353
+ - **关键句(决定我们能否沿用)**:在适度规模(约 **100 份资料、数百个页面**)下,靠 `index.md` 导航"**出奇地有效,避免了基于嵌入的 RAG 基础设施的需求**"。
354
+ - → 对我们的意义:**我们的 Tier-0 目录 + 三层,本质就是它在设备端的轻量实现**;差别是我们把"维护"模板化(自动沉淀),而不是让 LLM 自由重写(省 token、可审计)。
355
+
356
+ **② Claude Code · Grep agentic**([别再迷信RAG了!Grep回归](https://dbaplus.cn/news-141-7303-1.html))
357
+ - Boris Cherny:「早期版本的 Claude Code 使用了 RAG + 本地向量数据库,但我们很快发现 **agentic search 通常效果更好**」;「**Plain glob and grep, driven by the model, beat everything**」。
358
+ - 实现:LLM 驱动的多轮 `grep/glob/read` 循环(无硬编码流程);**GrepTool 默认只返回文件名**(故意控制信息量,避免一次 grep 淹没 context)、`head_limit` 默认 250;子 agent(Explore)做 **context 隔离**,只把结论回传主对话。
359
+ - 代价明账:**每轮的多次 LLM 工具调用**;Boris 也承认放弃 RAG 的决策**部分基于直觉**。
360
+ - → 对我们的意义:**语料性质不同** —— grep 吃"精确字面"(代码、路径、标识符),记忆是自然语言,用户往往说不出确切字面(例:他的"你上一轮并没有正常地纠错")。我们取其"**要不要搜由智能判断**"的思路,但判断交给本地 LR,不引入多轮 token。
@@ -0,0 +1,90 @@
1
+ # 会话文件可读性缺陷 · 分类与修复协议
2
+
3
+ - 建立:2026-09-14
4
+ - 触发:开启宿主会话内容检索(`session-query-sqlite`,`openAt: first-search`)后,索引器 fail-closed,51/191 个会话文件读不出来 → 检索形同未开。
5
+ - 结论先行:**51 个全部可救,但要分四组对症下药;"删行"这条路本身是错的(见 §2 硬规则 R2)**——ZCode 已修的 3 个会话正因此在我的读取路径下仍不可读。
6
+ - 本文件是执行手册:批准后按 §3 分组施工、按 §4 校验、按 §5 禁则避坑。
7
+
8
+ ## 1 五十一 个的真实构成(2026-09-14 实测,精确口径)
9
+
10
+ | 组 | 文件数 | 报错原文 | 病灶 | 来源 |
11
+ |---|---|---|---|---|
12
+ | 甲 | 39 | `subagent/descriptor 0 uses unsupported descriptor version 2` | `subagent/descriptor` 的 `version` 声明为 2,冻结清单只收 v3 | 宿主 08-15~08-23 自己写的 |
13
+ | 乙 | 7 | `permission/preset 75436 data has unexpected member "origin"` | `permission/preset` 事件的 `data.origin`(值 `"selection"`)不在冻结成员表 | 宿主 08-22~08-24 自己写的 |
14
+ | 丙 | 3 | `released v2 row N has seq gap (expected N, got N+k)` | **ZCode 删重复事件**留下的 seq 缺口(删 6 / 4 / 2 条) | 2026-09-14 ZCode 修复引入 |
15
+ | 丁 | 1 | `assistant/message 190486 message content[0] name must be a non-empty string` | 模型吐了一个空名工具调用,宿主原样写盘(同一轮 `tool/result` 记录 `ToolNotFoundError / UNKNOWN_TOOL`) | 宿主 08-24 自己写的 |
16
+ | 丁 | 1 | `cannot safely transform unclassified message source` | `user/message` 的 `source.kind = "anchored-monitor"`(2 处,锚定监控插件的干预提示注入) | 锚定监控插件写的 |
17
+
18
+ 合计 39 + 7 + 3 + 1 + 1 = 51。
19
+
20
+ **与被检对象无关的事实**:丁组两个文件**不是 ZCode 改的**——ZCode 自己的记忆(`~/.zcode/cli/memories/projects/dsh-auto-memory-…/memory/dsh-session-corruption-repair.md`)逐字写明它只实修了 3 个会话(`1ef5cee8` 删 6 条 / `a82b8e44` 删 4 条 / `9cc01f76` 删 2 条)= 本表丙组;且只有这 3 个目录里留有备份 `session.v3.jsonl.{broken,dup}-backup-*.zstd`(时间戳 2026-09-14 01:20–01:38)。丁组两个目录**无任何备份文件**,主文件 mtime 停在 `2026-08-20 00:44` / `2026-08-24 15:35`(原始写盘时间,未被触碰)。宿主全局包 `%APPDATA%\npm\node_modules\@deepseek-ai` 下 09-13 之后被修改的 `.js` **为 0 个** → 无静默打补丁。
21
+
22
+ ## 2 硬规则(修复前必须内化,全部来自宿主源码实测)
23
+
24
+ - **R1 写读不对称**:写入侧对 `source.kind`、`name` 等字段**不做白名单校验**,读取/迁移侧**严格校验**。所以"宿主能写出来的,宿主自己可能读不回来"——丁组两例都是这个不对称的产物。
25
+ - **R2 `seq` 必须严格连续**:`dsh-session-format-v1-to-v2/lib/index.js:244` 判定 `event.seq !== eventCount` 即抛 `released v2 row N has seq gap (expected N, got N+k)`。`eventCount` 是**行序号**,所以**删掉任何一行都会让该文件永久不可读**(v0 原始行的 seq 不受此约束,此约束针对"已发布 v2 形态"的行——v3 文件同样要过这一关)。
26
+ - **R3 一帧一行**:追加式多帧 zstd,**第一帧必须恰好只有 session 头一行**。违反 → 官方 `assertZstdHeaderFrame` 在启动扫描(`WorkspaceRegistry.listStoredHeaders`)时报 `corrupt Zstandard session log`,**整个 dsh web 起不来**(ZCode v1 踩过,本次施工必须复用其教训)。
27
+ - **R4 `source.kind` 白名单共 15 项**(`dsh-session-format-v2-to-v3/lib/index.js:14-30`):`user / plugin / model / tool / agent-instructions / session-reference / team-message / goal / skill-invocation / skill-catalog / coordinator / subagent-report / subagent-settled / webhook / agent-message`。
28
+ - **在白名单内的**(实测,别再误判):`goal`、`coordinator`、`skill-catalog`、`subagent-report`、`subagent-settled`。
29
+ - **不在白名单内**:`anchored-monitor`、`fallback`、`provider`——但 `fallback`/`provider` 只出现在**不做 source 校验的事件类型**上(如 `session/end-seed`、`request/context`),全库 191 个文件里**真正会被拦下的只有 1 个文件、2 处**(`anchored-monitor`)。
30
+ - **R5 校验只发生在 5 类事件**(同文件 `:98-108`):`user/message`(看 `data.source`)、`assistant/message` 与 `tool/result`(看 `data.message.source`)、`agent/inbox/spliced`(看 `data.inserted[].source`)、`session/title-llm-request`(看 `data.messages[].source`)。其余事件的 `source` 不受约束——排查时不要扩大口径。
31
+ - **R6 `sourceEventSeqs` 引用会随 seq 重编号失效**:丙组 3 个文件分别含 5 / 199 / 3 处带 `sourceEventSeqs` 的事件(类型 `tool/result`、`system/message`)。**重编号 seq 必须同步重映射这些引用**,否则会造出指向错位的新语义错误。
32
+
33
+ ## 3 分组处方
34
+
35
+ - **甲组(39)**:`subagent/descriptor` 的 `version: 2 → 3`。声明式升级,不改语义、不动 seq。已在副本上验证通过(39/39)。
36
+ - **乙组(7)**:删除 `permission/preset` 事件 `data` 内的 `origin` 成员(值为 `"selection"`)。不动 seq、不动行数。已在副本上验证通过(7/7)。
37
+ - **丙组(3)**:**不要再用删行的方式**。两条路线,择一:
38
+ - 路线 P(推荐):从同目录 `*.dup-backup-*.zstd` / `*.broken-backup-*.zstd` **恢复原始行**,再按"语义去重 + 全量重编号 + `sourceEventSeqs` 重映射"重写;
39
+ - 路线 Q(省事):在当前(已去重的)文件上**只做连续化**:把每行 `seq` 重写为行序号 1..N,并用同一映射改写所有 `sourceEventSeqs` 数组。
40
+ - 两条路线都必须同时满足 R2 + R3 + R6。
41
+ - **丁组-空工具名(1)**:把 `assistant/message.content[0].name` 与配对 `tool/call.data.name` 的空串填为占位名(建议 `"(unnamed)"`,与同轮 `ToolNotFoundError / UNKNOWN_TOOL` 的既有语义自洽)。**只改这一处 2 个字段**;不要删这一对事件(删了就撞 R2)。
42
+ - **丁组-未登记 kind(1)**:`source.kind: "anchored-monitor" → "plugin"`,保留同对象的 `form: "hint"`。`assertSource` 只对 `kind === "agent-message"` 做成员白名单校验,其余 kind 允许附加成员,因此改 kind 值即可,无需增删字段。
43
+ - **治本(防复发)**:锚定监控插件的干预注入改用白名单 kind(`"plugin"`,`form: "hint"`)。否则**每一次 L1/L2 干预都会让那个会话日后变成不可迁移/不可索引的文件**——这才是"检索越用越容易死"的机制性来源。
44
+ - **上游可报**:①写读不对称(写入接受空 `name`、任意 `kind`,读取 fail-closed 拒绝);②`subagent/descriptor` 冻结清单只收 v3、`permission/preset` 成员表与宿主自己的写入侧不一致;③索引器 fail-closed 应对畸形文件"跳过 + 计数 + 报告",而不是整体不可用(LightRAG 的反例已记在 `CROSS-SESSION-SEARCH-RESEARCH.md`)。
45
+
46
+ ## 4 施工流程(每个文件独立走完,任一步失败即跳过并计数)
47
+
48
+ 1. 同目录备份:`session.<ver>.jsonl.<原因>-backup-<ts>.zstd`(沿用 ZCode 命名,便于人眼识别)。
49
+ 2. 解码 → 按 §3 分组施改 → **逐行压缩**(一帧 = 一行 + 换行)拼接写回。
50
+ 3. 写前模拟官方校验路径:①首帧恰好一行且 `type === "session"` ②`seq` 与行序号严格一致 ③`call` / `result` 配对平衡 ④`sourceEventSeqs` 无悬挂引用 ⑤无非法 `source.kind` ⑥无空 `name`。
51
+ 4. 用真实读取路径复测该文件(`createRestore` + `recovery: 'strict'`)→ 必须成功。
52
+ 5. 全库复测:191 个文件全部通过 → **用户重启 dsh web**(内存里持着脏事件流与索引)。
53
+ 6. 重启后观察 `session-query.db` 是否建索引、检索是否返回 `[记忆检索|sessions]` 块。
54
+
55
+ ## 5 禁则
56
+
57
+ - **禁删行**(R2)。含"把重复事件删掉"这类在别的系统里正确的做法。
58
+ - **禁批量修 27 个"跨 turn 复用同一 tool_call_id"的老会话**——它们相隔数万条、一直正常跑,批量"去重"会误删正常历史(ZCode 已明确警告,本次复核同意)。
59
+ - **禁一次修完不留副本**。丙组正是"改了但没留可对照的原始行"的反面教材(备份是 ZCode 自己额外留的,属运气好)。
60
+ - **禁在未做 §4③ 校验的情况下写盘**(R3:不重启发现不了,一旦违反宿主直接起不来)。
61
+ - **禁把本协议用于语义内容的改写**:只改坐标/声明类字段(`seq`、`version`、成员表、`kind` 登记值、空 `name` 占位),不改任何消息正文。
62
+
63
+ ## 附录 A 施工口径的通俗说明(拍板用,一页纸)
64
+
65
+ **共同前提**:现在宿主开了会话内容检索,但它一遇到读不懂的文件就**整库罢工**(fail-closed),所以 51 个坏文件在 = 检索等于没开。下面四件事可任选组合,但至少要有一件,检索才会活。
66
+
67
+ | 口径 | 一句话 | 具体动什么 | 得到什么 | 代价 |
68
+ |---|---|---|---|---|
69
+ | **C 就地修复** | 把 51 个文件"治好",让宿主自己读得回来 | 用 Node 脚本改每个文件里的 1~2 个坐标类字段,**每个文件先备份**,写回保持"一帧一行" | 51 段历史回到宿主正规坐标系:能在会话列表看到、能被检索、能被插件 `scope='sessions'` 搜到 | 动到历史文件(有备份可整体还原);丙组 3 个要做 seq 重编号,风险最高的一步 |
70
+ | **B 索引器打补丁** | 让索引器"遇到读不懂的就跳过并记账",别整体罢工 | 改宿主包 `dsh-session-query-sqlite` 里那处 fail-closed 逻辑(先备份,留一个可重打的脚本) | 检索立刻可用,且以后宿主再写出畸形会话也不会一票压死全库 | 改的是 `node_modules` 里的宿主代码:**dsh 升级会被覆盖**,需要重打;属于本地补丁,非官方 |
71
+ | **A 隔离** | 把 51 个文件"搬出去",宿主看不见就不会罢工 | 移动到 `~/.dsh/sessions-quarantine/`(文件内容一个字不改) | 最保守、可秒级回退、检索可用 | 那 51 段历史**连会话列表里都消失**(不只是搜不到);22.6MB 那个最长的会话一起缺席 |
72
+ | **D 导出留档** | 先转成 Markdown 存一份,再隔离 | 解码 → 生成可读文本进插件自己的 memory 目录 | 内容仍可被插件的词法+语义检索搜到 | 脱离宿主的工具调用结构;且这是"另存一份",不是修好原件 |
73
+ | **E 只上报** | 本机不动,等官方修 | 写三份上游报告(issues 已关,只能发 discussion,需你浏览器粘贴) | 无本地风险 | 期间会话检索一直不可用;且上游何时修不可控 |
74
+
75
+ **推荐 = C + B**:C 让历史回到可检索状态(治标且是唯一能"救回历史"的路),B 做保险(因为宿主会继续写出同类畸形会话——写读不对称还没修)。若你只想要"今天就恢复",**只 B 是最快最保守**;若你只关心"别弄坏东西",**只 A 最安全**。三者不互斥:可以先 A 让检索立刻可用,改天再逐组做 C。
76
+
77
+ **施工纪律(无论选哪个)**:每个文件独立走完并留备份;写盘前跑启动级契约校验(首帧恰好一行);全库复测通过后**由你重启 dsh web**(这一步绝不代做)。
78
+
79
+ ### 附录 B 丁组那 2 个文件的问题,是什么意思
80
+
81
+ 丁组 = 只有 2 个文件需要**改字段值**(其余 49 个只动声明/成员表,不碰语义字段):
82
+
83
+ - `session-cc245cf1-…`(22.6MB,最长的一个):里面有 **1 处空工具名**——当时模型吐了一个没有名字的工具调用,宿主照原样存了(同一轮的返回记为 `ToolNotFoundError / UNKNOWN_TOOL`,即"调了个不存在的工具")。宿主的读取器现在拒绝空名字。修法二选一:①把那个空名字填成占位符 `"(unnamed)"`(与"未知工具"的既有语义自洽,只改 1 个字段的 2 个位置);②不修,把它划归 A 组隔离掉。
84
+ - `session-fc931245-…`(13.6MB):里面有 **2 处** `source.kind = "anchored-monitor"`——是**锚定监控插件**注入干预提示时写下的标记,宿主白名单不认这个值。修法二选一:①把 `"anchored-monitor"` 改成白名单里的 `"plugin"`(同时保留它已有的 `form:"hint"`,语义不丢);②不修,隔离。
85
+
86
+ **为什么要专门问你**:我们之前立过一条规矩——**历史只能"标记+追加",不能就地改写**。①就属于"就地改写",虽然是坐标类字段、虽然消息正文一个字不动、虽然有备份可整体还原,但它确实动了历史。所以这一步需要你点头;你若不同意,丁组这 2 个(都是最长的会话)退出检索即可。
87
+
88
+ **治本项与它们同源**:只要锚定监控继续用 `anchored-monitor` 这个 kind 注入,**每次干预都会再产出一个日后不可索引的会话**——所以推荐顺手把它改成 `"plugin"`(这是改插件的未来行为,不改历史)。
89
+
90
+ 两者**正交,都要做,但顺序不能反**:ZCode 解决的是"会话活不过来"(重复 `tool_call_id` → 每次发消息都 400 + UI 卡加载);本协议解决的是"会话活过来了但读不回来"(不可迁移 → 不可索引 → 检索死)。ZCode 的 3 个副本文件的**可读性**需要按丙组补做,其"备份优先"与"一帧一行"两条经验必须继承。