高级 RAG 优化策略系列(二)——“化整为零”的分块策略
分块是优化 RAG 的基础步骤,目标是将长文档拆分为 LLM 可处理的“小单元”。这些分块在嵌入后存入向量数据库,应用在查询时通过“相似度检索”快速找回最相关的内容。
从 ChatGPT 的爆火到 Claude、Gemini 的争锋,LLMs 正以惊人的速度渗透进我们的生活。它们不仅能聊天、创作,还能翻译、编程,甚至通过各种考试。但这场技术革命的背后,是自然语言处理(NLP)领域的巨大跃迁:过去的“小众学科”如今站在 AI 浪潮之巅,而它的每一次突破,都在重新定义人类与机器的交互方式。
虽然 LLMs 在生成高度流畅文本以及完成多种任务方面已经足够强大,但它们在实际应用中仍然天然受限,尤其体现在以下几个方面:
-
上下文窗口有限:直接处理长文档(如书籍、大型报告)仍然具有挑战。
-
长上下文检索能力有限:在法律、科研等数据密集场景下,模型可能难以从长文本中精准定位信息。
-
知识的时效性不足:训练数据是静态的,无法实时更新,对最新事件或领域知识敏感度不足。
为突破这些限制,目前业界的主流路径是通过 分块处理(Chunking) + 检索增强生成(RAG) 的组合方式,让模型具备“从外部知识库实时检索”-的能力,从而间接突破上下文窗口限制。
从分块到 RAG:为何向量数据库至关重要?
分块是 RAG 的基础步骤,目标是将长文档拆分为 LLM 可处理的“小单元”。这些分块在嵌入后存入向量数据库,应用在查询时通过“相似度检索”快速找回最相关的内容。

简单来说:
分块解决“切分文本”的问题,向量数据库解决“找回最相关分块”的问题。
在整个链路中,向量数据库起着决定性作用:
-
分块越细,向量数量越大 → 数据库压力越高
-
查询越复杂(如过滤、多条件召回)→ 数据库执行计划越重要
-
主动分块/语义分块等高级策略 → 召回次数与块数量更不可预测
因此,现代 RAG 系统普遍依赖高性能向量数据库。如 OriginHub MyScale 这类 AI 数据库在吞吐、延迟、过滤能力方面的优势,会直接影响上层 RAG 系统的完整效果。
分块处理:让大语言模型“分段消化”长文本
分块是将大型数据源或超长文档(如书籍、论文、对话记录)拆分为更小、语义连贯的片段,使受限于上下文窗口的 LLM 能逐步处理信息。
通常,这些块会被嵌入向量并存储在 向量数据库(如 MyScale) 中。用户查询时,数据库会找回最相关的块,并传给 LLM 生成结果。
与我们人类“分章节阅读”的方式类似,分块让 LLM 能够聚焦局部信息,提高响应的准确性和效率。

在当前 RAG 应用中,常见的分块策略包括:
-
固定长度分块
-
递归分块
-
语义分块
-
主动分块
接下来,我们逐一拆解其特性与适用场景。
固定长度分块
固定长度分块是最基础的方式:按照固定字数/字符数直接切分内容。
例如:
每 500 个字符作为一个块
块之间保留 50 字重叠
重叠(Overlap)用于避免句子或语义被切断而导致信息丢失。如下图所示:

