在 RAG(检索增强生成)应用中,向量数据库用于保存文档切分后的文本向量,并在用户提问时快速召回语义最相关的内容。本文以 Redis 和 Pinecone 两种向量数据库为例,梳理从文档加载、文本切分、向量入库到相似度检索与元数据过滤的完整流程。
一、RAG 离线与在线流程
整个流程可分为两部分:
-
离线数据处理:加载原始文档,将文档切分为较小的文本块,调用 Embedding 模型生成向量,再存入向量数据库。
-
在线检索问答:将用户问题转为向量,在向量库中检索相关文本块,把检索结果连同提示词交给大模型生成最终回答。
Markdown / PDF / 数据库
↓
文档加载(Loader)
↓
文本切分(Splitter)
↓
Embedding 向量化
↓
向量数据库(Redis / Pinecone)
↓
相似度检索 + 元数据过滤
↓
Prompt + LLM
↓
最终回答
二、Embedding 模型:文本与向量之间的桥梁
OpenAIEmbeddings 负责调用兼容 OpenAI 协议的 Embedding 服务,将文本转换为高维浮点向量。
from langchain_openai import OpenAIEmbeddings
import os
embeddings = OpenAIEmbeddings(
model="qwen3.7-text-embedding",
api_key=os.environ["DASHSCOPE_API_KEY"],
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
check_embedding_ctx_length=False,
)
核心参数说明:
-
model:指定向量模型。向量维度必须与向量数据库索引配置一致。 -
api_key:服务访问密钥,推荐从环境变量中读取。 -
base_url:兼容 OpenAI API 的服务地址。注意这里应为普通字符串,不能写成 Markdown 链接。 -
check_embedding_ctx_length=False:可避免部分兼容服务在分词或上下文长度检查上的兼容性问题;是否关闭应结合实际服务测试。
Embedding 的本质是让语义相近的文本在向量空间中距离更近。因此,"项目介绍"和"系统简介"即使字面不同,也可能被检索为相近内容。
三、文档加载与文本切分
Markdown 文档可通过 UnstructuredMarkdownLoader 加载:
from langchain_community.document_loaders import UnstructuredMarkdownLoader
loader = UnstructuredMarkdownLoader(
"../Docs/MarkDown/脚手架级微服务租房平台Q&A.md"
)
data = loader.load()
加载后得到的是 Document 对象列表,每个对象通常包含:
-
page_content:文本正文; -
metadata:来源文件、页码、自定义标签等元数据。
随后使用 CharacterTextSplitter 对文档切分:
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
chunk_size=200,
chunk_overlap=50,
)
docs = text_splitter.split_documents(data)
参数含义:
-
chunk_size=200:每个文本块的最大字符数。 -
chunk_overlap=50:相邻文本块保留 50 个字符重叠区域,降低切分边界导致的上下文丢失。
文本不宜过长,否则一个向量会混入多个主题;也不宜过短,否则缺少足够语义。实际项目中可根据文档类型、模型上下文窗口和检索效果调整切分大小。
四、元数据:让向量检索更可控
除了文本向量,还可以给每个文档块写入元数据:
for i, doc in enumerate(docs, start=1):
doc.metadata["category"] = "qa"
doc.metadata["num"] = i
这里:
-
category:文档类别,例如qa、product、faq; -
num:文本块序号,便于演示数值范围过滤。
元数据不参与文本语义计算,但可以在检索时缩小范围。例如,只在"问答"分类中检索,或只检索序号大于 6 的文档块。
五、Redis Vector Store:适合自建与精细过滤
Redis 在安装 Redis Stack 或 RedisSearch 模块后,可以支持向量检索。LangChain 通过 RedisVectorStore 将文档、向量和元数据写入 Redis。
from langchain_redis import RedisVectorStore, RedisConfig
config_redis = RedisConfig(
redis_url="redis://<host>:6379",
index_name="qa",
metadata_schema=[
{"name": "category", "type": "tag"},
{"name": "num", "type": "numeric"},
],
)
vectorstore = RedisVectorStore(
config=config_redis,
embeddings=embeddings,
)
1. Redis 索引与 Redis Key 的关系
Redis 向量检索并不是把所有数据直接放到一个"表"中,而是:
-
每一个文档块保存为一个 Redis Key;
-
文档内容、向量和元数据保存在对应 Key 的字段中;
-
RedisSearch 创建 Index,为这些字段建立检索索引;
-
查询时先通过 Index 找到匹配的 Key,再返回对应文档。
常见元数据字段类型包括:
-
TAG:精确匹配的分类或标签,例如category=qa; -
NUMERIC:整数或浮点数,可用于范围过滤; -
TEXT:全文文本检索; -
GEO:地理位置坐标检索。
因此,metadata_schema 不是可有可无的配置:只有声明后的元数据字段,才能被 RedisSearch 正确用于过滤。
2. 写入文档
for i in range(0, len(docs), 20):
vectorstore.add_documents(docs[i:i + 20])
批量写入可以减少网络调用次数。示例中每批 20 条,实际批次大小需要结合服务限制、文本长度和网络情况调整。
3. 元数据过滤检索
from redisvl.query.filter import Tag, Num
filter_config = (
(Tag("category") == "qa") &
(Num("num") >= 6)
)
search_docs = vectorstore.similarity_search_with_score(
"项目介绍",
k=2,
filter=filter_config,
fetch_k=10,
)
这里的逻辑是:
-
先将"项目介绍"转换成查询向量;
-
限定
category必须为qa; -
限定
num必须大于等于 6; -
从候选结果中返回最相近的 2 条。
k 表示最终返回数量,fetch_k 表示先召回的候选数量。过滤条件较多时,适当提高 fetch_k 通常有助于提高召回稳定性。
六、Pinecone Vector Store:适合托管式云向量检索
Pinecone 是托管式向量数据库,无需自行维护 Redis 服务或索引模块,更适合快速构建云端 RAG 应用。
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone()
index_name = "qa"
if not pc.has_index(index_name):
pc.create_index(
name=index_name,
dimension=1024,
metric="cosine",
spec=ServerlessSpec(
cloud="aws",
region="us-east-1",
),
)
index = pc.Index(index_name)
创建索引时需要重点关注:
-
dimension=1024:向量维度,必须与 Embedding 模型的实际输出维度完全一致。 -
metric="cosine":采用余弦相似度衡量文本语义接近程度。 -
cloud和region:指定 Pinecone 的部署云平台与区域,应尽量选择接近应用服务的区域以降低延迟。
通过 LangChain 封装索引:
from langchain_pinecone import PineconeVectorStore
vectorstore = PineconeVectorStore(
embedding=embeddings,
index=index,
)
写入与检索方式与其他 LangChain 向量库基本一致:
ids = vectorstore.add_documents(docs)
result = vectorstore.similarity_search(
query="项目介绍",
k=5,
)
七、Redis 与 Pinecone 的主要区别
| 对比项 | Redis Vector Store | Pinecone Vector Store |
|---|---|---|
| 部署方式 | 自建或使用托管 Redis | 云端托管服务 |
| 运维成本 | 需要维护 Redis、模块、索引和容量 | 平台负责底层运维 |
| 元数据过滤 | RedisSearch 的 TAG、NUMERIC 等字段类型清晰 | 支持元数据过滤,按 Pinecone 过滤语法使用 |
| 适用场景 | 已有 Redis 基础设施、低延迟内网检索、缓存与向量一体化 | 快速上线、云端 RAG、大规模向量检索 |
| 索引维度 | 通常由封装或索引配置处理 | 创建索引时必须显式指定 |
| 数据管理 | 可直接操作 Redis Key 与索引 | 通过 Pinecone Index API 管理 |
简单来说:已有 Redis 环境、希望细粒度控制数据和过滤规则时,可以选择 Redis;希望减少运维、快速使用云向量检索能力时,可以选择 Pinecone。
八、常见问题与注意事项
1. 向量维度不一致
Pinecone 的 dimension 必须等于 Embedding 模型输出维度。若不一致,写入向量时会失败。
2. similarity_search 与 similarity_search_with_score
-
similarity_search:只返回相关文档; -
similarity_search_with_score:返回文档及其相似度分数,便于调试召回效果和设置阈值。
九、总结
LangChain 将不同向量数据库的使用方式统一为相似接口:加载文档、切分文本、生成向量、写入向量库、执行相似度检索。真正需要重点关注的是:
-
Embedding 模型与索引维度是否匹配;
-
文本切分策略是否适合业务文档;
-
元数据设计是否支持后续过滤需求;
-
应根据部署成本、运维能力和检索规模选择 Redis 或 Pinecone。