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

什么是 RAG 中的分块?为什么需要分块?

RAG中的分块:核心概念与必要性

分块(Chunking)是RAG系统中将长文档切分成多个小片段的过程。每个片段称为一个"块"(Chunk),是后续向量化和检索的基本单元。


一、什么是分块?

1.1 直观理解

想象一本1000页的医学教科书:

  • 不分块:把整本书作为一个单元,无法精准定位到特定段落
  • 分块后:切成若干章节、段落、甚至句子,每个小块独立存储和检索
原始文档(1000页) │ ▼ 分块处理 ┌─────────────────────────────────────┐ │ 块1: 第1章 心血管系统概述 │ │ 块2: 第2章 高血压诊断标准 │ │ 块3: 第3章 高血压药物治疗 │ │ 块4: 第4章 高血压生活方式干预 │ │ ... │ │ 块10: 第2章 第3节 ACEI类药物 │ │ ... │ │ 块356: 第15章 第4段 病例讨论 │ └─────────────────────────────────────┘ │ ▼ 向量化 每个块 → 向量 → 存入向量数据库

1.2 代码示例

// 简单分块示例StringmedicalText=""" 高血压是一种常见的慢性病。 诊断标准:收缩压≥140mmHg或舒张压≥90mmHg。 治疗包括生活方式干预和药物治疗。 常用药物有ACEI、ARB、CCB等。 """;// 按句子分块List<String>chunks=Arrays.asList("高血压是一种常见的慢性病。","诊断标准:收缩压≥140mmHg或舒张压≥90mmHg。","治疗包括生活方式干预和药物治疗。","常用药物有ACEI、ARB、CCB等。");

二、为什么需要分块?

2.1 核心原因一览

原因说明不分块的后果
模型上下文限制LLM有token上限(如4K-128K)超长文本无法输入
检索精准度小块更容易匹配具体问题大块包含无关信息,召回率低
语义粒度每个块代表一个独立语义单元粒度太粗,难以定位答案
成本控制只将相关块传给LLM每次都传全文,token成本高
性能优化并行处理多个块检索速度慢

2.2 详细展开

原因一:模型上下文限制
// 问题示例Stringquestion="ACEI类药物的禁忌证是什么?";StringfullText=loadFullTextbook();// 100万字// ❌ 不分块:无法处理// 模型上下文窗口只有4K-128K tokenschatModel.call(fullText+question);// 超出限制!// ✅ 分块后:只取相关块List<DocumentChunk>relevantChunks=retrieve(question);// 只取2个相关块Stringanswer=chatModel.call(question+relevantChunks);// 在限制内
原因二:检索精准度

不分块的问题

文档块(整章,2000 tokens): "高血压治疗包括ACEI类药物如依那普利、赖诺普利...(大量内容)... 药物副作用包括干咳、血管性水肿..." ↑ 用户问:"ACEI类药物引起干咳怎么办?" ──────────────┘
  • 整个章节被检索到,但大部分内容无关
  • 难以精确定位到"干咳"相关内容
  • 向量相似度被其他内容稀释

分块后

