@ilaomianyang/dsh-memory-graph 0.10.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.
- package/CHANGELOG.md +259 -0
- package/LICENSE +21 -0
- package/README.en.md +466 -0
- package/README.md +459 -0
- package/client.js +1953 -0
- package/cordis.patch.yml +13 -0
- package/docs/auto-settings.png +0 -0
- package/docs/distill-button.png +0 -0
- package/docs/graph-dark.png +0 -0
- package/docs/graph-light.png +0 -0
- package/docs/session-tab-cards.png +0 -0
- package/docs/session-tab-open.png +0 -0
- package/docs/session-tab.png +0 -0
- package/docs/vault-panel.png +0 -0
- package/eval/REPORT.md +437 -0
- package/eval/questions.json +277 -0
- package/eval/run.mjs +460 -0
- package/eval/seed.mjs +489 -0
- package/icon.svg +26 -0
- package/index.js +243 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +77 -0
- package/src/auto.js +194 -0
- package/src/capture.js +237 -0
- package/src/config.js +280 -0
- package/src/distillapi.js +30 -0
- package/src/distillrun.js +106 -0
- package/src/extract.js +660 -0
- package/src/graph.js +1582 -0
- package/src/graphdata.js +475 -0
- package/src/http.js +32 -0
- package/src/pageapi.js +40 -0
- package/src/privacy.js +78 -0
- package/src/schema.js +323 -0
- package/src/search.js +317 -0
- package/src/tools.js +534 -0
- package/src/vault.js +888 -0
- package/test/auto.mjs +295 -0
- package/test/capture.mjs +264 -0
- package/test/client.mjs +1035 -0
- package/test/distillapi.mjs +212 -0
- package/test/extract.mjs +660 -0
- package/test/graphdata.mjs +295 -0
- package/test/live-supersede.mjs +78 -0
- package/test/live.mjs +156 -0
- package/test/page.mjs +116 -0
- package/test/schema.mjs +256 -0
- package/test/smoke.mjs +428 -0
- package/test/tools.mjs +238 -0
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
- insert:
|
|
2
|
+
- id: memory-graph
|
|
3
|
+
name: '@ilaomianyang/dsh-memory-graph'
|
|
4
|
+
config:
|
|
5
|
+
vaultDir: ''
|
|
6
|
+
capture:
|
|
7
|
+
enabled: true
|
|
8
|
+
extractor:
|
|
9
|
+
enabled: false
|
|
10
|
+
# harness = borrow the provider / model / thinking level selected in
|
|
11
|
+
# Settings → Models (no key needed). Switch to 'http' to post to your
|
|
12
|
+
# own OpenAI-compatible endpoint with baseUrl + apiKeyEnv instead.
|
|
13
|
+
transport: 'harness'
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/eval/REPORT.md
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# memory-graph 检索评测报告(第四轮 · 最后一轮)
|
|
2
|
+
|
|
3
|
+
本轮只做复核:你改完 `src/search.js` 之后,把全部数字、弱点 7 的 10 条变体、6 条探针重跑一遍,
|
|
4
|
+
然后照实改这份报告。**判据、题目、期望卡、fixture 一个字没动;`eval/` 里除这份报告外没有任何改动。**
|
|
5
|
+
|
|
6
|
+
## 结论
|
|
7
|
+
|
|
8
|
+
| 判分块 | 结果 | 门槛 | 判定 |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| 原 25 条 · recall@5 | 0.98 | >= 0.80 | 通过 |
|
|
11
|
+
| 原 25 条 · negative 误报 | 0 / 5 | <= 1 | 通过 |
|
|
12
|
+
| history 成对准确率 | **4 / 4 = 1.00** | >= 0.80 | 通过 |
|
|
13
|
+
|
|
14
|
+
`node eval/run.mjs` 退出码 **0**,13 条自检全 `ok`,临时 vault 正常清理。三块全绿,这是四轮里第一次。
|
|
15
|
+
|
|
16
|
+
你给的每一个数字我都复现出来了:e1 回到第 1(**7.272**,上一轮 4.808)、k6 回到第 1(4.224)、
|
|
17
|
+
history 4/4、t4 余量 0.074 → **0.14**、h3h 老卡 **8.977** 压过新卡 5.347。
|
|
18
|
+
|
|
19
|
+
但复现成功不等于没问题,本轮新查出来的三件事写在下面,都进弱点了:
|
|
20
|
+
|
|
21
|
+
1. **弱点 7 还剩 1/10 漏检**:`先是用 Zabbix 的吧` 没被识别(正则里有 `一开始`,没有 `先用`)。我没再加词。
|
|
22
|
+
2. **新增弱点 8**:`监控之前那套 Kuma 还留着吗` 被读成历史问句,**老卡 7.191 排第 1**,正确的现状卡 7.159 第 2,
|
|
23
|
+
差 0.032。问的是「还留着吗」= 现状,答的是「以前用 Zabbix」——**这比漏检更糟:漏检是找不到,这个是答错。**
|
|
24
|
+
3. **keyword 组 1.00 的余量变成 0.019**:k6 的正确答案 4.224 对干扰卡 4.205。字表收敛把上一轮 0.128 的余量吃掉了,
|
|
25
|
+
这条 1.00 是弦上的 1.00,不是稳稳的 1.00。
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 与上一轮对比
|
|
30
|
+
|
|
31
|
+
| 指标 | 第三轮 | 本轮 |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| keyword recall@1 / recall@5 / MRR | 1.00 / 1.00 / 1.00 | 1.00 / 1.00 / 1.00(k6 余量 0.128 → **0.019**) |
|
|
34
|
+
| entity-bridge recall@1 / recall@5 / MRR | 0.50 / 0.94 / 0.72 | **0.67 / 0.94 / 0.83** |
|
|
35
|
+
| temporal recall@1 / recall@5 / MRR | 0.60 / 1.00 / 0.80 | 0.60 / 1.00 / 0.80 |
|
|
36
|
+
| 时序规则(旧卡不得压过继任者) | 5/5 | 5/5 |
|
|
37
|
+
| negative 误报 | 0/5 | 0/5 |
|
|
38
|
+
| 全部 recall@1 / recall@5 / MRR | 0.75 / 0.98 / 0.87 | **0.80 / 0.98 / 0.90** |
|
|
39
|
+
| history 成对准确率 | 3/4 = 0.75 | **4/4 = 1.00** |
|
|
40
|
+
| 判定 / 退出码 | FAIL(history 0.75) / 1 | **PASS / 0** |
|
|
41
|
+
|
|
42
|
+
唯一没动的是 temporal 的 r@1 = 0.60(t2、t4 都是第 2,原因见弱点 6),
|
|
43
|
+
和历史组里那 4 条「问现状」侧的对侧卡依旧全部掉出前五(这是对的)。
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 分数与逐题名次(全部重跑,与你的表一致)
|
|
48
|
+
|
|
49
|
+
| 题型 | n | recall@1 | recall@5 | MRR | 备注 |
|
|
50
|
+
|---|---|---|---|---|---|
|
|
51
|
+
| keyword | 9 | 1.00 | 1.00 | 1.00 | 9 条全部第一 |
|
|
52
|
+
| entity-bridge | 6 | 0.67 | 0.94 | 0.83 | 未过 2 条(e5 / e6) |
|
|
53
|
+
| temporal | 5 | 0.60 | 1.00 | 0.80 | 时序规则 5/5 |
|
|
54
|
+
| negative | 5 | - | - | - | 误报 0/5,5 条正常兜底 |
|
|
55
|
+
| **全部** | 25 | **0.80** | **0.98** | **0.90** | 负面误报 0/5 |
|
|
56
|
+
|
|
57
|
+
`-` = 不在前五。
|
|
58
|
+
|
|
59
|
+
| 题号 | 类型 | 期望卡名次 | 与上一轮相比 |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| k1–k9 | keyword | 全部 1 | 不变 |
|
|
62
|
+
| k6 | keyword | 1 | 不变(但余量 0.128 → 0.019) |
|
|
63
|
+
| e1 | entity-bridge | **1**, 4, - | 3 → **1(恢复)** |
|
|
64
|
+
| e2 | entity-bridge | 2, 1 | 不变 |
|
|
65
|
+
| e3 | entity-bridge | 2, 1 | 不变 |
|
|
66
|
+
| e4 | entity-bridge | 2, 1 | 不变 |
|
|
67
|
+
| e5 | entity-bridge | 2 | 不变 |
|
|
68
|
+
| e6 | entity-bridge | 5, 3, 2 | 不变 |
|
|
69
|
+
| t1 | temporal | 1 | 不变 |
|
|
70
|
+
| t2 | temporal | 2 | 不变 |
|
|
71
|
+
| t3 | temporal | 1 | 不变 |
|
|
72
|
+
| t4 | temporal | 2 | 不变(余量 0.074 → **0.14**) |
|
|
73
|
+
| t5 | temporal | 2, 1 | 不变 |
|
|
74
|
+
| n1–n5 | negative | 0.050 兜底 | 不变 |
|
|
75
|
+
|
|
76
|
+
### history 组(4 对 8 题)
|
|
77
|
+
|
|
78
|
+
| 题号 | 侧 | 问题 | 期望卡名次 | 对侧卡名次 | 与上一轮相比 |
|
|
79
|
+
|---|---|---|---|---|---|
|
|
80
|
+
| h1h | 过去 | 抽取最早是不是默认开着的 | 1 | 2 | 不变 |
|
|
81
|
+
| h1c | 现在 | 抽取现在是显式调用才跑吗 | 1 | - | 不变 |
|
|
82
|
+
| h2h | 过去 | 监控当初用 Zabbix 的时候是怎么弄的 | 1 | 2 | 不变 |
|
|
83
|
+
| h2c | 现在 | 监控现在是用 Prometheus 还是 Kuma | 1 | - | 不变 |
|
|
84
|
+
| h3h | 过去 | 告警最早是发邮件的吗 | **1** | 2 | 2 → **1(修好了)** |
|
|
85
|
+
| h3c | 现在 | 告警现在只发手机吗 | 1 | - | 不变 |
|
|
86
|
+
| h4h | 过去 | 证书当初是手动 renew 的吗 | 1 | 2 | 不变 |
|
|
87
|
+
| h4c | 现在 | 证书现在自动续期吗 | 1 | - | 不变 |
|
|
88
|
+
|
|
89
|
+
**成对准确率 4/4 = 1.00。** 但这 4 对题的证据强度见「这份评测容易高估你的地方」——
|
|
90
|
+
**4 对题、一对值 0.25,是抛硬币级别的证据**,别拿它当「历史检索解决了」的证明。
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 改动 2(字表收敛):第一版字表把实词一起滤掉了
|
|
95
|
+
|
|
96
|
+
这条按你的要求留着,包括它是我的错报、你的修复。
|
|
97
|
+
|
|
98
|
+
### 上一轮发生了什么
|
|
99
|
+
|
|
100
|
+
改动 3 的第一版 `CJK_FUNCTION_CHARS` 里有 `有`、`不`、`要`、`得`。它们是高频字,看着像虚字,实际不是:
|
|
101
|
+
|
|
102
|
+
| 问句里的词 | 被切成的 bigram | 第一版字表的后果 |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| 所**有**项目 | `所有` / `有项` | 两个都丢(`有` 在表里) |
|
|
105
|
+
| 不**要**构建步骤 | `不要` / `要构` | 丢(`要` 在表里) |
|
|
106
|
+
| **不**用 sqlite | `不用` | 丢(`不` 在表里) |
|
|
107
|
+
|
|
108
|
+
而 `所有` 正是 e1「我是不是定过**所有**项目都要零依赖」在问的东西。于是 e1 从第 1 掉到第 3:
|
|
109
|
+
|
|
110
|
+
| 轮次 | #1 | #2 | #3 | 期望卡 |
|
|
111
|
+
|---|---|---|---|---|
|
|
112
|
+
| 第三轮(宽字表) | c-20260912-0030 **5.367** | c-20261020-0012 4.899 | c-20260520-0003 **4.808** | 第 3 名 |
|
|
113
|
+
| 本轮(收敛后) | c-20260520-0003 **7.272** | c-20260912-0030 5.358 | c-20261020-0012 4.883 | **第 1 名** |
|
|
114
|
+
|
|
115
|
+
**这是这条规则真正的成本**:它不是「噪声 vs 实词」的干净二分,`有` / `不` / `要` / `得` 既出现在虚词里
|
|
116
|
+
(`我有`、`了没`),也出现在实词里(`所有`、`不用`、`所有 DSH 插件`)。
|
|
117
|
+
按字做判断就必然在这一类字上犯错,只能选偏向哪一边。
|
|
118
|
+
|
|
119
|
+
### 收敛后的实测
|
|
120
|
+
|
|
121
|
+
字表从 39 字减到 36 字(拿掉 `有` `不` `得`,保留 `要`——它在实际出现的 bigram 里都是情态:`都要` / `要不要` / `要零`)。
|
|
122
|
+
当前实际的 tokenize 结果:
|
|
123
|
+
|
|
124
|
+
| 输入 | 现在切出 | 判断 |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `所有` | `所有` | **实词,保住了**(就是 e1 恢复的原因) |
|
|
127
|
+
| `有项` | `有项` | 实词(`所有项目` 的另一半),保住 |
|
|
128
|
+
| `不用` | `不用` | 实词,保住 |
|
|
129
|
+
| `都要` | `(空)` | 噪声,靠 `都` 丢掉 |
|
|
130
|
+
| `要不要` | `(空)` | 噪声,靠 `要` 丢掉 |
|
|
131
|
+
| `几个` | `(空)` | 噪声,丢掉 |
|
|
132
|
+
| `有记` | `有记` | **噪声,回来了**(`有` 不再是功能字) |
|
|
133
|
+
| `到底` | `到底` | 噪声,一直在(`到` `底` 都不在表里) |
|
|
134
|
+
| `部署` / `零依赖` | `部署` / `零依 依赖` | 实词,保住 |
|
|
135
|
+
|
|
136
|
+
**代价是明确的:噪声覆盖从 10/10 退回 9/10**(`有记` 又进索引),换来 `所有` / `有项` / `不用` 不被误杀。
|
|
137
|
+
这条规则不可能两头都赢,所以我把它写成「按字分类的规则有固有取舍」,
|
|
138
|
+
而不是「改动 3 已经完美」。上一轮那句「不含表内字的噪声照样留着」现在要更准确地说:
|
|
139
|
+
**含表内字的噪声也不再全丢,因为表变小了。**
|
|
140
|
+
|
|
141
|
+
### 顺手带出来的:k6 的 0.019
|
|
142
|
+
|
|
143
|
+
| 卡 | 本轮 | 上一轮 |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| c-20260425-0026(正确答案) | 4.224 #1 | 4.256 #1 |
|
|
146
|
+
| c-20260512-0016(干扰卡) | 4.205 #2 | 4.128 #2 |
|
|
147
|
+
|
|
148
|
+
k6 仍然第 1,但余量从 0.128 掉到 **0.019**:`不` 从功能字里拿掉之后,`不用` 这个 bigram 回到索引,
|
|
149
|
+
而 0016 的正文里有这类措辞,于是它涨了 0.077。
|
|
150
|
+
**keyword 组的 1.00 现在是 0.019 撑着的。** 再动一次字表,这一题就可能翻过去——
|
|
151
|
+
这不是把它算成弱点,是提醒读分的人:余量 0.019 的 1.00 和余量 1.9 的 1.00 不是一回事。
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 改动 4 的第二版:history 意图下不跑 supersedes 前向拉取
|
|
156
|
+
|
|
157
|
+
上一轮的诊断是三行对照,现在拿同一对照验收:
|
|
158
|
+
|
|
159
|
+
| 语料 / 代码 | #1 | #2 |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| 上一轮(拉取照跑) | 新卡 c-20261102-0035 **13.773** | 老卡 c-20260110-0036 9.001 |
|
|
162
|
+
| 上一轮(拆掉 supersede 边,仅作诊断) | 老卡 c-20260110-0036 **9.001** | 新卡 c-20261102-0035 5.355 |
|
|
163
|
+
| **本轮(history 时跳过拉取)** | **老卡 c-20260110-0036 8.977 #1** | 新卡 c-20261102-0035 5.347 #2 |
|
|
164
|
+
|
|
165
|
+
第三行与诊断时拆边的数字几乎重合(9.001 / 5.355 对 8.977 / 5.347,0.024 的差来自拉取链上另一张卡的边角分)。
|
|
166
|
+
**这说明修复拿掉的正是那 8.1 分的拉取加成,不是把线挪开**——老卡自己的分从头到尾就是 9 分左右,
|
|
167
|
+
上一轮那个 13.773 里有一大半不是它的。
|
|
168
|
+
|
|
169
|
+
history 组因此 3/4 → 4/4 = 1.00,退出码从 1 变 0;时序规则仍 5/5,问现状四侧的老卡仍全部掉出前五。
|
|
170
|
+
**两头方向都保住了,这才是这条开关做对的样子。**
|
|
171
|
+
|
|
172
|
+
### 但 t4 的 0.14 仍然是「判据内的过」
|
|
173
|
+
|
|
174
|
+
| 名次 | 卡 | 得分 |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| #1 | c-20261005-0011(讲遗忘机制的元卡,`方案` df = 1) | 4.220 |
|
|
177
|
+
| #2 | c-20260715-0006(期望的老卡) | **2.844** |
|
|
178
|
+
| #3 | c-20260802-0007(继任卡) | 2.704 |
|
|
179
|
+
|
|
180
|
+
老卡比继任卡高 0.14,比上一轮的 0.074 稳了一倍,但 #1 依然是那张无关卡——**弱点 6 一点没变,别写成已修**。
|
|
181
|
+
t4 的判据只查「旧卡别被新卡压下去」,照旧会放过「压了 0.14、但前面还有一张不相干的卡」这种情形。
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 弱点 7 的第二次攻击:1/10 漏检
|
|
186
|
+
|
|
187
|
+
同样的 10 条变体,一字未改,重跑:
|
|
188
|
+
|
|
189
|
+
| 变体 | 正则 | 老卡名次 | 现在返回的 #1 |
|
|
190
|
+
|---|---|---|---|
|
|
191
|
+
| 上一套监控是什么样的 | 命中 | **1** | 老卡 c-20260530-0027(superseded)3.86 |
|
|
192
|
+
| **先是用 Zabbix 的吧** | **没命中** | 2 | 新卡 c-20260706-0028 3.78 |
|
|
193
|
+
| 那会儿是怎么弄的 | 命中 | - | 0.050 兜底 |
|
|
194
|
+
| 起初的方案是什么 | 命中 | - | c-20261005-0011 4.22(弱点 6) |
|
|
195
|
+
| 当年用的是什么 | 命中 | - | 0.050 兜底 |
|
|
196
|
+
| 从前的做法还记得吗 | 命中 | - | 0.050 兜底 |
|
|
197
|
+
| 老版本的监控在哪 | 命中 | **1** | 老卡 c-20260530-0027(superseded)3.86 |
|
|
198
|
+
| 换方案之前怎么弄的 | 命中 | - | c-20261005-0011 4.22(弱点 6) |
|
|
199
|
+
| 回头查一下旧的做法 | 命中 | - | 0.050 兜底 |
|
|
200
|
+
| 最早那套监控是什么 | 命中 | **1** | 老卡 c-20260530-0027(superseded)3.86 |
|
|
201
|
+
|
|
202
|
+
**10 条里 9 条命中,还剩 1 条:`先是用 Zabbix 的吧`。** 正则里有 `一开始`,没有 `先用`。
|
|
203
|
+
我**没有**为了这一条再加词:加了 `先用` 之后还会有 `先搞的`、`最早先`、`当初先`。
|
|
204
|
+
|
|
205
|
+
三个要照实说的地方:
|
|
206
|
+
|
|
207
|
+
1. **命中正则不等于能答到。** 10 条里 4 条虽然命中,返回仍是 0.050 兜底
|
|
208
|
+
(`那会儿是怎么弄的`、`当年用的是什么`、`从前的做法还记得吗`、`回头查一下旧的做法`):
|
|
209
|
+
它们的内容词全被判成虚字(`那会` / `当年` / `从前` / `回头` / `的做法`),一个实词不剩。
|
|
210
|
+
意图开关只能决定「旧卡要不要打折」,救不了「这句话里没有可检索的词」。
|
|
211
|
+
2. **2 条命中了但答案被弱点 6 吃掉**:`起初的方案是什么`、`换方案之前怎么弄的` 都返回那张 `方案` 元卡 4.22。
|
|
212
|
+
历史侧真正的两个障碍是「意图」和「稀有实词抢位」,不是一个开关能一起解决的。
|
|
213
|
+
3. **只有 3 条真把老卡顶到第 1**:`上一套监控`、`老版本的监控`、`最早那套监控`——
|
|
214
|
+
共同点是老卡的独占词(`Zabbix` / `监控`)出现在问句里。这 3 条能过,一半功劳在词面,不全是正则。
|
|
215
|
+
|
|
216
|
+
### 反向误触发的复测:修好一个,暴出一个(见弱点 8)
|
|
217
|
+
|
|
218
|
+
| 问句 | 正则 | 本轮结果 | 上一轮 |
|
|
219
|
+
|---|---|---|---|
|
|
220
|
+
| 原来 Kuma 只做外部拨测啊(现状) | **不命中** | 新卡 **12.228** #1,老卡 1.850 掉出前二 | 12.240 对 **12.196**,差 0.044 |
|
|
221
|
+
| 监控之前那套 Kuma 还留着吗(现状) | 命中 | **老卡 7.191 #1**,新卡 7.159 #2 | 未测 |
|
|
222
|
+
| 备份之前先跑 restic check 吗(现状) | 命中 | 0032 11.219 #1(正确答案是 active 卡,无害) | 11.09 |
|
|
223
|
+
|
|
224
|
+
「单独拿掉 `原来`」这一手是对的:老卡从 12.196 掉到 1.850,反噬消失,代价是真要问
|
|
225
|
+
「原来那套监控是什么」得靠更窄的 `原来那`(正则里有,实测可用)。
|
|
226
|
+
但同一轮里 `之前` 这条暴出了新问题,见下。
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 弱点 8(本轮新加):「还留着吗」这类现状提问被读成历史
|
|
231
|
+
|
|
232
|
+
| 名次 | 卡 | 得分 | 状态 |
|
|
233
|
+
|---|---|---|---|
|
|
234
|
+
| #1 | c-20260530-0027 监控从 Zabbix 换到 Uptime Kuma | **7.191** | superseded |
|
|
235
|
+
| #2 | c-20260706-0028 监控换成 Prometheus + Grafana,Uptime Kuma 只留外部拨测 | **7.159** | active |
|
|
236
|
+
|
|
237
|
+
问句是「监控**之前**那套 Kuma **还留着吗**」。这句话问的是**现在还在不在**,
|
|
238
|
+
`之前` 在这里是定语(「之前那套」),不是时间状语。正则看到 `之前` 就当成历史,于是:
|
|
239
|
+
老卡从 0.15 放行到 1.0,**以 0.032 之差把正确答案压到第 2**。
|
|
240
|
+
0.032 的错答比漏检严重得多——漏检时用户看到 0.05 的兜底,知道没找到;
|
|
241
|
+
这里用户看到的是一个**语气确凿的错误答案**。
|
|
242
|
+
|
|
243
|
+
这不是 `之前` 一个词的毛病,是**二值意图判断的结构性代价**:
|
|
244
|
+
|
|
245
|
+
- `之前`、`当时`、`原来` 在中文里既能做时间状语(「之前怎么弄的」)也能做定语(「之前那套」);
|
|
246
|
+
- `那套`、`还留着`、`还在用` 是强现状信号,正则完全不看;
|
|
247
|
+
- 更根本的是:**「问过去还是问现在」几乎从来不是二值的**。「以前那套现在还留着吗」同时问了两个时间点。
|
|
248
|
+
|
|
249
|
+
上一轮我预言过这个形状(「一个这样的副词就能把作废卡放大 6.67 倍,这两条之所以没翻只是运气」)。
|
|
250
|
+
`原来` 那条救回来了,`之前` 这条翻了——**同一枚硬币,只是换了个面。**
|
|
251
|
+
|
|
252
|
+
修的方向(没动,等你定):
|
|
253
|
+
|
|
254
|
+
- 加**现状信号否决**:问句里出现 `还` / `还在` / `还有` / `现在` / `目前` 时,历史意图不成立,
|
|
255
|
+
或退化成「旧卡不加权、但允许出现」;
|
|
256
|
+
- 或者不做二值判断,把整条 supersede 链一起返回、链内按时序排列,让读者自己看两版——
|
|
257
|
+
这也更符合 c-20261005-0011 里写的那条设计原则(「旧方案还能查到,只是压在新方案下面」)。
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 题外探针:6 条,本轮实测
|
|
262
|
+
|
|
263
|
+
| 探针 | 库里有没有 | 本轮返回 | 与上一轮 | 判定 |
|
|
264
|
+
|---|---|---|---|---|
|
|
265
|
+
| Loki 日志留几天 | 有 | #1 c-20261030-0034,13.10 | 13.04 | 命中 |
|
|
266
|
+
| tailscale 现在还在用吗 | 有 | #1 c-20261027-0033,6.32 | 6.37 | 命中 |
|
|
267
|
+
| 那个 VPS 到底几个核 | 有 | #1 c-20260425-0026,2.94 | 2.97 | 命中(`到底` 仍是噪声,靠 `vps` 撑住) |
|
|
268
|
+
| 备份到底做了没有 | 有 | #1 c-20261016-0032 5.39,#2 c-20260320-0025 3.43 | 5.36 / 3.41 | 灰区:卡找对了,库里没记「跑成功了没有」 |
|
|
269
|
+
| 我有没有记过 Kubernetes 集群的部署流程 | **没有** | #1 c-20260708-0018,3.71 | 3.71 | **误报** |
|
|
270
|
+
| 评论区的字体是什么 | **没有字体这条** | #1 c-20260512-0016,4.29 | 4.27 | **判据灰区,不是检索问题** |
|
|
271
|
+
|
|
272
|
+
四条结论与上一轮一致:
|
|
273
|
+
|
|
274
|
+
- **Kubernetes 那条是真误报**:3.71 分,命中的是「部署靠 GitHub Actions」,只共享 `部署` 一个词,
|
|
275
|
+
库里没有一张 K8s 的卡。判据(`>= 0.5`)判它误报是对的。
|
|
276
|
+
- **字体那条是判据灰区**:`c-20260512-0016` 就是评论区那张卡(entities 里有 `评论`),排第 1 是**正确行为**;
|
|
277
|
+
38 张卡里没有一张提字体,前五也没有。这不是「找到了错的东西」,是「找到了对的东西,但那东西答不了这个问题」。
|
|
278
|
+
`>= 0.5 记为误报` 区分不了这两种情况,我没有为了让 p6 过而抬线(抬到 4.3 会让 p1 的 13.10 一起被埋)。
|
|
279
|
+
- `有记` 的回归没有在本轮探针里造成新误报(p5 与上一轮同分 3.71),但它进索引这件事是真的。
|
|
280
|
+
- **6 条里 3 命中、1 灰区、1 真误报、1 判据灰区。**
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 仍然存在的弱点
|
|
285
|
+
|
|
286
|
+
### 1. 噪声 bigram 靠「含虚字」过滤——两版都只是近似
|
|
287
|
+
|
|
288
|
+
第一版按字滤,把 `所有` / `不用` 一起滤掉了(改动 2 修了,代价是 `有记` 回来)。
|
|
289
|
+
现状:不含表内字的噪声(`到底`、`有记`、`先用`)照样进索引;含表内字的实词也可能被误杀。
|
|
290
|
+
这是近似规则的固有毛边,不是实现 bug。
|
|
291
|
+
|
|
292
|
+
### 2. 作废与继任者的方向——两侧都对了,但开关的判定不可靠
|
|
293
|
+
|
|
294
|
+
问现状时旧卡被压住(0.15 + 拉取),问历史时旧卡放行且不拉取(本轮修好),history 组 4/4。
|
|
295
|
+
剩下的不是「方向错」,而是「开关读不准」——见弱点 7、8。
|
|
296
|
+
另外 `c-20261005-0011` 正文写的「superseded 打 0.4 的折扣」与代码里的 0.15 早已不一致,
|
|
297
|
+
fixture 文本冻结,这里只记录:**文档与实现脱节,读者会按 0.4 理解。**
|
|
298
|
+
|
|
299
|
+
### 3. 一跳扩展权重太小,扩展出来的卡只能当陪跑(未动)
|
|
300
|
+
|
|
301
|
+
`0.25 × 种子分 × 实体覆盖率` 的量级,让 `via: linked:` 的结果稳定落在 0.5 一档。
|
|
302
|
+
看 t2 现在的排序:#2 是 3.78(正文命中),而 #3 0.91、#4 0.58、#5 0.53 全是 `linked:`——
|
|
303
|
+
扩展能**找到**东西,但永远挤不进前两名的量级。
|
|
304
|
+
|
|
305
|
+
### 4. 缺「最早 / 首次出现」信号(未动)
|
|
306
|
+
|
|
307
|
+
问「写作偏好这条最早是在哪里记下来的」,靠实体相连的正确答案 8.265 分,标题里直接含该词的卡 **9.686** 分排第一:
|
|
308
|
+
|
|
309
|
+
| 卡 | 得分 | 为什么 |
|
|
310
|
+
|---|---|---|
|
|
311
|
+
| c-20260811-0019 | 9.686 | 标题含 `写作偏好`,×3 权重 |
|
|
312
|
+
| c-20261029-0013 | 8.265 | 只在 entities 里出现一次,×1 权重 |
|
|
313
|
+
|
|
314
|
+
`最早` 现在能让 `HISTORY_INTENT` 命中、把老卡从 0.15 里放出来,但「哪张更早」仍然没有任何信号——
|
|
315
|
+
t4 里老卡只是恰好比继任卡高 0.14。**意图开关解决的是「要不要打折」,不是「谁更早」。**
|
|
316
|
+
|
|
317
|
+
### 5. recency 下限 + 共享实体 idf 偏低,最老的跨项目卡沉底(未动)
|
|
318
|
+
|
|
319
|
+
问「esm 这个选择在几个项目里一致吗」,期望三张卡里最老的 c-20260310-0014(237 天前)
|
|
320
|
+
只命中 `esm` 一个 token(df = 4,idf 低),乘 recency 下限 0.55 后 **1.244**,排第 5;
|
|
321
|
+
第 1 名 c-20261020-0012 拿 4.883。三轮下来这张卡是 6 → 5 → 5,1.19 → 1.24 → 1.24:
|
|
322
|
+
**没坏,也确实没动。**
|
|
323
|
+
|
|
324
|
+
### 6. 稀有实词压过内容卡(未动,本轮更显眼)
|
|
325
|
+
|
|
326
|
+
`方案` 在全语料 df = 1,只出现在 c-20261005-0011(讲「retracted 和 superseded 是降权不是删除」的机制卡)里,
|
|
327
|
+
出现两次。只要问句含 `方案`,这张**讲遗忘机制的元卡**就排第一:
|
|
328
|
+
|
|
329
|
+
| 题 | #1 | #2 |
|
|
330
|
+
|---|---|---|
|
|
331
|
+
| t2 监控现在到底是什么方案 | c-20261005-0011 **4.220** | c-20260706-0028(真正的答案)3.78 |
|
|
332
|
+
| t4 最早那版抽取方案是什么 | c-20261005-0011 **4.220** | c-20260715-0006(期望的老卡)2.844 |
|
|
333
|
+
| 探针·起初的方案是什么 | c-20261005-0011 **4.22** | 老卡不在榜上 |
|
|
334
|
+
|
|
335
|
+
它是 active 卡,分数不受任何乘数影响,两轮里 4.038 → 4.247 → 4.220,稳定压住真答案。
|
|
336
|
+
**一个词只要足够稀有,就能压过整句的主题**——df = 1 的短词是这个 BM25 配置的真实弱点。
|
|
337
|
+
|
|
338
|
+
### 7. 历史意图靠正则枚举:漏检 7/10 → 1/10,但机制没变(已扩,仍有漏)
|
|
339
|
+
|
|
340
|
+
上一轮 7/10 漏,本轮 1/10 漏(`先用`)。数字好看多了,但**设计没变**:还是一张照失败反推的词表,只是从 24 项扩到 33 项。
|
|
341
|
+
|
|
342
|
+
| 攻击轮次 | 词表规模 | 漏检 | 老卡进第 1 |
|
|
343
|
+
|---|---|---|---|
|
|
344
|
+
| 第三轮 | 24 项 | 7/10 | 3/10 |
|
|
345
|
+
| 第四轮 | 33 项 | **1/10** | 3/10 |
|
|
346
|
+
|
|
347
|
+
再加一批新人写的变体,第五次会漏几个我不知道——上一轮我也以为补完就够了。
|
|
348
|
+
具体剩下的问题:10 条里 4 条命中却仍 0.050 兜底(内容词全被判成虚字),2 条被弱点 6 抢位,
|
|
349
|
+
3 条真靠老卡独占词过。**「命中 9/10」和「答对 3/10」是两个数字。**
|
|
350
|
+
|
|
351
|
+
### 8. 「还留着吗」这类现状提问被读成历史(本轮新加)
|
|
352
|
+
|
|
353
|
+
见上面整节:`监控之前那套 Kuma 还留着吗` → 老卡 7.191 第 1、正确答案 7.159 第 2,差 0.032。
|
|
354
|
+
根因是二值意图判断 + 完全没有现状信号否决。**这是四轮里唯一一处「修复引入的新错误」**:
|
|
355
|
+
`原来` 的误触发被拿掉了,`之前` 的误触发就露出来了。
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## 能用的部分(别把上面的问题看过头)
|
|
360
|
+
|
|
361
|
+
- 有关键词支撑的短问句,recall@1 和 recall@5 都是 1.00:k1 到 k9 全部第一(k6 余量 0.019)。
|
|
362
|
+
- 跨项目实体在 token 够独特时拉得动:e1 恢复第 1(7.272),e2 / e3 / e4 各返回两张卡排在第 1、2 位。
|
|
363
|
+
- 问现状这一类是干净的:h1c / h2c / h3c / h4c 四条全部第一,四个老卡全部掉出前五。
|
|
364
|
+
- 问历史这一类也过了:h1h / h2h / h3h / h4h 四条老卡全部第 1、对侧新卡第 2(不再有拉取加成)。
|
|
365
|
+
- retracted 卡(c-20260820-0008)在 25 条题 + 8 条 history 题的前五里一次都没出现;
|
|
366
|
+
`limit` 放到 25 才在第 9 位出现,得分 0.000。撤回语义四轮都稳。
|
|
367
|
+
- 「什么都没找到」这条路是通的:n1 到 n5 全部退回 0.050 兜底。
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 这份评测容易高估你的地方
|
|
372
|
+
|
|
373
|
+
这一节给读分数的人看,不是给写检索的人看。
|
|
374
|
+
|
|
375
|
+
- **history 组 4 对 = 抛硬币级别的证据。** 一对值 0.25,门槛 0.8 意味着「最多错一对」。
|
|
376
|
+
上一轮 0.75 是因为错了 h3,本轮 1.00 是因为那一对修好了——**中间只差一道题**。
|
|
377
|
+
这个 1.00 不能读作「历史检索解决了」,只能读作「我们知道的那 4 对里没有反例」。
|
|
378
|
+
想要有意义的数字至少 20 对,而这 4 对还是我自己挑的主题。
|
|
379
|
+
- **4 对里有 3 对(h1 / h2 / h4)靠老卡独占词过关**,只有 h3(共享整个主题词 `告警`)真正在测机制。
|
|
380
|
+
也就是说 4 对题的有效信息量接近 1 对。
|
|
381
|
+
- **fixture 是我和你共同设计的,第三轮我还往里加了 3 张卡。** 真实 vault 不会这么整齐。
|
|
382
|
+
能自我安慰的一点:38 卡与 35 卡在原 25 条上逐题名次完全一致。
|
|
383
|
+
- **8 条 history 题是我在看完成对判据之后写的**:写完没改过,但「老卡 vs 继任卡」这个结构
|
|
384
|
+
本身就是我看到 t4 失败之后才想到的,所以它测的是我已经知道会失败的那一类。
|
|
385
|
+
- **38 张卡,分母很小。** 20 条可答题、一条值 0.05 的总 recall@5;每类 5 到 9 条,一条题就是 0.11 到 0.20 的类内分。
|
|
386
|
+
entity-bridge 从 0.50 到 0.67 只是 e1 一题回来。
|
|
387
|
+
- **单题余量比类内分数更值得看。** k6 的 1.00 是 0.019 撑着的,t4 的「过」是 0.14 撑着的,
|
|
388
|
+
e5 的第 2 是 1.42 的差距,e6 的第 5 差 3.6 分。同一张 1.00 的表里,四个「通过」的稳固程度差两个数量级。
|
|
389
|
+
- **negative 只有 5 条,1 条误报就是 20%。** 这 5 条正好是修复时被参考过的措辞;新写的 negative 探针仍有 1 条误报。
|
|
390
|
+
0/5 是「规则覆盖到了这 5 条」,不是「negative 问题解决了」。
|
|
391
|
+
- **总分对单题退步不敏感。** 第三轮 e1 掉到第 3、keyword 涨到 1.00,总分看起来一片大好,两者是同一处改动造成的;
|
|
392
|
+
这一轮反过来,e1 回来、k6 余量掉到 0.019,也抵消在同一个 0.80 里。
|
|
393
|
+
- **门槛和判据都是任意的。** 0.8、`<= 1`、negative 的 0.5 分线、时序题的「旧卡不得压过继任者」、
|
|
394
|
+
history 的「对侧卡不得压过期望卡」,都是按这份语料的分数量级定的。换语料要重新看一眼这几条线。
|
|
395
|
+
- **这轮的正则扩充是看着上一轮的 10 条失败写的。** 9/10 里有我自己的信息泄漏:
|
|
396
|
+
下一批 10 条变体(不是我写的)会掉到多少,这份报告给不出来。
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## 改进优先级
|
|
401
|
+
|
|
402
|
+
1. **二值意图判断换成连续先验 + 现状信号否决**(弱点 7 + 8):`还` / `还在` / `还有` / `现在` / `目前` 出现时
|
|
403
|
+
历史意图不成立;`之前` / `当时` 这类两可词不该单独决定方向。或者干脆不做判断,
|
|
404
|
+
把整条 supersede 链一起返回、按时序排。这是唯一一处「错答」级别的缺陷,优先级高于其他所有项。
|
|
405
|
+
2. **稀有短词的 idf 上限**(弱点 6):给 df = 1 的 token 封顶,或要求至少两个 token 命中才算有效命中。
|
|
406
|
+
同时压住 0011 元卡对 t2 / t4 / 两条历史变体的干扰,也顺带缓解「评论区的字体」那种判据灰区。
|
|
407
|
+
3. **答案充分性判据**(替代 negative 的 0.5 线):要求问句的话题实体在命中卡里出现,
|
|
408
|
+
才能把「话题命中但没答案」与「完全无关却高分」分开。
|
|
409
|
+
4. **历史问句的两段式处理**(弱点 7 里那 4 条 0.050 兜底):时间词只用于意图判断、不参与匹配,
|
|
410
|
+
剩下的内容词再走向量/词面匹配,而不是在同一套 token 里解决。
|
|
411
|
+
5. **抬高扩展分**(弱点 3):`0.25` 提到 `0.5` 以上,或给 `via: linked:` 留固定保底名额。
|
|
412
|
+
6. **实体命中加权**(弱点 4、5):entities 里的 token 权重从 1 提到 2。
|
|
413
|
+
7. **recency 下限 0.55 抬到 0.7**,或只在分数接近时当 tie-break。
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## 复现
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
node eval/seed.mjs # 只建 fixture 并打印摘要,目录保留
|
|
421
|
+
node eval/run.mjs # 跑分;不合格时保留 vault 并打印路径,退出码 1
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
`run.mjs` 判三块:原 25 条 recall@5 >= 0.80、negative 误报 <= 1、history 成对准确率 >= 0.8。
|
|
425
|
+
**当前状态:三块全过,退出码 0,临时 vault 自动清理。**
|
|
426
|
+
|
|
427
|
+
## 附:四轮改动一览(`eval/` 里改过什么)
|
|
428
|
+
|
|
429
|
+
| 轮次 | `seed.mjs` | `questions.json` | `run.mjs` |
|
|
430
|
+
|---|---|---|---|
|
|
431
|
+
| 第一轮 | 建 fixture(35 卡 / 2 链) | 25 条(keyword 9 / entity-bridge 6 / temporal 5 / negative 5) | 打分、判定、miss 明细 |
|
|
432
|
+
| 第二轮 | 未动 | 未动(`STOPWORDS` 在 `src/`,不在我的范围) | 未动 |
|
|
433
|
+
| 第三轮 | +3 卡、+2 链(告警渠道 / 证书续期)→ 38 卡 / 4 链 | +8 条 `kind: "history"`(4 对)+ legend | 成对准确率、独立门槛、3 条 history 自检 |
|
|
434
|
+
| 第四轮 | **未动** | **未动** | **未动**(只重跑 + 重写这份报告) |
|
|
435
|
+
|
|
436
|
+
第四轮我没碰 `eval/` 里任何代码:题、期望卡、`demote`、门槛、fixture 全部冻结,这一轮只是验收。
|
|
437
|
+
`src/` 四轮都没动过(改动 2 / 3 / 4 都是你改的,我只测)。
|