@a9i5k4/dsh-auto-memory 2.5.3 → 3.0.1
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.
- package/README.md +189 -7
- package/README.zh-CN.md +189 -7
- package/docs/CONTRIBUTORS.html +471 -0
- package/docs/FRONTEND-CO-CREATION.md +191 -0
- package/docs/GM53-HOMEPAGE-PROMPT.md +323 -0
- package/docs/HANDOFF-CRITERIA.md +92 -0
- package/docs/HOMEPAGE-CONTENT-FOR-GM53.md +299 -0
- package/docs/INTEGRATION-ANALYSIS.md +350 -348
- package/docs/PROMO-PROMPT-3.0.md +100 -0
- package/docs/USER-GUIDE.en.md +58 -3
- package/docs/USER-GUIDE.zh-CN.md +59 -4
- package/docs/WHITEPAPER.md +207 -0
- package/docs/internal/ACCEPT-35-LIVE.md +143 -0
- package/docs/internal/ACCEPTANCE-20260914.md +90 -0
- package/docs/internal/ARCH-REVIEW-BRIEF.md +411 -0
- package/docs/internal/ARCH-REVIEW-REQUEST.md +201 -0
- package/docs/internal/ARCH-REVIEW-ROUND2.md +169 -0
- package/docs/internal/ARCH-REVIEW-ROUND3.md +206 -0
- package/docs/internal/ARCHITECTURE-FOR-ZCODE-20260920.md +397 -0
- package/docs/internal/ART-DIRECTION-DEEPSEEK-20260920.md +351 -0
- package/docs/internal/ART-DIRECTION-WIREFRAME.md +191 -181
- package/docs/internal/ART-DIRECTION-WIREFRAME.md.bak-superseded +181 -0
- package/docs/internal/AUDIT-WB-GRAPH-FULL-20260916.md +314 -0
- package/docs/internal/BATTLE-PLAN-20260917.md +871 -0
- package/docs/internal/CONCURRENCY-INVESTIGATION-20260917.md +192 -0
- package/docs/internal/CROSS-SESSION-SEARCH-PATH-DECISION.md +72 -0
- package/docs/internal/CROSS-SESSION-SEARCH-RESEARCH.md +131 -0
- package/docs/internal/DECISIONS-20260914-SESSION.md +269 -0
- package/docs/internal/DESIGN-P1-STATE-COMMIT-20260915.md +219 -0
- package/docs/internal/DIRECTION-CHECK-WB-GRAPH-20260916.md +132 -0
- package/docs/internal/FEATURE-INVENTORY.md +531 -0
- package/docs/internal/FEEDBACK-TO-DSHAPI-RELAY.md +13 -0
- package/docs/internal/G-SERIES-EXECUTION-20260917.md +248 -0
- package/docs/internal/G3-DESIGN-20260918.md +82 -0
- package/docs/internal/G3-DISK-FORMAT-GAP-20260919.md +92 -0
- package/docs/internal/GH-DISCUSSION-5732-COMMENT.md +74 -0
- package/docs/internal/GPT-ACCEPTANCE-PROMPT-20260916.md +352 -0
- package/docs/internal/GPT-REVIEW-PROMPT.md +216 -0
- package/docs/internal/GROUP-WEBHOOK-SETUP.md +33 -0
- package/docs/internal/HANDOFF-TO-ZCODE-20260920.md +309 -0
- package/docs/internal/HERMES-DATA-VERIFICATION-20260919.md +120 -0
- package/docs/internal/HERMES-LEGACY-STATUS-20260919.md +74 -0
- package/docs/internal/ISSUE-55-58-VERIFICATION-20260918.md +175 -0
- package/docs/internal/ISSUE10-FIX-EXECUTION-20260919.md +389 -0
- package/docs/internal/ISSUE10-PLAN-20260919.md +254 -0
- package/docs/internal/ISSUE10B-FORENSICS-20260919.md +468 -0
- package/docs/internal/ISSUE9-PURGE-AND-R1-PLAIN-20260919.md +150 -0
- package/docs/internal/ISSUE9-RESIDUAL-FORENSICS-20260919.md +114 -0
- package/docs/internal/KICKOFF-P0.md +254 -0
- package/docs/internal/LESSON-TO-CANDIDATE-STATUS-20260919.md +79 -0
- package/docs/internal/MASTER-PLAN-3.0.md +411 -0
- package/docs/internal/MEMORY-GOVERNANCE-20260917.md +309 -0
- package/docs/internal/MEMORY-MUTATION-AND-INDEX-DESIGN.md +85 -0
- package/docs/internal/MERGE-CONFLICT-SCAN-20260914.md +222 -0
- package/docs/internal/PENDING-FIXES-20260916.md +289 -0
- package/docs/internal/PRE-FRONTEND-CHECKLIST-20260919.md +705 -0
- package/docs/internal/PRE-FRONTEND-CHECKLIST-20260919.md.bak-s10 +649 -0
- package/docs/internal/PROCEDURAL-MEMORY-AND-APPROVAL-DESIGN-20260918.md +225 -0
- package/docs/internal/PROGRESS-20260917.md +93 -0
- package/docs/internal/PROMPT-GAP-AUDIT-20260920.md +128 -0
- package/docs/internal/R1-DEGRADE-AUDIT-20260918.md +163 -0
- package/docs/internal/R1-READABILITY-FORENSICS-20260919.md +127 -0
- package/docs/internal/R2-EVIDENCE-DEEP-AUDIT-20260918.md +140 -0
- package/docs/internal/R3-DEGRADE-LEDGER-DESIGN-20260918.md +138 -0
- package/docs/internal/R4-RECALL-QUOTA-PLAN-20260918.md +218 -0
- package/docs/internal/RAG-KARPATHY-PROGRAM.md +229 -0
- package/docs/internal/REPORT-P0-NIGHTLY.md +212 -0
- package/docs/internal/REPORT-P5-ACCEPTANCE.md +31 -0
- package/docs/internal/REPORT-WB-GRAPH-NIGHTLY.md +153 -0
- package/docs/internal/RESUME-20260918.md +171 -0
- package/docs/internal/RESUME-20260919.md +104 -0
- package/docs/internal/REVIEW-WB-GRAPH-SELF.md +81 -0
- package/docs/internal/RHINELAB-TO-DEEPSEEK-FEASIBILITY.md +198 -0
- package/docs/internal/ROADMAP-20260917-WEEK.md +439 -0
- package/docs/internal/ROADMAP.md +106 -0
- package/docs/internal/RUN-P0-NIGHTLY.md +227 -0
- package/docs/internal/S10-CONSTRUCTION-HANDOFF-20260917.md +185 -0
- package/docs/internal/S10-GAP-INVENTORY-20260917.md +239 -0
- package/docs/internal/S10-GAPS-PLAIN-20260917.md +125 -0
- package/docs/internal/SEMANTIC-ARCHITECTURE-SPEC.md +360 -0
- package/docs/internal/SESSION-FILE-REPAIR-PROTOCOL.md +90 -0
- package/docs/internal/T6-EXECUTION-20260920.md +130 -0
- package/docs/internal/TELEMETRY-EFFECT-REPORT-DESIGN-20260918.md +146 -0
- package/docs/internal/THESIS-GAP-ANALYSIS-20260918.md +89 -0
- package/docs/internal/THESIS-OUTLINE-20260918.md +147 -0
- package/docs/internal/THREE-LAYER-CONTRACT.md +219 -0
- package/docs/internal/TODO-BACKLOG.md +263 -142
- package/docs/internal/TODO-GRAPH.html +715 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260914-v2 +493 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-alsfix +710 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-p1 +710 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-p6a-rev +703 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260915-wshint +710 -0
- package/docs/internal/TODO-GRAPH.html.bak-20260916-batch +715 -0
- package/docs/internal/UPSTREAM-ISSUE-PR-TRIAGE-20260919.md +297 -0
- package/docs/internal/UPSTREAM-ISSUES-3RD-AUDIT-20260920.md +104 -0
- package/docs/internal/WB-FORMAT-CONVENTION.md +112 -0
- package/docs/internal/WB-GRAPH-DECISIONS-20260914.md +71 -0
- package/docs/internal/reviews/CLAIM-VERIFICATION-20260914.md +56 -0
- package/docs/internal/reviews/PLAN-gpt6astra-round2-20260914.md +787 -0
- package/docs/internal/reviews/REVIEW-gpt6astra-20260914.md +112 -0
- package/docs/internal/reviews/ROUND3-REVIEW-INTEGRATION-20260914.md +230 -0
- package/docs/prompts/M8-3-enable-verify.md +49 -49
- package/docs/screenshots/promo/promo-0-banner-v3.png +0 -0
- package/lib/acceptance.js +71 -0
- package/lib/activation-host.js +153 -18
- package/lib/activation-inbox.js +25 -7
- package/lib/board-mode.js +30 -0
- package/lib/client.js +1758 -90
- package/lib/config-io.js +156 -0
- package/lib/context-bridge.js +5 -2
- package/lib/context-host.js +86 -15
- package/lib/degrade.js +385 -0
- package/lib/dsh-home.js +143 -0
- package/lib/engine-identity.js +149 -0
- package/lib/engine-switch.js +247 -0
- package/lib/episodic-store.js +63 -12
- package/lib/evidence-store.js +10 -3
- package/lib/fact-store.js +22 -3
- package/lib/fs-retry.js +46 -0
- package/lib/index-sync.js +13 -1
- package/lib/index.js +3446 -263
- package/lib/intent-clean-safe.js +258 -0
- package/lib/intent-clean.js +12 -16
- package/lib/l0-extract.js +478 -149
- package/lib/l0-index-sync.js +195 -0
- package/lib/l0-index.js +349 -239
- package/lib/ledger-criteria.js +142 -0
- package/lib/m4-corpus.js +8 -2
- package/lib/m7-index-sync-host.js +73 -5
- package/lib/m7-wire.js +3 -3
- package/lib/memory-anchor.js +56 -1
- package/lib/memory-envelope.js +257 -0
- package/lib/memory-hub.js +138 -13
- package/lib/memory-index.js +4 -2
- package/lib/memory-mutation.js +246 -0
- package/lib/memory-writer.js +204 -24
- package/lib/note-status-apply.js +118 -0
- package/lib/note-status.js +196 -0
- package/lib/procedure-observation.js +48 -0
- package/lib/procedure-store.js +118 -20
- package/lib/python-setup.js +1 -1
- package/lib/python-sidecar-client.js +29 -3
- package/lib/recall-fusion.js +83 -12
- package/lib/rerank-host.js +160 -0
- package/lib/rules-edit.js +159 -0
- package/lib/rules-layer.js +261 -0
- package/lib/semantic-decide.js +41 -8
- package/lib/semantic-js.js +66 -6
- package/lib/shadow-host.js +3 -5
- package/lib/shadow-retrieval.js +3 -3
- package/lib/skill-export-host.js +153 -0
- package/lib/skill-export.js +239 -0
- package/lib/state-commit.js +245 -0
- package/lib/storage-manage.js +6 -0
- package/lib/subagent-gc.js +4 -8
- package/lib/temporal-parse.js +191 -159
- package/lib/tier-layer-inject.js +650 -0
- package/lib/tier0-catalog.js +735 -0
- package/lib/water-window.js +263 -186
- package/lib/wb-contract.js +691 -0
- package/lib/wb-sidecar.js +890 -0
- package/lib/ws-overview-rank.js +2 -2
- package/package.json +1 -1
- package/python/m7_embedding_v1.py +5 -5
- package/python/worker_semantic_v1.py +17 -6
- package/python/worker_v1.py +38 -4
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# 语义引擎并发调查报告(2026-09-17)
|
|
2
|
+
|
|
3
|
+
> **触发**:用户报告「同时有两个模型在跑时,貌似会引起语义模型冲突,现在谁也没法注入了」。
|
|
4
|
+
> **方法**:静态读码 + 进程/产物实测 + 本会话自身注入快照取证。
|
|
5
|
+
> **纪律**:结论附代码行号证据;推断显式标注;未验证项单列。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 0. 结论先行
|
|
10
|
+
|
|
11
|
+
1. **不是算力不足。** 语义 worker 在实测采样点 **CPU 增量为 0.00s / 3s**(在闲着),内存 3.4GB 稳定,16 逻辑核 / 31GB 物理内存。算力完全够跑多份。
|
|
12
|
+
2. **是并发状态管理缺陷**:引擎里有 **3 个"单槽"共享点**被设计成"全局只此一份",两会话交替投递时**互相覆盖**。
|
|
13
|
+
3. **因此"谁也没法注入"是可解释的确定性后果**,不是玄学冲突。
|
|
14
|
+
4. **建议:不是"只开一个",而是把这 3 个点位改成按会话分片**——工作量可控(估计半天到一天),改完可真正并行。若短期不想动,则**明确承认局限并要求单开**。
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. 活证据:本会话正在降级(此刻)
|
|
19
|
+
|
|
20
|
+
用户本轮对话注入快照里实际出现:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
[降级] 语义索引未就绪(sync-in-progress)· 本轮降级为词法命中 + 常驻目录,未静默丢弃注入
|
|
24
|
+
[降级] 命中投影未复用(投影来自其它工作区)· 本轮不下探 Tier-1,仅常驻目录
|
|
25
|
+
[闸门] 本轮无语义命中(no-hit)→ 仅目录层,未下探 Tier-1/Tier-2
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**第二行是本次调查的决定性线索**:「投影来自**其它工作区**」—— 说明引擎手里那份命中投影,
|
|
29
|
+
此刻属于**另一个会话的工作区**,不是当前这个。这正是单槽覆盖的直接表征。
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. 三个单槽共享点(根因,带行号)
|
|
34
|
+
|
|
35
|
+
### 2.1 `engine._tierGateHits` —— 命中投影单槽 ★主因
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
// lib/activation-host-pre.js:157
|
|
39
|
+
engine._tierGateHits = { // ← 整体覆盖,无 key,全局只此一份
|
|
40
|
+
sessionId, agentId, workspaceKey, at, question,
|
|
41
|
+
contextVersion, miv, observationId, requestKey,
|
|
42
|
+
hits: [...].slice(0, 8),
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- 写:`activation-host-pre.js:157`(每次激活投递都**整份覆盖**)
|
|
47
|
+
- 读:`index.js:4720` `const gh = this._tierGateHits || null`
|
|
48
|
+
- 复用门:`lib/tier-layer-inject-pre.js` 的 `selectReusableTierHitsPre` —— 逐项比对
|
|
49
|
+
`sessionId/workspaceKey/miv/contextVersion` **四元组**,不匹配即判"不复用"
|
|
50
|
+
|
|
51
|
+
**行为**:A 会话投递 → 槽里是 A;B 会话投递 → 槽里变 B(覆盖 A);A 下一轮来取 → 四元组不匹配
|
|
52
|
+
⇒ `[降级] 命中投影未复用(投影来自其它工作区)` ⇒ A **不下探 Tier-1**,只剩目录层。
|
|
53
|
+
|
|
54
|
+
> **推断(非结论)**:这解释了用户说的"谁也没法注入"。严格说是**语义命中层被饿死**,
|
|
55
|
+
> 目录层仍在注入(故本会话仍能读到记忆,只是没有 Tier-1 下探与语义命中)。
|
|
56
|
+
|
|
57
|
+
### 2.2 `mivCache` —— 语料版本缓存单槽
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// lib/activation-host-pre.js:88-111
|
|
61
|
+
let mivCache = ... // 模块内单变量
|
|
62
|
+
function currentMiv(workspaceKey) {
|
|
63
|
+
...
|
|
64
|
+
mivCache = { wsRef: ws, miv: res.snapshot.memoryIndexVersion } // :102 覆盖
|
|
65
|
+
...
|
|
66
|
+
if (mivCache.wsRef === ws) return mivCache.miv // :108 只认最后一个 ws
|
|
67
|
+
return null // :109 否则 null
|
|
68
|
+
}
|
|
69
|
+
function setMiv(workspaceKey, miv) { mivCache = { wsRef: ..., miv } } // :111 覆盖
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**行为**:两个工作区来回切 ⇒ 每次都要重建语料快照(缓存必然 miss),M7 索引同步被反复触发。
|
|
73
|
+
|
|
74
|
+
### 2.3 `lastIndexDegrade` —— 降级标注单槽(跨会话污染)
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
// lib/context-host-pre.js:108
|
|
78
|
+
let lastIndexDegrade = null
|
|
79
|
+
// :360 任何会话的 index-not-ready 都写这里(带 sessionId 但读方不看)
|
|
80
|
+
lastIndexDegrade = { reason: indexNotReady, at: Date.now(), sessionId: ... }
|
|
81
|
+
// :361 并导出到 engine._lastIndexDegrade
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
// lib/index.js:4740 读方只判 10 分钟时间窗,**不判会话**
|
|
86
|
+
const indexNotReady = dg && Date.now() - (Number(dg.at) || 0) < 10 * 60000 ? dg.reason : null
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**行为**:B 会话遇到索引未就绪 ⇒ 写进全局槽 ⇒ **A 会话接下来 10 分钟的注入里
|
|
90
|
+
也会被标注"索引未就绪"**,哪怕 A 自己完全正常。这是**跨会话假降级**。
|
|
91
|
+
|
|
92
|
+
### 2.4 `engine._lastTierQuery` —— 本轮 query 单槽(第四个,补充确认)
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
// lib/context-host-pre.js:554 整体覆盖
|
|
96
|
+
engine._lastTierQuery = { at: Date.now(), sessionId: ..., text: String(jsDecideQueryText).slice(0,1200) }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- 写:`context-host-pre.js:554`
|
|
100
|
+
- 读:`activation-host-pre.js:154-156` —— 有**会话比对**(`lq.sessionId === req.sessionId`)+ 120 秒窗,
|
|
101
|
+
不匹配才退回 `req.triggerText`
|
|
102
|
+
|
|
103
|
+
**行为**:读取侧已有会话门,**危害低于 2.1**;但写入侧仍是无条件覆盖 ⇒ 当 A、B 交替投递时,
|
|
104
|
+
A 的 query 会先被 B 覆盖、读取侧再因会话不匹配而退回 `triggerText`(语义等而下之)。
|
|
105
|
+
**建议一并纳入方案 A 分片**。
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 3. 设计正确的部分(不需要改)
|
|
110
|
+
|
|
111
|
+
| 组件 | 作用域 | 判定 |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `readyCache` / `inFlight`(`m7-index-sync-host-pre.js:34-35`) | `Map`,key = `wsRef\|scope` | ✅ **多槽**,天然支持多工作区 |
|
|
114
|
+
| `context-host` 的 `states`(`:95`) | `WeakMap`:runtime → state | ✅ per-runtime |
|
|
115
|
+
| worker 侧索引(`python/worker_pre_v1.py:137`) | `self.derived = {}`,key = `(workspaceRef, scope)` | ✅ **多份**,支持多工作区 |
|
|
116
|
+
| `engine.state`(`index.js:1023-1028`) | `AsyncLocalStorage` + per-runtime,default runtime 仅镜像路径字段 | ✅ per-runtime(:4118-4131 已标注 mirror 语义) |
|
|
117
|
+
|
|
118
|
+
**结论**:架构**本来就是奔着多工作区设计的**,"谁也没法注入"是三处**遗漏分片**的实现细节,
|
|
119
|
+
不是架构性错误。这是"可以扩展",不是"必须推倒"。
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 4. 算力账(实测)
|
|
124
|
+
|
|
125
|
+
| 项 | 实测值 | 判定 |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| CPU | 16 逻辑核 | 充裕 |
|
|
128
|
+
| 物理内存 | 31.1 GB | 充裕 |
|
|
129
|
+
| **可用内存** | **5.4 GB** | ⚠️ **偏紧**(worker 独占 3.4GB) |
|
|
130
|
+
| GPU | RTX 4070 Ti SUPER(报 4GB VRAM) | 可用(一期未启用 GPU 精排) |
|
|
131
|
+
| python worker | 1 个逻辑 worker(父 5MB + 子 3392MB,00:49 启动) | **单例,模型常驻** |
|
|
132
|
+
| worker CPU | **3 秒采样增量 0.00s** | **在闲着 → 不是算力瓶颈** |
|
|
133
|
+
| node 进程 | 6 个(最大 811MB) | 正常 |
|
|
134
|
+
|
|
135
|
+
**结论**:跑两个会话的**推理/嵌入算力足够**;真正的稀缺资源是**内存(可用 5.4GB)**。
|
|
136
|
+
若有两个"朋友圈"(两套独立 DSH_HOME 各起 worker),每个 worker 再加 ~3.4GB ⇒ **会触顶**。
|
|
137
|
+
但**同一 DSH 内两个会话共享一个 worker**,内存不翻倍 ⇒ **这才是正确姿势**。
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 5. 关联已知问题
|
|
142
|
+
|
|
143
|
+
`docs/internal/TODO-GRAPH.html` 的 **P0-4e** 卡片(状态:**已实测复现**,未修)已记录同源问题:
|
|
144
|
+
|
|
145
|
+
> 索引同步防抖:持续写入会让语义索引永远不就绪(实测卡死 20 分钟)
|
|
146
|
+
> 成因:语料身份是整份哈希(miv),最近每轮都在写记忆 ⇒ 语料一直变 ⇒ 新 miv 的全量重嵌还没跑完,
|
|
147
|
+
> 下一轮又变 ⇒ 重建永远追不上
|
|
148
|
+
|
|
149
|
+
**本次调查补充**:并发会话会**放大**该效应 —— 因为 §2.2 的 `mivCache` 单槽使两工作区互相踢缓存,
|
|
150
|
+
miv 变化频率进一步上升 ⇒ 更容易永久不就绪。**修 #2.2 是修 P0-4e 的前置条件。**
|
|
151
|
+
|
|
152
|
+
另:`debounce` / `防抖` / `coalesce` 在 `m7-index-sync-host-pre.js` 与 `context-host-pre.js`
|
|
153
|
+
中 grep **命中 0** ⇒ 防抖确实未实现(与 P0-4e 卡片一致)。
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 6. 建议(三条路,按推荐度)
|
|
158
|
+
|
|
159
|
+
### 方案 A(推荐):分片化三处单槽 —— "可扩展"
|
|
160
|
+
把 `_tierGateHits` / `mivCache` / `lastIndexDegrade` 从单变量改成 `Map<sessionKey, value>`:
|
|
161
|
+
|
|
162
|
+
| 点位 | 改法 | 风险 |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| `_tierGateHits` | `Map<sessionId, projection>` + 读取时按当前 sessionId 取 | 低(读取点仅 `index.js:4720` 一处) |
|
|
165
|
+
| `mivCache` | `Map<wsRef, miv>` | 低(局部函数,两处写) |
|
|
166
|
+
| `lastIndexDegrade` | `Map<sessionId, degrade>` + 读方按会话取 | 低(读方一处) |
|
|
167
|
+
| `_lastTierQuery` | `Map<sessionId, query>`(与上同理,顺带修) | 低 |
|
|
168
|
+
|
|
169
|
+
**收益**:真正支持"两个朋友圈并行",且顺带缓解 P0-4e。
|
|
170
|
+
**代价**:约半天到一天(含回归 + 变异演示)。
|
|
171
|
+
**约束**:必须加"按会话隔离"的回归套件——否则改完只是把覆盖点从一个地方挪到另一个地方。
|
|
172
|
+
|
|
173
|
+
### 方案 B(保守):承认局限,单开
|
|
174
|
+
在设置页加显式提示:「本插件当前不支持多会话并行注入(语义命中层会被互相覆盖)、
|
|
175
|
+
若需长时攻关请只用单会话」+ 在降级标注里写清原因。
|
|
176
|
+
**代价**:近乎零;**缺点**:把架构缺陷固化成产品限制。
|
|
177
|
+
|
|
178
|
+
### 方案 C(不推荐):两套独立 DSH_HOME
|
|
179
|
+
各自起 worker ⇒ **内存翻倍(+3.4GB×2)**,而可用内存只有 5.4GB ⇒ 会触顶。
|
|
180
|
+
且两套记忆库互相不可见,违背"记忆是跨会话资产"的初衷。
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 7. 未验证项(诚实清单)
|
|
185
|
+
|
|
186
|
+
1. **未做双会话实测**:结论基于读码 + 单会话降级快照推断,**没有真起两个会话复现**。
|
|
187
|
+
若要坐实,需:开第二个会话 → 两会话交替投递 → 观察 `_tierGateHits` 是否被覆盖
|
|
188
|
+
(可在诊断面板看 `indexDegrade` / 投影 sessionId)。
|
|
189
|
+
2. **未测内存峰值**:可用 5.4GB 是瞬时值;两个会话 + 重嵌同时发生时的峰值未采样。
|
|
190
|
+
3. **P0-4e 是否就是用户此次症状的主因**:未分离验证(可能与 §2.1 叠加)。
|
|
191
|
+
4. ~~`_lastTierQuery` 也是单槽,本次未展开分析~~ → **已补充确认**(见 §2.4),
|
|
192
|
+
读取侧有会话门故危害较低,但写入侧仍无条件覆盖,建议一并分片。
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# 跨会话 / 跨 Agent 语义检索:路径决策(2026-09-14 预研,待拍板)
|
|
2
|
+
|
|
3
|
+
> 背景:本机把 DSH 的内容检索打开后,发现它被上游两个缺陷挡住(详见 `ACCEPTANCE-20260914.md` 附录与下文§3)。
|
|
4
|
+
> 由此暴露出一件更要紧的事:**本插件承诺的"跨会话检索"其实一直依赖 DSH 的可选特性**,而"跨 Agent 记忆检索"根本没有实现。
|
|
5
|
+
> 本文只做决策,不动工。状态约定:✅ 已核实 / ⚠️ 有缺口 / 🎯 待拍板。
|
|
6
|
+
|
|
7
|
+
## 1. 现状取证(全部带行号,可复核)
|
|
8
|
+
|
|
9
|
+
| 通路 | 现状 | 取证 |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| 本地记忆(每日日志 / 反思 / `MEMORY.md` / 用户级) | ✅ 可用:词法臂 + 语义臂(python dense 优先,失败回退 `_jsSemanticRank`)+ 时间臂 + 重要性加权 + L0/expand 两档 | `lib/index.js:3935-4050`(`recall`)、`:4019-4021`(语义臂择优) |
|
|
12
|
+
| 交接白板语料(PLAN + 账本 + archive) | ✅ 可用 | `:3946-3951`、`searchHandoffCorpus` |
|
|
13
|
+
| **跨 DSH 会话历史** | ⚠️ **完全外挂在 DSH 的 opt-in 特性上**:①DSH 出厂 `openAt: never` → 用户不做 DSH 侧配置就永久失败;②插件自注入的 guidance 却指示模型用 `memory_recall_pre(scope='sessions')`;③即便开了,老装机(含 v0 + `subagent/descriptor` v2 的老日志)会被上游 fail-closed 整条挡死 | 插件 `:3953-3960`(catch 后把上游错误原文回给模型);guidance `:2737`、`:2812-2816`;上游:`dsh-base/cordis.patch.yml:121-133`、`dsh-session-format-v0-to-v1/lib/index.js:1584-1587`、`dsh-session-query-sqlite/lib/index.js:724-739` |
|
|
14
|
+
| **外部 Agent 记忆文档**(Claude Code `CLAUDE.md`、WorkBuddy/CodeBuddy 画像、ZCode 项目记忆、TRAE/Cursor 规则) | ⚠️ **只被注入上下文,不进检索语料**:`discover()` 抓到 `content`(截 200KB),但 `recall(scope='all')` 的语料只由 handoff + 日志 + 反思 + 项目/用户记忆构成,**从不包含外部源** | `discover()` `:5822-5902`;`recall` 语料装配 `:3983-4002` |
|
|
15
|
+
| **外部 Agent 历史会话**(Claude Code / Codex / WorkBuddy / ZCode / Kimi) | ⚠️ 注释自述「**会话源只带文件索引**」「只注入路径不注内容」→ 只能进上下文摘要,不能检索 | `pushSessions()` `:5849-5863`、`:5880-5893` |
|
|
16
|
+
|
|
17
|
+
**一句话**:插件目前只有"自己的记忆"是可检索的;**别人的记忆(其他 Agent)与自己的历史会话,都不在检索面内**。
|
|
18
|
+
|
|
19
|
+
## 2. 对"本插件用户"的影响(回答 §研究其他用户)
|
|
20
|
+
|
|
21
|
+
- **没人会因为本插件踩到上游那个缺陷**:DSH 内容检索是 opt-in,本插件从不替用户打开它 → 用户侧默认是"服务在、但永远拒绝",插件把上游原话当错误信息回给模型。
|
|
22
|
+
- **但用户会踩到本插件自己的缺口**:插件在每轮注入的面板/接续 guidance 里**明确让模型去用 `scope='sessions'`**(`:2737`、`:2812-2816`),而这条路径默认不可用 → 模型照做就报错,用户体验是"说好的历史检索,用了就说不可用"。**这是产品缺陷,不是用户环境问题。**
|
|
23
|
+
- **另一个副作用**:`discover()` 白扫了外部源(读文件、算尺寸),结果只用于"注入摘要";用户在向导里勾选的那些来源,**勾选后其实检索不到**——卖点与能力不一致(与 §C 冷启动那批"幻觉 ON"同类)。
|
|
24
|
+
|
|
25
|
+
## 3. 为什么不能把宝押在 DSH 的 sessionQuery 上
|
|
26
|
+
|
|
27
|
+
1. 出厂 `openAt: never`(opt-in),插件不能替用户改 DSH 配置(也不该)。
|
|
28
|
+
2. 打开了也可能整条失败:**任一个读不动的老会话 → 全部检索失败**(fail-closed,无容错开关;配置面只有 9 个参数,无 tolerate/skip)。
|
|
29
|
+
3. 上游对"老数据"是硬拒:v0 日志里的 `subagent/descriptor` v2 被编解码器拒绝,**且 `next`(0.1.5-rc.2) 两处代码一字未改**(本次下 tarball 比对确认)→ 短期内修不了。
|
|
30
|
+
4. 社区已有同族报告:[#4811 单个坏会话让全局会话检索不可用](https://github.com/deepseek-ai/deepseek-harness/discussions/4811)、[#4910 各持久化格式硬拒非当前版本、零迁移路径](https://github.com/deepseek-ai/deepseek-harness/discussions/4910)、[#5694 Failed to load history](https://github.com/deepseek-ai/deepseek-harness/discussions/5694)。
|
|
31
|
+
5. 那篇官方设计注记本身就写着会话内容检索是 [opt-in 特性](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-13-session-content-search-opt-in.zh.md) —— 依赖它等于把核心卖点寄托在别人的开关上。
|
|
32
|
+
|
|
33
|
+
## 4. 三条可选路径
|
|
34
|
+
|
|
35
|
+
### 路径 A(推荐):插件自建"统一检索面",DSH sessionQuery 降级为可选加速
|
|
36
|
+
把检索语料**收归插件自己**,一句话:**凡是本机读得到的记忆与历史,都进同一个索引,读写自有容错**。
|
|
37
|
+
|
|
38
|
+
- **语料来源(全部本地、全部自解析)**:
|
|
39
|
+
1. 现有本地记忆 + 白板账本(已可用,不动)
|
|
40
|
+
2. **DSH 会话日志**:用插件自带解码器头帧解码(`decodeZstdFramesHead`,已存在且被 PR#29 加固过)抽出消息文本 → 切块入库
|
|
41
|
+
3. **外部 Agent 记忆文档**:把 `discover()` 已抓到的 `content` 真正入库(Claude Code / WorkBuddy / CodeBuddy / ZCode / TRAE / Cursor)
|
|
42
|
+
4. **外部 Agent 历史会话**:为每个工具写**容错适配器**(Claude Code `~/.claude/projects/**.jsonl`、Codex `~/.codex/sessions`、WorkBuddy、ZCode rollout、Kimi),单文件解析失败只跳过该文件
|
|
43
|
+
- **检索**:并入现有 `recall()` 管线(词法 + 语义臂 + L0/expand + 来源标注),`scope='sessions'` 变成"插件原生":**有 sessionQuery 就用它做补充,没有/失败就用自建索引**,永不把上游错误原文抛给模型
|
|
44
|
+
- **零依赖可用性**:不装 130MB 引擎也能跑(词法 + `_jsSemanticRank`);装了 python/BGE 档则自动升级召回
|
|
45
|
+
- **容错纪律(直接照抄上游的教训)**:逐文件 try/catch + 跳过 + 计数上报;**任何单点失败不得让整条检索失败**
|
|
46
|
+
- **成本控制**:增量索引(mtime+size 指纹)、头帧解码上限、条数/字节预算、按龄裁剪、静态节流(不在热路径上建索引)
|
|
47
|
+
- **隐私**:索引只落本机 `~/.dsh/memory/`;新增开关(默认开但可关 + 工作区排除名单);不索引 `reasoning` 原文(沿用现有 `reasoningObserverEnabled` 的既有边界)
|
|
48
|
+
|
|
49
|
+
**代价**:这是"下一版的主要工作量"(我估 P0 约 1 个版本、P1 再 1 个版本);要新增索引存储与迁移;要维护各工具格式适配器。
|
|
50
|
+
|
|
51
|
+
### 路径 B(最省事):只改进"提示与降级",能力仍依赖 DSH
|
|
52
|
+
- 插件检测 sessionQuery 是否可用:不可用就**不再在 guidance 里推荐 `scope='sessions'`**,改推荐 `scope='handoff'`;可用但失败就给可操作的诊断(而不是原样回上游错误)
|
|
53
|
+
- 顺手:把 `discover()` 抓到的外部 `content` 并入 `recall(scope='all')` 语料(这一小块很便宜,能立刻兑现"外部记忆可检索"的一半承诺)
|
|
54
|
+
- **代价**:跨会话检索对绝大多数用户仍然没有;跨 Agent 的**会话**仍不可检索
|
|
55
|
+
|
|
56
|
+
### 路径 C(折中·分两步):先自建 DSH 会话索引(P0),再纳外部 Agent(P1)
|
|
57
|
+
= 路径 A 的分期版,先只解决"插件自己承诺的那一条"(DSH 历史会话),验证容错与成本模型;外部 Agent 会话/文档作 P1。
|
|
58
|
+
**代价**:与 A 相同,只是风险前移、可早一版上线。
|
|
59
|
+
|
|
60
|
+
## 5. 拍板点(请逐条给结论)
|
|
61
|
+
|
|
62
|
+
1. **主路径**:A / B / C 选哪个?(我建议 **C**:先把插件自己承诺的能力做实,再扩到外部 Agent)
|
|
63
|
+
2. **范围**:外部 Agent 要覆盖到哪些?Claude Code / Codex / WorkBuddy / ZCode / Kimi / TRAE-Cursor 规则——**全要**还是先挑常用的两三个?
|
|
64
|
+
3. **零依赖底线**:是否接受"不装 130MB 引擎时用词法+JS 语义臂(召回弱一些但 0 下载)"作为默认?
|
|
65
|
+
4. **隐私边界**:会话索引默认**开**(可关 + 工作区排除名单)还是默认**关**(向导里一键开)?
|
|
66
|
+
5. **上游报告**:要不要我把本次这个具体案例(v0 + descriptor v2 + fail-closed)整理成一份 issue/discussion 稿(可并入已有的 #5732 系列)?
|
|
67
|
+
6. **落地节奏**:P0 现在开工,还是等大排期(界面/文档)先定?
|
|
68
|
+
|
|
69
|
+
## 6. 与既有待办的关系
|
|
70
|
+
|
|
71
|
+
- 本条**并入** `TODO-BACKLOG.md` §C(冷启动闭环)与 §A 末条(procedure 记忆机制整体重构)的同一类问题:**能力与承诺不一致**。若拍板走 C,我会在 §B 新增一节"跨会话/跨 Agent 检索"并排在下一版。
|
|
72
|
+
- DSH 侧那个上游缺陷**不阻塞**本路径:插件自建索引不依赖它;它只影响"DSH 侧边栏搜索"这一项,按 §5.5 单独上报即可。
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# 跨会话 / 跨 Agent 记忆检索 · 调研报告(2026-09-14)
|
|
2
|
+
|
|
3
|
+
> 与 `CROSS-SESSION-SEARCH-PATH-DECISION.md`(决策页)配套:那页定"走哪条路",本页回答"**具体怎么做、优缺点是什么**"。
|
|
4
|
+
> 证据分级:**[实测]** = 本机跑出来的数字;**[实证]** = 有公开 benchmark/事故报告支撑;**[经验]** = 工程界共识/无硬数据;**[估算]** = 由实测外推。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 一、一句话结论
|
|
9
|
+
|
|
10
|
+
**词法为主干(`node:sqlite` FTS5,Node 内置、零依赖)+ 轮次级分块 + 字节 offset 增量 + 逐文件跳过计数**,语义向量只作**可选增益**(装了走 RRF 融合,不装也必须独立可用)。
|
|
11
|
+
理由:LongMemEval-S(500 题,all-MiniLM-L6-v2)上 **BM25-only R@5 = 86.2% → BM25+向量 = 95.2% → 纯向量 96.6%** —— 加向量是单项收益最大的一步(+9pp),但混合与纯向量只差 1.4pp,**混合才是性价比点**([来源](https://raw.githubusercontent.com/rohitg00/agentmemory/a8e7d19a814a24a21818afc715f3301b3eaeee80/benchmark/LONGMEMEVAL.md))。**[实证]**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 二、本机实测:语料盘点与格式规则 [实测]
|
|
16
|
+
|
|
17
|
+
### 2.1 体量(决定了"能不能全量索引")
|
|
18
|
+
|
|
19
|
+
| 来源 | 文件数 | 体量 | 备注 |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| DSH 会话 `~/.dsh/sessions/**/session*.jsonl.zstd` | 191 | **321 MB**(压缩态) | 最大单文件 25 MB 压缩 |
|
|
22
|
+
| WorkBuddy `~/.workbuddy/projects/**/*.jsonl` | 89 | 155 MB | 最大单文件 **53 MB** |
|
|
23
|
+
| ZCode `~/.zcode/cli/rollout/*.jsonl` | 3 | 80 MB | **model-io 日志:同一段历史重复 N 次** |
|
|
24
|
+
| Codex `~/.codex/sessions/**/rollout-*.jsonl` | 17 | 46 MB | 最大单文件 25 MB |
|
|
25
|
+
| Claude Code `~/.claude/projects/**/*.jsonl` | 4 | 0.1 MB | 本机几乎没在用 |
|
|
26
|
+
| Kimi `~/.kimi-code/sessions` | 0 | — | 目录为空 |
|
|
27
|
+
| 外部记忆 markdown(CLAUDE/AGENTS/MEMORY.md) | 55 | 0.5 MB | 成本最低、收益最直接 |
|
|
28
|
+
|
|
29
|
+
### 2.2 DSH 会话的压缩比与正文占比 [实测]
|
|
30
|
+
|
|
31
|
+
抽样 4 个文件(含 3.4 MB 级):**压缩比 2.1x、正文占解压文本 52%**。
|
|
32
|
+
→ 外推:321 MB 压缩 ≈ **0.67 GB 解压文本 ≈ 0.35 GB 可索引正文**。
|
|
33
|
+
→ 速度:解码 5.5 MB 压缩(11 MB 文本、1.7 万事件)耗时 **0.7 s** → **全量扫一遍 DSH 会话约 1 分钟 CPU** [估算]。**结论:一次性全扫完全可接受,问题不在解码速度,而在索引体量。**
|
|
34
|
+
|
|
35
|
+
### 2.3 各源正文抽取规则(已逐源实测字段路径)
|
|
36
|
+
|
|
37
|
+
| 源 | 取哪些 | 字段路径 | 必须排除 |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| DSH | 消息事件文本 | 现有解码器 + 事件 type 过滤 | 系统提示/工具结果大块 |
|
|
40
|
+
| Claude Code | `user` / `assistant` | `message.content`(字符串或 blocks) | `file-history-snapshot`、`mode` |
|
|
41
|
+
| Codex | `response_item` | `payload.content[].text` | **`session_meta.payload.base_instructions.text`(系统提示,每文件 ~17 KB)**、`world_state` |
|
|
42
|
+
| WorkBuddy | `message` | `content[].text` | `reasoning`(思维链,默认不索引)、`file-history-snapshot` |
|
|
43
|
+
| ZCode | `model_io` | `request.body.input[].content` / `request.messages[].content` + `response` | **重复消费**:每次请求重发全史 |
|
|
44
|
+
|
|
45
|
+
**两个坑(不避开就会把索引撑爆或污染结果)**:
|
|
46
|
+
1. **Codex 的 `base_instructions` 是系统提示**(每个会话一份、上万字符),索引它等于把"我的插件说明"混进用户记忆。
|
|
47
|
+
2. **ZCode 是请求日志**:同一段对话在每次 API 调用里重复出现,**必须按 `turnId`/`requestId` 去重或只取最后一条**,否则 80 MB 里绝大多数是重复。[实测]
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 三、业界实证:怎么做才不翻车
|
|
52
|
+
|
|
53
|
+
| 议题 | 结论 | 证据 |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| 架构 | 词法打底 + 可选向量 + RRF 融合;RRF 是零调参行业默认 | **[实证]** LongMemEval 数据;[ADR 016](https://github.com/psmfd/agent-experise-api/blob/main/adrs/016-hybrid-rrf-search.md) |
|
|
56
|
+
| 分块粒度 | **轮次(round = user+assistant)优于会话级**;进一步压成"单条 fact"会因信息损失**整体变差**(只在多会话推理上更好) | **[实证]** LongMemEval 论文 §5.2 [arXiv 2410.10813](https://arxiv.org/abs/2410.10813) |
|
|
57
|
+
| 增益技巧 | 多键索引(抽取 user facts 扩展 key)recall@k **+9.4%**、QA +5.4%;**时间感知索引 + 查询扩展 时序 recall +6.8~11.3%** | **[实证]** 同上 |
|
|
58
|
+
| 增量 | 指纹 `(path, size, mtime)`;更稳是内容哈希做 chunk 级;**append-only JSONL 记字节 offset 续读**,不重解析 | **[经验]** |
|
|
59
|
+
| 容错 | **跳过 + 计数 + quarantine 表**,逐文件/逐行隔离;绝不 fail-closed | **[实证]** LightRAG 曾因"索引 FAILED 卡死所有查询",修复方式是显式 rebuild([PR#3177](https://github.com/HKUDS/LightRAG/pull/3177))—— 与 DSH 上游同款病灶 |
|
|
60
|
+
| 模型 | 中英混合:bge-small(24M/384d) 或 multilingual-e5-small(118M/384d);**bge-m3 2.27GB 与 130MB 预算不匹配**;量化可压 1/4 | **[经验]** |
|
|
61
|
+
| 隐私 | 入索引前做**路径级排除名单**(`.env`/credentials)+ 展示层高熵串脱敏;**全密文与可检索互斥**,不要设计成全密文本地检索 | **[经验]** |
|
|
62
|
+
| 换模型 | 必须版本化模型标识并全量重算,否则向量空间混用 | **[实证]** [Neo4j 迁移教训](https://neo4j.com/labs/agent-memory/how-to/migrate-embedding-model/) |
|
|
63
|
+
|
|
64
|
+
本机已有的可复用件:`decodeZstdFrames(Head)`(已按 PR#29 加固)、`_jsSemanticRank`(零依赖 JS 语义臂)、`_semanticRankBest`(python dense 择优)、`l0-extract-pre.js`(L0 摘要抽取)、`discover()`(外部源扫描,已抓 md `content`)。
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 四、三种实现方案的优缺点
|
|
69
|
+
|
|
70
|
+
### 方案 1:FTS5 词法索引(`node:sqlite`,Node 内置)— **推荐做 P0**
|
|
71
|
+
- **怎么做**:`node:sqlite`(Node ≥22.5 内置,本机 v24.18.0 已实测可用)建 `chunks(source, sids, ts, role, text)` + FTS5 虚表;写入按轮次切块;查询 `MATCH` + 元数据过滤(时间/工具/工作区)。
|
|
72
|
+
- **优点**:零依赖、不下载模型;毫秒级查询;索引体量小(估 FTS5 约为正文 30–60% → **100–200 MB** 级 [估算]);实现与测试成本最低;完全离线。
|
|
73
|
+
- **缺点**:**隐含偏好类查询是硬伤**(BM25 该类 60% vs 混合 83.3%);同义/换词检索弱。
|
|
74
|
+
- **适用**:所有用户默认路径(含没装引擎的)。
|
|
75
|
+
|
|
76
|
+
### 方案 2:向量索引(复用/扩展现有引擎)
|
|
77
|
+
- **怎么做**:轮次切块 → 现有 provider 抽象(bge-m3 / hash)或新增小模型 → 向量存 sqlite BLOB(int8)或分开的 `.bin`;查询 top-K 后与词法 RRF 融合。
|
|
78
|
+
- **优点**:召回最高(纯向量 96.6%),改述查询也能命中。
|
|
79
|
+
- **缺点**:**成本最高的部分** —— 本机语料量级 [估算] 需 embed ~25–40 万块;384 维 float32 约 **400–600 MB**(int8 约 100–150 MB);CPU 全量重算是分钟~小时级;模型/版本漂移要全量重算;现有 python 向量落盘是 JSON(`vectors-*.json`),**这个量级不能继续用 JSON 存**。
|
|
80
|
+
- **适用**:装了语义引擎的进阶用户;作为增益项。
|
|
81
|
+
|
|
82
|
+
### 方案 3:轻量"倒排 + JS 语义臂"(零依赖兜底)
|
|
83
|
+
- **怎么做**:纯 JS 倒排表(词→chunk ids)+ 现有 `_jsSemanticRank` 重排;索引落单个紧凑 jsonl/二进制。
|
|
84
|
+
- **优点**:兼容老 Node;无 sqlite 依赖;实现小。
|
|
85
|
+
- **缺点**:自建倒排的查询质量/性能都不如 FTS5;内存占用随语料涨;容易变成"自研半成品数据库"。
|
|
86
|
+
- **适用**:**仅当检测不到 `node:sqlite` 时的降级路径**(DSH Desktop 的 Electron Node 22 需实测),不要作为主路径。
|
|
87
|
+
|
|
88
|
+
### 横向对比
|
|
89
|
+
|
|
90
|
+
| 维度 | 方案 1 FTS5 | 方案 2 向量 | 方案 3 JS 倒排 |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| 依赖/下载 | 0 | 130 MB+(可选) | 0 |
|
|
93
|
+
| 首次建索引 | 分钟级 | 分钟~小时级 | 分钟级 |
|
|
94
|
+
| 索引体量 [估算] | 100–200 MB | +100–150 MB(int8) | 50–150 MB |
|
|
95
|
+
| 召回(LongMemEval 口径) | 86.2% | 96.6% | ~86% 或更低 |
|
|
96
|
+
| 实现风险 | 低 | 中(模型/版本/存储) | 中(自研存储) |
|
|
97
|
+
| 老 Node 兼容 | 需降级 | 需引擎 | 最好 |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 五、推荐组合与分阶段
|
|
102
|
+
|
|
103
|
+
**P0(零依赖基线,必须独立可用)**:DSH 会话 + 外部记忆 markdown 入 FTS5 + 轮次分块 + offset 增量 + 跳过计数 + 来源/时间元数据 + 时间感知查询扩展(词法下性价比最高项,+6.8~11.3% 时序召回)。**目标:不装任何模型也能检索。**
|
|
104
|
+
**P1(外部 Agent 会话)**:Claude Code / Codex / WorkBuddy / ZCode 适配器(按 §2.3 规则;ZCode 先按 turnId 去重),**逐源可开关**、单源失败不影响其他源。
|
|
105
|
+
**P2(语义增益)**:小模型(bge-small / e5-small 量级)向量 + RRF 融合;沿用"模型标识版本化 + 不匹配即重算"。
|
|
106
|
+
**P3(体验)**:`scope='sessions'` 改为插件原生(有 DSH sessionQuery 就补充、没有/失败就用自建索引);面板里显示"索引了多少条 / 跳过了几个文件"。
|
|
107
|
+
|
|
108
|
+
**硬性预算(默认值建议)**:时间窗 90 天 + 单源上限 2 万块 + 总量上限 10 万块 + 单文件解码上限 16 MB;超限只索引"最近优先"并**在面板如实显示跳过/截断数量**。理由:本机语料 [估算] 会产生 25–40 万块,无上限必然失控。
|
|
109
|
+
|
|
110
|
+
**隐私默认**:入索引前路径级排除(`.env`、credentials、密钥目录)+ 高熵串脱敏;索引只落本机 `~/.dsh/memory/`;提供"一键清除索引"与工作区排除名单。
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 六、风险清单(按优先级)
|
|
115
|
+
|
|
116
|
+
1. **fail-closed 传染**(最高危):任何"单文件坏 → 整库不可用"的设计直接否决 —— 这是 DSH 上游正在发生的病灶,必须反着做。
|
|
117
|
+
2. **规模失控**:600 MB 压缩语料全量索引必然爆预算 → 必须时间窗 + 条数上限 + 如实计数。
|
|
118
|
+
3. **敏感内容入库不可逆**:脱敏要在入索引前;排除名单要能改并支持重建索引。
|
|
119
|
+
4. **热路径阻塞**:索引只在空闲/后台做,单批限量;查询只扫 top-K。
|
|
120
|
+
5. **重复内容污染**(ZCode 请求日志、Codex 系统提示):先做源级去重与字段白名单,否则"检索到 10 条其实是一条"。
|
|
121
|
+
6. **模型/版本漂移**:向量必须带模型标识,换模型全量重算。
|
|
122
|
+
7. **格式漂移**:各家会话格式会变 → 适配器版本化 + 解析失败即跳过并计数(不要抛给用户)。
|
|
123
|
+
8. **跨工具隐私**:索引别人的记忆目录(Claude Code / Codex)等于把别的工具的对话搬进来 → 默认只索引"用户勾选过的源"。
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 七、与上游那份缺陷的关系
|
|
128
|
+
|
|
129
|
+
- 本方案**不依赖** DSH 的 `sessionQuery`:自建索引是主路径,它只作可选补充。→ 上游那个 fail-closed 缺陷**不再是阻塞**。
|
|
130
|
+
- 建议仍单独上报(可并入 #5732 系列):①v0 日志里 `subagent/descriptor` v2 被编解码器硬拒(DSH 自己写的数据);②索引器 fail-closed 且无容错开关。社区同族:#4811、#4910、#5694。
|
|
131
|
+
- 决策状态:**等大排期一起拍板,暂不动工**(用户 2026-09-14 决定)。
|