块A: "ACEI类药物包括依那普利、赖诺普利、培哚普利..." 块B: "ACEI类药物的常见副作用:干咳(发生率10-20%)、血管性水肿..." 块C: "干咳的处理方法:换用ARB类药物、对症治疗..." 用户问:"ACEI类药物引起干咳怎么办?" → 精准匹配块B和块C
原因三:语义粒度控制
// 不同粒度对比publicclassChunkGranularity{// 粒度太粗(章节级)voidtooCoarse(){Chunkchunk=newChunk("第3章 心血管疾病治疗(5000 tokens)");// 问题:"β受体阻滞剂的心率控制目标"// 检索结果:整章,但答案只在第3节第2段}// 粒度合适(段落级)voidappropriate(){Chunkchunk=newChunk("β受体阻滞剂的心率控制目标:静息心率55-60次/分",Map.of("section","3.2","topic","心率管理"));// 问题:"β受体阻滞剂的心率控制目标"// 检索结果:直接命中这个块}// 粒度太细(句子级)voidtooFine(){Chunkchunk=newChunk("静息心率55-60次/分");// 问题:"β受体阻滞剂的心率控制目标"// 检索结果:可能命中,但丢失了上下文(药物名称)}}
原因四:成本优化
不分块模式: 用户问题 → 检索整本书 → 传递所有内容给LLM → 成本 = 全文字数 × 每次调用 分块模式: 用户问题 → 检索相关块(2-5个) → 只传递相关块给LLM → 成本 = 块大小 × 调用次数 成本对比: - 不分块:100万字文档 × 1000次调用 = 10亿 tokens - 分块后:500字/块 × 2块 × 1000次调用 = 100万 tokens 成本降低约 1000 倍!
原因五:支持增量更新
// 知识库更新场景publicclassIncrementalUpdate{// 不分块:更新一个知识点需要重新处理整本书voidupdateWholeBook(){Documentbook=loadBook();book.updateSection("高血压诊断标准","新标准:130/80mmHg");// 需要重新索引整本书(1000页)reindexAll(book);// 耗时、成本高}// 分块:只更新相关块voidupdateChunks(){DocumentChunkchunk=findChunk("高血压诊断标准");chunk.updateContent("新标准:130/80mmHg");// 只重新向量化这个块vectorStore.update(chunk);// 快速、低成本}}

三、分块策略对比

3.1 常见分块方法

策略原理优点缺点适用场景
固定大小按固定token数切割简单、可控可能打断语义通用、快速原型
句子级按句子边界切割语义完整粒度太细短文本、FAQ
段落级按段落边界切割保留上下文长度不固定通用文档
语义级基于内容相似度聚类语义连贯计算复杂高质量需求
结构级按标题/章节切割保留层次依赖格式结构化文档
递归级先粗后细,逐级切割灵活适应实现复杂长文档、混合内容

3.2 医疗场景的分块策略

