AI 查询召回失准 · 容器词自指与命中率区分度
入档:2026-08-24 来源:蛛网之上(tiaozhuxiansheng.com)知识库 AI 查询「小织」的召回质量整治,由用户一张截图触发,四个提交(790daea…ed0aae3)全部上线并线上验证 状态:已上线;八道真实问题在 442 篇真实索引上逐条比对,本地与线上一致
一句话总结
读者问「这个知识库里有哪些关于 Midjourney 的笔记」,召回的却全是「知识库沉淀与分发」那一类——因为「这个知识库」「笔记」在别处是废话,在这座库里恰恰是强索引词(库里就有讲知识库维护的笔记),它们把六个来源名额全占了。修它靠的不是调 prompt,而是量化:一条检索词命中全库多少比例,就是它有多少区分度——命中 100% 的「prompt」「AI」和命中 90% 的口语碎片「用的」,与命中 12% 的「Suno」不该抢同一个名额。
背景与事实
- 触发点是用户发来的一张截图:小织答「本轮检索到的片段集中在知识库维护、对外分发规范和视频脚本节奏,没有覆盖 Midjourney prompt 技巧的具体内容」。她说的是实话——递到她手上的六篇确实与 Midjourney 无关,而库里明明有 51 篇 prompt 模板库笔记。
- 前篇 AI问答板块收尾_打通判据与小圆头像构图律_v1 解决的是「整句口语提问零命中」,本篇解决的是它的下一章:命中了,但六篇全是错的。
- 全程以真实索引(442 篇)为判据,八道问题逐条比对修前修后;单元测试只覆盖降级规则本身,不能证明召回变好。
- 四个提交依次是:容器词剥离与名额分配 → 整句降级为兜底 + 泛词降级 → 索引页降级 → 全库篇数改用构建期注入。
可复用 insight
1. AI 越诚实,检索故障越隐蔽 ⚠️首次
RAG 系统里,模型老老实实说「现有笔记里没有足够依据」时,第一嫌疑人是检索而不是模型。 这套问答的规矩是「只依据本轮来源作答,没有依据就直说」——规矩执行得越好,故障表现得越像「AI 不行」:用户看到的是一句得体的推辞,看不到递进去的六篇是什么。截图里那句回答挑不出毛病,唯一的破绽是它列举的主题(知识库维护、对外分发)和问的主题(Midjourney)毫无关系,而这恰恰是检索跑偏的指纹。
判据固定成一条:AI 说「没依据」时,先去看递给它的来源清单,再考虑动 prompt。 与 成稿链接存进库没人读_写入方不等于展示方_v1 的「手工兜底掩盖系统缺口」同构——这次替系统兜底的是模型的礼貌。
2. 自指知识库的容器词陷阱 ⚠️首次
问句里描述容器的词——「这个知识库」「笔记」「文章」「关于」——在通用检索里是无害废话,在一座「记录自身如何维护」的知识库里是最强的索引词。 本库有讲知识库沉淀、对外分发、Knowledge Base Curator 工作流的笔记,于是问句里那句客套的「这个知识库里有哪些……的笔记」直接把召回引到那一堆去,真正的检索词一个名额都没抢到。
修法是容器词与口语词同等对待,一起剥;并且要连带剥掉粘在后面的方位词与动词:
- 只剥「知识库」,「知识库里讲工作流的笔记」会剩下
里讲工作流——它命中率只有 8%,看着比工作流(38%)还精准,召回却明显更差。低命中率可能是「罕见的错误组合」,不是「精准」。 - 剥到一个词都不剩时(「知识库里关于 sref 的笔记」),就只认问句里的工具名
sref;一个工具名都没有才退回未剥的词块兜底。 - 守住边界:「笔记的整理方法」剥完仍是
整理方法,不能把正经词吃掉。
3. 命中率是区分度的度量,词长不是 ⭐
一条检索词命中全库多少比例,就是它有多少区分度。 原实现按「词块越长越重要」排序,于是:
| 检索词 | 命中 / 442 | 占比 | 判定 |
|---|---|---|---|
prompt AI 音乐 | 442 | 100% | 泛 |
是用 | 413 | 93% | 泛 |
用的 | 397 | 90% | 泛 |
回事 | 203 | 46% | 泛 |
音乐生成 | 190 | 43% | 泛 |
工作流 | 166 | 38% | 留 |
Skill | 137 | 31% | 留 |
角色一致性 | 85 | 19% | 留 |
Suno | 54 | 12% | 留 |
技巧 | 24 | 5% | 留 |
问 Suno 时,音乐生成(43%)因为比 Suno(12%)长而排在前面,一口气吃掉五个名额。阈值卡在 40%:拦得住口语碎片与 音乐生成,又不误伤 Skill 工作流 这类真词——这条线是数据里的一道空隙,不是拍脑袋。
两条配套:
- 垫后而不是丢掉。 泛词自身的命中排序仍有信息量:搜
prompt的第一条正是《Prompt Master Skill》。丢掉它等于扔掉一个可用名额。 - 都泛的时候彼此再比一次,命中少的先挑。「Skill 是怎么用的?」拆成
用的(90%)和Skill(31%),两个都过线,但后者明显更像个正经词。
排名额的方式也要改:每条查询保底一席,余额再按语义强弱贪心。 纯贪心时排第一的那条会把六个名额一口吃光,别的查询连露面机会都没有。
4. 整句检索对自然语言问句系统性失准 ⚠️首次
长问句被切成许多词,覆盖面广的长文档因为凑齐了更多词而胜出,真正的关键词反被稀释。「库里有没有讲 Suno 音乐生成的笔记?」整句召回六篇,没有一篇讲 Suno(是三篇栏目索引 + Remotion BGM 复盘 + 蒙眼剪辑法);而单搜 Suno 前五篇全对。六道题逐条比对,整句没有一次贡献过有价值的结果。
于是把主次颠倒过来:关键词检索是主力,整句只在关键词全部落空时兜底。
顺带证伪一个性能顾虑:第一次测到「整句要 1.6 秒」,像是长句慢;换个顺序再测,先搜短词 82ms、再搜整句只要 36ms——那 1.6 秒是首次搜索加载索引分片的开销,与句子长短无关。 拿计时下结论前先换一次执行顺序。
5. 索引页是召回污染源,判据落在文件名 ⚠️首次
栏目索引 / MOC 这类页面,正文几乎全是别的笔记的标题——本库五篇索引页最多的一篇有 244 个内链,于是什么词都沾一点。 当导航看很好,当问答依据就是灾难:它挤掉真正讲这件事的笔记,而自身除了标题列表没有可引用的内容。442 篇里只有 5 篇,却在整句检索里占了半壁。
修法:构建期给笔记页标一个 kind 过滤条件,检索先只看正文笔记,凑不满才放开让索引页补位;老索引没有这个条件时第一轮全空,自动回到原行为。
判据落在文件名(以「索引」结尾或名为 *_INDEX),不落在 frontmatter——展示站的 kb-content 是从知识库同步来的外部副本,不该要求内容仓库为展示站加标记。实测 442 篇里正好命中那 5 篇,dws块级插入_index语义陷阱与倒序插入法_v1 这种正文笔记不受影响。
6. 构建期就知道的数,别在运行时查 ⭐
泛词降级要知道「全库多少篇」。这个数绕了三圈才回到原点:
- Pagefind 空查询
search(null)——本地几十毫秒,线上 6 秒(它要把全量文档索引拉下来),首次提问被拖到 14 秒,一题直接超时; - 改走
pagefind.filters()(只读过滤索引)——线上 1.7 秒,并挪到「面板打开时后台预热」; - 线上验证发现预热在真实网络下形同虚设:读者点开面板就提问时它还没就绪,第一个问题永远享受不到这层降级。
而这个数构建期就知道:栏目地图(本来就注入在页面里)的篇数一加就是 442。改成求和后零延迟零请求,顺手删掉预热、WeakMap 缓存那一整套,净减 67 行。
教训是:为一个「运行时才能拿到」的数设计缓存与预热之前,先问它是不是构建期就能算出来。 预热永远救不了第一个请求,而第一个请求恰恰是最多人经历的那个。
7. Pagefind 的 filter 一个属性只能放一个 ⚠️首次
data-pagefind-filter="type:note, kind:note" 不会被解析成两个条件,而是把整条 note, kind:note 当成 type 的值——结果连原来的 type=note 都匹配不上,所有 AI 查询召回全空。逗号不是分隔符,多个 filter 要挂在不同元素上。
排查提示:pagefind.filters() 会把索引里实际认到的 filter 结构原样吐出来,一眼就能看见 {type: {"note, kind:index": 5}} 这种畸形值。过滤条件不生效时,先打印索引方认到的是什么,别从查询侧猜。
顺手教训
- 检索质量只能用真实索引验,单测只覆盖规则本身。 单元测试能钉住「容器词被剥掉」「泛词排后面」,但证明不了召回变好——文档里因此写明了五道验收问题及其应有的召回方向。
- 单一维度排序都会有反例。 中途试过「工具名(拉丁词)一律排最前」,Suno 那题立刻变好,角色一致性那题却变差(
Midjourney太泛,把精准的角色一致性挤到后面)。改用「命中率分档 + 组内保底」才两边都成立。凡是想用一个维度一刀切排序的,先找反例。 - 本地快不等于线上快。 同一次调用本地几十毫秒、线上 6 秒,差在要不要把索引分片拉过网络。涉及「按需加载」的东西,本地计时没有参考价值。
- 自测探针两个坑(已记入项目 memory):CDP 里写的登录态会被站点自己的
prune()在首次readStore()时判掉并写回空,要在页面 ready 之后再写一次;页面内for(600){await sleep(100)}长轮询会被 headless 的后台定时器节流,6 秒完成的事被判成 60 秒超时,改成从 Node 侧每 2 秒采样。
关联文档
- ⭐ AI问答板块收尾_打通判据与小圆头像构图律_v1 —— 直接前篇:那次解决「整句口语提问零命中」,本篇解决「命中了但六篇全错」;两篇合起来才是这套问答的检索全貌
- ⭐ 任务书接AI辅助填写_模型只产草稿与思考额度陷阱_v1 —— 同站 AI 接入的另一条线;「服务端把模型输出当草稿再洗一遍」在本篇的变体是「模型说没依据时先查递进去的料」
- ⭐⭐ 成稿链接存进库没人读_写入方不等于展示方_v1 —— 「手工兜底掩盖系统缺口」同族:那次替系统兜底的是人手写的交付情况,这次是模型的礼貌推辞
- 静态站接账号系统_内容归git状态归库的双源切分_v1 —— 同站架构基座;本篇的「构建期注入而非运行时查」是那条「正文归 git、状态归库」在检索参数上的延伸
- 小织的人设与记忆_承诺要代码兜住而非模型自律_v1 —— 同轮姊妹篇:同一个助手的人设、助产式对话与登录后记忆