掘金 人工智能 07月11日 17:09
RAG 每日一技(三):不止文本,代码和Markdown如何优雅地分块?
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了如何针对代码、Markdown等结构化文本进行更有效的分块处理,以提升AI对内容的理解能力。文章指出,传统的通用文本分割方法在处理结构化文本时效果不佳,容易破坏代码逻辑和文档结构。为了解决这个问题,文章介绍了LangChain框架提供的针对特定语言的分割器,这些分割器基于编程语言的语法结构或Markdown的标题层级进行分割,从而更好地保留了文本的逻辑单元。通过Python代码示例和Markdown文本示例,展示了如何使用这些分割器,并强调了其在RAG系统中的重要性。

💡 传统的通用文本分割方法在处理代码和Markdown等结构化文本时,容易破坏代码的逻辑单元和Markdown的章节结构,导致AI理解内容时出现偏差。

💻 针对特定语言的分割器 (Language-Specific Splitters) 基于编程语言的语法结构(如类、函数、导入语句)或Markdown的标题层级进行分割,能够更智能地保留文本的逻辑单元。

🐍 LangChain框架提供了`RecursiveCharacterTextSplitter.from_language()`方法,支持多种编程语言和格式,例如Python、CPP、Markdown等,只需传入对应的枚举值即可轻松实现特定语言的分块。

📚 在Markdown文件中,分割器会根据标题层级(如`#`, `##`, `###`)进行分割,保持文档的章节结构,使得后续的检索和生成更加准确。

🚀 通过使用特定语言的分割器,可以为RAG系统提供更优质的文本块,为后续的Embedding和信息检索打下坚实的基础。

前情回顾

上一篇文章 中,我们掌握了强大的递归字符分块法,它能智能地按段落和句子来分割通用文本,效果拔群。对于大多数文章、文档类的处理,它已经足够优秀。

但现实世界是复杂的。作为开发者,我们经常需要让AI理解的,不仅仅是纯文本,还有:

如果继续用之前的方法来处理这些带有鲜明结构化特征的内容,会发生什么?

想象一下,一个完整的Python函数被从中间拦腰截断,或者一个Markdown的二级标题和它的内容被分到两个不同的块里。这无疑是一场灾难,会严重误导后续的检索和生成。

所以,今天我们的任务就是:为特定格式的内容,找到专属的、更优雅的分块方法。

针对特定语言的分割器 (Language-Specific Splitters)

幸运的是,像 LangChain 这样的框架已经为我们考虑到了这一点。它内置了针对多种主流编程语言的分割器。

其核心思想是:不再基于通用的标点符号,而是基于编程语言本身的语法结构(如类、函数、导入语句等)来进行分割。

我们以 Python 为例,直接上代码。

# 导入针对Python的递归字符分块器from langchain.text_splitter import (    RecursiveCharacterTextSplitter,    Language,)# 一段Python代码示例python_code = """import osimport sysclass MyClass:    def __init__(self, name):        self.name = name    def say_hello(self):        print(f"Hello, {self.name}!")def my_function(x, y):    return x + yif __name__ == "__main__":    instance = MyClass("World")    instance.say_hello()    result = my_function(5, 3)    print(f"Result is {result}")"""# 使用 RecursiveCharacterTextSplitter.from_language() 方法# 传入语言枚举值 Language.PYTHONpython_splitter = RecursiveCharacterTextSplitter.from_language(    language=Language.PYTHON, chunk_size=150, chunk_overlap=0)# 进行分块chunks = python_splitter.split_text(python_code)# 我们来看看分块结果for i, chunk in enumerate(chunks):    print(f"--- Chunk {i+1} ---")    print(chunk)    print(f"(长度: {len(chunk)})\n")

输出结果:

--- Chunk 1 ---import osimport sys(长度: 19)--- Chunk 2 ---class MyClass:    def __init__(self, name):        self.name = name    def say_hello(self):        print(f"Hello, {self.name}!")(长度: 129)--- Chunk 3 ---def my_function(x, y):    return x + y(长度: 38)--- Chunk 4 ---if __name__ == "__main__":    instance = MyClass("World")    instance.say_hello()    result = my_function(5, 3)    print(f"Result is {result}")(长度: 141)

效果分析

太漂亮了!看看这个分割结果:

这种基于语法的分割,完美地保留了代码的逻辑单元。当用户提问“MyClass类有什么功能?”时,检索系统能精准地定位到Chunk 2,为大模型提供最相关的、最完整的上下文。

除了Python,LangChain 还支持 CPP, GO, JAVA, JS, PHP, PROTO, RUBY, RST, SCALA, SWIFT, MARKDOWN, LATEX, HTML 等多种语言和格式。你只需要在 language 参数中传入对应的枚举值即可,非常方便。

Markdown文件的分割

Markdown是我们写技术文档和笔记的利器。它的标题层级(#, ##, ###)天然就是内容的逻辑分割线。

RecursiveCharacterTextSplitter 在处理 Language.MARKDOWN 时,会智能地将这些标题符号作为高优先级的分割符。

# Markdown文本示例markdown_text = """# RAG系统概述RAG(Retrieval-Augmented Generation)是一种强大的AI框架。## 核心组件RAG系统主要包含两个核心组件:1.  **检索器 (Retriever)**:负责从知识库中快速找到相关文档。2.  **生成器 (Generator)**:基于检索到的信息生成答案。### 检索器的技术细节检索器通常使用向量数据库实现..."""# 使用针对Markdown的分割器markdown_splitter = RecursiveCharacterTextSplitter.from_language(    language=Language.MARKDOWN, chunk_size=100, chunk_overlap=0)chunks = markdown_splitter.split_text(markdown_text)for i, chunk in enumerate(chunks):    print(f"--- Chunk {i+1} ---")    print(chunk)    print(f"(长度: {len(chunk)})\n")

输出结果:

--- Chunk 1 ---# RAG系统概述RAG(Retrieval-Augmented Generation)是一种强大的AI框架。(长度: 57)--- Chunk 2 ---## 核心组件RAG系统主要包含两个核心组件:1.  **检索器 (Retriever)**:负责从知识库中快速找到相关文档。2.  **生成器 (Generator)**:基于检索到的信息生成答案。(长度: 99)--- Chunk 3 ---### 检索器的技术细节检索器通常使用向量数据库实现...(长度: 34)

可以看到,分割完全按照 h1, h2, h3 的标题层级进行,保持了文档的章节结构,非常符合预期。

总结与预告

今日小结:

    处理代码、Markdown等结构化文本时,不要使用通用的文本分割器。应该使用针对特定语言的分割器 (Language-Specific Splitters),它能基于语法和标记(如函数、类、Markdown标题)进行更智能、更符合逻辑的分割。在 LangChain 中,通过 RecursiveCharacterTextSplitter.from_language() 方法可以轻松实现这一点。

到目前为止,我们已经掌握了如何将各种类型的文档“优雅地”切分成高质量的文本块 (Chunks)。

我们的“原材料”准备好了。下一步,就是要将这些文本块转化成机器能够理解和比较的数学形式——向量 (Vectors)

这个过程,就是 Embedding。选择什么样的Embedding模型,将直接决定你的RAG系统能否“读懂”文本的深层含义。

明天预告:RAG 每日一技(四):不止是切分,如何让机器读懂文本的“灵魂”——初探Embedding

准备好进入向量的世界了吗?明天我们不见不散!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LangChain 文本分割 RAG 代码处理 Markdown
相关文章