
随着大语言模型(LLM)的爆发式增长,企业级知识问答系统面临新的机遇与挑战。一方面,通用大模型具备强大的语义理解与生成能力;另一方面,私有数据无法直接注入模型参数,且存在数据安全与合规要求。检索增强生成(Retrieval-Augmented Generation, RAG) 架构以“外部知识库 + 条件生成”的方式,优雅地解决了这一矛盾。
DeepSeek 系列模型(如 DeepSeek-R1、DeepSeek-V3 等)凭借出色的中文理解能力和开放的权重,成为本地化部署的热门选择。本文将手把手教你构建一套完全本地部署的 RAG 知识库系统,涵盖从文档解析、向量检索到 DeepSeek 模型推理的全链路,并提供可落地的优化方案。
适用场景:企业内部文档问答、科研文献分析、法律/医疗垂直领域辅助。
RAG 的本质是 “先检索,后生成”:
这一模式有效缓解了幻觉问题,并能实时更新知识源(无需重训模型)。
我们采用 轻量级微服务 风格,各组件可独立扩展:
组件 | 技术选型 | 说明 |
|---|---|---|
文档解析 | pypdf / docx / markdown | 支持 PDF、Word、TXT、MD |
文本分割 | LangChain 递归字符分割器 | 保持语义完整性 |
Embedding 模型 | BAAI/bge-large-zh-v1.5 | 中文语义向量,本地加载 |
向量数据库 | ChromaDB(或 Qdrant) | 持久化存储,支持相似度检索 |
LLM 推理 | DeepSeek-R1-Distill-Qwen-14B(Ollama 部署) | 也可替换为 DeepSeek-V3(需更强GPU) |
编排层 | 自定义 Python 服务(FastAPI) | 提供 RESTful API 与 Web 交互 |
整体流程:
用户Query → Embedding → 向量检索 → 召回TopK → Prompt组装 → DeepSeek生成 → 返回答案# 创建虚拟环境
conda create -n rag_deepseek python=3.10
conda activate rag_deepseek
# 核心库
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install langchain langchain-community chromadb sentence-transformers
pip install fastapi uvicorn pypdf python-docx markdown
pip install ollama # 用于调用DeepSeekOllama 是目前最便捷的本地推理工具,支持 DeepSeek 系列:
# 安装 Ollama(Linux/macOS/WSL2)
curl -fsSL https://ollama.com/install.sh | sh
# 拉取 DeepSeek-R1 蒸馏版(14B 量化)
ollama pull deepseek-r1:14b
# 测试推理
ollama run deepseek-r1:14b "你好,请介绍一下RAG"若需更高性能,可改用 vLLM 部署,但 Ollama 已满足大多数场景。
我们创建一个通用加载器,支持多种格式:
from langchain.document_loaders import PyPDFLoader, Docx2txtLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
def load_documents(file_paths):
docs = []
for path in file_paths:
if path.endswith('.pdf'):
loader = PyPDFLoader(path)
elif path.endswith('.docx'):
loader = Docx2txtLoader(path)
else:
loader = TextLoader(path, encoding='utf-8')
docs.extend(loader.load())
return docs分块策略直接影响检索精度。我们采用 递归字符分割,并设置重叠(overlap)以避免上下文断裂:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个块最大字符数
chunk_overlap=100, # 重叠字符
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
length_function=len,
)
chunks = text_splitter.split_documents(docs)使用 sentence-transformers 加载轻量级中文模型(约 1.2GB):
from sentence_transformers import SentenceTransformer
embedding_model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
# 也可用 'shibing624/text2vec-large-chinese'
def get_embedding(text):
return embedding_model.encode(text, normalize_embeddings=True).tolist()注意:
normalize_embeddings=True对余弦相似度计算有利。
Chroma 支持持久化,我们按集合(Collection)组织知识库:
import chromadb
from chromadb.config import Settings
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection(
name="knowledge_base",
metadata={"hnsw:space": "cosine"} # 使用余弦距离
)
# 批量写入
ids = [f"chunk_{i}" for i in range(len(chunks))]
metadatas = [{"source": doc.metadata.get("source", "")} for doc in chunks]
documents = [chunk.page_content for chunk in chunks]
embeddings = [get_embedding(text) for text in documents]
collection.add(
ids=ids,
documents=documents,
embeddings=embeddings,
metadatas=metadatas
)查询时,先向量化用户问题,再执行相似度搜索:
def retrieve(query, top_k=5):
query_embedding = get_embedding(query)
results = collection.query(
query_embeddings=[query_embedding],
n_results=top_k,
include=["documents", "distances", "metadatas"]
)
# 返回文档列表及分数
return results['documents'][0], results['distances'][0]良好的 Prompt 模板可提升答案质量。我们采用经典的 “角色 + 上下文 + 问题” 结构:
system_prompt = """你是一个专业的知识助手。请严格基于以下提供的参考信息回答用户问题。
如果参考信息不足以回答问题,请明确说明“根据已有知识无法回答”,不要编造。
参考信息:
{context}
"""
def build_prompt(query, context_docs):
context = "\n\n".join([f"[文档{i+1}] {doc}" for i, doc in enumerate(context_docs)])
return system_prompt.format(context=context) + f"\n用户问题:{query}\n回答:"Ollama 提供 HTTP API,也可使用 Python 库:
import requests
import json
def generate_deepseek(prompt, model="deepseek-r1:14b", temperature=0.3):
url = "http://localhost:11434/api/generate"
payload = {
"model": model,
"prompt": prompt,
"stream": False,
"options": {"temperature": temperature, "top_p": 0.9}
}
response = requests.post(url, json=payload)
if response.status_code == 200:
return response.json()["response"]
else:
raise Exception(f"Ollama error: {response.text}")若使用 vLLM 部署,则改用 OpenAI 兼容接口,代码类似。
我们将上述模块封装为 Web 服务,便于前端调用:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI(title="DeepSeek RAG Knowledge Base")
class QueryRequest(BaseModel):
question: str
top_k: int = 5
class QueryResponse(BaseModel):
answer: str
retrieved_docs: list
scores: list
@app.post("/ask", response_model=QueryResponse)
async def ask(request: QueryRequest):
try:
docs, scores = retrieve(request.question, request.top_k)
prompt = build_prompt(request.question, docs)
answer = generate_deepseek(prompt)
return QueryResponse(answer=answer, retrieved_docs=docs, scores=scores)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# 启动:uvicorn main:app --host 0.0.0.0 --port 8000Weaviate 或 Elasticsearch 实现。stream=True,提升用户体验。模型 | 参数量 | 显存需求 | 适用场景 |
|---|---|---|---|
deepseek-r1:7b | 7B | 8GB | 快速实验 |
deepseek-r1:14b | 14B | 16GB | 生产级通用 |
deepseek-v3 | 671B(MoE) | 多卡 | 顶级效果(需付费或集群) |
Git 仓库结构建议:
rag_deepseek/
├── index.py # 索引构建脚本
├── retrieval.py # 检索模块
├── generation.py # DeepSeek 调用
├── app.py # FastAPI 服务
├── config.py # 配置项
├── documents/ # 原始文档存放
└── chroma_db/ # 向量库持久化config.py 示例:
EMBEDDING_MODEL = "BAAI/bge-large-zh-v1.5"
CHUNK_SIZE = 500
CHUNK_OVERLAP = 100
COLLECTION_NAME = "knowledge_base"
OLLAMA_MODEL = "deepseek-r1:14b"
TOP_K = 5启动服务后,可通过 curl 测试:
curl -X POST "http://localhost:8000/ask" \
-H "Content-Type: application/json" \
-d '{"question": "什么是RAG?", "top_k": 3}'bge-large-zh 在 C-MTEB 榜单领先,但显存占用约 2GB,可考虑 text2vec-small 提速。ollama serve 配合负载均衡。本文从零搭建了一套基于 DeepSeek 大模型与 RAG 架构的本地知识库系统。你可以在内网安全部署,无需上传敏感数据至云端。通过替换文档源和调优检索策略,该系统可适配多种垂直领域。
未来可扩展的方向包括:多模态文档(图片、表格)、对话记忆机制、权限管理与审计日志。希望这篇实践指南能为你开启本地智能知识助手的大门。
代码完整版已上传至 GitHub:https://github.com/yourname/rag-deepseek-local (示例链接,读者可自行整理)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。