对 Markdown 文本进行切分,LangChain 提供了两种核心方案,分别适用于不同的场景。最推荐且最灵活的方式是组合使用它们:先用MarkdownHeaderTextSplitter按标题结构切分,再用RecursiveCharacterTextSplitter控制块大小。
下面我来详细分析这两种方案,并给出完整的代码示例。
🔍 两种核心切分方案对比
方案 | 核心原理 | 优势 | 适用场景 |
| 根据 Markdown 标题(如 | 最大限度地保留文档的语义结构和上下文。检索时可以根据标题元数据进行过滤,精确找到特定章节的内容。 | 需要利用文档结构进行检索的 RAG 应用,例如基于技术文档、产品手册的问答系统。 |
| 通过一个包含 Markdown 语法特定分隔符(如 | 实现简单,能有效控制块的大小,防止单个块过大或过小,通用性强。 | 对文档结构要求不高,主要目标是控制输入大模型文本长度的场景。 |
🚀 最佳实践方案:组合切分
在实际应用中,通常将两者结合,以达到最佳效果:
第一阶段:按标题切分- 使用
MarkdownHeaderTextSplitter将文档按标题层级分割成大的语义块,并提取元数据。第二阶段:按字符递归切分- 对每个大的语义块,使用
RecursiveCharacterTextSplitter进一步切分成适合嵌入(Embedding)和检索的小块,并继承第一阶段的元数据。
代码示例
以下是一个完整的 Python 代码示例,演示了如何对 Markdown 文档进行组合切分,并查看结果。
# 首先,安装必要的库 (如果尚未安装) # pip install langchain langchain-text-splitters from langchain.text_splitter import MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter # 1. 准备一个示例 Markdown 文档 markdown_document = """ # 人工智能简介 人工智能(AI)是计算机科学的一个分支,它致力于创建能够执行通常需要人类智能的任务的系统。 ## 机器学习 机器学习是 AI 的一个子集,它使系统能够从数据中学习并改进,而无需明确编程。 ### 监督学习 监督学习使用标记数据集来训练算法,以分类数据或预测结果。 ### 无监督学习 无监督学习使用未标记的数据,算法必须自己找到数据中的模式和关系。 ## 深度学习 深度学习是机器学习的子集,它使用包含多个层的神经网络。这也被称为深度神经网络。 # AI 的应用领域 ## 自然语言处理 自然语言处理(NLP)使计算机能够理解、解释和生成人类语言。 ## 计算机视觉 计算机视觉赋予计算机“看”和理解视觉世界的能力。 """ # 2. 第一阶段:定义我们想要切分的标题层级和对应的元数据键名 headers_to_split_on = [ ("#", "H1"), # 一级标题 ("##", "H2"), # 二级标题 ("###", "H3"), # 三级标题 ] # 创建 MarkdownHeaderTextSplitter 实例 # strip_headers=False 表示保留标题文本在内容中,True 则移除标题文本 markdown_splitter = MarkdownHeaderTextSplitter( headers_to_split_on=headers_to_split_on, strip_headers=False ) # 按标题进行切分,返回一个 Document 列表,每个 Document 都带有 metadata md_header_splits = markdown_splitter.split_text(markdown_document) print("="*30) print("第一阶段切分结果:") print("="*30) for i, doc in enumerate(md_header_splits): print(f"Chunk {i+1}:") print(f" Metadata: {doc.metadata}") print(f" Content Preview: {doc.page_content[:50]}...") print("-"*20) # 3. 第二阶段:对每个标题块进一步进行递归字符切分 # 设置目标块大小和重叠量 chunk_size = 100 chunk_overlap = 20 text_splitter = RecursiveCharacterTextSplitter( chunk_size=chunk_size, chunk_overlap=chunk_overlap, # 可以自定义分隔符列表,例如添加中文句号以优化中文分割 separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] ) # 对按标题切分后的文档列表进行递归切分,每个小块会继承其来源的标题元数据 final_chunks = text_splitter.split_documents(md_header_splits) print("\n" + "="*30) print("第二阶段(最终)切分结果:") print("="*30) for i, chunk in enumerate(final_chunks): print(f"Final Chunk {i+1}:") print(f" Metadata: {chunk.metadata}") print(f" Length: {len(chunk.page_content)} chars") print(f" Content: {repr(chunk.page_content)}") print("-"*30)代码输出示例
============================== 第一阶段切分结果: ============================== Chunk 1: Metadata: {'H1': '人工智能简介'} Content Preview: # 人工智能简介 人工智能(AI)是计算机科学的一个分支... -------------------- Chunk 2: Metadata: {'H1': '人工智能简介', 'H2': '机器学习'} Content Preview: ## 机器学习 机器学习是 AI 的一个子集,它使... -------------------- Chunk 3: Metadata: {'H1': '人工智能简介', 'H2': '机器学习', 'H3': '监督学习'} Content Preview: ### 监督学习 监督学习使用标记数据集来训... -------------------- Chunk 4: Metadata: {'H1': '人工智能简介', 'H2': '机器学习', 'H3': '无监督学习'} Content Preview: ### 无监督学习 无监督学习使用未标记的数据,算... -------------------- Chunk 5: Metadata: {'H1': '人工智能简介', 'H2': '深度学习'} Content Preview: ## 深度学习 深度学习是机器学习的子集,它使... -------------------- Chunk 6: Metadata: {'H1': 'AI 的应用领域'} Content Preview: # AI 的应用领域 ## 自然语言处理 自然语言处理(NLP)... -------------------- Chunk 7: Metadata: {'H1': 'AI 的应用领域', 'H2': '自然语言处理'} Content Preview: ## 自然语言处理 自然语言处理(NLP)使计算机能... -------------------- Chunk 8: Metadata: {'H1': 'AI 的应用领域', 'H2': '计算机视觉'} Content Preview: ## 计算机视觉 计算机视觉赋予计算机“看”和理解... -------------------- ... (后续会展示第二阶段切分后的更小块)💡 参数调优建议
chunk_size和chunk_overlap:这是最关键的参数。chunk_size通常在500-1000个字符之间效果较好。chunk_overlap一般设置为chunk_size的10%-20%,以防止关键信息在切分边界处丢失。separators优化:在处理中文文档时,可以在RecursiveCharacterTextSplitter的separators列表中添加中文句号(。)、感叹号(!)、问号(?)等,使切分更符合中文的语义边界。strip_headers:MarkdownHeaderTextSplitter的参数。如果希望在最终块的内容中保留标题文本以便模型阅读上下文,设置为False;如果希望内容更纯净,仅将标题用于元数据过滤,设置为True。return_each_line:MarkdownHeaderTextSplitter的参数。如果希望对每个文本行进行更精细的控制(例如,自定义聚合逻辑),可以启用此选项,让分割器返回单行文档。