ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DeepSeek RAG系统部署实战:Dify与vLLM全链路指南

DeepSeek RAG系统部署实战:Dify与vLLM全链路指南 简介面向希望基于DeepSeek搭建RAG系统的深度学习与NLP开发者这份docx实战教程系统梳理了从技术栈选型到多服务器环境落地的完整路径。内容以Dify应用开发平台为入口围绕ECS-1、ECS-2、ECS-3三台服务器分工覆盖CUDA驱动配置、Docker部署、xinference推理框架安装、bge-reranker-large与bge-large-zh-v1.5模型调用以及VLLM部署、Python依赖整理等关键环节。资源为单个docx文档压缩包约580KB内含清晰的目录结构与命令示例便于按步骤对照实践。目前已有324人学习既适合刚接触RAG环境搭建的读者快速上手也为需要复现DeepSeek相关推理环境的中高级工程师提供了可参考的排错与版本匹配经验。1. 从零到能跑基于 DeepSeek 搭建 RAG 系统的环境部署路线这套教程解决的是 RAG 系统从「架构图」到「真能跑」之间那段最磨人的距离。网上讲 RAG 原理的文章一抓一大把但真正把 Dify 工作台、bge 向量模型、rerank 重排模型、DeepSeek-R1 推理服务这一整条链路串起来、并且按三台服务器的角色分工一步步落地的资料少之又少。这份资源的价值在于它直接给出了每台机器该装什么、模型文件放哪、端口怎么开、版本怎么钉死照着搭能省掉大量靠报错信息反推环境的时间。适合手里有 GPU 资源、想把 DeepSeek 接入带知识库的对话应用、但还没摸清 Dify 和 vLLM 配合方式的开发者。下面我按实际部署顺序拆开讲重点放在我复现时觉得最容易被卡住的地方。2. Dify 平台先行为什么先用 Docker 把编排层跑起来2.1 Dify 在整个 RAG 链路里的角色RAG 系统不是只有一个大模型它至少要包含三个核心部件知识库的向量化与检索、检索结果的精排、以及最终负责生成的生成模型。如果这三块各自独立部署你就要自己写胶水代码去串联还要处理接口鉴权、会话管理、文档解析这些杂活。Dify 在这里扮演的是编排层和应用层它把知识库管理、流程编排、智能体对话这些功能做成可视化界面底层模型通过标准化接口对接进来。教程里把 Dify 单独放在 ECS-1并且特意强调「对显卡没什么要求」因为推理任务根本不在它这里发生它只做请求转发和流程控制。这意味着你可以用一台低配的 CPU 机器甚至云上的轻量服务器来跑 Dify把宝贵的 GPU 资源全部留给后面的模型服务。2.2 部署方式容器化几乎是唯一省心选项Dify 官方推荐用 Docker Compose 部署教程里也是这么做的。它的依赖组件比较多包括 PostgreSQL、Redis、Weaviate 或者 Qdrant 这类向量数据库还有 worker 和 API 服务等多个容器。如果不用容器编排手动逐个安装配置这些中间件不仅耗时而且版本稍微错一点就起不来。Docker 方式的好处是整个环境被镜像固化换机器迁移也方便。部署前确认服务器上已经有 Docker 和 Docker Compose 插件docker --version docker compose version这两条命令分别检查 Docker 引擎和 Compose 插件是否存在。如果第二条报错说明 Docker 版本较老或 Compose 没装全需要先单独安装 docker-compose-plugin。接下来克隆 Dify 的源码仓库并进入 docker 目录git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d这里cp .env.example .env是把默认配置复制成实际生效的配置.env里包含各服务端口、密钥、数据库连接等参数首次部署用默认值即可后期再按需调整。docker compose up -d会拉取镜像并在后台启动全部服务。启动完成后用docker compose ps查看容器状态确保所有服务都是 running。Dify 的 Web 界面默认跑在 80 端口浏览器访问服务器公网 IP 或内网 IP 就能进入初始化页面设置管理员账号后就可以创建应用了。2.3 Dify 接入模型时的关键配置Dify 本身不内置模型权重它需要通过「模型供应商」配置来对接外部推理服务。在 Dify 的管理后台里找到「设置 - 模型供应商」这里要填的是你在 ECS-2 和 ECS-3 上启动的模型服务地址。教程里的架构决定了 Dify 需要配置三类模型对话生成模型指向 ECS-3 上 vLLM 启动的 DeepSeek 服务Embedding 模型和 Rerank 模型都指向 ECS-2 上 xinference 启动的服务。注意这里填的地址不能写localhost因为 Dify 和模型服务不在同一台机器上必须写模型服务器的实际 IP比如http://192.168.1.100:9997和http://192.168.1.101:8008。如果跨公网访问还需要在云控制台的安全组里放行对应端口。我一般习惯先用 curl 确认模型服务的接口能通再去 Dify 里配置避免两边来回猜问题。3. 向量与重排模型用 xinference 一套工具拉起两个模型3.1 bge-large-zh-v1.5 和 bge-reranker-large 的分工很多第一次搭 RAG 的人会把 embedding 模型和 rerank 模型搞混觉得都是「让检索更准」实际它们工作在管线的不同阶段。bge-large-zh-v1.5 是 embedding 模型作用是把文档切片转换成向量存入向量数据库用户提问时也转成向量做相似度检索这是粗筛阶段。bge-reranker-large 是重排模型它接收 embedding 粗筛出来的候选文档再和用户问题做更精细的相关性打分把最相关的文档排到最前面这是精排阶段。两个模型都跑在 ECS-2 上因为它们的显存需求不大教程给的是单张 Tesla T4 16GB完全能同时承载这两个模型。选 bge 系列的原因很直接中文场景效果好、社区生态成熟、对显存的要求比较友好。3.2 安装 xinference 并正确配置环境变量xinference 是一个模型推理管理工具它能把模型注册、启动、状态查询这些操作统一收口。安装本身不复杂用 pip 装完整依赖包即可但安装后有一个环节容易被忽略——环境变量的配置pip install xinference[all] export XINFERENCE_HOME/tmp/xinference xinference-local --host 0.0.0.0 --port 9997第一条命令安装 xinference 及其所有可选依赖这里要特别注意[all]这个 extras 标记它会把运行各类模型所需的依赖都装齐否则后面启动模型时容易报缺少某个库。第二条命令设定 xinference 的数据存储目录模型缓存、日志文件都写在这里建议换成磁盘空间充足的路径。第三条命令用--host 0.0.0.0监听所有网卡--port 9997固定端口。需要持久运行时改用 nohup 后台启动输出重定向到日志文件方便排查。启动后先跑xinference --help确认命令可用再决定是前台调试还是后台挂起。如果只是调试阶段前台启动能看到实时日志排错更方便模型都跑通之后再切到后台运行稳妥。3.3 自定义模型注册config.json 是核心xinference 内置了很多常用模型的启动配置但 bge 系列不一定在默认列表里所以教程里用了「自定义模型」的方式。思路是先把模型权重从 Hugging Face 下载到本地再写一个 config.json 描述模型名、类型、文件路径然后注册到 xinference 里。以 bge-reranker-large 为例config.json 的写法是关键{ model_name: custom-bge-reranker-large, type: normal, language: [en, zh], model_id: BAAI/bge-reranker-large, model_uri: file:///path/to/bge-reranker-large }这里的model_name是这个自定义模型在 xinference 里的唯一标识后续 launch 和调用都用这个名字model_id是 Hugging Face 上的原始仓库名xinference 会参考它来确定模型结构model_uri必须指向模型文件在服务器上的本地目录整个模型文件夹通常包含 config.json、pytorch_model.bin 或 safetensors 权重文件、tokenizer 文件等。需要注意的是model_uri的格式是 file:// 协议路径要写绝对路径。注册和启动的命令是xinference register --model-type rerank --file model.json --persist xinference registrations --model-type rerank xinference launch --model-name custom-bge-reranker-large --model-type rerank第一条命令把 config.json 里的模型信息注册进 xinference--persist让注册信息持久化保存重启 xinference 后依然有效。第二条命令查看是否注册成功如果列表里能看到刚才的模型名就说明注册正确。第三条命令真正启动模型启动后 xinference 会分配一个端口用于推理调用。embedding 模型的配置和启动大同小异只是 config.json 里多了dimensions和max_tokens两个字段{ model_name: custom-bge-large-zh-v1.5, dimensions: 768, max_tokens: 512, language: [zh], model_id: BAAI/bge-large-zh-v1.5, model_uri: file:///path/to/bge-large-zh-v1.5 }dimensions表示向量维度bge-large-zh-v1.5 的默认输出是 768 维这个值必须和模型实际输出保持一致max_tokens限制单次输入的最大 token 数量切文档时要注意单块文本长度不能超过 512 token否则超长部分会被截断。启动命令换成--model-type embedding即可。注册后发现模型配置文件写错了可以先用xinference unregister --model-type rerank --model-name custom-bge-reranker-large注销掉改好配置再重新注册不需要重启整个 xinference 服务。提示模型权重下载建议先在本地用huggingface-cli download工具拉完整再打包上传服务器。直接在生产服务器上执行 huggingface 下载不稳定且失败断点续传不方便本地下载完用 scp 上传更可控。4. 环境搭建避坑清单驱动、CUDA、依赖依赖依赖这些坎4.1 CUDA 11.4 镜像和 vLLM 的版本冲突教程里 ECS-3 的镜像标注了 CUDA 11.4但后面 vLLM 的版本选定又写了cuda12.1。这个矛盾不是笔误而是不同工具链对 CUDA 版本的要求不同。服务器买来时的驱动和 CUDA 版本是云厂商预装的满足基础环境运行但 vLLM 0.4.3 预编译的 wheel 包依赖 CUDA 12.1 的运行时。这里最省事且不会伤到现有环境的做法是不去动系统级的 CUDA而是用 conda 创建独立的 Python 3.10 虚拟环境在这个环境里装对应版本的 PyTorch同时把新下载的 CUDA toolkit 路径加到虚拟环境变量里。实际踩坑时遇到最典型的报错是加载 vLLM 时提示 CUDA driver 版本不匹配本质是系统驱动的 CUDA 版本太老而 PyTorch 或 vLLM 需要的运行时版本更高。现象 → RuntimeError: CUDA error: no kernel image is available for execution on the device 原因 → 显存足够但 GPU 的算力版本低于 PyTorch 编译时的目标算力或者 CUDA 运行时版本与驱动不匹配 解决 → 先执行 nvcc -V 查看当前 CUDA 版本再执行 nvidia-smi 查看驱动支持的 CUDA 版本确认两者都是 12.x如果系统装的是老驱动先升级到支持 CUDA 12.1 的驱动版本如 530.30.02再重装对应 PyTorch这个报错特别容易误导人因为它直接提到 device 和 kernel很多人会以为是显卡坏了其实是版本层级的错位。4.2 模型文件下载慢、断点续传难bge 系列模型每个大概 1GB 左右DeepSeek-R1-Distill-Qwen-14B 的权重文件超过 9GB从 Hugging Face 直接下载到国内服务器速度很不稳定而且长连接容易断。第一次复现时我直接在生产服务器上执行下载命令结果跑到 90% 断了又要重头开始极其折磨。后来改成在本地网络环境好的机器上用 huggingface-cli 下载完整目录然后用 rsync 或分卷压缩的方式上传到服务器。值得注意的一点是模型目录里的文件不能省不光权重文件config.json、tokenizer.json、generation_config.json 这些配套文件缺失任何一个加载时都可能报错或不认识模型结构。传输完成后一定要检查文件数先看原始仓库的目录结构再和服务器上对比避免漏文件。4.3 pip 依赖被 vLLM 强行钉板vLLM 0.4.3 安装时会校验 PyTorch、transformers、tokenizers 等核心依赖的版本版本对不上直接给你抛一个ERROR: pips dependency resolver报错并且还会顺带要求你安装指定版本的flash-attn这类加速组件。第一次遇到时我天真地把要求的版本都装了一遍结果又引发了新的冲突。后来学乖了严格按照教程里的做法——先把 PyTorch 版本用官方命令钉到 2.3.0再装 vLLM这样报错面会小很多。如果中间还是报依赖错误就按报错提示执行它给出的 pip install 命令逐条补齐注意不要用pip install vllm让它自动解析因为自动解析经常把 PyTorch 升级到最新版导致 GPU 驱动不兼容。现象 → pip 安装 vllm 时报冲突要求安装特定版本的 transformers 或 tokenizers 原因 → vLLM 预编译 wheel 依赖严格锁定的版本范围与当前虚拟环境中的版本不一致 解决 → 先装 torch 2.3.0 系列再装 vllm 0.4.3中间报错按 pip 提示逐个安装指定版本不走自动解析4.4 显存分配不合理导致启动即崩vLLM 启动 DeepSeek-R1-Distill-Qwen-14B 时默认的显存分配策略可能不够智能如果同时还在同一块 GPU 上跑其他模型显存一下子就爆了。教程里给了一个--gpu-memory-utilization 0.95的参数很多人不理解为什么不是 1.0。原因是必须预留一小部分显存给 CUDA context、算子和临时张量全部塞满会直接导致 OOM。另外--max-model-len 5120这个参数要结合你的知识库文档长度来调它决定了模型能处理的最大上下文长度开太小长文档会被截断开太大会占用更多显存。在 V100 32GB 上跑 14B 模型如果同时要处理长上下文建议先用nvidia-smi观察空闲显存再决定 5120 是否需要调大。实际复现时我把--max-model-len调大后触发过显存溢出后来在单卡 32GB 上保持默认值才稳定。4.5 Dify 与模型服务的 → 连接超时Dify 容器在 ECS-1 上模型服务在 ECS-2 和 ECS-3 上第一次配置模型供应商后测试连接的时候很大概率遇到超时。这个问题的根源通常不是 Dify 配置错了而是安全组或防火墙根本没放行对应端口。服务器一般有两层防护云控制台的「安全组规则」和操作系统自带的 firewalld 或 iptables。排查时先确认安全组放行了 9997 和 8008 端口再在 ECS-1 上用telnet或nc测试到目标端口的连通性。另外还要注意 Dify 容器内部解析模型服务地址时如果写的是域名或内网 IP要确认容器网络能路由到对应网段。5. vLLM 部署 DeepSeek-R1-14B启动参数与验证技巧5.1 算力评估为什么 V100 32GB 能跑 14BDeepSeek-R1-Distill-Qwen-14B 是从 Qwen 2.5 系列蒸馏出来的参数量 14B 左右。在 V100 32GB 上部署理论上模型权重用半精度加载大约占 28GB 显存这就基本接近极限了。教程里特意加了一堆「省显存」参数比如--enforce-eager用来关闭 CUDA graph 优化——这个优化本来能提升推理速度但会额外预分配显存在显存吃紧时反而容易失败--max-model-len 5120限制上下文长度--max-num-batched-tokens 5120限制单次批量处理的最大 token 数--max-num-seqs 5限制并发序列数量。这些参数组合下来核心思路就是牺牲一点吞吐量来换取单卡能稳定跑起来。如果换更大的模型或者更高的并发需求就得考虑多卡 Sharded 或者换成更大显存的卡。5.2 vLLM 服务启动的完整命令解析环境准备部分教程里给出了 CUDA 环境变量配置和依赖安装的步骤见上一章的避坑清单。基础依赖就绪后模型权重上传到服务器某个目录比如/root/work/ds/pretrained然后执行启动命令python -m vllm.entrypoints.openai.api_server \ --model /root/work/ds/pretrained \ --dtype half \ --trust-remote-code \ --tensor-parallel-size 1 \ --max-model-len 5120 \ --enforce-eager \ --gpu-memory-utilization 0.95 \ --max-num-batched-tokens 5120 \ --max-num-seqs 5 \ --host 0.0.0.0 \ --served-model-name DeepSeek-R1-14B \ --port 8008 逐项说明关键参数的作用。--dtype half表示用 FP16 加载权重直接决定显存占用减半。--trust-remote-code允许加载模型仓库中的自定义 Python 代码这是 Qwen 系列模型的必要参数不加可能会报推理代码缺失。--tensor-parallel-size 1表示单卡推理不做张量并行。--host 0.0.0.0让服务对外可访问--served-model-name是暴露给外部调用的模型名Dify 里配置的就是这个名字它不需要和 Hugging Face 仓库名一致。--enforce-eager用于关闭 CUDA graph牺牲一点性能换显存余量。命令末尾的是后台运行标记但建议第一次启动先不加前台运行看到Starting serving process和端口监听成功的日志后再 CtrlC 杀掉改成 nohup 后台方式。5.3 服务连通性验证vLLM 启动完成后不要急着去 Dify 配置先在 ECS-3 本机验证一下接口是否通。vLLM 提供的是 OpenAI 兼容接口可以用 curl 直接测试curl http://localhost:8008/v1/models这个请求应该返回模型的元信息包括刚才设定的served-model-name。拿到正常响应后再测实际对话能力curl http://localhost:8008/v1/chat/completions \ -H Content-Type: application/json \ -d { model: DeepSeek-R1-14B, messages: [{role: user, content: 你好介绍一下你自己}], max_tokens: 512 }上面这段 curl 验证里有两个地方比较重要model字段的值必须和启动时--served-model-name一致否则接口直接报 model not foundmax_tokens决定单次生成的回复长度上限如果启动时max-model-len只设了 5120要确保这个值不要超过余量。当 curl 能正常返回一个带choices字段的 JSON 时说明 ECS-3 的模型服务已经稳定工作。之后的联调路径就顺理成章了Dify 后端会以 OpenA 兼容的方式把对话请求转发到 ECS-3 的 8008 端口拿到结果再结合知识库检索到的上下文合成回答。只有跑通这一步整个 RAG 链路才算真正验证到了点子上也才知道显存参数设置的到底是「够用」还是「紧巴巴」。5.4 联调时的最后一道检查Dify 配置完成后的首次问答值得盯着日志观察一遍完整链路。在 ECS-1 上执行docker compose logs -f api能看到 Dify 的转发日志ECS-3 上查看 vLLM 的启动日志能看到每次请求的处理时间和 token 消耗ECS-2 上 xinference 的日志则能确认 embedding 和 rerank 是否被调用。如果回答内容跟知识库完全无关先检查 Dify 里的知识库是否成功切分并向量化。一个常见的坑是文档上传到 Dify 后embedding 模型配置的 API 地址不对导致向量化任务静默失败但从界面上看文档状态还是「已完成」。所以首次问答必须能引用到知识库原文才算链路真正通了否则只是「大模型对话」和 RAG 毫无关系。从那以后我每次部署完 RAG都会强制走一遍「curl 模型接口 → Dify 知识库问答 → 日志验证三步到达」这个流程不发散、不跳过确认没问题才交付使用。这套习惯是从第一次被「看似成功实则翻车」的部署坑过之后养成的。希望你搭的时候每一步都能少踩一个这种暗坑。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进