上图是固定长度分块的示例,每个块由唯一的颜色表示。绿色部分表示块之间的重叠部分,确保模型在处理下一个块时可以访问相关上下文。
这种方法优势在于简单、可控、执行稳定,非常适合:
-
数据结构较规则
-
对语义连贯性要求没那么高
-
策略落地需要简单可靠
代码示例
现在我们来带着大家重新创建这个示例,这里用到 LangChain 来实现固定长度分块。
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 使用固定大小分块和重叠的函数
def split_text_with_overlap(text, chunk_size, overlap_size):
# 创建一个带有重叠的文本分割器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=overlap_size
)
# 分割文本
chunks = text_splitter.split_text(text)
return chunks
# 示例文本
text = """人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。"""
# 定义块大小和重叠大小
chunk_size = 80 # 每个块80个字符
overlap_size = 10 # 块之间10个字符的重叠
# 获取带有重叠的块
chunks = split_text_with_overlap(text, chunk_size, overlap_size)
# 打印块和重叠部分
for i in range(len(chunks)):
print(f"块 {i+1}:")
print(chunks[i]) # 打印块本身
# 如果有下一个块,打印当前块和下一个块之间的重叠部分
if i < len(chunks) - 1:
overlap = chunks[i][-overlap_size:] # 获取重叠部分
print(f"与块 {i+2} 的重叠部分:")
print(overlap)
print("\n" + "="*50 + "\n")
执行上述代码将生成以下输出:
块 1:
人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
与块 2 的重叠部分:
用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
==================================================
块 2:
用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
与块 3 的重叠部分:
通过机器学习和深度学习提高性能。
==================================================
块 3:
通过机器学习和深度学习提高性能。
递归分块
递归分块(Recursive Chunking)是一种通过多级切分保持语义完整性的方式。
例如:
-
先按标题/章节切分
-
再对每个章节按段落切分
-
再按句子切分
-
…
与固定分块不同,它确保每个块仍然保持逻辑完整,比如技术文档、论文等都有“结构性”,递归分块非常适合。递归分块的优势在于:
-
保留上下文:子块自动继承父块语义(如“3.1节”下的段落关联该节主题);
-
自适应结构:灵活处理非均匀长度文本(如小说对话 vs. 技术文档);
-
优化LLM处理:可与 RAG 结合实现分级检索(先定位章节,再提取段落)。

上图的示例使用递归分块将文本分成四个块,每个块用不同的颜色表示。每个块包含多达80个单词,块之间没有重叠。颜色编码有助于显示内容如何分成逻辑部分,使模型更容易处理和理解长文本而不丢失重要的上下文。
代码示例
现在让我们编写一个示例代码,来实现递归分块。
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 将文本使用递归分块分割的函数
def split_text_recursive(text, chunk_size=80):
# 初始化RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size, # 每个块的最大大小(80个单词)
chunk_overlap=0 # 块之间没有重叠
)
# 将文本分割成块
chunks = text_splitter.split_text(text)
return chunks
# 示例文本
text = """人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。"""
# 使用递归分块分割文本
chunks = split_text_recursive(text, chunk_size=80)
# 输出结果块
for i, chunk in enumerate(chunks):
print(f"块 {i+1}:")
print(chunk)
print("="*50)
上述代码将生成以下输出:
块 1:
人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
==================================================
块 2:
通过机器学习和深度学习提高性能。
==================================================
无论采用哪种分块策略,最终都需要依赖向量数据库快速检索大量块。以 MyScale 为例,由于其底层使用 ClickHouse 的列式存储与并发执行模型,在处理百万乃至十亿级向量时依旧能保持极高吞吐量,这使得更精细的分块策略不会带来检索性能瓶颈。
语义分块
语义分块是基于语义相似度、嵌入向量或主题检测进行智能切分的方法。
它尝试回答:
“哪些内容应该被放在同一个块里?”
例如:
-
AI 技术段落被归为同一个块
-
Prompt Engineering 内容被归为另一个块
语义分块非常适合内容主题高度多样的文本,如:
-
新闻
-
访谈
-
分章节不明显的学术文本
-
多语种混杂内容

