DGX Spark 部署本地模型
DGX Spark 部署本地模型
本文记录在 DGX Spark / 128G 级别机器上下载、启动、测试和压测本地 vLLM 模型。
以下内容默认在 DGX 的 Linux shell 中执行,模型统一放在:
1 | ~/.cache/huggingface/models |
1. 结论和模型选择
| 场景 | 推荐模型 | 启动方式 | 说明 |
|---|---|---|---|
| 日常代码 Agent、IDE 补全、轻量多人使用 | Qwen3-Coder-30B-A3B-Instruct-FP8 |
NVIDIA vLLM Docker | 30G FP8,短上下文响应快,Docker 镜像可直接加载 |
| 复杂代码任务、较长上下文、质量优先 | Qwen3-Coder-Next-FP8 |
NVIDIA vLLM Docker | 54.1G FP8,可跑 16K/64K 场景,但多人高并发延迟明显变差 |
| 当前最值得保留的综合模型 | Qwen3.6-35B-A3B-FP8 |
本机 venv vLLM | 短上下文、中等上下文、长上下文都表现较好,但启动后主机内存占用很高 |
| 非 FP8 质量对照、8K 内测试 | Qwen3.5-35B-A3B |
本机 venv vLLM | 能跑通,但需要保守参数,不适合作为长上下文默认模型 |
不放入主流程的内容:
| 模型 | 原因 |
|---|---|
Qwen3-Coder-Next |
75G,实测内存不够 |
GLM-4.7-Flash |
启动后机器进入极重加载/换页状态,未进入 benchmark |
Docker 方式启动 Qwen3.6-27B-FP8 / Qwen3.6-35B-A3B-FP8 |
nvcr.io/nvidia/vllm:26.01-py3 内置软件栈不识别 qwen3_5 / qwen3_5_moe 架构,需要换新版 vLLM/Transformers |
2. 环境检查
先检查 Hugging Face、代理和离线变量,避免下载或启动时被旧环境变量影响。
1 | echo $HF_ENDPOINT |
如果要下载模型,确保不要处于离线模式:
1 | unset HF_HUB_OFFLINE TRANSFORMERS_OFFLINE |
如果代理不可用或会干扰访问,可以先清掉代理:
1 | unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy |
国内网络建议使用 Hugging Face 镜像:
1 | export HF_ENDPOINT=https://hf-mirror.com |
参数说明:
| 变量 / 命令 | 含义 | 影响 |
|---|---|---|
HF_ENDPOINT |
Hugging Face Hub 访问入口 | 设成 https://hf-mirror.com 后,hf download 会从镜像站下载 |
HF_HUB_OFFLINE=1 |
Hugging Face Hub 离线模式 | 启动或压测本地模型时很有用,避免联网检查;下载模型前必须取消 |
TRANSFORMERS_OFFLINE=1 |
Transformers 离线模式 | 避免 Transformers 联网找配置;本地文件完整时建议用于服务启动和 benchmark |
HTTP_PROXY / HTTPS_PROXY / ALL_PROXY |
网络代理 | 代理错误会导致下载失败;确认代理可用后再设置 |
3. 下载模型
下载前先用 curl 验证镜像站是否能访问模型配置文件:
1 | curl -I https://hf-mirror.com/Qwen/Qwen3-Coder-Next-FP8/resolve/main/config.json |
下载 Qwen3-Coder-Next-FP8:
1 | export HF_ENDPOINT=https://hf-mirror.com |
下载命令参数说明:
| 参数 | 含义 | 影响 |
|---|---|---|
hf download |
Hugging Face CLI 的下载命令 | 会把模型仓库文件下载到本地 |
Qwen/Qwen3-Coder-Next-FP8 |
Hugging Face 模型仓库名 | 换模型时改这里 |
--local-dir |
指定本地保存目录 | vLLM 启动时直接指向这个目录;建议所有模型统一放到 ~/.cache/huggingface/models |
确认模型目录大小:
1 | du -sh ~/.cache/huggingface/models/Qwen3-Coder-Next-FP8 |
删除不需要的模型前先确认目录:
1 | du -sh ~/.cache/huggingface/models/Qwen3-Coder-Next |
rm -rf 会直接删除目录,执行前必须确认路径完整且没有变量拼错。
4. 用 Docker 启动 vLLM
Docker 方式适合 Qwen3-Coder-30B-A3B-Instruct-FP8 和 Qwen3-Coder-Next-FP8。原测试使用镜像:
1 | nvcr.io/nvidia/vllm:26.01-py3 |
4.1 启动 Qwen3-Coder-30B-A3B-Instruct-FP8
1 | docker run -it --gpus all --network host \ |
适用判断:
| 项目 | 结果 |
|---|---|
| 模型大小 | 约 30G |
| 512 输入 / 256 输出 / 20 请求 / 1 RPS | 全部成功,Mean TTFT 约 256ms,Mean TPOT 约 57ms |
| 推荐用途 | 默认代码 Agent、日常 IDE、轻量多人 |
启动后使用 watch -n 1 free -h 观察 DGX 主机内存:

