如何用 RAG 搭建私有知识库问答系统
大语言模型(LLM)虽然强大,却有两个明显短板:知识截止日期和幻觉问题。当你问它公司的内部流程或最新的产品参数时,它要么回答"我不知道",要么一本正经地胡说。RAG(Retrieval-Augmented Generation,检索增强生成)正是解决这个问题的钥匙——它在 LLM 生成答案之前,先从你的私有知识库中检索相关文档,让模型基于真实资料作答。
本文将带你从零搭建一个 RAG 知识库问答系统,覆盖完整的技术链路。
RAG 的核心架构
RAG 的工作流程可以概括为三个阶段:
- 索引(Indexing):将你的文档切分、向量化并存入向量数据库
- 检索(Retrieval):根据用户问题,从向量数据库中召回最相关的文档片段
- 生成(Generation):将检索到的片段和用户问题一起发给 LLM,生成最终答案
这套架构的优势在于:知识是动态更新的(更新文档即可,无需重新训练模型),答案可溯源(每个回答都能追溯到原文),且幻觉大幅减少。
第一步:文档处理与切分
原始文档(PDF、Markdown、网页等)不能直接使用。需要先提取纯文本,然后切分成合适大小的 chunk:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个 chunk 约 500 字符
chunk_overlap=50, # 相邻 chunk 重叠 50 字符,保持上下文连贯
separators=["\n\n", "\n", "。", ".", " ", ""]
)
chunks = text_splitter.split_documents(documents)
chunk_size 是关键参数:太大则检索精度下降、超出 LLM 上下文窗口;太小则丢失上下文。中文内容建议 300-800 字符,英文 500-1000 字符。务必保留 overlap 避免关键信息被截断。
第二步:向量化(Embedding)
将文本 chunk 转换成高维向量,语义相近的文本在向量空间中距离也近:
from openai import OpenAI
client = OpenAI()
def get_embedding(text: str) -> list[float]:
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
2026 年主流的 Embedding 模型包括 OpenAI text-embedding-3-large(3072 维)、Google text-embedding-004,以及开源方案如 bge-large-zh-v1.5(中文效果好)。
第三步:向量数据库选型与写入
向量数据库负责高效存储和检索海量向量。常见选择:
- Pinecone:全托管服务,零运维,适合快速上线
- Weaviate / Qdrant:开源自托管,数据不出域
- Milvus:分布式架构,适合亿级向量规模
- ChromaDB:轻量级,适合原型和中小型项目
import chromadb
client = chromadb.PersistentClient(path="./knowledge_db")
collection = client.get_or_create_collection("company_docs")
for i, chunk in enumerate(chunks):
collection.add(
ids=[f"doc_{i}"],
embeddings=[get_embedding(chunk.page_content)],
documents=[chunk.page_content],
metadatas=[{"source": chunk.metadata.get("source", "")}]
)
第四步:检索 Pipeline
用户提问后,将问题向量化,在数据库中做相似度搜索:
def retrieve(query: str, top_k: int = 5):
query_embedding = get_embedding(query)
results = collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
return results["documents"][0]
进阶技巧:使用 HyDE(假设文档嵌入)先让 LLM 生成一个假设答案,再拿假设答案去检索——对短查询效果提升明显。还可以引入 重排序(Re-ranking),用 Cross-Encoder 对召回结果二次打分。
第五步:LLM 生成答案
def generate_answer(query: str, contexts: list[str]) -> str:
prompt = f"""你是一个专业的企业知识助手。请严格基于以下资料回答问题。
如果资料中找不到答案,请明确说"根据现有资料无法回答",不要编造。
【参考资料】
{"\n\n".join(contexts)}
【用户问题】
{query}
【回答】"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.2
)
return response.choices[0].message.content
关键设计:明确限制 LLM 不要编造,提供引用来源让用户自行核实,以及低 temperature 保证回答稳定。
实践中的常见坑
- 检索精度不足:检查 chunk 大小、尝试 Hybrid Search(关键词 + 语义混合检索)
- 文档格式复杂:PDF 表格、扫描件需要 OCR + 结构化提取,推荐 Unstructured.io
- 上下文窗口不够:检索结果太多?用 Re-ranking 压缩,或换用支持更长上下文的模型
- 成本控制:缓存常见问题的答案,避免重复调用 LLM;Embedding 结果也可缓存
总结
RAG 是 2026 年 AI 应用开发中最实用的模式之一。完整的落地路径是:文档处理 → 向量化 → 存储 → 检索 → 生成 → 界面。对于快速验证,LangChain + ChromaDB + Streamlit 三天就能跑通 MVP;对于生产级部署,建议将检索和生成解耦为独立微服务,方便独立扩展和监控。
掌握了 RAG,你就可以为律所搭建案件检索助手、为电商搭建产品问答机器人、为企业搭建内部 wiki 助手——可能性无穷。