RAG从入门到精通:文档处理与向量化,垃圾进垃圾出?不存在的!
如何用 RecursiveCharacterTextSplitter 智能切分文档。如何用 sentence-transformers 和 ChromaDB 将文本向量化并持久化。源码及依赖下载地址:https://pan.baidu.com/s/1CNntkxr226Xeo_jmnrCCkg?pwd=ek4t下一章,我们将进入检索与生成根据用户问题检索相关文档块。把检索结果和问题一起提交给Dee
大家好,我是阿龙。上一章我们搞定了环境配置和DeepSeek API,今天终于进入RAG系统的核心基石:文档处理与向量化。
这一章有个铁律:垃圾进,垃圾出。如果你的文档切分得像“碎纸机里的残骸”,那检索系统就只能给你“驴唇不对马嘴”的片段,大模型再牛也白搭。
别慌,阿龙今天手把手带你优雅地处理文档,从切分到向量化,每一步都讲透,让你直接打出“组合拳”!
1.1 文档加载与切分(Chunking)—— 切出“黄金语义块”
为什么必须切分?
大模型有上下文窗口限制(比如DeepSeek是64K),但更关键的是:过长的文本会稀释关键信息。想象一下,把一本《十万个为什么》直接塞给模型,它还能精准回答“为什么天是蓝的”吗?
切分的目标是:保持语义完整,同时块大小适中。比如客服知识库,每个段落本身就是独立的“知识点”,切分时就该以段落为边界。
代码实战:模拟加载客服文档
我们先模拟一段客服知识库文本(实际项目里你会用 pypdf 读取PDF,或者用 python-docx 读Word)。
python
from langchain_text_splitters import RecursiveCharacterTextSplitter
import os
# 模拟读取客服知识库文档
def load_documents():
text = """
【退换货政策】
我们的产品支持7天无理由退换货。用户需保证商品包装完好,不影响二次销售。
退款将在收到退回商品后的3个工作日内原路返还。
【发货说明】
每日下午4点前的订单当天发货,4点后的订单次日发货。
合作快递包括顺丰和中通,不支持指定快递。
【会员权益】
注册会员可享受全场98折优惠。
金牌会员(年消费满1000元)享受全场9折及免费上门取件退货服务。
"""
return text
切分器配置:让“剪刀”更智能
LangChain的 RecursiveCharacterTextSplitter 是“递归字符文本分割器”,它会按优先级尝试用不同的分隔符切割,尽量保证块边界在自然断点(比如段落、句号)。
python
def split_text(text):
# chunk_size: 每个块的最大字符数
# chunk_overlap: 块之间的重叠字符数,防止语义被切断(比如句子被切分后,上下文丢失)
splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=20,
separators=["\n\n", "\n", ".", "!", "?"] # 按优先级:段落、换行、句号、感叹号、问号
)
chunks = splitter.split_text(text)
print(f"文档已切分为 {len(chunks)} 个片段")
return chunks
参数详解(面试/项目复盘必问):
- chunk_size:块的最大字符数(不是token数)。如果按字符切分,中文一般一个字算一个字符,但英文单词长度不同。如果追求精准,可以用 TokenTextSplitter(基于token计数)。
- chunk_overlap:重叠大小。比如一句话被切分到两个块里,重叠部分能让后一个块保留前文线索。
- separators:分隔符列表,切分器会按顺序尝试,直到块大小符合要求。这里我加了中文常用的“。”和“!”,避免把一句话切成两半。
运行一下:
python
if __name__ == "__main__":
raw_text = load_documents()
chunks = split_text(raw_text)
for i, chunk in enumerate(chunks):
print(f"块 {i}: {chunk}\n{'-'*40}")
输出结果(示例):
(rag_fresh) fulongmin@fulongdeMacBook-Pro rag % python /Users/fulongmin/Desktop/zm/rag/knowledge_base.py
文档已切分为 3 个片段
块 0: 【退换货政策】
我们的产品支持7天无理由退换货。用户需保证商品包装完好,不影响二次销售。
退款将在收到退回商品后的3个工作日内原路返还。
----------------------------------------
块 1: 【发货说明】
每日下午4点前的订单当天发货,4点后的订单次日发货。
合作快递包括顺丰和中通,不支持指定快递。
----------------------------------------
块 2: 【会员权益】
注册会员可享受全场98折优惠。
金牌会员(年消费满1000元)享受全场9折及免费上门取件退货服务。
----------------------------------------
(rag_fresh) fulongmin@fulongdeMacBook-Pro rag %
注意:实际开发中,chunk_size需要根据你的模型和文档特点调整。太小会丢失上下文,太大则检索精度下降。一般经验值:中文场景 200~500 字符,英文 100~300 token。
4.2 向量化存储(Embedding)—— 把文字变成“数学语言”
计算机不懂文字,只懂数字。所以我们需要把切分好的文本块转换成向量(Embedding),然后存入向量数据库。
选择Embedding模型
我们用 sentence-transformers 的 all-MiniLM-L6-v2 模型,它轻量、效果好,适合入门。首次运行会自动下载模型(约80MB)。
如果没有自动下载,可以执行下面的命令:
pip install chromadb
初始化ChromaDB(持久化存储)
ChromaDB是一个轻量级向量数据库,支持本地持久化,非常友好。
python
import chromadb
from chromadb.utils import embedding_functions
# 初始化客户端,指定持久化路径(之后重启程序也能加载数据)
chroma_client = chromadb.PersistentClient(path="./chroma_db")
# 创建Embedding函数
emb_fn = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="all-MiniLM-L6-v2"
)
def store_vectors(chunks):
# 获取或创建集合(Collection相当于数据库中的表)
collection = chroma_client.get_or_create_collection(
name="customer_service_kb",
embedding_function=emb_fn
)
# 生成唯一的ID
ids = [f"id_{i}" for i in range(len(chunks))]
# 添加元数据(比如来源、时间戳),方便后续过滤
metadatas = [{"source": "policy_doc"} for _ in chunks]
# 添加向量数据
collection.add(
documents=chunks, # 原始文本
metadatas=metadatas, # 元数据
ids=ids # 唯一ID
)
print(f"成功存储 {len(chunks)} 条向量数据")
return collection
整合流程
把前面的函数串起来:
python
if __name__ == "__main__":
# 1. 加载文档
raw_text = load_documents()
# 2. 切分文档
chunks = split_text(raw_text)
# 3. 存储向量
collection = store_vectors(chunks)
运行后,你会在项目目录下看到一个 chroma_db 文件夹,里面就是持久化的向量数据。
常见问题与技巧
Q1: 切分时如何保留Markdown/HTML结构?
- 可以用 MarkdownHeaderTextSplitter 或 HTMLHeaderTextSplitter,按标题层级切分,并保留上下文信息。
Q2: 中文句号切分不准确?
- RecursiveCharacterTextSplitter 的分隔符列表里加上中文标点,比如 。!?,同时注意编码。如果文本中有英文句点,可能导致误切,可以优先用段落切分。
Q3: 向量化模型怎么选?
- 英文场景:all-MiniLM-L6-v2(快)、BAAI/bge-large-en(准)。中文场景:uer/sbert-base-chinese-nli、moka-ai/m3e-base。如果想省钱,也可以用DeepSeek的Embedding API(后面会讲)。
Q4: ChromaDB的数据怎么查询?
- 用 collection.query(query_texts=["你的问题"], n_results=3) 就能检索最相似的3个文本块。后面会专门讲检索。
Q5: 文档更新后怎么增量添加?
- ChromaDB支持 add 相同ID会覆盖,或者你可以先 delete 再 add。也可以维护版本号在metadata里。
总结与预告
今天你学会了:
- 如何用 RecursiveCharacterTextSplitter 智能切分文档。
- 如何用 sentence-transformers 和 ChromaDB 将文本向量化并持久化。
- 源码及依赖下载地址:https://pan.baidu.com/s/1CNntkxr226Xeo_jmnrCCkg?pwd=ek4t
下一章,我们将进入检索与生成环节:
- 根据用户问题检索相关文档块。
- 把检索结果和问题一起提交给DeepSeek API,生成最终答案。
- 构建一个完整的客服问答机器人原型!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)