截图显示:总内存约 121Gi,已用约 109Gi,可用约 11Gi,swap 基本没有明显压力。这说明 30B FP8 虽然已经占用大部分主机内存,但仍保留了一定余量,适合作为日常代码 Agent 默认模型。
4.2 启动 Qwen3-Coder-Next-FP8
短上下文或中等上下文启动:
1 | docker run -it --gpus all --network host \ |
16K 上下文启动:
1 | docker run -it --gpus all --network host \ |
适用判断:
| 项目 | 结果 |
|---|---|
| 模型大小 | 约 54.1G |
| 2048 输入 / 512 输出 / 20 请求 / 1 RPS | 全部成功,Mean TTFT 约 4.4s,Mean TPOT 约 124ms |
| 2048 输入 / 512 输出 / 50 请求 / 4 RPS | 全部成功,但 Mean TTFT 约 9s,P99 TTFT 超过 20s |
| 14336 输入 / 1024 输出 / 3 请求 / 0.1 RPS | 全部成功,16K 级上下文可用 |
| 32768 输入 / 8192 输出 / 2 请求 / 0.03 RPS | 全部成功,但总耗时约 6 分钟 |
| 推荐用途 | 复杂任务、长上下文单人或低并发 |
| 不推荐用途 | 多人高并发默认模型 |
启动后使用 watch -n 1 free -h 观察 DGX 主机内存:

