一个几乎所有人都会犯的错要把代码切成块(chunk)喂给向量模型,最"专业"的做法是什么?大多数工程师的第一反应是:按 AST(抽象语法树)切,一个函数一个 chunk。理由很硬——函数是最自然的语义单元,AST 精确对齐了语义边界,不会把一个函数拦腰截断。相比之下,按固定行数硬切(比如每 20 行一块)显得又土又蠢,会把函数切得七零八落。听起来无懈可击。可实验数据把这个直觉打了个响亮的耳光。在同一份 266 行的 Python 代码上,我跑了三种 Chunking 策略。结果是:AST 函数级分割的得分最低。那个"又土又蠢"的固定行分割,反而拿了满分。这不是随机噪声,背后有一个非常值得挖的机制。三种策略数据集:266 行 Python 代码,涵盖认证、数据库、缓存、支付、通知 5 个模块,共 27 个函数。Embedding 模型统一用bge-large-zh-v1.5,评估用 12 个自然语言查询。三种切法:策略 1:固定行分割(每 20 行,overlap=3)不管代码结构,每 20 行切一刀,相邻 chunk 重叠 3 行防止边界信息丢失。Chunk 1: 第 1-20 行 Chunk 2: 第 18-37 行 ← 和上一块重叠 3 行 Chunk 3: 第 35-54 行 ...策略 2:文件级分割(整个文件一个 chunk)简单粗暴,整份代码就是一个 chunk。Chunk 1: 第 1-266 行 ← 全塞进去策略 3:AST 函数级分割(一个函数一个 chunk)用 Python 的ast模块解析语法树,按函数定义精确切割。Chunk 1: def validate_jwt_token(...) 第 9-18 行 Chunk 2: def hash_password(...) 第 20-28 行 Chunk 3: def create_payment_intent(...) 第 ... ...先看一眼固定行分割"土"在哪里。以validate_jwt_token这个函数为例(第 9-18 行,共 10 行):函数 'validate_jwt_token'(第 9-18 行,10 行) 被切进 2 个 chunk: Chunk 第 1-20 行: 包含函数第 9-18 行(10/10 行) Chunk 第 18-37 行: 包含函数第 18-18 行(1/10 行) 问题:没有任何一个 chunk 包含完整的函数。 一个关于 'validate_jwt_token' 的查询会检索到一段残缺的实现。看到没?函数的最后一行(第 18 行)被切到了下一个 chunk 里。这正是固定行分割最被诟病的地方——它不认识函数边界,说切就切。按理说,这种残缺应该会拖累检索效果。AST 分割每个函数都完完整整,怎么看都该赢。运行结果Strategy Chunks AvgLen R@3 R@5 vs AST R@5 ──────────────────────────── ─────── ─────── ─────── ─────── ────────── 1_fixed_lines_20 16 755 0.917 1.000 +0.042 2_file_level 1 10270 1.000 1.000 +0.042 3_ast_function 27