手把手教你用 DeepSeek + LangChain 搭建企业级 RAG 知识库问答机器人
# 手把手教你用 DeepSeek + LangChain 搭建企业级 RAG 知识库问答机器人
> 大模型很强,但它不认识你公司的内部文档。本文带你 30 分钟从零搭建一个基于 DeepSeek 的 RAG(检索增强生成)知识库问答机器人,完整代码可直接运行。
## 一、为什么需要 RAG?
直接问大模型一个企业内部问题,比如"我们公司的报销流程是什么",它大概率会一本正经地胡说八道——这就是著名的**幻觉问题**。原因很简单:训练数据里根本没有你公司的私有知识。
微调(Fine-tuning)可以解决一部分问题,但成本高、周期长,且知识更新一次就要重新训练。而 **RAG(Retrieval-Augmented Generation,检索增强生成)** 提供了一条更轻量的路径:
```
用户提问 → 检索私有知识库 → 找到相关片段 → 拼入 Prompt → 大模型生成答案
```
RAG 的三大优势:
1. **知识实时更新**:新文档入库即可被检索,无需重训模型;
2. **答案可溯源**:可以标注答案出自哪份文档哪个章节;
3. **成本极低**:只需一个 API Key + 几十行代码。
## 二、技术选型
| 组件 | 方案 | 说明 |
|------|------|------|
| 大模型 | DeepSeek Chat | API 便宜、中文能力强,兼容 OpenAI SDK |
| Embedding | bge-small-zh-v1.5 | 开源中文向量模型,本地运行,无需额外 API Key |
| 向量库 | Chroma | 轻量级本地向量数据库,适合入门与中小规模 |
| 编排框架 | LangChain | 文档加载、切分、检索一整套工具链 |
## 三、环境准备
Python 3.10+,安装依赖:
```bash
pip install openai langchain langchain-community chromadb sentence-transformers pypdf
```
然后到 DeepSeek 开放平台(platform.deepseek.com)申请一个 API Key,费用很低,充 10 元钱够用很久。
## 四、第一步:先跑通 DeepSeek 对话
用 OpenAI 兼容接口调用 DeepSeek,几行代码即可:
```python
from openai import OpenAI
client = OpenAI(
api_key="sk-你的密钥",
base_url="https://api.deepseek.com"
)
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个简洁的企业知识库助手。"},
{"role": "user", "content": "什么是增值税专用发票?"}
],
)
print(response.choices[0].message.content)
```
能正常输出,说明链路已通。但此时它还不会回答你的私有知识——接下来把它变成"读过公司文档"的助手。
## 五、第二步:文档加载与切分
假设你有一份 PDF《员工手册.pdf》。为什么要切分?因为向量检索是按"片段"匹配的,整篇文档直接向量化会稀释语义,导致检索不准。
```python
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 加载 PDF
loader = PyPDFLoader("员工手册.pdf")
documents = loader.load()
# 切分:每块 500 字符,重叠 50 字符防止语义被截断
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", ",", " "]
)
chunks = splitter.split_documents(documents)
print(f"共切分出 {len(chunks)} 个知识片段")
```
`chunk_overlap` 是个容易被忽视的细节:段落边界处的信息会同时出现在相邻两个分块里,避免"关键句恰好被切断"的尴尬。
## 六、第三步:向量化并入库
把每个片段转成向量,存入 Chroma:
```python
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
from langchain_community.vectorstores import Chroma
# 本地向量模型,首次运行会自动下载(约 100MB)
embeddings = HuggingFaceBgeEmbeddings(
model_name="BAAI/bge-small-zh-v1.5"
)
# 持久化到本地目录,下次启动无需重新向量化
vectordb = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
```
首次执行需要下载模型和构建索引,之后所有知识都落在 `./chroma_db` 目录中,新增文档时增量入库即可。
## 七、第四步:检索增强问答(核心)
有了向量库,完整的 RAG 问答流程如下:
```python
def rag_answer(question: str, top_k: int = 3) -> str:
# 1. 语义检索最相关的 top_k 个片段
docs = vectordb.similarity_search(question, k=top_k)
context = "\n\n".join(
f"【片段{i+1}】{doc.page_content}"
for i, doc in enumerate(docs)
)
# 2. 构造带上下文的 Prompt
prompt = f"""请仅根据以下参考资料回答问题。如果资料中没有相关信息,
请直接回答"根据现有知识库无法回答该问题",不要编造。
参考资料:
{context}
问题:{question}"""
# 3. 交给 DeepSeek 生成答案
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是严谨的企业知识库助手,只依据参考资料作答。"},
{"role": "user", "content": prompt}
],
temperature=0.1, # 低温度保证回答稳定
)
return response.choices[0].message.content
print(rag_answer("公司的年假有几天?病假怎么扣工资?"))
```
注意 Prompt 中的两句关键约束:
- **"仅根据参考资料回答"**——压制模型自由发挥;
- **"没有相关信息请直接说明"**——给模型一个"认输"的出口,减少幻觉。
## 八、效果对比
| 提问 | 直接问 DeepSeek | RAG 后 |
|------|----------------|--------|
| 公司年假有几天? | 编造一个通用标准(如 5-15 天) | 准确引用员工手册条款 |
| 报销审批流程? | 泛泛而谈常见流程 | 按手册给出具体审批人时限 |
这正是 RAG 的价值:**让通用大模型说你的"方言"**。
## 九、进阶优化方向
入门版跑通后,还可以按需升级:
1. **重排序(Rerank)**:召回 20 条 → 用 bge-reranker 精排出 5 条再送入模型,准确率显著提升;
2. **混合检索**:向量检索 + BM25 关键词检索,兼顾语义与精确匹配(如型号、编号);
3. **多文档增量更新**:给 chunk 加 metadata(文档名、章节、更新时间),支持溯源与过期清理;
4. **引用溯源**:把 `doc.metadata["source"]` 拼进回答,让用户知道答案出自哪份文档。
## 十、总结
RAG 不是什么高深技术,本质就是"**先查资料,再回答**"。本文方案的全部成本只有一个 DeepSeek API Key,却能快速让大模型掌握你的私有知识。当你需要更快的检索、更大的知识规模时,再把向量库换成 OpenSearch 或 Elasticsearch 即可,整体架构不变。
建议你拿自己手头的任意一份 PDF 试跑一遍,10 分钟就能看到效果。欢迎在评论区交流你搭建过程中遇到的问题。
---
**本文收录于:AI 大模型应用实战系列**
- 点赞
- 收藏
- 关注作者
评论(0)