截图显示:总内存约 121Gi,已用约 98Gi,可用约 23Gi,swap 使用约 1.7Gi。相比 30B FP8,Next-FP8 启动时主机可用内存更多,但已经出现 swap 使用;后续做长上下文和并发压测时,需要同时看 free -h 和 vLLM 日志里的 KV cache / Waiting 状态。
4.3 Docker 参数说明
| 参数 | 含义 | 影响 |
|---|---|---|
docker run |
创建并运行容器 | 每次执行会启动一个新的 vLLM 服务容器 |
-it |
交互式终端 | 适合前台观察日志;SSH 断开或终端关闭时服务可能停止 |
--rm |
容器退出后自动删除 | 适合一次性 benchmark,不适合长期服务 |
-d |
后台运行容器 | 适合生产或长时间服务,需配合 docker logs 查看日志 |
--name <name> |
指定容器名 | 方便 docker logs <name>、docker stop <name> 管理 |
--gpus all |
把所有 GPU 暴露给容器 | vLLM 才能使用 NVIDIA GPU;如果只想用部分 GPU,需要改成指定设备 |
--network host |
使用宿主机网络 | 容器内监听 8000 等同宿主机 8000;最简单,但端口冲突要自己处理 |
--ipc=host |
使用宿主机 IPC 命名空间 | 减少共享内存限制导致的问题,常用于大模型容器 |
--ulimit memlock=-1 |
允许锁定内存无限制 | 避免部分 CUDA / NCCL / 推理路径受内存锁定限制影响 |
--ulimit stack=67108864 |
设置栈大小为 64MiB | 防止深调用或底层库栈空间不足 |
-e HF_HUB_OFFLINE=1 |
容器内开启 Hugging Face 离线模式 | 本地模型完整时建议开启,避免启动时联网 |
-e TRANSFORMERS_OFFLINE=1 |
容器内开启 Transformers 离线模式 | 避免 Transformers 联网拉配置 |
-v ~/.cache/huggingface:/root/.cache/huggingface |
挂载宿主机模型缓存到容器 | 容器内模型路径要写 /root/.cache/huggingface/... |
nvcr.io/nvidia/vllm:26.01-py3 |
NVIDIA vLLM 容器镜像 | 决定 vLLM、Transformers、CUDA、Torch 版本;新模型架构不识别时需要换镜像或 venv |
bash -lc '<cmd>' |
在容器内用 bash 执行命令 | benchmark 命令较长时方便传入多行命令 |
4.4 vLLM serve 参数说明
| 参数 | 含义 | 影响 |
|---|---|---|
vllm serve <model_path> |
启动 OpenAI 兼容服务,加载指定模型目录 | <model_path> 必须包含 config.json、tokenizer 和权重文件 |
--host 0.0.0.0 |
监听所有网卡 | 局域网其他机器可以访问;只本机访问可用 127.0.0.1 |
--port 8000 |
服务端口 | OpenAI 兼容接口会暴露在 http://<host>:8000/v1;端口冲突会启动失败 |
--served-model-name |
对外暴露的模型名 | API 请求里的 "model" 必须和它一致;可以和目录名不同 |
--max-model-len |
单请求最大上下文长度 | 必须大于等于输入 tokens + 输出 tokens;值越大,KV cache 预留越多,显存/内存压力越高,并发能力可能下降 |
--enable-prefix-caching |
开启前缀缓存 | 多个请求有相同系统提示词或相同代码上下文前缀时可减少重复 prefill;会占用额外缓存管理资源 |
--gpu-memory-utilization |
vLLM 可使用的 GPU 显存比例 | 值越高,KV cache 越大、可支持更长上下文或更多并发;太高可能 OOM 或影响系统稳定 |
--tensor-parallel-size |
张量并行 GPU 数 | 单卡机器设 1;多卡模型切分时才调大 |
--reasoning-parser qwen3 |
使用 Qwen3 推理内容解析器 | 适合 Qwen3 系列 reasoning 输出格式;不需要 reasoning 格式时可省略 |
--language-model-only |
只启用语言模型能力 | 避免多模态等额外逻辑;纯文本模型建议启用 |
--enable-auto-tool-choice |
开启自动工具调用选择 | opencode 这类 Agent 会通过 OpenAI tool calling 协议让模型决定是否调用工具;不开时工具调用兼容性会变差 |
--tool-call-parser qwen3_coder |
指定工具调用解析器 | Qwen3 / Qwen3-Coder 系列接 opencode 时建议使用 qwen3_coder;实测 hermes 会导致 opencode 没什么输出 |
--moe-backend triton |
MoE 专家计算后端 | 某些非 FP8 MoE 模型默认后端会 JIT 失败,用 triton 可避开部分问题 |
--max-num-seqs |
同时调度的最大序列数 | 降低它可以减少 cache 和调度压力;太低会限制并发吞吐 |
关键调参关系:
1 | max-model-len >= 输入 tokens + 输出 tokens |
5. 用本机 venv 启动新版架构模型
Qwen3.6-27B-FP8 和 Qwen3.6-35B-A3B-FP8 在 Docker 镜像 nvcr.io/nvidia/vllm:26.01-py3 中启动失败,原因是该镜像内置 Transformers/vLLM 不识别 qwen3_5 / qwen3_5_moe 架构。
已经跑通的本机环境:
| 项目 | 结果 |
|---|---|
| vLLM | 0.22.0 |
| Transformers | 5.9.0 |
| Torch | 2.11.0+cu130 |
| 启动方式 | source ~/.venv/bin/activate 后直接 vllm serve |
5.1 启动 Qwen3.6-35B-A3B-FP8
前台启动:
1 | source ~/.venv/bin/activate |
后台启动:
1 | source ~/.venv/bin/activate |
启动后使用 watch -n 1 free -h 观察 DGX 主机内存:

