简介这份教程面向希望快速上手检索增强生成系统的开发者与运维人员围绕DeepSeek模型完整讲解RAG系统从技术栈认知到多机部署的落地路径。内容涵盖CUDA并行计算、vLLM大模型推理加速与Docker容器化部署等关键工具并按Dify服务器、Rerank与Embedding模型服务器、DeepSeek模型服务器三台ECS实例逐步展开涉及xinference安装、bge-reranker-large与bge-large-zh-v1.5部署、环境版本选定及Python依赖配置等实操细节。资源包为1个docx文档约580KB以图文步骤与目录结构呈现便于按章节对照操作。目前已有324人学习。读者可借此掌握多节点环境搭建思路、模型选型依据与常见配置排错方法适合作为RAG系统部署的入门与参考手册。1. 从零搭一套能跑的 DeepSeek RAG为什么环境这一步最容易翻车很多人第一次做 RAG注意力全在提示词和向量库选型上结果卡在环境这一步整整两天。我见过最典型的场景是模型权重下好了向量库也装了import一跑就报 CUDA 版本不匹配或者 DeepSeek 的 tokenizer 加载时提示 transformers 版本过低。RAG 系统本质上是「检索 生成」两条链路拼起来的工程检索侧要 embedding 模型和向量库生成侧要 DeepSeek 的推理服务或 API两边对 Python、CUDA、依赖版本的要求经常打架。这篇实战笔记就围绕「基于 DeepSeek 搭建 RAG 系统」的环境搭建展开把 Python 环境、DeepSeek 接入方式、向量库、embedding 模型这几块拆开讲清楚每一步都给可复现的命令和参数。适合两类人一是刚接触 RAG、想在自己机器上跑通最小闭环的新手二是已经写过 demo、但环境一换就崩、想搞清楚依赖边界的老手。环境搭建不是走个过场它决定了你后面调 chunk 大小、换 embedding 模型时会不会被底层报错反复打断。2. DeepSeek 接入方式选型本地权重还是 API环境差在哪2.1 两种接入路径的依赖差异DeepSeek 在 RAG 里承担的是生成侧角色接入方式直接决定你环境里要装什么。常见做法有两类一类是调用官方 API本地只需要一个 HTTP 客户端和 API Key环境极轻另一类是本地部署权重需要 GPU、CUDA、PyTorch 和推理框架环境重但数据不出本地。选型不是拍脑袋先看你的约束条件。维度API 接入本地权重部署显存要求无7B 量化约 6-8GB全精度更高依赖复杂度低仅需 requests/openai SDK高需 CUDA PyTorch 推理框架数据流向请求发往服务端全程本地适合场景快速验证、原型、无 GPU数据敏感、离线、长期高频调用环境搭建耗时10 分钟半天到两天如果你只是想先把 RAG 闭环跑通我一般建议先用 API 接入把检索链路调顺再考虑换本地权重。因为 RAG 的坑大部分在检索侧生成侧换实现相对独立先跑通再替换能省很多来回。2.2 用 conda 隔离一个干净的 Python 环境不管走哪条路第一步都是隔离环境。RAG 项目依赖又多又杂直接装在 base 环境里后面装向量库或换 embedding 模型时极易冲突。用 conda 建一个独立环境Python 版本选 3.10 或 3.11这两个版本对 PyTorch、transformers、主流向量库的兼容性最稳。# 创建名为 rag-deepseek 的独立环境指定 Python 3.10 conda create -n rag-deepseek python3.10 -y # 激活环境 conda activate rag-deepseek # 升级 pip避免旧版 pip 解析依赖出错 python -m pip install --upgrade pip # 确认 Python 版本应为 3.10.x python --version逻辑说明conda create -n的-n指定环境名python3.10锁定解释器版本-y跳过交互确认。激活后所有 pip 安装都只影响这个环境不会污染系统 Python。参数上Python 不要选 3.12 以上部分向量库和推理框架的预编译轮子还没跟上容易触发源码编译编译又依赖一堆系统库是新手翻车高发区。2.3 安装核心依赖并锁定版本环境建好后装依赖。RAG 最小闭环需要四类包HTTP 客户端调 DeepSeek API、embedding 模型库、向量库、文本处理工具。这里给一份能直接跑的依赖清单版本号是我实测比较稳的组合。# DeepSeek API 兼容 OpenAI SDK 格式直接用 openai 客户端 pip install openai1.30.0 # embedding 模型与分词 pip install transformers4.40.0 sentence-transformers2.7.0 # 向量库chromadb 轻量、零配置适合起步 pip install chromadb0.4.24 # 文本切分与工具 pip install langchain-text-splitters0.0.1 numpy1.26.4逻辑说明openai包用来调 DeepSeek 的兼容接口sentence-transformers负责把文本转成向量chromadb做本地向量存储langchain-text-splitters提供递归切分器。参数上numpy锁 1.26.4 是因为 2.x 版本和部分向量库的 C 扩展不兼容会报_ARRAY_API not found这是血泪经验。装完用一条命令验证python -c import openai, transformers, chromadb, sentence_transformers; print(deps ok)能打印deps ok说明依赖层没问题。如果报ImportError先看是不是环境没激活再看具体缺哪个包不要盲目重装。3. 检索侧环境embedding 模型与向量库怎么配才不打架3.1 embedding 模型选型与本地缓存检索侧的核心是把文本转成向量embedding 模型的选择直接影响召回质量。常见做法是用sentence-transformers加载一个中文友好的模型比如BAAI/bge-small-zh-v1.5体积小、速度快适合起步。第一次加载会从远端下载权重国内网络下经常卡住所以要先配好缓存目录必要时手动下载。from sentence_transformers import SentenceTransformer # 指定模型名首次运行会下载权重到缓存目录 model SentenceTransformer(BAAI/bge-small-zh-v1.5) # 把一句话转成向量normalize 后便于用余弦相似度 vec model.encode(DeepSeek 的 RAG 环境怎么搭, normalize_embeddingsTrue) # 打印维度bge-small-zh 应为 512 print(vec.shape)逻辑说明SentenceTransformer构造时会检查本地缓存没有就下载。encode的normalize_embeddingsTrue把向量归一化这样向量库用内积就等价于余弦相似度省去额外计算。参数上bge-small-zh-v1.5输出 512 维bge-base-zh-v1.5是 768 维维度越高表达力越强但存储和检索越慢起步用 small 就够。如果下载卡住设置环境变量HF_HOME指向一个空间足够的目录再重试。3.2 向量库初始化与持久化目录向量库选 Chroma 是因为它零配置、支持本地持久化适合单机 RAG。初始化时要显式指定持久化路径否则默认存在内存里进程一退数据就没了这是新手最常踩的坑之一。import chromadb # 指定持久化目录数据会落盘到 ./chroma_db client chromadb.PersistentClient(path./chroma_db) # 创建或获取一个集合集合类似关系库里的表 collection client.get_or_create_collection( namedeepseek_rag, metadata{hnsw:space: cosine} # 用余弦距离 ) print(collection.count()) # 首次应为 0逻辑说明PersistentClient的path参数决定数据落盘位置重启后能恢复。get_or_create_collection幂等存在就取、不存在就建。metadata里的hnsw:space指定距离度量用cosine和前面 embedding 的归一化配套。参数上集合名一旦写入不要随意改改了等于新建一个空集合旧数据还在但查不到容易误判成「数据丢了」。3.3 把切分、向量化、入库串成一条链路环境配好后用一段最小代码验证检索链路是否通。这里把文本切分、向量化、入库三步串起来跑通就说明检索侧环境没问题。from langchain_text_splitters import RecursiveCharacterTextSplitter # 准备一段测试文本 text DeepSeek 是一个大语言模型。RAG 是检索增强生成。 * 20 # 递归切分chunk_size 控制每块长度overlap 保留上下文 splitter RecursiveCharacterTextSplitter( chunk_size200, chunk_overlap40, separators[\n\n, \n, 。, ] ) chunks splitter.split_text(text) print(f切出 {len(chunks)} 块) # 向量化并入库 embeddings model.encode(chunks, normalize_embeddingsTrue).tolist() collection.add( ids[fid_{i} for i in range(len(chunks))], documentschunks, embeddingsembeddings ) print(collection.count())逻辑说明RecursiveCharacterTextSplitter按分隔符优先级递归切先按段落再按句子尽量不切断语义。chunk_size200是字符数中文场景下 200-500 比较常见太小丢上下文太大检索不精准。chunk_overlap40让相邻块有重叠避免关键信息正好卡在边界被切掉。collection.add的ids必须唯一重复会报错实际项目里用文档 ID 加序号生成。跑完collection.count()应该等于切块数对不上就检查是不是切分或入库环节漏了。4. 生成侧环境DeepSeek 调用与检索结果拼接4.1 用 OpenAI SDK 调 DeepSeek 接口DeepSeek 的接口兼容 OpenAI 格式所以直接用openai包把base_url指向 DeepSeek 的服务地址即可。API Key 不要硬编码在代码里用环境变量读取这是基本习惯。import os from openai import OpenAI # 从环境变量读 Key避免写死在代码里 client OpenAI( api_keyos.environ[DEEPSEEK_API_KEY], base_urlhttps://api.deepseek.com ) resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: 用一句话解释 RAG}], temperature0.3 ) print(resp.choices[0].message.content)逻辑说明base_url指向 DeepSeek 的兼容端点model填deepseek-chat。temperature0.3让输出更稳定RAG 场景不需要太发散。参数上Key 通过os.environ读取在 shell 里用export DEEPSEEK_API_KEY你的key设置不要提交到代码仓库。如果报 401先确认环境变量在当前 shell 生效报连接超时检查网络和 base_url 是否写错。4.2 检索结果拼进提示词的模板生成侧的关键是把检索到的文档拼进提示词让模型基于上下文回答。模板设计要明确告诉模型「只根据给定资料回答」否则模型容易自由发挥。def build_prompt(question, docs): # 把检索到的文档拼成上下文编号便于模型引用 context \n\n.join( f[{i1}] {d} for i, d in enumerate(docs) ) return f根据以下资料回答问题资料中没有的信息不要编造。 资料 {context} 问题{question} # 检索把问题向量化后查库 q_vec model.encode([question], normalize_embeddingsTrue).tolist() res collection.query(query_embeddingsq_vec, n_results3) docs res[documents][0] prompt build_prompt(question, docs)逻辑说明build_prompt把文档编号拼接方便模型在回答里引用来源。collection.query的n_results3控制召回条数太少可能漏信息太多会撑爆上下文且引入噪声起步用 3-5 比较稳。参数上query_embeddings必须是二维列表即使只查一条也要包成[q_vec]这是 Chroma 的接口约定写错会报维度错误。4.3 端到端跑通一次问答把检索和生成接起来跑一次完整问答验证整条链路。question RAG 是什么 q_vec model.encode([question], normalize_embeddingsTrue).tolist() res collection.query(query_embeddingsq_vec, n_results3) docs res[documents][0] prompt build_prompt(question, docs) resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.3 ) print(resp.choices[0].message.content)逻辑说明这段把前面所有环节串起来问题向量化、查库、拼提示词、调模型。能打印出基于资料的回答说明环境搭建完成。参数上如果回答里出现资料中没有的内容说明提示词约束不够把「不要编造」写得更强硬或降低temperature。如果召回文档和问题不相关问题多半在 embedding 模型或切分粒度不是生成侧的事。5. 环境搭建避坑五个让我重装过环境的真实问题5.1 现象import chromadb 报 hnswlib 编译失败原因pip 找不到预编译轮子回退到源码编译而系统缺 C 编译工具链。解决优先升级 pip 到最新让它拉预编译轮子仍失败就装系统编译工具Linux 下apt install build-essentialmacOS 下xcode-select --install。实在不行换 Python 3.10轮子覆盖最全。5.2 现象embedding 模型下载卡在 0%原因默认从境外源拉权重网络不稳定。解决设置HF_HOME指向本地目录用镜像源加速或手动下载权重后放到缓存目录对应位置。注意缓存目录结构是models--组织名--模型名放错位置不会被识别。5.3 现象向量库重启后数据为空原因初始化时用了Client()而不是PersistentClient()数据只在内存。解决改成PersistentClient(path...)并确认 path 是绝对路径或相对当前工作目录的稳定路径。如果工作目录变了相对路径会指向新位置看起来像数据丢了。5.4 现象调 DeepSeek 报 400 或返回乱码原因messages格式不对或model名写错。解决确认messages是[{role: user, content: ...}]结构model填deepseek-chat。乱码多半是编码问题确保请求内容用 UTF-8。5.5 现象检索结果和问题完全不相关原因embedding 模型和向量库距离度量不匹配或切分粒度过大。解决确认入库和查询用的是同一个 embedding 模型向量库距离度量设为cosine且 embedding 做了归一化。切分粒度调小到 200-300 字符再试。6. 进阶技巧用一次「冷启动自检」把环境问题挡在写业务之前环境搭完别急着写业务代码先做一次冷启动自检。所谓冷启动就是把环境完全重建一遍从空目录开始跑通最小闭环。这一步能暴露很多「当前 shell 有残留状态」掩盖的问题比如某个包是之前手动装的、某个环境变量是临时 export 的。我一般会写一个自检脚本把依赖检查、模型加载、向量库读写、API 调用四件事串起来每次换机器或升级依赖后跑一遍。import os, sys def self_check(): # 1. 依赖检查 import openai, transformers, chromadb, sentence_transformers print([1/4] deps ok) # 2. embedding 模型加载 from sentence_transformers import SentenceTransformer m SentenceTransformer(BAAI/bge-small-zh-v1.5) v m.encode(自检, normalize_embeddingsTrue) assert v.shape[0] 512, embedding 维度异常 print([2/4] embedding ok) # 3. 向量库读写 import chromadb c chromadb.PersistentClient(path./self_check_db) col c.get_or_create_collection(check, metadata{hnsw:space: cosine}) col.add(ids[1], documents[测试], embeddings[v.tolist()]) assert col.count() 1, 向量库写入失败 print([3/4] vector store ok) # 4. API 调用 from openai import OpenAI cli OpenAI(api_keyos.environ[DEEPSEEK_API_KEY], base_urlhttps://api.deepseek.com) r cli.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: 回复 ok}], temperature0 ) assert r.choices[0].message.content, API 返回为空 print([4/4] api ok) if __name__ __main__: self_check()逻辑说明四步分别覆盖依赖、embedding、向量库、API任何一步失败都会中断并暴露具体环节。assert用来做硬性校验维度不对、写入失败、返回为空都会立刻报错比事后排查省时间。参数上自检用的向量库路径单独设./self_check_db不污染正式数据temperature0让 API 返回确定便于判断连通性。自检脚本建议纳入版本管理每次改依赖或换机器先跑。我自己的习惯是任何 RAG 项目开工前先跑自检四步全绿再写业务。这样后面调 chunk、换模型时能确定问题出在业务逻辑而不是环境。环境搭建这件事前期多花半小时做自检后期能省下几小时的玄学排查。希望帮到你。本文还有配套的精品资源点击获取