@ComponentpublicclassMedicalChunkingStrategy{/** * 临床指南:按结构切割 */publicList<DocumentChunk>guidelineChunk(Stringtext,Structurestructure){// 保留章节层级List<DocumentChunk>chunks=newArrayList<>();for(Sectionsection:structure.getSections()){DocumentChunkchunk=newDocumentChunk();chunk.setContent(section.getContent());chunk.setMetadata(Map.of("section_title",section.getTitle(),"section_level",section.getLevel(),"guideline_name",structure.getTitle(),"version",structure.getVersion()));// 章节过长则递归切割if(chunk.getTokenCount()>800){chunks.addAll(recursiveChunk(chunk));}else{chunks.add(chunk);}}returnchunks;}/** * 药品说明书:按字段切割 */publicList<DocumentChunk>drugInsertChunk(Stringtext){// 预定义字段Map<String,String>fields=extractFields(text,List.of("通用名","商品名","适应证","用法用量","禁忌证","不良反应","注意事项","药物相互作用"));returnfields.entrySet().stream().map(entry->{DocumentChunkchunk=newDocumentChunk();chunk.setContent(entry.getValue());chunk.setMetadata(Map.of("field",entry.getKey(),"drug_name",fields.get("通用名"),"type","drug_insert"));returnchunk;}).collect(Collectors.toList());}/** * 患者病历:语义切割 */publicList<DocumentChunk>medicalRecordChunk(Stringtext){// 按时间线切割List<String>episodes=extractByTimeLine(text);returnepisodes.stream().map(episode->{DocumentChunkchunk=newDocumentChunk();chunk.setContent(episode);chunk.setMetadata(Map.of("type","clinical_episode","date",extractDate(episode)));returnchunk;}).collect(Collectors.toList());}/** * 医学文献:递归切割 */publicList<DocumentChunk>literatureChunk(Stringtext){// 先按章节切割List<DocumentChunk>sectionChunks=splitBySections(text);List<DocumentChunk>finalChunks=newArrayList<>();for(DocumentChunkchunk:sectionChunks){if(chunk.getTokenCount()>800){// 章节过长,按段落再切割finalChunks.addAll(splitByParagraphs(chunk));}elseif(chunk.getTokenCount()<200){// 章节过短,合并到上一章mergeWithPrevious(finalChunks,chunk);}else{finalChunks.add(chunk);}}returnfinalChunks;}}

四、分块的最佳实践

4.1 黄金法则

publicclassChunkingBestPractices{/** * 法则1:保留边界上下文 */publicvoidoverlappingChunk(){// 块之间有重叠,避免信息在边界处断裂TokenTextSplittersplitter=newTokenTextSplitter(512,// 块大小50// 重叠50个token);// 块1: tokens 0-512// 块2: tokens 462-974 ← 与块1重叠// 块3: tokens 924-1486 ← 与块2重叠}/** * 法则2:保留元数据 */publicvoidpreserveMetadata(){DocumentChunkchunk=newDocumentChunk();chunk.setContent("ACEI类药物可引起干咳...");chunk.setMetadata(Map.of("source","高血压诊疗指南2024","section","第3章 药物治疗","page",156,"author","中华医学会","confidence",0.95,"doc_type","clinical_guideline"));// 检索时可以按元数据过滤}/** * 法则3:根据应用场景选择粒度 */publicChunkSizeselectChunkSize(ApplicationTypeappType){returnswitch(appType){caseQUESTION_ANSWERING->newChunkSize(300,50);// 细粒度caseDOCUMENT_SUMMARY->newChunkSize(800,100);// 粗粒度caseFACT_RETRIEVAL->newChunkSize(150,30);// 很细粒度caseCONTEXT_UNDERSTANDING->newChunkSize(500,75);// 中等粒度};}/** * 法则4:支持父子块关系 */publicvoidparentChildChunking(){// 父块:章节级(用于上下文)ParentChunkparent=newParentChunk("第3章 高血压药物治疗","本章介绍高血压的药物治疗方案,包括...");// 子块:段落级(用于检索)List<ChildChunk>children=Arrays.asList(newChildChunk("ACEI类药物:...",parent.getId()),newChildChunk("ARB类药物:...",parent.getId()),newChildChunk("CCB类药物:...",parent.getId()));// 检索时:先找到子块,再关联父块获取完整上下文ChildChunkretrieved=search("ACEI禁忌证");ParentChunkcontext=loadParent(retrieved.getParentId());// 答案 = 子块内容 + 父块上下文}}

4.2 常见问题与解决方案

问题影响解决方案
语义断裂答案被切分到两个块增加重叠、使用语义切割
粒度不当召回率低或成本高根据场景调整、A/B测试
元数据丢失无法溯源和过滤保留来源、章节、页码
表格/代码破坏结构信息丢失特殊处理、保留格式
多语言混合分词不准确使用多语言分词器

五、分块效果的量化评估

@ComponentpublicclassChunkingEvaluator{/** * 评估分块质量 */publicChunkingMetricsevaluate(List<DocumentChunk>chunks,List<TestQuery>testQueries){intsemanticIntegrity=0;// 语义完整性分数intretrievalAccuracy=0;// 检索准确率intcontextSufficiency=0;// 上下文充足度for(TestQueryquery:testQueries){// 检查答案是否完整包含在单个块中if(isAnswerInSingleChunk(query,chunks)){semanticIntegrity++;}// 检查检索能否命中相关块if(canRetrieveCorrectChunk(query,chunks)){retrievalAccuracy++;}// 检查块是否包含足够上下文理解答案if(hasSufficientContext(query,chunks)){contextSufficiency++;}}returnnewChunkingMetrics(semanticIntegrity/(double)testQueries.size(),retrievalAccuracy/(double)testQueries.size(),contextSufficiency/(double)testQueries.size());}/** * 对比不同分块策略 */publicStrategyComparisoncompareStrategies(){returnStrategyComparison.builder().fixedSize(0.65,0.70,0.55).sentenceBased(0.55,0.85,0.45).semanticBased(0.85,0.80,0.75).structureBased(0.90,0.75,0.85).build();}}

六、总结

分块是RAG系统的基石,它决定了:

  1. 检索的精度:粒度合适才能精准匹配
  2. 生成的品质:上下文完整才能准确回答
  3. 系统的成本:块大小直接影响token消耗
  4. 维护的便捷:细粒度支持增量更新

核心要点

  • 分块是为了在"语义完整性"和"检索精度"之间找到平衡
  • 医疗场景需要根据文档类型(指南/说明书/病历)采用不同策略
  • 重叠、元数据、父子关系是提升分块质量的三大技术
  • 分块策略需要通过实际评估来优化
http://www.cnnetsun.cn/news/4118882.html

相关文章:

  • Axure 汉化原来这么简单:axure-cn 中文语言包 9/10/11 全版本速通指南
  • 锤子助手第124个开关:启用自动下载图片的位置、安全验证与图片隐私边界
  • Capture软件原理图信号联通笔记
  • 电脑掌柜库存管理实战:进销存、库存预警、供应商管理一条龙,0基础电脑店老板 5 分钟上手
  • Unity独立开发艺术展馆漫游:从基础功能到工程化实战
  • XMC1300 ADC读数不稳?从硬件到软件的完整排查与优化指南
  • Python自动化:基于文件名与正则表达式批量分类PDF发票文件
  • 计算机单片机毕设实战-基于 STM32 单片机的防干烧多模式烧水控制系统设计 基于 STM32 的自动手动双模式智能出水装置设计(012104)
  • 构建自主AI智能体的因果推理引擎:反事实思考与时间一致性
  • 算法竞赛制胜关键:构建高效数据结构工具箱,实现降维打击
  • 调度器多副本,不引 ZooKeeper:DB CAS + slot 分片就够了
  • RTL8720DN双模物联网SoC开发:从硬件架构到低功耗实战
  • 脑机接口实战:用Python实现脑电波意念控制与信号处理
  • Sib:用Git版本控制管理AI对话历史的命令行LLM客户端
  • 1.6T光模块:技术演进、市场现状与工程挑战深度解析
  • 【YOLO26创新改进】TIP顶刊 2023 | Conv创新改进篇 | 利用 CSFCN 上下文与空间特征校准网络,使网络能够获得更准确的语义信息,适合目标检测、语义分割、图像分割任务,高效涨点
  • TrenchesWIP:一战战术射击游戏入门指南与BOT对战技巧
  • 信息技术EI期刊发表全攻略:从选刊到检索的实战指南
  • B站视频下载终极指南:免费开源工具一键保存4K大会员与充电专属视频
  • 华为认证高频易错题库解析:攻克IP计算、网络设备与协议核心难点
  • Python实现LSTM时间序列预测教程
  • 让2011年的老Mac跑上macOS Sequoia:OpenCore Legacy Patcher 一次点亮的完整上手指南
  • 电视浏览器(CCTV_Viewer):观看央视卫视直播的安卓 TV 盒子
  • Go源码分析:Mutex与读写锁实现
  • AI如何从混沌中看见世界?解析非结构化数据处理的算法演进与工程实践
  • 保时捷Taycan核心技术解析:800V架构与两速变速箱如何重塑电动性能标杆
  • WSL 2原生Docker环境搭建:告别Docker Desktop,打造高效容器开发平台
  • ExComm:构建抗错多智能体通信,实现测试时稳定扩展
  • DS 3 Crossback E-Tense改款前瞻:三电升级与智能座舱革新
  • OpenAI高管教网友用Claude跑GPT-5.6 Sol,开发者照做却被封号,CC之父火速下场回应后还想挖角却遭拒