当前位置: 首页 > news >正文

中文RAG分块应该按字符还是Token?长度、重叠与边界完整性实测思路

文章摘要

中文RAG项目经常使用“每500个字符切一段”或“每300个Token切一段”,但字符数与Token数并不是同一个概念,不同模型的Tokenizer也可能给出不同结果。分块过小会丢失条件,过大则降低检索精度并增加上下文成本。本文解释字符、Token、句子和语义边界的区别,并给出中文制度、合同、产品手册和FAQ的分块参数建议与评测方法。

一、为什么字符数和Token数不能混用

字符数是字符串长度。

例如:

平台支持经销商收货与终端动销分析。

中文字符、标点和英文字符都可以直接统计。

Token是模型分词器处理后的单位。

同一段内容在不同模型中可能被切成不同数量的Token。

影响因素包括:

  • 模型Tokenizer;
  • 中文词语;
  • 英文缩写;
  • 数字;
  • 标点;
  • JSON;
  • 代码;
  • 空格和换行。

因此:

500个中文字符 ≠ 固定500个Token

如果向量模型和生成模型使用不同Tokenizer,差异还会更大。

二、按字符分块的优点与问题

优点

  • 实现简单;
  • 不依赖模型Tokenizer;
  • 速度快;
  • 参数直观;
  • 适合预处理和初步切分。

示例:

defsplit_by_chars(text:str,chunk_size:int=500,overlap:int=80)->list[str]:chunks:list[str]=[]start=0whilestart<len(text):end=min(start+chunk_size,len(text))chunks.append(text[start:end])ifend==len(text):breakstart=end-overlapreturnchunks

问题

  • 可能从句子中间切开;
  • 表格被拆断;
  • 条款条件和结论分离;
  • 代码结构损坏;
  • 无法准确控制模型上下文;
  • 不同文本密度差异大。

字符切分适合作为最后一道长度限制,不适合成为唯一规则。

三、按Token分块的优点与问题

优点

  • 更接近模型真实上下文成本;
  • 便于控制Embedding输入上限;
  • 便于预算生成上下文;
  • 中英文混合内容更可控。

伪代码:

defsplit_by_tokens(text:str,tokenizer,max_tokens:int,overlap_tokens:int)->list[str]:tokens=tokenizer.encode(text)chunks:list[str]=[]start=0whilestart<len(tokens):end=min(start+max_tokens,len(tokens))chunks.append(tokenizer.decode(tokens[start:end]))ifend==len(tokens):breakstart=end-overlap_tokensreturnchunks

问题

  • 仍可能切断语义;
  • 依赖具体Tokenizer;
  • 更换Embedding模型后参数可能变化;
  • Token解码可能影响空格和格式;
  • 处理成本高于字符计数。

Token长度控制的是容量,不等于保证内容完整。

四、真正重要的是语义边界

推荐切分优先级:

文档 → 章节 → 小节 → 条款 → 段落 → 句子 → Token或字符兜底

例如制度文件:

第四章 差旅标准 4.1 交通标准 4.2 住宿标准 4.3 餐饮补贴

应该先按章节和条款切分,再检查是否超过Token上限。

错误做法:

直接每500字符切开

可能把4.2的适用对象留在前一块,把金额留在后一块。

五、重叠区间有什么作用

Overlap用于保留边界上下文。

例如:

Chunk 1:……申请人必须在出差前提交审批。 Chunk 2:提交审批后,由直属负责人审核……

如果边界切在中间,重叠可以减少信息损失。

但重叠不是越大越好。

过大重叠会导致:

  • 索引体积增加;
  • 相似Chunk重复召回;
  • 上下文重复;
  • Token浪费;
  • Reranker结果单一。

常见起点:

Overlap占Chunk的10%—20%

但最终应以检索评测为准。

六、不同文档类型的建议

1. FAQ

一问一答天然是Chunk。

建议:

每个FAQ独立 保留分类和关键词 通常不需要重叠

2. 企业制度

建议按:

章节 → 条款 → 子条款

每个Chunk带:

  • 制度名称;
  • 版本;
  • 章节标题;
  • 条款编号;
  • 生效日期。

3. 合同

建议按条款切分,不要把不同责任条款合并。

需要保留:

  • 合同类型;
  • 甲乙方;
  • 条款号;
  • 定义引用;
  • 附件关系。

4. 产品手册

建议按功能或操作任务:

功能说明 前置条件 操作步骤 异常处理

不要把多个完全不同功能放在同一Chunk。

5. API文档

建议按接口:

Method+Path 请求参数 响应参数 错误码 示例

一个接口可以有父子Chunk。

6. 表格

不要直接按字符切表格。

应该:

  • 保留表头;
  • 每行带表头语义;
  • 大表按业务分组;
  • 必要时转为结构化JSON;
  • 保留原始页码和表名。

七、推荐的两阶段分块

第一阶段:结构切分

Markdown标题 PDF章节 Word样式 条款编号 列表 表格

第二阶段:长度控制

如果结构块超过上限,再按句子和Token切分。

伪代码:

