
DeepSeek 的模型写代码确实顺手但每次在云端 API 上跑长任务我心里都在默默换算 token 账单一到高峰时段排队和限流又让人抓狂。刚好手上有两台 DGX Spark我决定把它们组成本地双机推理集群专门跑 DeepSeek-V4-Flash。整个过程从硬件互联、分布式推理到接口层的 thinking mode 报错踩了不少坑。这篇文章把这套方案完整记录下来新手可以照着从零搭起来有经验的同学可以直接跳到第 5 节看reasoning_content这类高频报错的解法。先说明一点DeepSeek-V4-Flash 这个名字主要出现在 DeepSeek 的 OpenAI 兼容接口里和deepseek-v4-pro一起作为模型名暴露给调用方定位偏向“更快、更省”的推理场景。本文假设你已经能拿到可部署的权重文件如果官方只提供 API 而不开放权重也别急着硬套路径可以用同规格的开源模型DeepSeek-R1 蒸馏系列、Qwen 系列等验证同一套分布式推理流程。这样既能把两台机器跑起来也能把性能摸底搞清楚。1. 背景与核心概念1.1 DGX Spark 到底是一台什么机器DGX Spark 是 NVIDIA 在 GTC 2025 上发布的“个人 AI 超算”核心是 GB10 Grace Blackwell 超级芯片。它和普通游戏主机、工作站是两类东西它把 Grace CPU 和 Blackwell GPU 集成在一起提供 128GB 统一内存官方宣传的 FP4 算力在 1 PFLOPS 左右。对普通开发者来说最直观的感受是——一台桌面主机大小的设备可以本地跑几十亿到几百亿参数的大模型不用每次请求都打到云端。但这里要特别提醒一个容易误判的点DGX Spark 的 128GB 是统一内存内存带宽和服务器上动辄几个 TB/s 的 HBM 不在一个量级具体规格请以 NVIDIA 官方文档为准。这意味着它更适合“能装下大模型 低并发推理 数据不出机器”的场景而不是用来和八卡 H100 集群拼吞吐。1.2 DeepSeek-V4-Flash 是什么从接口视角看DeepSeek-V4-Flash 是 DeepSeek 平台上和deepseek-v4-pro并列的一个模型名Flash 后缀通常意味着更低的延迟、更快的首 token 响应适合代码补全、对话、轻量 Agent 这类对交互速度敏感的任务。它和“满血旗舰”Pro 版本之间的关系可以类比“轻量版”和“标准版”。在本地部署时我们不需要区分它到底是 API 名还是开源权重名只需要在推理服务里把模型加载出来然后给客户端一个统一的 OpenAI 兼容接口。本文会在第 4 节完整演示这套链路。1.3 为什么要把两台并联起来单台 DGX Spark 的 128GB 内存已经不算小但跑大模型时会遇到两个瓶颈一是 200B 量级的模型在 4bit 量化后大约需要 100GB 以上的权重空间单机装下后 KV cache 余量很紧张二是单机内存带宽有限单流解码速度上不去。两台并联之后总内存来到 256GB模型权重可以按“张量并行”方式切到两张卡上每个节点只需要读取自己那一半权重单流解码速度有机会接近翻倍同时还能承载更大的模型和更高的并发。这就是“两台比一台更香”的核心原因。2. 环境准备与版本说明2.1 硬件清单本次搭建使用的基础硬件如下设备规格作用DGX Spark × 2128GB 统一内存4TB NVMe推理计算节点万兆交换机或直连线缆两台机器间数据传输张量并行通信电源与 UPS按两台整机总功耗预留稳定供电管理终端任意一台工作电脑SSH 登录与部署两台 DGX Spark 之间建议使用高带宽、低延迟的网络方案。张量并行每一步都要做激活值同步节点间带宽越低速度损耗越明显。实际部署时先查一下网卡是否支持 RDMA 或 GPUDirect这通常是分布式推理性能的分水岭。2.2 软件栈说明DGX Spark 出厂一般预装 DGX OS基于 Ubuntu 的定制系统并带好 NVIDIA 驱动和容器运行时。本文示例采用的软件栈如下操作系统DGX OS / Ubuntu 22.04 LTS 及以上架构注意Grace CPU 是 ARM 架构aarch64很多 pip 预编译包默认是 x86_64安装前要确认是否有 aarch64 版本Python3.10 或 3.11推理框架vLLM社区方案生产环境也可考虑 NVIDIA NIM / Triton Inference Server客户端OpenAI SDK、httpx、curl版本需要根据你的项目实际情况调整本文重点演示配置思路不要盲目照抄固定版本号。2.3 网络与主机名规划为了让两台机器在分布式集群里互相识别建议先配置静态 IP 和主机名。编辑两台机器的/etc/hosts192.168.1.10 dgx-spark-01 192.168.1.11 dgx-spark-02然后配置 SSH 免密登录确保 01 节点能免密 ssh 到 02 节点。后面的 Ray 集群和 vLLM 分布式启动都依赖这个基础。3. 核心原理从单机推理到张量并行3.1 为什么解码阶段特别吃内存带宽大模型生成是自回归过程每生成一个 token都要把模型权重从内存搬运到计算单元完成一次完整前向计算。因此单流解码速度的物理上限可以近似写成单流解码 tokens/s ≈ 可用内存带宽 / 每一步读取的权重字节数举个例子70B 稠密模型做 4bit 量化后权重大约 35GB。DGX Spark 单机内存带宽如果按 273GB/s 算理论上单流解码上限约 7.8 tokens/s实际还会被 KV cache 读取、中间激活、并行开销吃掉一部分落到 4~6 tokens/s 是很正常的。这不是机器不行而是自回归解码的带宽约束。3.2 单并发到底能跑多少 token先给结论再讲怎么算。以两台 DGX Spark 做张量并行、模型为 70B 4bit 量化为例部署方式每节点读取权重理论单流上限实测参考区间单机约 35GB约 7.8 tokens/s4~6 tokens/s双机 TP2约 17.5GB约 15.6 tokens/s8~12 tokens/s双机 TP2 / 200B 模型约 50GB约 5.5 tokens/s3~5 tokens/s上面的“实测参考区间”是经验范围不是任何官方基准具体要以你自己的权重、量化格式和网络环境实测为准。还有一个重要变量如果模型是 MoE混合专家架构每个 token 只会激活部分专家实际读取的权重远小于总参数量解码速度可能明显高于按总参数量估算的结果——这也是很多服务端推理“看着模型很大跑起来却不慢”的原因。3.3 双机张量并行的收益与陷阱张量并行Tensor Parallelism会把每一层的权重按维度切成两份两台机器各算一半每算完一层就通过节点间网络做一次通信同步。收益有三个第一能装下单机装不下的模型第二单流解码时每台机器只读一半权重速度提升第三整体内存变多可以支撑更高的并发。陷阱也有两个。一是节点间通信延迟会被放大网络不稳定时双机速度甚至可能不如单机。二是单并发场景下如果模型本来就很小、单机跑得动双机收益有限优先级反而不如“单机多并发”。所以做决定前先算清楚模型规模和你到底要单流速度还是并发吞吐。4. 完整实战两台 DGX Spark 部署 DeepSeek-V4-Flash4.1 模型下载与项目结构先在 01 节点上创建统一目录把模型权重放到共享或各自可访问的路径mkdir -p /data/models cd /data/models # 以 Hugging Face 下载为例仓库名按真实存在替换 huggingface-cli download 你的模型仓库 \ --local-dir /data/models/deepseek-v4-flash如果网络环境对 Hugging Face 不稳定可以用 ModelScope 的modelscope download命令下载后同样放到/data/models下。模型目录权限建议设为仅部署用户可读写避免误删。4.2 安装推理框架 vLLM在 01 节点创建 Python 虚拟环境并安装 vLLM。注意先确认机器的架构和 wheel 是否兼容python3 -m venv /opt/vllm-venv source /opt/vllm-venv/bin/activate pip install -U pip pip install vllm如果 pip 直接装不上 aarch64 的 vLLM不要硬试。两个替代方案一是使用 NVIDIA 官方提供的容器镜像二是从源码编译。对生产环境我更推荐先用官方容器跑通再考虑自定义编译。4.3 启动 Ray 集群vLLM 多机分布式推理依赖 Ray。先在 01 节点初始化 head再让 02 节点加入# 01 节点执行head ray start --head --node-ip-address 192.168.1.10 --port 6379 # 02 节点执行worker ray start --address192.168.1.10:6379 --node-ip-address 192.168.1.11启动成功后在 01 节点执行ray status应该能看到两个节点都处于活跃状态。如果 worker 一直显示“waiting for head”优先检查 02 节点能否 ssh 回 01以及防火墙是否放行了 6379 和 8265 端口。4.4 启动 vLLM 推理服务在 01 节点执行下面的命令关键参数是--tensor-parallel-size 2它告诉 vLLM 把模型切到两台机器上cd /data/models source /opt/vllm-venv/bin/activate vllm serve /data/models/deepseek-v4-flash \ --served-model-name deepseek-v4-flash \ --tensor-parallel-size 2 \ --distributed-executor-backend ray \ --host 0.0.0.0 \ --port 8000 \ --max-model-len 32768 \ --max-num-seqs 8 \ --gpu-memory-utilization 0.9参数说明--served-model-name对外暴露的模型名客户端请求时用这个名字--tensor-parallel-size张量并行度数两台机器就是 2--max-num-seqs最大并发序列数本地测试不建议开太大--gpu-memory-utilization统一内存中给模型和 KV cache 的可用比例0.9 表示预留 10% 给系统如果是量化权重按格式追加--quantization awq或--quantization gptq非量化权重则不要加。日志里出现Available routes和Uvicorn running on http://0.0.0.0:8000就表示启动成功。4.5 验证接口与吞吐测试先用 curl 验证模型列表和基本调用curl http://192.168.1.10:8000/v1/models curl -X POST http://192.168.1.10:8000/v1/completions \ -H Content-Type: application/json \ -d { model: deepseek-v4-flash, prompt: 用 Python 写一个快速排序并解释时间复杂度。, max_tokens: 512, temperature: 0.6 }然后写一个简单的客户端脚本做单并发和多并发压测。下面是一个基于 OpenAI SDK 的串行测试脚本# 文件路径benchmark_client.py from openai import OpenAI client OpenAI( base_urlhttp://192.168.1.10:8000/v1, api_keyEMPTY, ) prompt 用 Python 实现一个 LRU Cache给出完整代码和注释。 resp client.completions.create( modeldeepseek-v4-flash, promptprompt, max_tokens256, temperature0.6, ) print(resp.choices[0].text)如果需要多并发压测推荐用oha这类 HTTP 压测工具oha -z 60s -c 8 \ -m POST \ -H Content-Type: application/json \ -d {model:deepseek-v4-flash,prompt:写一段 Python 代码,max_tokens:256} \ http://192.168.1.10:8000/v1/completions建议分别测 1、4、8 三个并发档位记录数据后用下面的表格整理并发数首 token 延迟单流速度总吞吐失败率148读结果时注意一个规律并发从 1 涨到 8单流速度通常会被摊薄但总吞吐会上升。如果你发现并发升高后总吞吐几乎不涨大概率是带宽或通信已经打满而不是计算芯片不够快。5. API 接入与高频报错排查5.1 OpenAI 兼容接口的基本配置vLLM 启动后对外提供的是 OpenAI 兼容接口客户端只需要改三个地方base_url指向http://节点IP:8000/v1model写deepseek-v4-flashapi_key随便填一个占位字符串即可因为本地服务通常不做鉴权。5.2 高频报错reasoning_content必须回传这是本文要重点讲的坑。很多人在接入 DeepSeek 的 thinking mode 时会遇到类似这样的报错upstream_status: http 400 cause: the reasoning_content in the thinking mode must be passed back to the api.这个报错的根因是DeepSeek 的思考模型在开启 thinking mode 后接口返回的 assistant 消息里会额外带一个reasoning_content字段里面是模型的思考过程。当你把这一轮消息作为历史记录发回去做多轮对话时DeepSeek 要求你必须把这个字段原样传回。如果中间经过某个本地代理或者客户端 SDK 时这个非标准字段被过滤掉了上游 API 就会返回 400。解决办法有三种按推荐顺序排列关闭 thinking mode如果你的任务不需要思考过程最简单就是关掉接口不再返回reasoning_content问题自然消失让代理层保留该字段检查你使用的本地代理或网关脚本确保透传 assistant 消息时保留reasoning_content正确构造多轮消息不要在构造历史消息时丢弃思考内容。下面是一个使用 httpx 构造多轮消息的示例关键在 assistant 消息里带上reasoning_content# 文件路径keep_reasoning_content.py import httpx url http://192.168.1.10:8000/v1/chat/completions headers {Content-Type: application/json, Authorization: Bearer EMPTY} data { model: deepseek-v4-flash, messages: [ {role: user, content: 帮我分析这段代码的性能问题}, { role: assistant, content: 上一条回答内容, reasoning_content: 上一条回答对应的思考过程, }, {role: user, content: 那再给出优化后的版本}, ], } resp httpx.post(url, headersheaders, jsondata) print(resp.status_code, resp.json())需要注意的是具体开启或关闭 thinking 的参数名可能因 API 版本不同而不同接入前先查看最新的 DeepSeek 官方 API 文档不要照搬旧项目的字段。5.3 高频报错模型名不在支持列表还有一类报错长这样the supported api model names are deepseek-v4-pro or deepseek-v4-flash, but ...出现这个报错说明客户端请求里写的model字段和上游接口支持的模型名不一致。常见原因有三个写成了别名比如deepseek-chat、deepseek-v4但接口只认deepseek-v4-flash大小写或符号不一致DeepSeek-V4-Flash和deepseek-v4-flash在严格校验的网关里可能不同本地代理层做了模型名映射把deepseek-v4-flash强转成了别的名字。排查方式就是打印实际发出去的请求体确认model字段的精确值然后改成接口提示支持的名字。项目里如果多处配置了模型名优先统一维护在环境变量中避免散落各处。5.4 其他加载与访问问题问题现象常见原因解决思路模型加载失败权重路径不对或量化格式与启动参数不匹配检查/data/models目录内容调整--quantization报错model may not exist客户端本地模型列表没有该名字确认模型名精确匹配刷新客户端配置Ray 节点无法加入集群防火墙、SSH 免密、端口未放行检查 6379/8265 端口与 hosts 配置多轮对话 400thinking mode 的reasoning_content被丢弃按 5.2 小节回传该字段响应很慢节点间网络带宽不足检查网卡速率、换直连或升级交换机6. 成本盘点满屏金币到底划不划算6.1 一次性的硬件投入DGX Spark 发布时官方定价大约在 3999 美元级别两台就是 8000 美元左右叠加上网络设备、UPS、存储整体投入在数万元人民币量级。如果你只是偶尔跑几个代码任务这笔钱够在云上买很多 token但如果你是高频开发、隐私敏感、或者长期跑 Agent 任务本地部署的边际成本会越来越低。6.2 电费与折旧怎么摊本地部署不是零成本。DGX Spark 整机功耗在几百瓦级别两台机器 7×24 小时运行的话按整机平均功耗和当地电价可以这样粗算年电费 ≈ 单台功耗(千瓦) × 2台 × 24小时 × 365天 × 电价(元/度)假设单台平均 350W、电价 0.6 元/度两台一年电费大约是 3679 元。再加上