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

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

相关推荐
程序员爱钓鱼43 分钟前
Go语言实战案例-简易计算器(加减乘除)
后端
学不会就看1 小时前
Django--01基本请求与响应流程
后端·python·django
Nejosi_念旧6 小时前
解读 Go 中的 constraints包
后端·golang·go
风无雨6 小时前
GO 启动 简单服务
开发语言·后端·golang
小明的小名叫小明6 小时前
Go从入门到精通(19)-协程(goroutine)与通道(channel)
后端·golang
斯普信专业组6 小时前
Go语言包管理完全指南:从基础到最佳实践
开发语言·后端·golang
一只叫煤球的猫8 小时前
【🤣离谱整活】我写了一篇程序员掉进 Java 异世界的短篇小说
java·后端·程序员
你的人类朋友9 小时前
🫏光速入门cURL
前端·后端·程序员
aramae11 小时前
C++ -- STL -- vector
开发语言·c++·笔记·后端·visual studio
lifallen11 小时前
Paimon 原子提交实现
java·大数据·数据结构·数据库·后端·算法