Skip to content

分块策略与向量数据库

分块 (Chunking) 是 RAG 中至关重要的一步。分块太大,检索不精确;分块太小,丢失上下文。就像切面包——切太厚一片吃不完,切太薄又散架。

三种分块策略
1. 固定大小分块 (Fixed-size)
[500字][500字][500字][500字]
简单但可能在句子中间截断

2. 语义分块 (Semantic)
[段落1][──段落2──][3][──段落4─]
按语义边界切分,长度不等

3. 递归分块 (Recursive)
先按 \n\n 分 → 太长则按 \n 分 → 仍太长按句号分
[自然段][自然段][句子][自然段]
LangChain 默认策略,平衡性最好
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块最大字符数
chunk_overlap=50, # 相邻块重叠字符数
separators=["\n\n", "\n", "", "", " ", ""], # 中文优化
)
text = """第一章 引言
人工智能正在改变世界。本书将介绍 AI Agent 的核心概念。
第二章 基础
Agent 是能够感知环境并采取行动的自主实体。"""
chunks = splitter.split_text(text)
for i, chunk in enumerate(chunks):
print(f"Chunk {i}: {chunk[:50]}...")
参数小值大值
chunk_size检索精确,但缺乏上下文上下文丰富,但检索噪音大
chunk_overlap节省存储,但可能丢失边界信息保留连贯性,但冗余增加

经验值:

  • chunk_size: 300-1000 字符(中文建议 300-500)
  • chunk_overlap: chunk_size 的 10-20%
flowchart TD
    subgraph Light["轻量/原型"]
        Chroma["Chroma\n本地嵌入"]
        pgvector["pgvector\n用现有 PG"]
    end
    subgraph Prod["生产级"]
        Pinecone["Pinecone\n全托管 SaaS,零运维"]
        Milvus["Milvus\n十亿级向量,大规模场景"]
        Weaviate["Weaviate\n多模态友好,GraphQL"]
    end

详细对比:

数据库部署方式规模特点适用场景
Chroma嵌入式/本地零配置,Python 原生原型开发、个人项目
pgvectorPostgreSQL 扩展复用已有 PG 基础设施已有 PG 的团队
Pinecone全托管 SaaS零运维,自动扩缩不想管基础设施
Milvus自部署/云超大十亿级向量、GPU 加速大规模企业应用
Weaviate自部署/云GraphQL API、多模态复杂查询需求

选型建议:

  • 刚起步 → Chroma(5 分钟上手)
  • 已有 PostgreSQL → pgvector(无需新增组件)
  • 生产环境、不想运维 → Pinecone
  • 大规模、需要自控 → Milvus

仅靠向量相似度检索不够精准,Metadata 过滤可以大幅提升质量:

# 存储时附加 metadata
vector_db.add(
documents=["FastAPI 3.0 发布了新特性..."],
embeddings=[embedding],
metadatas=[{
"source": "blog",
"category": "python",
"date": "2025-06-01",
"author": "张三",
}],
ids=["doc_001"],
)
# 检索时使用 metadata 过滤
results = vector_db.query(
query_embeddings=[query_embedding],
n_results=5,
where={
"$and": [
{"category": {"$eq": "python"}},
{"date": {"$gte": "2025-01-01"}},
]
},
)

Metadata 过滤的典型用途:

  • 按时间 —— 只检索最近的文档
  • 按来源 —— 只搜公司内部文档
  • 按权限 —— 用户只能搜索有权限的内容
  • 按类别 —— 技术文档 vs 法律文档分开搜索

  • 中文分块用英文分隔符:默认的 RecursiveCharacterTextSplitter 分隔符优先列表针对英文设计(如 \n\n. ),中文应使用 等中文标点。
  • chunk_size 单位混淆chunk_size 是字符数而非 Token 数。中文 1 字符 ≈ 1-2 Token,英文 1 Token ≈ 4 字符。建议同时检查 Token 数是否超出 Embedding 模型限制。
  • 忽略文档结构:对 Markdown/HTML 文档不利用标题层级信息,导致一个 chunk 跨越多个不相关的章节。可用 MarkdownHeaderTextSplitter 按标题切分。
自测题 1:递归分块为什么是最推荐的分块策略?
它按优先级依次尝试多种分隔符(段落→换行→句子),尽量在自然语义边界切分,兼顾了块大小的一致性和语义的完整性。
自测题 2:chunk_overlap 的作用是什么?
让相邻块之间有重叠内容,避免重要信息恰好在切分边界被截断,保持上下文连贯性。
自测题 3:什么场景下应该选 pgvector 而不是 Pinecone?
团队已有 PostgreSQL 基础设施、数据量中等、希望减少外部依赖、数据不能出境(合规要求)的场景。