RAG 分块策略实测:固定窗口 vs 递归切分 vs 结构感知,用 100 道题说话

📅 发布时间:2026/9/12 19:13:55
RAG 分块策略实测:固定窗口 vs 递归切分 vs 结构感知,用 100 道题说话
RAG检索增强生成落地时分块chunking把长文档切成喂给向量库的小段大概是工程师踩的第一个参数坑。怎么切、切多大网上的答案是清一色的理论推演“语义完整性”、“粒度平衡”、“建议 512”。这些建议有没有数字撑腰我把自己的 10 篇技术长文切了跑了个对照实验。一、实验怎么搭的语料2026 年本人写的 10 篇实测长文DeepSeek Harness 系列 4 篇、ARC-AGI-3 harness 实测、DseWiki 数据实拉、SkillSpector 扫描、两篇模型对比、一篇 Code Review 规范重写其中 7 篇已发在本账号3 篇是没发的稿子——语料按域选齐不看发布状态。共 74,727 字符清洗掉导航行和状态注记代码块和表格原样保留——中文技术文带代码、带表格是分块策略最容易出事故的文体。测试集100 道题。每篇文章出 10 题分两档——A 档 30 道主题级问文章主线话题B 档 70 道细节级必须读到正文里的具体数字、命令、报错才能答比如DSH 用 npm 发了多少个版本。题目按真实搜索口吻写不允许出现这篇文章这种元指涉。ground truth标准答案标到文章级。变量与固定量被测的是三种分块策略 × 三种粒度——固定窗口递归切分结构感知实现字符滑窗LangChainRecursiveCharacterTextSplitter中文分隔符自建按 Markdown 标题分节代码块不切断粒度256 / 512 / 1024 字符同左同左嵌入模型固定 bge-small-zh-v1.5向量库 Chromatop-k5重叠overlap固定 50 字符。3×3 共 9 组配置每组 100 题全量检索共 900 次。CPU 跑完一组 10~15 秒。二、主结果总体差异小得意外配置块数Hit1A 档 Hit1B 档 Hit1MRR5代码块切断次数固定-2563660.8300.7670.8570.87723固定-5121650.8300.7670.8570.87710固定-1024800.8300.8670.8140.8857递归-2564710.8200.7670.8430.87512递归-5122030.8200.7670.8430.8754递归-1024900.8100.7670.8290.8652结构-2563470.8100.7670.8290.86710结构-5121880.8100.7670.8290.8678结构-1024970.8200.7670.8430.8722九组配置的 Hit1 全挤在 0.81~0.83。选错分块策略的代价比网上说的小得多——至少在万字级语料、文章级 ground truth 这个口径下策略之间拉不开数量级差距。但 A/B 分层看结论才站得住。三、A/B 档方向相反A 档主题级只有固定-1024 突出0.867其余八组齐刷刷 0.767。大窗口把整篇文章的主题语境塞进一个块里主题级查询的语义匹配更稳。B 档细节级反过来固定-1024 掉到 0.814是三种策略的 1024 粒度里最差的256 和 512 粒度下三策略的差距压在 2 题以内0.829~0.857。细节事实分散在全文各处窗口越大单块里被稀释掉的上下文越多。说直白点如果你的 RAG 主要答这份文档讲了什么级别的问题大窗口是免费收益如果答细节大窗口开始亏。四、1024 字符组藏着截断伪影实验里最反直觉的一组数字bge-small-zh-v1.5 的输入窗口是 512 token我用 tokenizer 逐块实测——固定-1024 有 90% 的块超长被模型静默截断递归-1024 是 72%结构-1024 是 61%。也就是说1024 粒度组测的根本不是1024 字符的分块效果而是1024 字符的块被截成前半段的效果。那固定-1024 的 A 档优势是真的吗我补了个对照同样的分块一组保留前 510 token模型默认行为一组保留后 510 token——截断方向A 档 Hit1B 档 Hit1保头默认0.8670.814保尾0.8330.729保尾让 B 档掉了 8.5 个百分点。细节事实散布在块的全文截掉哪头都丢内容而主题词天然集中在块的开头静默截断恰好护住了主题信号——固定-1024 的 A 档领先一部分是截断方向的运气不是大窗口本身的功劳。顺带一个实操提醒选大 chunk 前先查嵌入模型的 max_seq_length否则你在测一个自己没意识到的混合体。五、结构感知的真实价值在代码块结构感知策略在命中率上没赢但它赢了另一张表代码块被切断的次数。同样是 256 字符固定窗口切了 23 次代码块结构感知只切 10 次拉到 1024结构感知和递归都只剩 2 次固定窗口还有 7 次。切断的代码块在检索层看不出来——数字上它照样命中——但下游生成层拿到半截package.json或半条命令就是幻觉的直接原料。如果 RAG 检索结果要喂给模型生成答案代码完整性比 2 个点的命中率值钱。六、5 道题9 组配置全部失手有 5 道题在所有配置下 Hit1 全军覆没。一个个拆开看死法几乎一样全死在跨文章语义重叠。“dsh 启动后 web 界面默认开在哪个端口”答案在 DSH 上手实录top1 却是 197 包架构解读dsh 官方自带哪几个预设模式问的也是上手实录被插件市场文抢走dsh 的 patch 文件里空数组后面能追加条目吗指向插件市场文top1 是上手实录DSH 的 197 个包按功能分成了哪几大类问 197 包文还是被上手实录压过去只读沙箱里的 agent 怎么把 wiki 页面改掉的指向 DseWiki 数据实拉top1 是 DSH 插件开发——沙箱执行语境强重叠。五道题里四道死在 DSH 系列内部互抢同一个系列写多了篇与篇的检索边界自然糊掉。这不是分块的锅。任何 chunking 配置都救不回语义层的歧义这个锅在下游——重排序rerank拿原查询对候选块精排或元数据过滤。这也是系列第 2 篇的入口chunking 榨不出来的分得去重排序那层取。七、工程结论别为分块策略焦虑9 组配置的差距被普遍高估先把嵌入模型、测试集和 top-k 调明白收益更大按问题类型选粒度答主题选大窗口答细节选 256~512两种都要就上父子分块粗粒度检索、细粒度喂给模型大 chunk 先查嵌入窗口超窗的截断是静默的必要时把 chunk 控制在模型 max_seq_length 的 token 数内带代码的语料优先结构感知命中率没赢代码完整性完胜生成质量的钱在这省分块解决不了语义歧义留预算给重排序。数据核验说明语料 10 篇共 74,727 字符清洗规则与文件清单见 rag-lab 仓库corpus/测试集 100 题A 档 30 / B 档 70LLM 按篇生成、人工全检元指涉与 schema 错误均为 0跨篇撞题用 6 字滑窗初筛后人工复核为 0全实验 900 次检索为单次运行无重复CPU 每组 10~15 秒嵌入模型 bge-small-zh-v1.5512 维向量库 chromadb 1.5.9递归切分为 langchain-text-splitters 实现ground truth 标文章级top-k 命中目标文章即记 hit是宽松口径——数字只用于 9 组横向对比不代表端到端问答质量语料 10 篇全部为本人原创的中文技术文AI 实测域已发布 7 篇、未发稿 3 篇Java 老文尚未混入跨域干扰指标本期为 0、留待语料扩充后补测结论不外推英文语料与其他文体截断对照只覆盖固定-1024 的头/尾两方向未做 3×2 全因子n100 报分层观察不做显著性检验。一条命令复现gitclone https://github.com/ethanliang2016/rag-labcdrag-lab pipinstall-rrequirements.txt python src/run_eval.py模型自动从 hf-mirror 下载全部结果含 100 题逐题命中记录、5 道顽固题明细、截断对照数据在results/目录。留个问题你们的 RAG 里 chunk 大小是怎么定的是拍的还是测的评论区聊聊下一篇我拿重排序来救那 5 道顽固题。相关实测《RAG 重排序实测双编码召回 CrossEncoder 精排500 条真实查询上的收益与代价》—— 分块撞墙之后往下游要精排能救回多少《RAG 生成层实测把答案递到模型嘴边7B 还是漏掉一半》—— 检索修到 0.506 之后生成层还漏多少完整导航博客导航agent 安全 / RAG 实测 / AI 代码治理都在这