
简介面向需要在生产环境落地RAG系统的深度学习开发者与LLM运维工程师这份教程围绕DeepSeek模型给出完整的RAG环境搭建路径。文档以三台阿里云ECS服务器为部署基线逐项讲解Dify平台部署、Rerank与Embedding模型选型以及DeepSeek模型服务落地同时穿插CUDA驱动安装、VLLM推理框架配置、Docker容器化部署等关键环节帮助读者避开GPU驱动、Python依赖、端口映射等常见坑点。资源包为单个docx文档总大小约580KB正文以文字步骤、命令示例和配置说明为主适合边阅读边操作已有324人学习。教程具体列出xinference安装与启动、bge-reranker-large和bge-large-zh-v1.5部署、DeepSeek-R1-Distill-Qwen-14B推理环境选定等实用内容并附带Dify官网部署指引。对刚接触RAG的初学者可从中获得一套从零搭建的参考流程对已有基础的专业人士也可借此对比不同服务器角色下的环境配置策略。1. 用 DeepSeek 搭 RAG第一道坎在环境而不是模型把 DeepSeek 接进 RAG 系统最容易被低估的不是模型本身而是环境。想跑通一个能用的本地知识库问答需要同时搞定模型运行时、嵌入模型、向量数据库、中文文本拆分这四件事任何一环版本不对系统就能给你跑出一个“看着像样、实则胡编”的答案。这篇环境搭建实战教程面向想用 DeepSeek 构建 RAG 检索增强生成系统的开发者目标是在本地机器上从零搭出最小可用的 RAG 闭环并提前避开我踩过的那些坑模型拉取失败、显存不足、中文检索不到、图片资料答不出来。读完你会得到一套可复现的环境清单和能直接改的代码。2. 给 RAG 选型DeepSeek 部署形态、向量库与框架的搭配逻辑写代码之前先做三个决策用什么形态承载 DeepSeek、用什么存向量、用什么方式组织 RAG 流程。环境搭建的很多痛苦其实是一开始选型贪大引出来的。2.1 先定 DeepSeek 的部署形态官方 API、Ollama 本地部署、vLLM 服务“基于 deepseek 搭建 RAG 系统”里 DeepSeek 只是生成模型它有三种常见承载形态选型直接决定后面全部环境配置。部署形态适合场景显存需求成本结构DeepSeek 官方 APIdeepseek-chat个人原型、快速验证、轻量生产不需要本地 GPU按 token 计费Ollama 本地运行deepseek-r1 量化版零基础可复制的本地 RAG、完全离线8GB 起步推荐 16GB一次性硬件成本vLLM 部署DeepSeek 大模型服务化团队级并发、私有化部署多卡或大显存硬件与运维成本高如果你只是想验证 RAG 流程的正确性官方 API 是最快路径。DeepSeek API 的调用方式很直白用 OpenAI 的 Python SDK把base_url指到https://api.deepseek.com就行模型名填deepseek-chat。这也是热搜里“deepseek api如何调用”的高频答案它不需要你折腾 GPU 驱动环境搭建时间能压缩到十分钟内。如果想在一台普通笔记本上复现我建议走 Ollama。很多“零基础可复制”的本地 RAG 教程都是建立在 Ollama 上的。Ollama 的优势是把模型下载、量化、常驻服务、OpenAI 兼容接口全部包好安装完基本不需要手动配置 CUDA。vLLM 适合生产规模但它对 Python 版本、CUDA 版本、显卡驱动有严格的版本矩阵初学者在 RAG 原型阶段引入 vLLM等于给自己加戏。我的建议是第一版优先选 API 或 Ollama把链路跑通再评估要不要迁到 vLLM。2.2 向量数据库选型Chroma、Milvus、FAISS 分别适合谁RAG 系统里的向量库负责把文本相似度检索变成可能。三个主流方案的边界要分清不然会出现“装了个企业级数据库最后只存了几百个片段”的尴尬。Chroma 是嵌入式轻量向量库pip install chromadb一条命令装完数据落盘在本地目录典型容量从几百 MB 到几 GB。它最适合单机、原型、教程环境我搭个人知识库时默认用它。FAISS 严格说是一个算法库不是一个服务适合程序内做大规模向量检索但持久化、过滤、并发都需要自己处理工程成本高。Milvus 是独立服务面向生产支持批量索引、标量过滤、分布式部署适合企业知识库正式上线。选型结论第一版一律 Chroma。注意热搜里关于“rag框架”“rag知识库”的疑问本质上都不该在选型阶段卡住。RAG 概念上只有三步——嵌入、召回、生成但环境里必须同时有三个组件在线嵌入模型把文本变成向量向量库做近邻召回DeepSeek 根据召回片段生成回答。缺一个链路就断。2.3 框架选型LangChain 还是自己写流程RAG 流程可以用 LangChain 或 LlamaIndex 组装也可以裸写。框架在环境搭建早期会引入隐藏依赖比如 LangChain 某个子包的版本与 Chroma 不兼容或者 langchain-text-splitters 拉下来的依赖和你已有的包冲突。你问“RAG 瓶颈”在哪很多时候瓶颈不是检索算法而是被框架版本拖死。我的判断标准很简单流程只有“加载 → 切分 → 向量化 → 检索 → 拼 prompt → 调 LLM”六步时自己写每个环节透明可查需要快速对比多种检索策略时用 LangChain 的抽象涉及图谱关系、结构化知识库区分时再考虑 LlamaIndex 或 GraphRAG。这篇教程里我会展示最小依赖写法框架只用来做文档加载和文本拆分核心链路全用手写这样每一行都能解释。3. 环境搭建实战把 DeepSeek、嵌入模型和向量库跑起来这一章是重头戏所有命令都在 Linux/macOS 终端验证过Windows 用户把命令替换成 PowerShell 等价写法即可。我会按顺序把环境拆成四块Python 虚拟环境、DeepSeek 接入、嵌入模型、向量库。3.1 创建 Python 虚拟环境并安装基础依赖先建一个干净的工作目录和虚拟环境这一步能避免后面所有“我这包里怎么多了一堆东西”的问题。mkdir -p ~/rag-deepseek cd ~/rag-deepseek python -m venv venv source venv/bin/activate pip install --upgrade pip pip install chromadb0.4,0.6 sentence-transformers openai逻辑说明python -m venv venv把整个项目的 Python 依赖隔离在./venv里source venv/bin/activate激活环境。Chromadb 用 0.4 到 0.6 的大版本区间是因为 0.5.x 的 API 最稳定新版本接口变动容易让教程代码报错。sentence-transformers 负责提供中文嵌入模型openai 是调用 DeepSeek API 的客户端它同时兼容官方 OpenAI 接口和本地 Ollama 接口。如果你选择本地部署 DeepSeek还需要单独安装 Ollamacurl -fsSL https://ollama.com/install.sh | sh ollama pull deepseek-r1:7b注意ollama pull会下载约 4.7GB 的量化模型文件存放在~/.ollama/models下。下载完成后用一行命令验证ollama run deepseek-r1:7b 你好请用一句话介绍RAG首次运行需要几秒加载模型能看到回答说明本地部署成功。3.2 两种方式接入 DeepSeek本地 Ollama 与官方 API我一般会同时把两种方式配好因为开发调试用 API、离线演示用 Ollama切换成本很低。方式一Ollama 本地接口。Ollama 启动后会监听11434端口。两种接入方式我一般都会同时配好因为开发调试用 API 快离线演示用 Ollama 稳切换成本很低。更省事的是把 Ollama 当成 OpenAI 兼容服务用。# test_ollama_connection.py from openai import OpenAI client OpenAI( base_urlhttp://localhost:11434/v1, api_keyollama # Ollama 不校验 key随便填 ) resp client.chat.completions.create( modeldeepseek-r1:7b, messages[{role: user, content: 什么是RAG}] ) print(resp.choices[0].message.content)这段代码的关键在于base_url指向本地11434/v1。Ollama 从 0.1.4 版本开始提供 OpenAI 兼容端点这意味着你写一套调用代码后面接 DeepSeek API 只需要换base_url和api_key不用改业务逻辑。方式二DeepSeek 官方 API。# test_deepseek_api.py from openai import OpenAI client OpenAI( api_keysk-你的key, base_urlhttps://api.deepseek.com ) resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: 什么是RAG}] ) print(resp.choices[0].message.content)deepseek-chat是官方 API 里的通用对话模型便宜且速度快。两段代码对比能看到Ollama 和官方 API 的差异只在于base_url和model两个字段后者不需要本地 GPU。提示不要在代码里硬编码 API key用环境变量export DEEPSEEK_API_KEYsk-xxxx管理更安全。3.3 加载中文嵌入模型把向量库跑起来嵌入模型是 RAG 的向量化来源中文场景我首选BAAI/bge-m3它比 OpenAI 的 text-embedding-3 在中文长文本上的表现稳定且完全本地运行。# test_embedding.py from sentence_transformers import SentenceTransformer model SentenceTransformer(BAAI/bge-m3) vec model.encode(如何搭建基于DeepSeek的RAG系统) print(vec.shape) # 输出 (1024,)首次运行会自动从 Hugging Face 下载模型大约 2.3GB存放在~/.cache/huggingface/hub。如果下载失败原因多半是网络无法直连 Hugging Face这个坑我在第 5 章给出解决办法。向量库这边用 Chroma 的持久化模式启动# test_chroma.py import chromadb client chromadb.PersistentClient(path./chroma_data) collection client.get_or_create_collection(kb) collection.add( documents[RAG是检索增强生成的简称, DeepSeek是开源中文大模型], ids[doc1, doc2] ) res collection.query(query_texts[什么是RAG], n_results1) print(res[documents])逻辑说明PersistentClient会把数据落盘到./chroma_data目录下次重启还能读到。get_or_create_collection表示不存在就创建。这里query_texts会让 Chroma 用默认的 embedding 函数实际项目里我会在 4.2 节改成显式传入嵌入向量保证与检索时用的模型一致。4. 把 RAG 流水线建起来加载、拆分、检索、生成一步到位环境通了接下来把完整的 RAG 流水线串起来。我会先建知识库再写问答入口整条链路不用 LangChain 的 Chain 抽象每一步都能看到输入输出。4.1 用 TextLoader 加载文档并做中文文本拆分先准备一个knowledge_base.md文件内容是你想让 RAG 系统掌握的资料。然后执行加载与拆分# build_kb.py from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter loader TextLoader(knowledge_base.md, encodingutf-8) docs loader.load() splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap100, separators[\n\n, \n, 。, , , , , , ], ) chunks splitter.split_documents(docs) print(f拆分得到 {len(chunks)} 个片段)这里最值得解释的是separators参数。RecursiveCharacterTextSplitter会按顺序尝试用这些分隔符切分文本先按段落再按换行然后按中文句末标点。当整段文本仍然超过chunk_size时会继续降级到逗号、空格最后才按字符硬切。把中文标点放在英文逗号和空格前面是为了避免在中文句子中间切断语义。chunk_size500和chunk_overlap100是一组我常用的起点参数。500 个字符的片段对中文问答来说信息量适中100 的 overlap 保证跨片段的关键信息至少出现在两个片段里降低检索召回时的遗漏风险。4.2 把切分后的文本向量化并写入 Chroma拆分完成后继续在build_kb.py里追加向量化与入库逻辑from sentence_transformers import SentenceTransformer import chromadb embedder SentenceTransformer(BAAI/bge-m3) client chromadb.PersistentClient(path./chroma_data) collection client.get_or_create_collection(kb) texts [c.page_content for c in chunks] metadatas [{source: c.metadata.get(source, )} for c in chunks] collection.add( documentstexts, metadatasmetadatas, ids[fchunk_{i} for i in range(len(texts))], embeddingsembedder.encode(texts, batch_size32).tolist() ) print(f入库 {len(texts)} 条向量)逻辑说明我显式传入了embeddings而不是让 Chroma 内部自己算。好处是保证入库和检索用的嵌入模型绝对一致坏处是后面换嵌入模型时必须删除 collection 重建因为不同模型输出的向量维度可能不同bge-m3 是 1024 维换成一个 768 维的模型往同一个 collection 里写会直接报错。batch_size32是为了控制编码速度和显存占用数据集比较大时可以减少到 8 或 16避免内存溢出。4.3 写一个检索加生成的问答函数知识库建好后进入最关键的一步把 Chroma 检索到的片段拼进 prompt交给 DeepSeek 生成最终答案。# ask_rag.py from openai import OpenAI import chromadb from sentence_transformers import SentenceTransformer import os embedder SentenceTransformer(BAAI/bge-m3) client chromadb.PersistentClient(path./chroma_data) collection client.get_or_create_collection(kb) def search(query, top_k4): q_emb embedder.encode([query]).tolist() res collection.query(query_embeddingsq_emb, n_resultstop_k) return res[documents][0] def ask(query): hits search(query) context \n----\n.join(hits) llm_client OpenAI( api_keyos.environ.get(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) prompt f你是一个严谨的工程师只能基于下面的资料回答用户问题。 资料 {context} 问题{query} 如果资料中没有相关信息请直接回答“资料中没有相关信息”不要编造。 resp llm_client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.3 ) return resp.choices[0].message.content if __name__ __main__: print(ask(RAG的环境需要哪些组件))代码链路很直白query先经过embedder.encode变成向量再交给 Chroma 做近邻检索拿到 top_k 个最相似的片段拼进 prompt最后调 DeepSeek 生成回答。两个参数需要细说。top_k4是平衡点太少答案缺料太多会往 prompt 里塞进噪声导致答案跑偏。temperature0.3适合知识问答场景数值低一点能让模型更忠实于资料而不是自由发挥。如果你用的是 Ollama 本地部署只需要把ask函数里llm_client的base_url改成http://localhost:11434/v1model改成deepseek-r1:7b其余代码原封不动。5. 踩坑自查DeepSeek 环境搭建与 RAG 检索常见问题排查这一章把我自己翻过车的问题整理成五条每条按现象、原因、解决的顺序写你可以当成排查手册用。5.1 现象DeepSeek 模型拉取失败、嵌入模型下载超时ollama pull deepseek-r1:7b跑到一半卡住或者 sentence-transformers 下载 bge-m3 时反复超时。这个现象在国内网络环境下非常常见。原因有两个层面Ollama 默认从官方源下载模型网络连接不稳定时会中断Hugging Face 的模型托管域名在某些网络环境下载速度极慢。解决Ollama 端我一般会先从返回码判断如果ollama pull反复失败检查磁盘空间后重试嵌入模型则设置镜像端点再重新下载export HF_ENDPOINThttps://hf-mirror.com python build_kb.py镜像端点只改变下载地址模型内容不变。下载完成后可以在~/.cache/huggingface/hub确认文件完整。5.2 现象本地部署 DeepSeek 显存不足生成速度极慢Ollama 跑deepseek-r1:7b时8GB 显存的显卡加载后报 Out of Memory或者每个字要等好几秒。原因deepseek-r1:7b虽然量化过但模型权重加 KV cache 后实际占用超过 8GB。另一部分原因是你可能同时加载了嵌入模型显存被两边分掉。解决优先确认显存占用用nvidia-smi看看谁在吃显存。如果确实紧张换更小的模型ollama pull deepseek-r1:1.5b是原型验证的兜底方案或者把生成模型切到官方 API本地只保留嵌入模型和向量库。CPU 跑小模型也能用只是延迟会更高这个取舍要在环境搭建第一天想清楚。5.3 现象PDF 和图片里的知识检索不到RAG 知识库能存图片吗把带截图和表格的 PDF 直接喂给 TextLoader问答时系统对图片内容毫无反应。热搜里“rag知识库能存储图片嘛”指的就是这个场景。原因传统文本嵌入模型只接收纯文本图片本身无法直接被向量化PDF 里嵌的图在文本文档加载阶段就被丢掉了。解决务实的方案是引入 OCR 管道。用 PaddleOCR 或 Tesseract 把图片中的文字抽出来转成文本片段和正文一起入库。只有当你确实需要“看到图表再回答”时才需要升级到多模态模型加 CLIP 类向量模型那会让环境复杂度上一个量级。多数知识库场景OCR 再入库已经够用。5.4 现象检索片段与问题不相关DeepSeek 基于无关信息硬答top_k 返回的片段看起来和问题毫无关系但模型还是基于这些片段给出了流畅且有误导性的答案。原因RAG 的瓶颈往往在检索侧这就是常说的“rag瓶颈”。chunk 切太大导致一个片段包含多个主题、嵌入模型处理中文长文本能力弱、缺少精排三个原因都会让检索结果跑偏。解决第一步调参数chunk_size降到 300 到 500chunk_overlap保持在 80 到 120top_k提高到 8 到 10第二步引入重排序模型比如bge-reranker-large先粗召回 20 条再精排取 5 条。这套组合拳能解决绝大部分中文检索不相关的问题。5.5 现象RAG 问答超过对话上限后新对话不承接上一个话题这是“deepseek到达对话上限之后怎么让新对话承接上一个对话”这类问题的 RAG 版用户连着问了几轮RAG 系统完全不记得前面聊过什么。原因ask函数每次只把检索片段和当前问题传给模型没有携带历史对话。模型不具备记忆能力越是纯粹的 RAG 结构越容易出这个问题。解决在ask函数里维护一个messages列表把最近三到五轮问答和当前检索片段一起传进去。更进一步可以让 DeepSeek 把“那它呢”这类指代问题改写为完整问题后再去检索。这个“query 改写 历史上下文拼接”就是我常用的对话承接方案不需要引入额外的记忆框架。6. 进阶用法RAG 搭建完成后的验证方法与参数优化技巧环境搭好、链路跑通只是开始。RAG 系统最迷惑人的地方是“看着能答但答得对不对你不知道”所以我最后的建议是先用一套低成本评估方法确认质量再做参数调优。我习惯准备二十到三十条真问题组成测试集每条问题记录下来它应该命中哪份资料。跑完一轮后用 DeepSeek 当裁判自动打分eval_prompt f对比资料、参考答案和模型回答。 资料{chunk} 参考答案{gold_qa} 模型回答{pred} 评价标准 1. 模型回答是否忠实于资料 2. 是否包含资料之外的编造内容。 请给出1到5分的整数分数不要输出解释。把所有测试问题的平均分作为质量基线。这个“用大模型评大模型”的方式有误差但用来筛选明显翻车的版本已经足够。条件允许时再人工抽检十份重点看两条正确性——是否引有所出忠实度——有没有超出检索片段的胡编。质量基线建立后调参才有意义。我常用的参数起点和调整方向如下表参数常用起点检索噪声多时召回缺失时chunk_size500调小到 300调到 800 或按标题层级拆分chunk_overlap100减小到 60加大到 150-200top_k4减小到 2-3增到 8-10 并加重排rerank不启用启用 bge-reranker-large粗召回 20 条精排取 5 条调参逻辑要理解本质chunk_size调小检索到的片段主题更单一但长答案的信息可能被切碎调大上下文完整但噪声增加。两种方向都不能同时满足时就需要靠 rerank 弥补。RAG 调参其实是在找检索精度和上下文完整性的平衡点没有一组参数能通吃所有文档。最后提醒一个环境层面的隐藏坑换嵌入模型必须重建向量库 collection。bge-m3的向量维度是 1024m3e-base是 768维度不同不能混写进同一个 collection。我在这里吃过亏测试时换模型没重建库系统沉默地返回空结果排查了半天。所以现在我的习惯是每个实验目录单独建一个chroma_data并把pip freeze requirements.txt固定依赖版本翻车时能准确知道改了什么。基于 DeepSeek 搭建 RAG 系统的环境本质不难每个组件单独看都很简单难的是把它们组合起来之后你愿意一步步排查、量化、调参。我的习惯是调参前记录一组检索命中片段调完对比命中变化而不是只看最终回答顺不顺。希望帮到你——现在可以动手从第一条ollama pull开始。本文还有配套的精品资源点击获取