关键词检索的三个打分缺陷

**「只在标题级文本里做 substring 匹配、按 token 长度打分、中文按整句切分」这三件事叠加,会让检索只在「提问措辞恰好出现在标题」时有效;改进顺序是:正文入索引并加字段权重 → IDF → 中文 bigram。**

一、现状的检索长什么样

  1. 分词:取最后一条用户消息,按标点切,token 长度 ≥ 2。纯中文长句基本是整句一刀。
  2. 打分:hay = term + abbr + fullName + oneLiner,命中 token 就 score += token.length。正文完全不参与。
  3. 选取:按分降序取前 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 语义召回(见 检索要按难度迭代)。

相关

  • 检索要按难度迭代(检索的三层:引擎 / 协议 / Agent loop)
  • 长尾查询(搜索源的选择)
  • 上下文按信任等级分层(哪些内容该优先进 context)