在上图中,每个块由不同的颜色表示,蓝色表示 AI,黄色表示Prompt Engineering。这些块之间被分开,因为它们涵盖了不同的主题。这种方法确保模型可以清楚地理解每个主题,而不会混淆它们。
代码示例
现在让我们编写一个示例代码,来实现语义分块。
import os
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings
# 将OpenAI API密钥设置为环境变量(替换为您的实际API密钥)
os.environ["OPENAI_API_KEY"] = "replace with your actual OpenAI API key"
# 将文本分割为语义块的函数
def split_text_semantically(text, breakpoint_type="percentile"):
# 使用OpenAI嵌入初始化SemanticChunker
text_splitter = SemanticChunker(OpenAIEmbeddings(), breakpoint_threshold_type=breakpoint_type)
# 创建文档(块)
docs = text_splitter.create_documents([text])
# 返回块的列表
return [doc.page_content for doc in docs]
def main():
# 示例内容(国情咨文或您自己的文本)
document_content = """
人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
Prompt Engineering涉及设计输入提示,以指导AI模型生成准确和相关的响应,改善文本生成和摘要等任务。
"""
# 使用选择的阈值类型(百分位数)拆分文本
threshold_type = "percentile"
print(f"\n使用{threshold_type}阈值的块:")
chunks = split_text_semantically(document_content, breakpoint_type=threshold_type)
# 打印每个块的内容
for idx, chunk in enumerate(chunks):
print(f"块 {idx + 1}:")
print(chunk)
print()
if __name__ == "__main__":
main()
上述代码将生成以下输出:
使用百分位数阈值的块:
块 1:
人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
块 2:
Prompt Engineering涉及设计输入提示,以指导AI模型生成准确和相关的响应,改善文本生成和摘要等任务。
主动分块
主动分块是是一种动态、智能化的文本分割技术,其核心在于利用 GPT 等大语言模型作为代理,根据具体任务目标和内容特性实时调整分块策略。与传统的固定规则分块(如按字数机械分割)不同,主动分块会结合语义分析、任务需求和实时反馈,动态决定最优分割方案。你可以把它看作:
让模型理解全文后,自己决定合适的分段方式。
例如处理法律合同时,系统会主动识别"违约责任"等关键条款边界;面对学术论文时,则可能优先按"方法-结果"的科研逻辑划分。这种技术让文本预处理从"一刀切"转变为"量体裁衣"。我们。与手动确定如何分割内容不同,LLMs 主动根据其对输入的理解来组织或分割信息。
主动分块通过三重机制实现智能化:
-
任务感知:分析下游应用需求(如问答/摘要/分类),自动匹配分块粒度——问答任务需要精细到句子级,而摘要可能保留完整段落。
-
内容理解:运用NLP技术检测语义边界(如话题转折、对话轮次),结合版式特征(标题/表格)辅助决策。
-
动态优化:采用强化学习或在线反馈机制,持续改进分块策略。例如当系统发现某类分块常导致问答错误时,会自动调整分割阈值。
同样,我们通过一个代码示例来看看如何实现。
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.agents import initialize_agent, Tool, AgentType
# 初始化OpenAI聊天模型(替换为您的API密钥)
llm = ChatOpenAI(model="gpt-3.5-turbo", api_key="replace with your actual OpenAI API key")
# 步骤1:定义分块和摘要的提示模板
chunk_prompt_template = """
您获得了一大段文本。您的任务是,如果需要,将其分成更小的部分(块),并对每个块进行摘要。
一旦所有部分都被摘要,将它们合并成最终摘要。
如果文本已经足够小,可以一次提供完整的摘要。
请对以下文本进行摘要:\n{input}
"""
chunk_prompt = PromptTemplate(input_variables=["input"], template=chunk_prompt_template)
# 步骤2:定义分块处理工具
def chunk_processing_tool(query):
"""处理文本块并生成摘要,使用定义的提示。"""
chunk_chain = LLMChain(llm=llm, prompt=chunk_prompt)
print(f"处理块:\n{query}\n") # 显示正在处理的块
return chunk_chain.run(input=query)
# 步骤3:定义外部工具(可选,可用于获取额外信息)
def external_tool(query):
"""模拟可以获取额外信息的外部工具。"""
return f"基于查询的外部响应:{query}"
# 步骤4:使用工具初始化代理
tools = [
Tool(
name="分块处理",
func=chunk_processing_tool,
description="处理文本块并生成摘要。"
),
Tool(
name="外部查询",
func=external_tool,
description="获取额外数据以增强分块处理。"
)
]
# 使用定义的工具和零样本能力初始化代理
agent = initialize_agent(
tools=tools,
agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
llm=llm,
verbose=True
)
# 步骤5:主动分块处理函数
def agent_process_chunks(text):
"""使用代理处理文本块并生成最终输出。"""
# 步骤1:将文本分块为更小、可管理的部分
def chunk_text(text, chunk_size=500):
"""将大型文本分割为更小的块。"""
return [text[i:i + chunk_size] for i in range(0, len(text), chunk_size)]
chunks = chunk_text(text)
# 步骤2:使用代理处理每个块
chunk_results = []
for idx, chunk in enumerate(chunks):
print(f"处理块 {idx + 1}/{len(chunks)}...")
response = agent.invoke({"input": chunk}) # 使用代理处理块
chunk_results.append(response['output']) # 收集块的结果
# 步骤3:将块的结果合并为最终输出
final_output = "\n".join(chunk_results)
return final_output
# 步骤6:在示例大型文本输入上运行代理
if __name__ == "__main__":
# 示例大型文本内容
text_to_process = """
人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
Prompt Engineering涉及设计输入提示,以指导AI模型生成准确和相关的响应,改善文本生成和摘要等任务。
"""
# 处理文本并输出最终结果
final_result = agent_process_chunks(text_to_process)
print("\n最终输出:\n", final_result)
上述代码将生成以下输出:
处理块 1/3...
> 进入新的AgentExecutor链...
我应该使用分块处理来提取提供的文本中的关键信息。
操作:分块处理
操作输入:人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。处理块:
人工智能(AI)模拟人类智能,用于视觉感知、语音识别和语言翻译等任务。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。
观察:人工智能(AI)通过视觉感知、语音识别和语言翻译等任务模拟人类智能。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。AI在不同领域发挥着重要作用,如视觉感知、语音识别和语言翻译。AI在提高效率和推动创新方面发挥着重要作用。
思考:我需要关于AI在不同领域的影响的更具体信息。
操作:外部查询
操作输入:AI在医疗保健领域的影响
观察:基于查询的外部响应:AI在医疗保健领域的影响
思考:我现在需要关于AI在金融领域的影响的信息。
操作:外部查询
操作输入:AI在金融领域的影响
观察:基于查询的外部响应:AI在金融领域的影响
思考:我现在对AI在医疗保健和金融领域的影响有了更好的了解。
最终答案:人工智能通过视觉感知、语音识别和语言翻译等任务模拟人类智能。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。AI在医疗保健领域帮助诊断疾病、解释医学图像和预测患者结果,在金融领域帮助检测欺诈、管理投资和自动化客户服务。
> 完成链。
处理块 2/3...
> 进入新的AgentExecutor链...
这个问题讨论了与广泛采用AI相关的伦理问题和开发负责任的重要性。
操作:分块处理
操作输入:提供的文本处理块:
提供的文本
观察:很抱歉,但您没有提供任何要摘要的文本。请提供文本,以便我可以帮助您进行摘要?
思考:我需要为分块处理提供文本以进行摘要。
操作:外部查询
操作输入:检索与AI采用和负责任开发相关的伦理问题相关的文本
观察:基于查询的外部响应:检索与AI采用和负责任开发相关的伦理问题相关的文本
思考:现在我有了与AI采用和负责任开发相关的文本,我可以继续进行分块处理。
操作:分块处理
操作输入:检索到的文本处理块:
检索到的文本
观察:很抱歉,但似乎您没有提供任何要摘要的文本。请提供您希望我摘要的文本。谢谢!
思考:我需要确保为分块处理提供与AI采用和负责任开发相关的文本以生成摘要。
操作:外部查询
操作输入:检索与AI采用和负责任开发相关的伦理问题相关的文本
观察:基于查询的外部响应:检索与AI采用和负责任开发相关的伦理问题相关的文本
思考:现在我有了与AI采用和负责任开发相关的文本,我可以继续进行分块处理以生成摘要。
操作:分块处理
操作输入:与AI采用和负责任开发相关的文本处理块:
与AI采用和负责任开发相关的文本
观察:很抱歉,但您没有提供任何要摘要的文本。请提供您希望我摘要的文本。谢谢!
思考:我需要确保为分块处理提供与AI采用和负责任开发相关的文本以生成摘要。
操作:分块处理
操作输入:与AI采用和负责任开发相关的文本处理块:
与AI采用和负责任开发相关的文本
观察:文本讨论了围绕人工智能(AI)采用的伦理问题以及负责任开发的重要性。它强调了AI算法中的偏见、侵犯隐私以及自主AI系统做出有害决策的潜在问题。文本强调了确保AI技术以负责任的方式开发和部署的透明度、责任和伦理准则的重要性。
思考:文本提供了与AI采用和负责任开发相关的伦理问题的信息,强调了监管、透明度和责任的必要性。
最终答案:文本讨论了围绕人工智能(AI)采用的伦理问题以及负责任开发的重要性。
> 完成链。
处理块 3/3...
> 进入新的AgentExecutor链...
这个问题似乎是关于AI对全球经济的影响和潜在影响的。
操作:分块处理
操作输入:提供的文本处理块:
提供的文本
观察:很抱歉,但您没有提供任何要摘要的文本。请提供您希望我摘要的文本。
思考:我需要为分块处理提供文本以进行摘要。
操作:外部查询
操作输入:获取有关AI对全球经济及其影响的文本
观察:基于查询的外部响应:获取有关AI对全球经济及其影响的文本
思考:现在我有了关于AI对全球经济及其影响的文本,我可以继续进行分块处理。
操作:分块处理
操作输入:获取的文本处理块:
获取的文本
观察:文本讨论了人工智能(AI)对全球经济的重大影响。它强调了AI通过提高生产力、降低成本和创造新的就业机会来改变行业。然而,人们对工作岗位流失和需要重新培训工人以适应不断变化的环境的担忧。总体而言,AI正在重塑经济,促使企业运营方式的转变。
思考:基于分块处理生成的摘要,AI对全球经济的影响似乎是重大的,既有积极的方面,也有负面的影响。
最终答案:AI对全球经济的影响是重大的,它通过提高生产力、降低成本、创造新的就业机会,但也引发了对工作岗位流失和工人重新培训的担忧。
> 完成链。
最终输出:
人工智能通过视觉感知、语音识别和语言翻译等任务模拟人类智能。它已从基于规则的系统发展到基于数据驱动的模型,通过机器学习和深度学习提高性能。AI在医疗保健领域帮助诊断疾病、解释医学图像和预测患者结果,在金融领域帮助检测欺诈、管理投资和自动化客户服务。
文本讨论了围绕人工智能(AI)采用的伦理问题以及负责任开发的重要性。
AI对全球经济的影响是重大的,它通过提高生产力、降低成本、创造新的就业机会,但也引发了对工作岗位流失和工人重新培训的担忧。
分块策略比较
为了更容易理解不同的分块方法,下表比较了固定大小分块、递归分块、语义分块和主动分块。它突出了每种方法的工作原理、最佳用途和局限性。
| 分块类型 | 描述 | 方法 | 最适用于 | 工程局限 | 对数据库的要求 |
|---|---|---|---|---|---|
| 固定长度分块 | 按字符或词数均匀切分 | 固定区间+重叠 | 文本结构简单、对语义要求不高 | 容易断句;块数量大 | 高吞吐 ANN 检索、支持大量向量 |
| 递归分块 | 按标题/段落等结构多级切分 | 自顶向下递归 | 结构化文本(论文、协议) | 块大小不均;需保留层级信息 | 强过滤能力(章节、层级)、并行查询 |
| 语义分块 | 根据含义或相关主题将文本分割成块。 | 使用 NLP 技术(如句子嵌入)识别具有相似含义或语义结构的文本部分。 | 对上下文敏感的任务,连贯性和主题连续性至关重要。 | 需要 NLP 技术;实现更复杂。 | |
| 主动分块 | LLM 自动决定切分方式 | LLM 任务感知+语义识别 | 复杂任务、个性化需求 | 查询量波动大;成本高 | 稳定并行执行、低延迟、过滤与向量混合查询 |
结论
分块策略和 RAG 对于增强 LLMs 至关重要。分块有助于将复杂数据简化为更小、可管理的部分,从而实现更有效的处理,而 RAG 通过在生成工作流中融入实时数据检索来改进 LLMs。这些方法的共同作用使 LLMs 能够通过将有组织的数据与活跃的、实时的信息相结合,提供更精确、上下文感知的回复。分块处理是 LLM 应对长文本的“化整为零”策略,虽不完美,但结合检索增强(RAG)等技术,已成为当前突破上下文窗口限制的主流方案。
分块策略提供了多种“如何切文本”的方案,而向量数据库提供了“如何快速找回合适的块”的能力。两者共同构成:
-
大模型上下文补全能力
-
实时知识更新能力
-
多文档深度理解能力
而 MyScale 在整个链路中扮演的是:让所有分块策略真正有效的“性能和稳定性基石”。无论你选择固定分块、递归分块、语义分块还是主动分块,最终都需要一个高性能、具备 SQL 与向量一体化能力的数据库来支撑整个 RAG 系统。MyScale 的加入让本文所有的策略不仅停留在概念层面,而是真正能在企业级场景落地。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐

所有评论(0)