截图显示:总内存约 121Gi,已用约 118Gi,可用约 3.0Gi,buff/cache 约 3.3Gi。这和后续测试记录一致:Qwen3.6-35B-A3B-FP8 能跑通长上下文和真实 Agent 任务,但主机内存余量非常小。因此这个模型可以保留为高质量默认候选,但不建议继续做 64K/128K 多人并发压测。
后台启动参数说明:
| 参数 / 写法 | 含义 | 影响 |
|---|---|---|
source ~/.venv/bin/activate |
激活本机 Python 虚拟环境 | 使用 venv 里的新版 vLLM / Transformers |
nohup ... & |
后台运行,终端退出后继续服务 | 适合长期服务;日志不会直接显示在终端 |
> /tmp/xxx.log 2>&1 |
stdout 和 stderr 都写入日志 | 用 tail -f /tmp/xxx.log 观察加载和运行状态 |
echo $! > /tmp/xxx.pid |
保存后台进程 PID | 后续可用 kill $(cat /tmp/xxx.pid) 停止服务 |
启动成功日志:
1 | Resolved architecture: Qwen3_5MoeForConditionalGeneration |
注意:这个模型启动后的主机内存占用非常高,测试前后可用内存最低只有约 3.6-6.2GiB,并出现过 swap 使用约 3.3GiB。因此不建议继续做 64K/128K 多人并发压测。
测试结果摘要:
| 场景 | 成功 / 失败 | Mean TTFT | Mean TPOT | 输出吞吐 | 结论 |
|---|---|---|---|---|---|
| 512 输入 / 256 输出 / 20 请求 / 1 RPS | 20 / 0 | 312ms | 68ms | 146 tok/s | 短上下文体验好 |
| 2048 输入 / 512 输出 / 20 请求 / 1 RPS | 20 / 0 | 755ms | 90ms | 165 tok/s | 中等代码上下文可用 |
| 2048 输入 / 512 输出 / 30 请求 / 3 RPS | 30 / 0 | 1.64s | 121ms | 221 tok/s | 多人中等上下文可稳定跑完 |
| 14336 输入 / 1024 输出 / 3 请求 / 0.1 RPS | 3 / 0 | 2.71s | 29ms | 51 tok/s | 16K 可用 |
| 28672 输入 / 1024 输出 / 1 请求 / 0.05 RPS | 1 / 0 | 5.64s | 21ms | 21.6 tok/s | 32K 单请求可用 |
| 57344 输入 / 2048 输出 / 1 请求 / 0.02 RPS | 1 / 0 | 13.2s | 24ms | 18.2 tok/s | 64K 单请求可用 |
| 122880 输入 / 1024 输出 / 1 请求 / 0.01 RPS | 1 / 0 | 37.6s | 30ms | 6.1 tok/s | 近 128K 单请求可用,但首 token 等待很长 |
5.2 启动 Qwen3.6-27B-FP8
1 | source ~/.venv/bin/activate |
启动成功日志:
1 | Resolved architecture: Qwen3_5ForConditionalGeneration |
测试结果摘要:
| 场景 | 成功 / 失败 | Mean TTFT | Mean TPOT | 输出吞吐 | 结论 |
|---|---|---|---|---|---|
| 512 输入 / 256 输出 / 20 请求 / 1 RPS | 20 / 0 | 2.40s | 165ms | 86 tok/s | 短上下文交互速度不理想 |
| 2048 输入 / 512 输出 / 20 请求 / 1 RPS | 20 / 0 | 3.69s | 180ms | 95 tok/s | 中等上下文可跑,但慢 |
| 14336 输入 / 1024 输出 / 3 请求 / 0.1 RPS | 3 / 0 | 7.83s | 145ms | 17 tok/s | 16K 可跑但慢 |
| 122880 输入 / 1024 输出 / 1 请求 / 0.01 RPS | 1 / 0 | 100s | 160ms | 2.8 tok/s | 近 128K 可跑,但不适合作为默认模型 |
5.3 启动 Qwen3.5-35B-A3B
这个模型不是 FP8,权重占用约 64.69GiB,KV cache 只剩约 3.91GiB。默认 MoE backend 容易遇到 FlashInfer JIT 被 kill 或 Mamba cache blocks 不足的问题,需要使用保守参数。
1 | source ~/.venv/bin/activate |
启动成功日志:
1 | Model loading took 64.69 GiB memory and 91.50 seconds |
测试结果摘要:
| 场景 | 成功 / 失败 | Mean TTFT | Mean TPOT | 输出吞吐 | 结论 |
|---|---|---|---|---|---|
| 512 输入 / 256 输出 / 20 请求 / 1 RPS | 20 / 0 | 628ms | 131ms | 102 tok/s | 可用 |
| 2048 输入 / 512 输出 / 20 请求 / 1 RPS | 20 / 0 | 1.12s | 150ms | 110 tok/s | 可用,但不快 |
| 7168 输入 / 512 输出 / 5 请求 / 0.2 RPS | 5 / 0 | 1.91s | 66ms | 44 tok/s | 8K 内可作为质量对照 |
6. API 连通性测试
6.1 查看模型列表
1 | curl http://localhost:8000/v1/models |
如果从局域网其他机器访问,把 localhost 换成 DGX 的 IP,例如:
1 | curl http://192.168.50.75:8000/v1/models |
6.2 Chat Completions 测试
1 | curl http://localhost:8000/v1/chat/completions \ |
请求参数说明:
| 参数 | 含义 | 影响 |
|---|---|---|
/v1/chat/completions |
OpenAI 兼容聊天接口 | Cline、Roo Code、Continue、OpenAI SDK 等可以接这个接口 |
Content-Type: application/json |
请求体格式 | 必须设置,否则服务端可能无法解析 JSON |
model |
请求使用的模型名 | 必须等于启动时的 --served-model-name |
messages |
聊天上下文 | 包含 system/user/assistant 消息;内容越长,prefill 越慢,TTFT 越高 |
role |
消息角色 | system 适合放全局指令,user 放用户问题,assistant 放历史回答 |
content |
消息文本 | 计入输入 tokens,占用上下文窗口 |
max_tokens |
最大生成 tokens | 输出上限;越大,总耗时和显存占用越高 |
temperature |
采样随机性 | 越低越稳定、越确定;代码生成建议 0.1-0.3 |
6.3 Python SDK 测试
1 | from openai import OpenAI |
Python 参数说明:
| 参数 | 含义 | 影响 |
|---|---|---|
base_url |
OpenAI 兼容服务地址 | 本机用 http://localhost:8000/v1,局域网机器用 DGX IP |
api_key="EMPTY" |
占位 API key | vLLM 默认不校验 key,但 OpenAI SDK 要求传入 |
client.chat.completions.create |
调用聊天补全接口 | 和 curl 的 /v1/chat/completions 等价 |
6.4 opencode 局域网接入
本地电脑上的 opencode 可以通过局域网连接 DGX 上的 vLLM OpenAI 兼容接口。例如 DGX 地址是 192.168.50.75,服务端口是 8000,则 opencode 侧模型服务地址应指向:
1 | http://192.168.50.75:8000/v1 |
DGX 启动 Qwen3.6-35B-A3B-FP8 时,需要加上工具调用相关参数:
1 | source ~/.venv/bin/activate |
实测结论:
| 项目 | 结论 |
|---|---|
--enable-auto-tool-choice |
必须加。opencode 会使用工具调用协议,不开启自动工具选择会影响 Agent 调用工具的行为 |
--tool-call-parser qwen3_coder |
必须使用这个 parser。它能正确解析 Qwen3 系列工具调用输出 |
--tool-call-parser hermes |
不适合这里。实测 opencode 会没什么输出 |
--host 0.0.0.0 |
必须监听所有网卡,否则局域网电脑无法访问 |
--port 8000 |
opencode 侧 base URL 要和这个端口一致 |
一次 opencode 任务日志观察:本地电脑 192.168.50.52 通过局域网请求 DGX,让模型写一个一维有限元算法程序。服务端多次出现:
1 | 192.168.50.52:<port> - "POST /v1/chat/completions HTTP/1.1" 200 OK |
这说明 opencode 到 DGX 的 OpenAI 兼容接口连通正常,HTTP 请求都成功返回。日志里的推理状态大致如下:
| 日志项 | 观察结果 | 解读 |
|---|---|---|
Running |
多数时间为 0 或 1 | 这是单个 opencode Agent 任务,没有形成多人并发压力 |
Waiting |
一直为 0 | 没有排队,服务端当前处理能力够用 |
GPU KV cache usage |
约 0.0%-0.9% | KV cache 压力非常低,这次不是上下文容量瓶颈 |
Prefix cache hit rate |
0.0% | 本轮请求没有命中前缀缓存;opencode 多轮工具调用的 prompt 可能变化较多 |
Avg prompt throughput |
约 56-3192 tokens/s,后期多次到 2500-3100 tokens/s | prefill 能跑起来,且上下文没有压满 |
Avg generation throughput |
约 4-55 tokens/s 波动 | 工具调用和短输出片段会让瞬时吞吐波动,不能只按单条日志判断模型整体速度 |
日志中还出现了几类 Triton JIT warning:
1 | Triton kernel JIT compilation during inference: _zero_kv_blocks_kernel |
这些 warning 的含义是:某些 Triton kernel 在实际推理过程中才第一次编译,会造成当次请求的延迟尖刺。它不是接口失败,也不是模型输出错误。更稳的做法是服务启动后先做几轮 warmup,覆盖 opencode 常见的 prompt 长度、工具调用形态和输出长度,减少正式使用时的 JIT 编译抖动。
这段日志的整体判断:
1 | opencode -> DGX -> vLLM 的链路是通的。 |
7. Benchmark 压测
压测前先启动模型服务,然后另开一个 shell 执行 benchmark。
7.1 短上下文基线
1 | docker run --rm --gpus all --network host \ |
7.2 中等代码上下文
1 | docker run --rm --gpus all --network host \ |
7.3 多人并发
1 | docker run --rm --gpus all --network host \ |
7.4 16K 长上下文
1 | docker run --rm --gpus all --network host \ |
7.5 Benchmark 参数说明
| 参数 | 含义 | 影响 |
|---|---|---|
vllm bench serve |
vLLM 的服务端压测工具 | 对已经运行的 OpenAI 兼容服务发请求 |
--backend openai |
使用 OpenAI 兼容协议 | 对应 vLLM 的 /v1 接口 |
--base-url |
服务基础地址 | 本机一般是 http://localhost:8000 |
--endpoint |
压测接口 | /v1/completions 是文本补全接口;聊天应用也可用 chat 接口另测 |
--model |
请求模型名 | 必须等于服务启动时的 --served-model-name |
--tokenizer |
tokenizer 路径 | 用于生成指定长度的随机输入;应指向同一个模型目录 |
--num-prompts |
总请求数 | 越大越接近真实负载;也会让压测耗时更长 |
--request-rate |
请求注入速率,单位 RPS | 越高越容易形成排队;实际完成速率可能远低于注入速率 |
--random-input-len |
每个请求的输入 token 长度 | 越大 prefill 越慢,TTFT 越高,KV cache 占用越大 |
--random-output-len |
每个请求的输出 token 长度 | 越大 decode 时间越长,总耗时越高 |
--random-input-len + --random-output-len 必须小于或等于服务启动时的 --max-model-len。例如输入 14336、输出 1024,总计 15360,需要 --max-model-len 至少 16384。
7.6 压测指标说明
| 指标 | 含义 | 怎么看 |
|---|---|---|
Successful requests |
成功请求数 | 应等于 --num-prompts |
Failed requests |
失败请求数 | 应为 0;非 0 要看是否超上下文、OOM、服务断开 |
Benchmark duration |
压测总耗时 | 用于判断整体完成时间 |
Request throughput |
实际完成请求速率 | 不一定等于 --request-rate,模型慢时会低很多 |
Output token throughput |
总输出 token 吞吐 | 代表服务整体生成能力 |
Peak output token throughput |
峰值输出吞吐 | 看短时间最高生成能力 |
Peak concurrent requests |
峰值并发请求数 | 反映 vLLM 批处理调度情况 |
Mean TTFT |
平均首 token 延迟 | 影响用户等待第一段回答的体验 |
P99 TTFT |
最慢 1% 首 token 延迟 | 看尾延迟;多人并发时尤其重要 |
Mean TPOT |
后续每个 token 平均耗时 | 越低,生成速度越快 |
P99 TPOT |
最慢 1% 后续 token 耗时 | 看生成阶段稳定性 |
服务端日志也要同时观察:
| 日志字段 | 含义 | 判断方式 |
|---|---|---|
Running |
正在运行的请求数 | 长时间很高说明服务在持续消化请求 |
Waiting |
排队等待的请求数 | 持续大于 0 说明注入压力超过服务处理能力 |
GPU KV cache usage |
KV cache 使用率 | 高到接近满时会限制长上下文和并发 |
Avg generation throughput |
平均生成吞吐 | 看 decode 阶段整体 token/s |
7.7 真实 Agent 任务测试:一维 FEM 程序
除了合成 benchmark,还做过一次更接近真实开发场景的测试:本地电脑上的 opencode 通过局域网连接 DGX 上的 Qwen3.6-35B-A3B-FP8,让模型编写和多轮修复一个一维有限元算法程序 fem_1d.py。随后使用 Codex 对程序做审查、构造反例测试、指出不足,再让 opencode 根据这些反馈继续修复。
相关记录文件:
| 文件 | 内容 |
|---|---|
对话记录.md |
opencode 生成和修复 fem_1d.py 的过程摘要 |
conversation_history_codex.md |
Codex 对 fem_1d.py 的审查、测试和问题定位 |
historyChat.md |
opencode 根据问题反馈修复非零边界、非法区间、非法单元数等问题的记录 |
fem_1d.py |
多轮修复后的最终一维 FEM 程序 |
任务特点:
1 | 任务类型:代码生成 + 数值算法调试 + 多轮修复 |
最终程序包含的主要模块:
| 函数 / 结构 | 功能 |
|---|---|
FEMResult |
保存插值解、节点解、网格等结果 |
element_stiffness(h) |
计算线性单元刚度矩阵 (1/h) * [[1, -1], [-1, 1]] |
element_load(f, h, a) |
使用 2 点 Gauss 积分计算单元载荷,并正确做参考坐标到物理坐标的映射 |
assemble(mesh, f) |
组装全局刚度矩阵和载荷向量 |
apply_bc(K, F, bcs) |
施加 Dirichlet 边界条件,并修正非零边界值对右端项的贡献 |
evaluate_at_points(...) |
将节点解插值到密集采样点 |
compute_errors(...) |
计算 L2 和 Linf 误差 |
solve_1d_poisson(...) |
求解 -u'' = f(x),支持自定义区间、单元数、左右 Dirichlet 边界值和自定义线性求解器 |
多轮修复中暴露和解决的问题:
| 问题 | 表现 | 修复结果 |
|---|---|---|
| 单元载荷坐标映射错误 | 网格加密后误差反而增大,收敛率为负 | element_load 增加单元左端点 a,正确映射 xg = a + 0.5 * h * (1 + xi) |
| 非零 Dirichlet 边界条件错误 | u(0)=1, u(1)=2 这类问题内部节点值错误 |
apply_bc 在清零边界列前执行 F[j] -= K[j, idx] * value,把已知边界值贡献转移到自由 DOF |
domain=(1.0, 1.0) |
产生 nan 和除零警告 |
增加 a < b 校验,非法区间抛 ValueError |
n_elems=0 |
返回退化网格,物理意义不明确 | 增加正整数校验 |
n_elems=-1 |
触发 IndexError |
统一抛出明确的 ValueError |
n_elems=4.0 |
类型语义不清 | 拦截非整数单元数 |
np.trapz 弃用 |
后续维护有兼容风险 | 改为 np.trapezoid |
最终复测环境使用本地 Windows 解释器:
1 | E:\miniconda\envs\AgentTool\python.exe |
语法检查通过:
1 | & 'E:\miniconda\envs\AgentTool\python.exe' -m py_compile fem_1d.py |
内置 demo 复现线性 FEM 理论二阶收敛:
1 | N h L2 error L2 rate Linf error Linf rate |
关键反例复测结果:
1 | zero_load_nonzero_bc: max_err=0.000e+00 |
这次真实任务的模型表现判断:
1 | Qwen3.6-35B-A3B-FP8 能完成多轮代码生成和修复任务。 |
8. 常用调参建议
8.1 只做本机 / 单人代码 Agent
1 | --max-model-len 8192 |
适合普通代码问答、短文件编辑、低并发。首 token 延迟更低,显存压力更小。
8.2 中等代码库上下文
1 | --max-model-len 16384 |
适合 2K-8K 输入、512-1024 输出。需要重点看 TTFT,如果首 token 超过几秒,说明 prefill 已经成为主要瓶颈。
8.3 长上下文单人任务
1 | --max-model-len 65536 |
适合大段代码、长日志、长文档总结。不要直接上多人并发,先用 1-3 个请求验证。
8.4 近 128K 上下文
1 | --max-model-len 131072 |
只建议在已经确认模型能稳定启动后做单请求验证。近 128K 输入会显著增加 prefill 时间,首 token 等待可能达到几十秒甚至更久。即使 KV cache 没打满,计算吞吐也可能成为瓶颈。
8.5 多人并发
多人并发不要只看能否跑完,还要看:
1 | Mean TTFT |
如果 Waiting 持续大于 0,或者 P99 TTFT 超过 10-20 秒,说明当前模型或参数已经不适合作为多人默认服务。
9. 停止服务和查看日志
Docker 前台启动时,直接在终端按:
1 | Ctrl+C |
Docker 后台启动时:
1 | docker ps |
venv 后台启动时:
1 | tail -f /tmp/codex_vllm_qwen36_35b.log |
如果服务没有保存 PID,可以查进程:
1 | ps aux | grep 'vllm serve' |
确认端口占用:
1 | ss -lntp | grep 8000 |
10. 推荐落地配置
如果只保留一个默认服务,优先使用:
1 | Qwen3.6-35B-A3B-FP8 |
原因是它在短上下文、中等上下文、16K、64K、近 128K 单请求测试中都能跑通,且比 Qwen3.6-27B-FP8 更快。缺点是启动后主机内存占用很高,不建议继续做 64K/128K 多人并发。
如果希望用 Docker 保持部署简单,优先使用:
1 | Qwen3-Coder-30B-A3B-Instruct-FP8 |
它是更稳的日常代码 Agent 默认模型。Qwen3-Coder-Next-FP8 可以作为复杂任务备用模型,但不建议作为多人高并发默认模型。


