idea_world_labDEV JOURNAL
2026年6月28日星期日

方案 B:仅使用 BM25

流程

原始 chunkText
  -> tokenizer
  -> BM25
  -> 返回 top JSONL

BM25所看到的

BM25大致通过以下要素来计算得分。

TF: 在此文档中单词出现了多少次  
IDF: 在整个语料库中该单词有多稀少  
Length normalization: 对长文档进行校正,使其不会自动占优势

所以基准块的后续单词变得重要。

animatedsprite2d
is_action_pressed
move_left
move_right
normalized
clamp
screen_size
vector2
zero

在基准块中成功的原因

在原始笔记的模拟中,以下文档会出现在上方。

outputs/godot_docs_full/pages/getting_started__first_2d_game__03.coding_the_player__161d377b.md

直接匹配的令牌如下。

animatedsprite2d
is_action_pressed
move_left
move_right
normalized
play
stop
input
speed
length
velocity
vector2
zero

特别是以下标记在语料库中较为罕见,因此对得分贡献很大。

animatedsprite2d
move_left
move_right
is_action_pressed
screen_size
clamp

失败候选

在 BM25 only 中,也可能出现 3D movement 文档。

原因是以下公共标记。

Input.is_action_pressed
move_right
move_left
normalized
speed

但是基准块是二维的,以下线索很重要。

AnimatedSprite2D
Vector2
position.clamp
screen_size

BM25是基于词分数的,因此无法完全理解2D/3D上下文。

PoC 模拟

将基准 chunk 作为 BM25 查询输入。

输入:

func _process(delta):
  Input.is_action_pressed(...)
  velocity.normalized() * speed
  $AnimatedSprite2D.play()
  position.clamp(Vector2.ZERO, screen_size)

BM25会给出高分的词元:

animatedsprite2d
is_action_pressed
move_left
move_right
normalized
clamp
screen_size
vector2
zero

预计候选:

排名 候选 为什么出现 判断
1 first_2d_game / coding_the_player Input.is_action_pressedmove_leftmove_rightvelocity.normalizedAnimatedSprite2D.play/stop 直接匹配 accept
2 first_2d_game / clamp/screen section position.clampVector2.ZEROscreen_sizeAnimatedSprite2D 匹配 accept
3 first_3d_game / player_movement_code Input.is_action_pressedmove_leftmove_rightnormalizedspeed 重叠 false positive

第 1 名候选上榜的原因:

animatedsprite2d:
  在整个文档中很少出现的 token,因此 IDF 很大

move_left / move_right:
  在教程输入代码中直接出现

is_action_pressed:
  与输入处理代码直接匹配

velocity.normalized:
  与移动向量归一化流程直接匹配

3位候选人一起出现的原因:

3D movement 文档也说明了输入处理和归一化移动流程。  
因此在 BM25 的视角下,query token overlap 相当大。  
但这与基准 chunk 的核心——AnimatedSprite2D、Vector2、screen_size、position.clamp——并不匹配。

PoC中确认的日志

在 BM25 PoC 中,展示每个候选项的 token 贡献度是很重要的。

示例:

candidate: first_2d_game / coding_the_player
matched_terms:
  animatedsprite2d   high
  is_action_pressed  high
  move_left          high
  move_right         high
  normalized         medium
  play               medium
  stop               medium

candidate: first_3d_game / player_movement_code
matched_terms:
  is_action_pressed  high
  move_left          high
  move_right         high
  normalized         medium
missing_terms:
  animatedsprite2d
  screen_size
  position.clamp

眼前的结论:

BM25 能很好地检索相关文档。  
但是也会一起检索到相似的输入/移动代码。  
因此在 BM25 的下一阶段需要 reranker 或 validator。

优点

  • 原理透明。
  • 调试容易。
  • 没有模型费用。
  • 可以直接使用原始块。
  • 对代码/API 精确字符串搜索很强。

缺点

  • 对同义词和说明文弱。
  • 如果 API 名称未直接出现可能会错过。
  • 像 3D movement 这样的相似代码可能会混入误报。

判定

必须审查的第一候选搜索  
但是单独使用不足