返回博客
人工智能 2025年4月11日 6 分钟阅读 · 1326 字
RAG 检索增强生成实战:用向量数据库构建企业知识库
从 Embedding 到检索排序,搭建基于私有数据的 AI 问答系统。
#RAG
#向量数据库
#Embedding
#知识库
本文由 AI 辅助生成,经人工审核发布
RAG 是什么
RAG(Retrieval-Augmented Generation,检索增强生成)是一种将外部知识库与大语言模型结合的技术。它通过在生成回答前检索相关文档,让 AI 能够基于私有数据回答问题,而不需要重新训练模型。
为什么需要 RAG
| 问题 | 纯 LLM | RAG |
|---|---|---|
| 知识时效性 | 训练数据截止后无法更新 | 实时检索最新文档 |
| 私有数据 | 无法访问企业内部数据 | 检索私有知识库 |
| 幻觉问题 | 可能编造信息 | 基于真实文档回答 |
| 成本 | 微调成本高 | 无需训练,成本低 |
| 可溯源 | 无法追溯信息来源 | 引用具体文档段落 |
RAG 架构全流程
文档处理:PDF/Word/网页 → 文本提取 → 分块(Chunking) → Embedding → 存入向量数据库
查询流程:用户提问 → Query Embedding → 向量检索 → 取 Top-K 文档 → 拼接 Prompt → LLM 生成回答
文档切分策略
固定长度切分
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块 500 字符
chunk_overlap=50, # 块间重叠 50 字符
separators=["\n\n", "\n", "。", "!", "?", ",", " ", ""]
)
chunks = splitter.split_text(long_document)
参数选择建议
| 文档类型 | chunk_size | overlap | 说明 |
|---|---|---|---|
| 技术文档 | 500-800 | 50-100 | 保持段落完整 |
| 代码文档 | 300-500 | 30-50 | 按函数/类切分 |
| FAQ 问答 | 200-300 | 0 | 每条一个块 |
| 长篇论文 | 800-1200 | 100-200 | 保留上下文 |
| 法律条文 | 按条款 | 0 | 自然分界 |
语义切分
from langchain.text_splitter import SemanticChunker
from langchain.embeddings import OpenAIEmbeddings
splitter = SemanticChunker(
OpenAIEmbeddings(),
breakpoint_threshold_type="percentile",
breakpoint_threshold_amount=95
)
chunks = splitter.split_text(document)
语义切分根据相邻句子的语义相似度决定切分点,效果优于固定长度,但成本更高。
Embedding 模型选择
主流模型对比
| 模型 | 维度 | 最大输入 | 多语言 | 部署方式 | 价格 |
|---|---|---|---|---|---|
| text-embedding-3-large | 3072 | 8191 | 是 | API | $0.13/M tokens |
| text-embedding-3-small | 1536 | 8191 | 是 | API | $0.02/M tokens |
| BGE-M3 | 1024 | 8192 | 是 | 本地 | 免费 |
| M3E-base | 768 | 512 | 中英 | 本地 | 免费 |
| Cohere embed v3 | 1024 | 512 | 是 | API | $0.10/M tokens |
中文场景推荐
# 使用 OpenAI Embedding(效果稳定)
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 使用本地 BGE 模型(免费、中文优化)
from langchain_huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-m3",
model_kwargs={"device": "cuda"}
)
向量数据库对比
| 数据库 | 类型 | 部署方式 | 适用规模 | 特色 |
|---|---|---|---|---|
| Chroma | 嵌入式 | 本地 | <100万 | 轻量、零配置 |
| Pinecone | 云服务 | SaaS | 任意规模 | 全托管、高性能 |
| Weaviate | 开源 | 自托管/云 | 中大型 | 混合检索 |
| Milvus | 开源 | 自托管 | 超大规模 | 分布式、高可用 |
| Qdrant | 开源 | 自托管/云 | 中大型 | Rust 编写、高性能 |
| pgvector | PG 扩展 | 自托管 | 中小型 | 与 PostgreSQL 集成 |
Chroma 快速上手
import chromadb
client = chromadb.PersistentClient(path="./vector_db")
collection = client.get_or_create_collection(
name="knowledge_base",
metadata={"hnsw:space": "cosine"}
)
# 添加文档
collection.add(
documents=["文档内容1", "文档内容2"],
metadatas=[{"source": "file1.pdf"}, {"source": "file2.pdf"}],
ids=["doc1", "doc2"]
)
# 检索
results = collection.query(
query_texts=["用户问题"],
n_results=5
)
检索优化
基础检索
def basic_retrieve(query: str, k: int = 5):
"""基础向量检索"""
query_embedding = embeddings.embed_query(query)
results = vectorstore.similarity_search_by_vector(
query_embedding, k=k
)
return results
Hybrid Search(混合检索)
from langchain.retrievers import BM25Retriever, EnsembleRetriever
# 关键词检索(BM25)
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 5
# 向量检索
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# 混合检索
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.3, 0.7] # BM25 权重 30%,向量权重 70%
)
results = ensemble_retriever.invoke("用户问题")
重排序(Reranking)
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
# 先检索 Top-20,再重排序为 Top-5
compression_retriever = ContextualCompressionRetriever(
base_retriever=vectorstore.as_retriever(search_kwargs={"k": 20}),
base_compressor=CohereRerank(top_n=5)
)
results = compression_retriever.invoke("用户问题")
检索质量对比
| 方法 | 召回率 | 准确率 | 延迟 | 成本 |
|---|---|---|---|---|
| 纯向量检索 | 中 | 中 | 低 | 低 |
| 纯关键词检索 | 中 | 高 | 低 | 低 |
| 混合检索 | 高 | 高 | 中 | 中 |
| 混合+重排序 | 最高 | 最高 | 高 | 较高 |
完整 RAG 实现
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
# 1. 准备检索器
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 5}
)
# 2. 设计 Prompt
system_prompt = """你是一个知识库助手。根据以下检索到的上下文回答用户问题。
如果上下文中没有相关信息,请明确说明"根据现有资料,我无法回答这个问题"。
回答时请引用来源文档。
上下文:
{context}
"""
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", "{input}"),
])
# 3. 构建 RAG 链
llm = ChatOpenAI(model="gpt-4o", temperature=0)
question_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_chain)
# 4. 提问
response = rag_chain.invoke({
"input": "公司的请假制度是什么?"
})
print(response["answer"])
企业部署建议
| 维度 | 建议 |
|---|---|
| 文档管理 | 建立文档更新机制,定期重新索引 |
| 权限控制 | 按部门/角色过滤检索范围 |
| 监控指标 | 追踪检索命中率、回答满意度 |
| 成本控制 | 缓存高频查询结果 |
| 评估体系 | 构建 Q&A 测试集,定期评估准确率 |
| 容灾方案 | 向量数据库备份与恢复 |
总结
RAG 是目前将大模型能力与企业私有数据结合的最实用方案。通过合理的文档切分、Embedding 模型选择、向量数据库选型和检索优化,可以构建出准确、高效、可溯源的 AI 知识库系统。随着 reranking 模型和混合检索技术的成熟,RAG 系统的准确率正在快速提升,已经在客服、知识管理、法律咨询等场景实现了生产级应用。