【昇腾】本地 27B 编程模型接入 Claude Code 实战:Qwopus3.6-27B-Coder 在 vLLM-Ascend 上的部署与踩坑 四张 910B4 跑 27B 模型接入 Claude Code效果比预期要好——虽然慢一、为什么是 Qwopus3.6-27B-Coder项目背景Qwopus 是一个由社区开发者 Jack Rong 自费训练的开源模型系列名字是Qwen Opus的组合——用高质量推理轨迹对 Qwen 基座模型做微调目标是在本地硬件上达到接近 Claude Opus 的推理和编程能力。这个系列经过多轮迭代目前最新版本是Qwopus3.6基于阿里刚发布的Qwen3.6-27B稠密模型使用 GSPOGeneralized Supervised Preference Optimization训练方法。其中 Coder 变体在 SWE-bench Verified 上达到了 67.0%无 thinking 模式Q5_K_M 量化和 Claude 4.0 Opus 的 67.6% 非常接近作为本地模型来说相当亮眼。为什么选择这一版Qwopus 项目以GGUF 格式为主要分发形式生态上主要面向llama.cpp部署。这个路线的优势是量化版本丰富Q4_K_M / Q5_K_M / Q6_K / Q8_0单卡即可运行。但我手头是4 张 Ascend 910B4各 64GB HBMllama.cpp 目前对昇腾的支持还不够成熟。另一边昇腾上最成熟的推理框架是 vLLM-Ascend它对 Hugging Face 原生的 safetensors 格式即 BF16 权重支持最好。Qwopus3.6-27B-Coder 在 Hugging Face 上同时发布了 BF16 版本因此最终的选择是使用 BF16 版 Qwopus3.6-27B-Coder通过 vLLM-Ascend 部署在 4×910B4 上这个选择的一个额外好处是Qwen 本身就是 vLLM 社区支持最完善的架构之一各种高级特性prefix caching、async scheduling、tool call 等都能直接使用。二、vLLM-Ascend 部署部署本身并没有花太多时间。vLLM-Ascend 官方提供了 openEuler 基础镜像quay.io/ascend/vllm-ascend:v0.20.2rc1-openeulerQwen3.6 的架构在其中已经得到了原生支持直接拉起容器即可。关键启动参数sudodockerrun-d--namevllm-qwopus-coder\--networkhost\--device/dev/davinci0...全部8个 NPU 设备\-v/data/models:/data/models\-eASCEND_RT_VISIBLE_DEVICES0,1,2,3\quay.io/ascend/vllm-ascend:v0.20.2rc1-openeuler\vllm serve /data/models/Qwopus3.6-27B-Coder\--port8001\--tensor-parallel-size4\--gpu-memory-utilization0.9\--max-num-seqs8\--trust-remote-code首次启动后需要等待 3-5 分钟CANN 会对 27B 模型进行 torch.compile 编译预热之后请求就正常了。三、接入 Claude Code协议层的坑这才是最花时间的部分。整个链路走通涉及三个协议层问题逐一拆解。链路全貌先看一下最终跑通的架构┌────────────────────────────┐ │ Claude Code CLI │ │ ANTHROPIC_BASE_URL │ │ http://localhost:18002 │ └──────────┬─────────────────┘ │ POST /v1/messages │ (Anthropic Messages API) ▼ ┌─────────────────────────────────────┐ │ anthropic-system-promote.py :18002 │ ← 自定义代理 │ │ │ 功能: │ │ 1. system 字段上提 │ │ 2. max_tokens 强制 ≤ 4096 │ │ 3. 禁用 thinking 模式 │ │ 4. greedy 解码 │ └──────────────┬──────────────────────┘ │ 透传修改后的请求 ▼ ┌─────────────────────────────────────┐ │ vLLM-Ascend 容器 :8001 │ │ OpenAI API /v1/chat/completions │ │ /v1/messages (兼容) │ └─────────────────────────────────────┘坑 1Claude Code 的 system 消息在 vLLM 上会 400Claude Code SDK 按 Anthropic API 标准发送消息其中角色为system的内容有时放在messages[]数组里有时放在顶层system字段。而 vLLM-Ascend v0.20.2 虽然新增了/v1/messages端点对标 Anthropic Messages API 的名字但底层校验仍然沿用了 OpenAI Chat Completions 的 schema ——messages[].role只接受user和assistant收到system就直接返回 400API Error: 400 Input should be user or assistant坑 2vLLM 默认关闭 tool callClaude Code 为了支持 MCP 工具调用每次请求都会发tools: [...]和tool_choice: {type: auto}。vLLM 默认不开启 tool call parser收到工具参数就会报 400。坑 3Proxy 不是真正的流式转发导致超时最初写的anthropic-system-promote.py用的是 Python 标准库的http.client.HTTPConnection其resp.read()会缓冲整个 chunked 响应后才返回。vLLM 以 ~8 tokens/s 的速度生成 token一个 519 tokens 的 thinking 响应需要 ~65 秒才能生成完。期间 proxy 不向 Claude Code 发任何数据——因为resp.read()还在等 vLLM 发完。Claude Code 的客户端超时约 60 秒就会触发。坑 4Thinking 模式输出过长放大延迟Qwopus3.6-27B-Coder 默认会输出冗长的thinking.../thinking链。实测一个简单的 “你好” 问候thinking 模式下输出了519 tokens而非 thinking 模式只有18 tokens——缩短 96%。坑 5input output 超出上下文限制vLLM 报 500vLLM 有一个硬约束input_tokens output_tokens ≤ max-model-len。在编程使用场景上下文会积累多轮对话后输入会不断增长上下文就会超过 max-model-len 上限vLLM 直接返回 500API Error: 500 ... 300004096 32768 max-model-len解决方案写一个 30 行的代理做协议适配与其在 litellm 这种重量级代理上修 bug不如自己写一个轻量级的代理做协议适配放在 Claude Code 和 vLLM 之间。最终写了一个 Python 脚本anthropic-system-promote.py监听 18002 端口做了五件事来修上面五个坑坑解决方案坑 1system 字段 400把messages[]中的 system role 内容提取出来合并到顶层system字段消息体中的 role 只保留 user/assistant坑 2tool call 报 400vLLM 启动时加--enable-auto-tool-choice --tool-call-parser qwen3_coder必须是qwen3_coder因为 Qwopus 使用 Qwen3-Coder 风格的 XML tool call 格式坑 3proxy 不流式导致超时重写 proxy 用socket 直连 vLLM手动解码 chunked 编码收到一个 chunk 就立刻转发给客户端坑 4thinking 输出过长注入chat_template_kwargs {enable_thinking: false}回复从 519 tokens 压缩到 18 tokens缩短 96%坑 5inputoutput 超出上下文增大 vLLM 的--max-model-len32K → 64K → 256K需要 4 张 910B4消息流变成Claude Code ──POST /v1/messages──→ system-promote:18002 ──→ vLLM:8001 ↑ │ └──────────────────── chunked stream ────────────────────┘四、配置 Claude CodeClaude Code 本身配置很简单。环境变量设置如下exportANTHROPIC_BASE_URLhttp://localhost:18002# 指向代理注意不要带 /v1exportANTHROPIC_AUTH_TOKENdummyexportANTHROPIC_MODELQwopus3.6-27B-Coder需要注意一个坑~/.claude/settings.json的env段优先级高于 shell 环境变量。如果用cc-switch切换过 provider它会把配置写进 settings.jsonshell export 就不再生效。解决方式是用switch_provider.sh脚本直接 patch settings.json或者手动编辑.claude/settings.local.json{env:{ANTHROPIC_BASE_URL:http://localhost:18002,ANTHROPIC_AUTH_TOKEN:dummy,ANTHROPIC_MODEL:Qwopus3.6-27B-Coder,CLAUDE_CODE_MAX_CONTEXT_TOKENS:65536,CLAUDE_CODE_AUTO_COMPACT_WINDOW:40000,API_TIMEOUT_MS:600000}}五、上下文大小问题64K 不够用日常编程任务中我们几乎习惯了主流模型通常在200K tokens 左右甚至到1M tokens——代码库摘要、多轮对话历史、MCP 工具调用结果等。实测 64K 上下文的配置下大约4-5 轮 tool call 交互后上下文就消耗得差不多了Claude Code 开始频繁触发 compact 压缩历史影响对话连贯性。256K 配置与权衡Qwopus3.6-27B-Coder 的原生max_position_embeddings是 262144256K因此在 vLLM 中可以直接配置--max-model-len262144但 256K 配置有代价。KV cache 的大小与序列长度线性相关。27B 模型 256K 上下文意味着每张卡需要约 50GB 显存来存放 KV cacheQwen3.6 的 head_dim256、num_kv_heads4、64 层。虽然 4 张 910B4 总共 256GB但模型权重本身也占 ~54GBBF16留给 KV cache 的空间并没有想象中充裕。实际测试下来256K 配置的权衡如下上下文优点缺点64K延迟低首次 prefill 快4-5 轮交互后开始 compact128K可支持 8-10 轮交互prefill 慢内存压力大256K接近原生上限长对话无压力prefill 极慢数分钟跑满 4 卡也只能支持 4 个并发六、性能问题与优化基线速度初始部署TP22 卡的生成速度场景速度非流式请求~8 tokens/s流式请求1.6-7.6 tokens/s单次 4096 tokens 回复~8.5 分钟最慢情况这个速度对于交互式编程来说显然太慢了。一个claude --print请求动辄 30-60 秒才能拿到完整回复。做了哪些优化Step 1Prefix Caching✅ 已启用有效Claude Code 每轮对话都会重发约 2K tokens 的 system prompt tool definitions。开启--enable-prefix-caching后这部分 KV cache 得以复用每轮对话的 prefill 开销只计算一次。Qwen3.6 架构的 prefix-caching align 阈值是 528 block而 Claude Code 的 system prompt 远超这个阈值确认受益。Step 2Speculative Decoding❌ 尝试后放弃Qwopus3.6-27B-Coder 原生支持MTPMulti-Token Prediction头。理论上 MTP 可以在不降低质量的前提下实现约 2 倍的加速llama.cpp 上实测确实如此。但 vLLM-Ascend 上的情况不同MTPvLLM 能识别到 Qwen3_5MTP 架构并启动成功但输出始终是response而非真实内容。推测是 Unsloth 微调版的 MTP 头权重与上游不一致。N-gram启动后 vLLM 日志显示 “Async scheduling not supported with ngram, will be disabled”关闭 async scheduling 后速度反而下降到 3.5 t/s。结论投机解码暂时关闭待后续优化改进。Step 3Greedy 解码✅ 已启用有效在代理中注入temperature0, top_p1, top_k-1。跳过采样运算decode 阶段加速 10-30%。代价是输出失去多样性同输入永远同输出。Step 4禁用 Thinking 模式✅ 效果显著Qwopus3.6-27B-Coder 默认会输出冗长的thinking.../thinking链。注入chat_template_kwargs {enable_thinking: false}后测试结果519 tokens → 18 tokens缩短 96%回答质量无可见下降优化前后对比指标优化前优化后提升单次回复时间4096 tokens8 分钟~3 分钟~2.6×stream first token15-30s5-10s~3×上下文利用率thinking 占 500 tokens几乎为零tokens 利用效率提升还有哪些优化空间当前最大瓶颈仍然是生成速度。8 tokens/s 在交互式场景中意味着每次回复都要等 1-3 分钟。后续优化方向MTP 修复——vllm-ascend 对 Qwen3.6 MTP 架构的支持完善后理论上能实现 2× 加速量化——BF16 权重是最大的性能开销。如果 vllm-ascend 支持 FP8 或 INT4 量化显存带宽利用率可以大幅提升更小的模型——Qwopus3.6-35B-A3BMoE3B active如果接入推理速度会是 27B 的数倍七、实际效果与感受说实话以目前的速度1~3 分钟一次回复还不能用在大规模编程任务上。做一次代码审查、跑一遍完整测试再修 bug可能需要等十几分钟甚至半小时。更深层次的评测需要等效率问题解决后才能进一步展开。但日常跑下来我自己感觉是有戏的。简单总结代码库理解给一个中小项目做文档总结能准确提取关键模块的职责和调用关系BUG 修复定位和修复一些中等难度的 bug单个函数级别的逻辑错误基本没问题工具调用走通了 MCP 工具链路包括检索知识库、执行 Shell 命令、读写文件等直觉上比之前用过的 Kimi-K2.5 要好——尤其是在代码生成质量和对复杂指令的理解上明显更接近云端模型的水准如果不考虑效率实测过claude code接入模型后能自主运行 5 小时直至任务完成不过实际工作量可能只有云端模型1.5小时的工作量。更重要的是这条路如果走通意味着充分释放本地算力完全替代云端 API 调用。毕竟本地闲置的算力也是闲置可以节省下云端 API 的订阅费用对于需要大量迭代的编程任务来说边际成本几乎为零。