关键词检索的三个打分缺陷
一、现状的检索长什么样
- 分词:取最后一条用户消息,按标点切,token 长度 ≥ 2。纯中文长句基本是整句一刀。
- 打分:
hay = term + abbr + fullName + oneLiner,命中 token 就score += token.length。正文完全不参与。 - 选取:按分降序取前 N,再按顺序塞进字符预算。
二、因此会哑火的场景
- 答案在正文里但标题没有 → 命中 0 条(例如问"怎么找到用户真正想要的东西",正文有 job story,标题没有)。
- 中文近义改述("目标用户画像" vs "典型用户长什么样")匹配不上。
- 长 token 天然占优(按长度加权),且同一 token 重复命中不重复加分 ——
"JTBD JTBD JTBD"和"JTBD"同分。 - 完全没有 IDF:到处出现的"用户"和稀有的"job story"权重一样。
三、分级改进
L1(纯代码,零新依赖,收益最大)
- 索引字段扩到
+ body + points;标题命中 ×3、正文命中 ×1,并给单文档贡献设上限,防长词条通吃。 - 引入 IDF:
tf * log(N/df),让高频词降权、稀有词升权。 - 中文改用 bigram(
用户研究→用户/户研/研究),英文小写化 + 简单词干。 - 命中位置和次数都计入,而不是只算一次 substring。
L2(结构化,适合个人知识库体量)
- 每条词条手写
related: id[],或从正文用约定标记自动抽取。 - 当前词条的相关词条永远优先进 context,关键词检索只补剩余槽位。质量上限由结构决定,而不是靠运气匹配。
仍未解决的:L1/L2 都是词面匹配,同义改述依旧召回不到 —— 那需要 embedding 语义召回(见 检索要按难度迭代)。