defhierarchical_split(document:Document,tokenizer,max_tokens:int=400)->list[Chunk]:sections=split_by_structure(document)result:list[Chunk]=[]forsectioninsections:ifcount_tokens(section.text,tokenizer)<=max_tokens:result.append(to_chunk(section))continuesentences=split_sentences(section.text)result.extend(merge_sentences_by_token_limit(sentences,tokenizer,max_tokens=max_tokens,overlap_tokens=60))returnresult

八、父子分块如何兼顾召回和完整性

小Chunk更容易精准召回,大Chunk更容易提供完整答案。

父子分块:

父Chunk:完整章节 子Chunk:段落或条款

检索:

对子Chunk生成Embedding → 找到高相关子Chunk → 返回对应父Chunk或邻接内容

适合:

  • 制度;
  • 合同;
  • 长产品手册;
  • 技术文档。

要避免父Chunk过大,否则上下文又会膨胀。

九、参数从哪里开始

以下只是起始值,不是通用答案。

文档子Chunk起始范围Overlap
FAQ一问一答0
制度条款200—450 Token30—60
产品手册300—600 Token50—100
合同单个完整条款视引用关系
API文档单接口或子模块少量
代码函数或方法通常不用固定Overlap

如果Embedding模型对长文本支持更好,也不代表应该无限扩大Chunk。

十、如何评测分块质量

准备真实问题,每个问题标注:

正确文档 正确条款 答案所需最小证据

比较不同参数:

300 Token+50重叠 500 Token+80重叠 父子分块 语义分块

指标:

  • Answer-Bearing Recall@K;
  • MRR;
  • 重复Chunk比例;
  • 平均上下文Token;
  • 答案正确率;
  • 忠实度;
  • 查询延迟。

十一、字符数是否完全没用

不是。

字符数适合:

  • 快速预估;
  • 输入长度保护;
  • 文本清洗;
  • 不绑定模型的基础规则;
  • 发现异常超长内容。

推荐:

结构边界决定怎么切 Token决定是否超限 字符数负责快速保护和监控

十二、常见错误

1. 所有文档使用同一参数

FAQ、合同和代码不应使用相同规则。

2. 只看Chunk平均长度

还要看是否包含完整答案。

3. 重叠设置过大

造成重复召回。

4. 忽略标题和Metadata

Chunk正文短,但缺少章节语义。

5. 更换Embedding模型后不重测

Tokenizer和语义能力都可能变化。

总结

中文RAG分块不应该在“字符还是Token”之间二选一。

更合理的方式是:

先按文档结构和语义边界切分 → 再用Token控制模型上限 → 用字符数做保护 → 通过真实问题评测参数

决定效果的核心不是Chunk恰好有多少字,而是答案所需的条件和结论是否完整地留在同一个可检索单元中。

http://www.cnnetsun.cn/news/3564264.html

相关文章:

  • 工程师的AI觉醒时刻:从写代码到定义问题,4步完成认知升维(含21个真实转型失败复盘案例)
  • 定时定量:把模糊愿望变成执行指令。
  • 深入底层:xAI Grok CLI 的线级协议分析与数据隐私透视
  • OpenCode 2.0 发布:重构 API、迁移运行环境,解决内存与排队难题!
  • abap中程序跳转(全)
  • React-Blog:错误处理与日志记录的最佳实践
  • 居家安防的坚固屏障 —— 防盗门
  • puzzle(1015)明灯谜局、马赛克、线段填格
  • Event Loop事件循环
  • AI4R核心功能大揭秘:从分类器到Transformer的全方位解析
  • 计算机毕业设计之网上书店系统
  • java汉诺塔(递归实现)
  • ubuntu-post-install完全指南:让你的Ubuntu系统初始化效率提升10倍的终极脚本集
  • 一款基于车载协议的socket通讯工具
  • 面向对象的思考
  • next-data-hooks性能优化:深入理解代码消除机制
  • TCP三次握手:为什么需要三次,每一次握手的作用是什么
  • 供需双增叠加政策迭代,动力电池行业开启高质量竞争新周期
  • [Android] az录屏大师 -1080p高清录制
  • 386 · Longest Substring with At Most K Distinct Characters最多有k个不同字符的最长子字符串(滑动窗口)
  • 不群发、不买链接、不写客座文章——我只靠一条原创数据拿到了200条外链
  • 第三章 镜像仓库总结-001篇
  • smsBomb配置完全指南:从配置文件到API密钥的详细设置
  • 运维工程师转型渗透测试:思维重塑与6-9个月实战路线图
  • GameVault多平台支持:Windows与Linux游戏兼容性终极指南 [特殊字符]
  • Claude Code实战避坑指南:7大核心痛点与解决方案
  • 【WorkBuddy从入门到精通实战教程】使用手册 第 5 章 WorkBuddy加载一个真正用得上的 Skill
  • shell数组的一些总结
  • 告别文献焦虑✅Okbiye千万文献库+学术翻译!搞定论文参考文献、外文研读全流程
  • 递归对抗拓扑学(RAT)主纤维丛建模认知冲突完整框架(世毫九实验室原创研究)