RAG 每日一技(三):不止文本,代码和Markdown如何优雅地分块?

前情回顾

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

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

  • 我们自己写的项目代码
  • 我们整理的技术笔记(Markdown格式)

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

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

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

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

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

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

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

python 复制代码
# 导入针对Python的递归字符分块器
from langchain.text_splitter import (
    RecursiveCharacterTextSplitter,
    Language,
)

# 一段Python代码示例
python_code = """
import os
import sys

class MyClass:
    def __init__(self, name):
        self.name = name

    def say_hello(self):
        print(f"Hello, {self.name}!")

def my_function(x, y):
    return x + y

if __name__ == "__main__":
    instance = MyClass("World")
    instance.say_hello()
    result = my_function(5, 3)
    print(f"Result is {result}")
"""

# 使用 RecursiveCharacterTextSplitter.from_language() 方法
# 传入语言枚举值 Language.PYTHON
python_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")

输出结果:

python 复制代码
--- Chunk 1 ---
import os
import 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)

效果分析

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

  • 导入语句(import) 被单独分为一块。
  • 整个 MyClass,包含它的构造函数和方法,被完整地保留在了一个块里。
  • 独立的 my_function 函数 也自成一块。
  • 主执行模块 if __name__ == "__main__" 的内容也被聚合在一起。

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

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

Markdown文件的分割

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

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

python 复制代码
# 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")

输出结果:

markdown 复制代码
--- 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

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

相关推荐
codervibe2 小时前
中高交互蜜罐升级 🚀
后端
codervibe2 小时前
多协议蜜罐初体验 🐝
后端
SamsongSSS2 小时前
《C++ Primer Plus》读书笔记 第二章 开始学习C++
c++·后端
9号达人2 小时前
Java18 新特性详解与实践
java·后端·面试
我不是混子2 小时前
java浮点数精度问题及解决方案
java·后端
karry_k2 小时前
混合存储架构
后端
yunxi_052 小时前
我用 Elasticsearch 做 RAG 检索的一些“土经验”
后端·llm
JaguarJack2 小时前
PHP 8.2 vs PHP 8.3 对比:新功能、性能提升和迁移技巧
后端·php
学历真的很重要2 小时前
Claude Code 万字斜杠命令指南
后端·语言模型·面试·职场和发展·golang·ai编程
稻草猫.3 小时前
Java线程安全:volatile与wait/notify详解
java·后端·idea