← 返回
AI技术

Qwen 3.8 在笔记本上能否真正取代 Claude Opus 进行 Agentic 编码?

✍️ zhirenhun 📅 2026/9/11 👁 7 阅读 ⏱ 66 分钟
Qwen 3.8 在笔记本上能否真正取代 Claude Opus 进行 Agentic 编码?

原文发布于 deepu.tech

AI 编程热潮刚兴起时,我仍持怀疑态度。和大多数技术爱好者一样,我尝试过,但当时对模型的编码能力并不印象深刻。我仍然在使用它们,但主要只是 VS Code 的自动补全工具。一切在我使用 Claude Code 的 Opus 4.6 时改变了。那是我第一次感觉到模型在大多数时候的编码效率和智慧实际上已经超过了我。当然它仍然需要一些引导,偶尔会犯低级错误,但总体来看,我在实现功能和修复 bug 的速度比独自工作快很多。我被吸引了。我开始把它用于所有编码任务,甚至用于一些个人项目。我惊讶于在模型的帮助下,我能够完成任务的速度提升了这么多。

大约在 2026 年 2 月或 3 月左右。自那时起已经过去了大约六个月,而现在我在写这篇博客时,笔记本电脑上正运行着一个本地模型,正在为 LlamaStash(一个复杂且庞大的 Rust 项目)实现一个巨大的功能。如今,我在进行的大多数编码工作中都专门使用本地模型。想到能够在消费级 GPU 上运行的来自中国实验室的开源 LLMs 已经赶上了需要巨型数据中心才能运行的美国公司前沿模型,这真是令人惊讶 😉。更令人印象深刻的是,我可以在笔记本电脑上运行这些强大的模型,完全不依赖云端,这不仅更环保,还能大幅降低能源消耗。特别感谢中国实验室使这一切成为可能,并将这些模型开源。

在这篇文章中,我将展示我在笔记本电脑上如何运行 Qwen 3.8,以及它与像 Claude Opus 这样的前沿模型在代理编码方面的对比。

Qwen 3.8 27b

Qwen 3.6 27b 发布时,我感到兴奋并被其能力所打动。我用它尝试了一些轻量级的编码。虽然它表现不错,但始终感觉不到它能取代像 Claude Opus 这样的前沿模型,因为它在质量上有所欠缺,而且速度较慢。我仍然在大多数编码任务中使用 Claude/Kimi/GLM 等模型,而将 Qwen 3.6 用于小型离线任务、日常维护等。

但当 Qwen 3.8 27b 发布时,我被它的质量震撼到了。它能够理解复杂的编程任务并给出准确的解决方案,也能根据代码上下文提供相应的建议。我开始把它用在一些主要的编码任务上,效果惊人。当然,它在长前填充时间和平均 10‑15 token/秒的解码速度上仍然很慢,但对我个人来说这不是问题,因为我可以把任务交给它,让它运行几个小时甚至过夜,它完成的任务质量能够媲美 Opus 4.6。社区也得出了类似结论:在下面的人工分析指数图表中,27b 在 xhigh 下的得分为 34,而 Opus 4.6 得分为 32。

我做的大部分编码都是开源的,所以模型比前沿云模型耗时更长对我来说不是问题。它确实需要一些调校和设置(下面会详细说明),并且会偶尔陷入循环、几次在会话中途崩溃(可能是电源供应的问题),恢复时需要一些人工干预,但总体来说,它在最少干预的情况下就能完成大部分任务。我对它的能力印象深刻,于是开始用它处理更复杂的任务,并让类似 Opus 5 的前沿模型来审查它的输出。

这里 是我交给它的第一个严肃任务以及我得到的结果。它制定了计划并一次性完成了实现。查看 Opus 5 的审查意见,它们主要是小问题,而 Qwen 3.8 27b 在后续提交中修复了这些问题。我对它的能力印象深刻,因为项目 LlamaStash 非常复杂,且拥有庞大的 Rust 代码库,但 Qwen 3.8 27b 能够理解代码库并在最少干预的情况下实现该功能。我开始把它用于 更多工作,它一直在交付成果,我终于觉得不再需要订阅云端 AI 服务的时刻到了。

Qwen 3.8 Flash Next

然后出现了 Qwen 3.8 Flash Next,哇,我的思维再次被震撼。它在质量上略微优于 27b,但最大的改进在于整体速度。它在 prefill 阶段仍然较慢,且 decode 的 tok/s 大致相似,但由于它没有像 27b 那样花费太多时间思考,整体完成任务所需的时间更少。这里有一个 真实世界的例子

数据说明比直观感受更有说服力。Flash Next 并不是解码更快,而是它不像 27b 那样过度思考。表格的前两行是一个简短的贪婪提示,其余是五个编码任务,生成的代码会在隐藏测试上运行。

Flash Next 27b ROCmFP4
解码 23.7 token/秒 24.5 token/秒
预填充 96 token/秒 150 token/秒
正确率,5 项任务 5/5 5/5
消耗的 token 2,320 4,223
墙钟时间 76.5 秒 289.8 秒

答案相同,但 token 消耗减少了 45%,完成速度提高了 3.8 倍,然而在原始速度指标上,27b 仍然领先。

我认为 Flash Next 在质量上与 Opus 4.8 不相上下,就目前的使用体验而言(它们的 AA 分数分别为 40 和 42)。再次感谢阿里巴巴和 Qwen 团队。它在我的 128GB Strix Halo 上运行需要更多内存,大约占用 86 GiB,而 27b 仅占用 31 GiB,因此它目前还不是唯一的选择。我将其用于更复杂的任务以及需要更快完成的任务。对于其他情况,27b 仍然是我的首选,因为在 31 GiB 内存下我可以同时加载两个实例,并在不重启的情况下切换思考模式,而且正如图表所示,它们在质量上相差不大。

我的当前设置

硬件:Strix Halo

我写过一篇文章,详细介绍了我的全离线 AI 辅助 Linux 开发机。先说结论:这是一台华硕 ROG Flow Z13,搭载 Ryzen AI Max+ 395 处理器(16 核 32 线程)、AMD Radeon 8060S 集成显卡(40 个计算单元)和 128GB 统一内存。我在上面运行 Arch Linux,桌面用的是 Niri + DMS。

编排工具:LlamaStash

我使用自己开发的工具 LlamaStash 来编排模型、管理会话。它是一个快速的 TUI、CLI、守护进程兼 OpenAI 兼容代理,可通过 llama.cppvLLM 等后端运行本地 LLM。它提供了许多实用功能,让本地模型的运行和管理变得轻松省心,比如多后端支持、预设文件、命名启动、自动启动等。

我的后端主要跑 llama.cpp,针对不同模型使用不同的编译版本。以下是我对应的 LlamaStash 配置。

backend:
  llamacpp:
    # llama-server build variants; first entry is the default binary.
    servers:
      - binary: /mnt/work/Workspace/llms/llama.cpp/build-hip/bin/llama-server # ROCm0
      - binary: /mnt/work/Workspace/llms/llama.cpp/build-vulkan/bin/llama-server # Vulkan0
      # Shim, not raw binary: sources q38rocm's setup_env.sh (RADV_PERFTEST,
      # unified memory, ICD pin) that llamastash has no env hook for.
      - binary: /home/deepu/.local/bin/q38rocm-llama-server
        name: ROCmFP4 # ROCm0 + Vulkan0
      # unslothai fork: only needed to load qwen4exp MTP draft heads, which stock
      # rejects (~1.3x speedup). Drop when MTP support lands upstream.
      - binary: /mnt/work/Workspace/llms/llamacpp-unsloth/llama-server
        name: UnslothMTP # ROCm0
      # Fork build for the DFlash2 sidecar drafter; --spec-draft-adaptive was
      # never upstreamed.
      - binary: /home/deepu/.local/bin/dflash-llama-server
        name: DFlash2 # Vulkan0
  ds4:
    enabled: true
    servers:
      - binary: /mnt/work/Workspace/llms/ds4/ds4-server
  vllm:
    enabled: true
    servers:
      - binary: /home/deepu/.venvs/vllm/bin/vllm
  lemonade:
    enabled: true

一台机器上装四个 llama.cpp 构建,乍看有点傻,但真到用的时候就值了。原版 ROCm 是默认选项,在 ROCmFP4 分支上 Vulkan 的解码速度更胜一筹,而另外两个被点名的分支之所以单独存在,只是因为它们的投机解码实现一直没被合并进上游(截至撰写本文时)。LlamaStash 预设可以固定指定用哪个构建,我完全不必费心去记哪个是哪个。

Agent 框架:Pi

写代码这件事,我如今大多用 Pi 来充当 Agent 框架。它与 Qwen 系列模型配合得很顺畅,我还给它配置了与我那套 Claude Code 相同的规则和记忆——后者但愿能早日光荣退休。下面就是 ~/.pi/agent/models.json 中的 LlamaStash provider 配置块,由 llamastash integrations 命令替你自动写入。

{
  "providers": {
    "llamastash": {
      "api": "openai-completions",
      "apiKey": "!llamastash api-key",
      "baseUrl": "http://127.0.0.1:11435/v1",
      "name": "LlamaStash",
      "models": [
        {
          "id": "Qwen3.8-Flash-Next-UD-Q4_K_XL",
          "name": "Qwen3.8-Flash-Next",
          "contextWindow": 131072,
          "maxTokens": 8192
        },
        {
          "id": "Qwen3.8-27B-Q8_0",
          "name": "Qwen3.8-27B-Q8_0",
          "contextWindow": 131072,
          "maxTokens": 8192
        },
        {
          "id": "Qwen3.8-27B-ROCmFP4-FAST",
          "name": "Qwen3.8-27B-ROCmFP4-FAST",
          "contextWindow": 131072,
          "maxTokens": 8192
        },
        {
          "id": "Qwen3.8-27B-UD-Q6_K@xhigh",
          "name": "Qwen3.8-27B (xhigh)",
          "contextWindow": 131072,
          "maxTokens": 8192
        },
        {
          "id": "Qwen3.8-27B-UD-Q6_K@medium",
          "name": "Qwen3.8-27B (medium)",
          "contextWindow": 131072,
          "maxTokens": 8192
        }
      ]
    }
  }
}

最后两项才是有意思的地方。一个 <model-id>@<name> 形式的 id 会把请求固定到某个正在运行的 launch 上,而不是让代理自行挑选——正因为如此,模型选择器里才能同时出现两种思考模式。Pi 会把自定义的 provider id 原样传给 API,所以 @name 会被一字不差地送到 LlamaStash。

这两项是我手动添加的。llamastash integrations 只会在磁盘上为每个模型写入一行记录,它并不清楚你会给 launch 起什么名字。目前有一个尚未关闭的 issue,准备让补丁工具支持具名 launch。

模型量化版本

我做了一些调研和基准测试,为 Qwen 3.8 27b 和 Flash Next 选定了下面这些量化版本。就我的使用场景而言,这些量化版本在速度和质量之间取得了最佳平衡。

  • Qwen3.8-Flash-Next-UD-Q4_K_XL(104 GB):质量最好、执行更快,但只能跑单 agent。需要 unslothai/llama.cpp 这个 fork 才能加载它的 MTP draft heads,官方原版 llama.cpp 会拒绝它们(截至撰写本文时)。
  • Qwen3.8-27B-UD-Q6_K(20 GB):多 agent 工作的默认模型
  • Qwen3.8-27B-Q8_0(27 GB):适合对质量要求更高、不介意多花些时间完成的任务
  • Qwen3.8-27B-ROCmFP4-FAST(14 GB):适合需要尽快完成、可以在质量上稍作妥协的一次性任务。这个版本需要 julianmb/q38rocm 这个 fork,官方原版 llama.cpp 无法加载。

在这套硬件上,解码的瓶颈是内存带宽而非算力。27.1 GiB 的文件跑到 7.27 tok/s 时,GPU 实际拉取的带宽约为 212 GB/s,对比 LPDDR5X 约 256 GB/s 的峰值上限,相当于跑在了理论峰值的 83%。这也解释了为什么上面各版本的大小几乎精确对应着速度排序:文件越小,每个 token 的字节数越少,解码就越快。

优化 Qwen 3.8 的速度与效率

用预设调优配置

所有模型我都使用 128k 上下文,而不是完整的 256k,为的是避免过长的 prefill 以及长上下文带来的性能下降。同时,我为所有模型都采用下面这组设置,以获得最佳的性能和质量。这些设置通过 LlamaStash 预设来应用,这样我就能通过 TUI 或 CLI 在不同模型和设置之间轻松切换,也能方便地复现这些配置。

presets:
  # qwen35 arch: hybrid SSM, full attention every 4th layer, one embedded MTP
  # layer at blk.64, native ctx 262144. Draft n=5 measured best, see below.
  Qwen3.8-27B-*:
    default: coding-xhigh
    entries:
      coding-xhigh:
        knobs:
          mtp: true
          mtp-draft-n: 5
          ctx-size: 131072
          n-gpu-layers: 99
          flash-attn: true
          no-mmap: true
          parallel: 1
        extras:
          - --reasoning-format
          - deepseek
          - --reasoning-preserve
          - --reasoning-effort
          - xhigh
          - --cont-batching
          - --spec-draft-p-min
          - "0.0"
          - --temperature
          - "0.0"
          - --presence-penalty
          - "0.0"
          - --repeat-penalty
          - "1.0"

Qwen3.8-27B-* 这样的通配键可以覆盖该模型的所有量化版本,因此 Q6_K、Q8_0 等全部继承同一份配置。coding-medium 则是同一个配置块加上 --reasoning-effort medium,下文还会再提到它。

这些配置中有两项尤为关键。

mtp: true 开启的是 Multi Token Prediction(多令牌预测),一个直接内置在 GGUF 文件里的投机解码头。它能让解码提速 2.3 到 3.1 倍,具体取决于构建版本,整份配置里没有哪一项能与之相比。模型会逐一验证每个草稿 token,所以在原版 llama.cpp 上输出结果完全不变,变的只是速度。

--temperature 0.0 是有意为之,尽管它与 Qwen 官方建议相悖——后者要求思考模式下使用 temp 1.0 / top-p 0.95 / top-k 20。我实测过官方采样参数,同样的两个问题耗时达到了 2.8 倍的墙钟时间:772 秒对 273 秒。原因在于,一旦采样器与草稿头不再"步调一致",MTP 的草稿接受率就会从 59.6% 骤降到 45.7%。厂商的推荐参数默认你并没有在跑投机解码。此外,贪心解码还能让生成结果逐字节可复现,正是这一点让我得以分清两个配置之间真实的差异,而不是碰巧掷出来的运气。

Flash Next 拥有独立预设,主要是因为它必须锁定在能加载其草稿头的分支构建上。

Qwen3.8-Flash-Next-*:
  default: coding-xhigh
  entries:
    coding-xhigh:
      server: llamacpp-UnslothMTP
      knobs:
        ctx-size: 131072
        flash-attn: true
        mode: chat
        mtp: true
        mtp-draft-n: 4
        n-gpu-layers: 99
        parallel: 1
      extras:
        - --reasoning-format
        - deepseek
        - --reasoning-preserve
        - --reasoning-effort
        - xhigh
        - --cont-batching
        - --spec-draft-p-min
        - "0.0"
        - --temperature
        - "0.0"
        - --presence-penalty
        - "0.0"
        - --repeat-penalty
        - "1.0"

⚠️ 切勿在 Flash Next 上设置 no-mmap该模型的逐层 token 嵌入表足有 26.8 GiB,llama.cpp 会通过文件映射懒加载式地流式读取它,而且每生成一个 token 都要读一遍。一旦关闭 mmap,加载器就会把整张表拉进匿名内存——在一台只有约 20 GiB 余量的机器上,这完全是背道而驰。至于没有懒加载张量的 27b,开 no-mmap 则无伤大雅。

命名启动

LlamaStash 提供了一个 --name 选项,让你可以同时运行同一模型的多个实例。每个 --name 都是一个独立进程,拥有各自的 KV cache 和预设。这在并行运行多个 agent 时很有用,比如让每个 agent 各自持有独立的上下文和推理模式。在 TUI 里,按 Alt+Enter 则会改为提示输入名称。

💡 命名启动是在 LlamaStash 0.3.0 中落地的。在此之前,同一模型的第二个实例可以照常启动,却怎么也访问不到,因为代理会把每个请求都交给它遍历途中遇到的第一个 Ready 状态实例。

用预设切换推理力度

我把预设各复制了一份,分别配上 xhighmedium 两档推理力度,这样就能借助 LlamaStash 的命名启动,在 Pi 的模型选择器里来回切换。推理力度这一设置是在聊天模板层面引导模型的:medium 不做任何引导;xhigh 会注入一条“认真思考”的指令;low 则注入“思考保持简短”的指令。

  • xhigh(模板默认值):“推理力度已设为 xhigh。请仔细思考任务,验证关键假设,考虑其他合理的方案,并在最终答案中优先保证正确性、一致性和清晰度。”
  • low:“推理力度已设为 low。请让思考保持简短聚焦,直奔结论,不要做多余铺陈。”
  • medium:什么都没有。模板里根本没有对应的分支,因此指令字符串始终为空。

模型确实会老老实实照办这些简短指令,输出上的差别一目了然。

推理力度是服务端标志,而不是按请求设置的参数。一个 llama-server 进程只能跑一种模式,过去想在 xhighmedium 之间切换,就意味着重启模型、苦等一次冷加载。命名启动解决了这个问题:把同一个模型用不同预设跑两份,然后在 Pi 的 /model 选择器里挑选模式即可。

llamastash run Qwen3.8-27B-UD-Q6_K --preset coding-xhigh --name xhigh
llamastash run Qwen3.8-27B-UD-Q6_K --preset coding-medium --name medium

现在 Qwen3.8-27B-UD-Q6_K@xhigh@medium 都出现在了 Pi 中。平时的大部分工作交给 @medium,遇到需要模型真正停下来思考的任务再切换到 @xhigh——会话中途即可切换,无需重启。

并行编码智能体

我还可以用一个规划智能体派生出多个编码智能体,让它们分别使用不同的推理强度和上下文,并以 Qwen3.8-27B-UD-Q6_K@planner@coder-one@coder-two 来称呼。处理复杂任务时,若想并行运行多个智能体,这种做法非常实用。

llamastash run Qwen3.8-27B-UD-Q6_K --preset coding-xhigh --name planner
llamastash run Qwen3.8-27B-UD-Q6_K --preset coding-medium --name coder-one
llamastash run Qwen3.8-27B-UD-Q6_K --preset coding-low --name coder-two

三个 Q6_K 实例各开 128k 上下文,大约要占掉 125.5 GiB 可用内存中的 93 GiB,所以三开就是这台机器比较从容的上限。

那改用 --parallel 呢?

单个服务器配上 --parallel N,同样只需一份权重就能同时服务 N 个会话,看起来是更省的方案。确实更省,而且在当前版本的 llama.cpp 上它还更快。如果多个会话要用同一套模型预设,这是个不错的选择。不过它依然替代不了上面的方案,只是原因比我最初想的要窄。

三个会话,每个 30k 上下文,各输出 1024 个 token,Q6_K 开启 MTP,两种方案里每个会话的窗口都固定在 40960。实际耗时统计的是冷启动那一轮,也就是开启会话的那一轮:

三个会话,各 30k 上下文 --parallel 3 3 个单独启动的实例
预填充,合计 453 tok/s 146 tok/s
解码,单会话平均 5.7 tok/s 5.3 tok/s
有效解码速度 4.95 tok/s 3.24 tok/s
冷启动轮,实际耗时 557 s 815 s
生成的 token 数 2,755 2,640
草稿接受率 0.59 / 0.62 / 0.59 0.55 / 0.53 / 0.59
内存占用 30.8 GiB 70.6 GiB
每个会话的上下文长度(-c 131072 43.8k 128k
可用的思考模式 一种,全服务器统一 每个实例各一种

差距在预填充,不在解码。连续批处理让三个提示词在同一台服务器上交错执行,聚合速度达到 453 tok/s;而拆成三个独立进程只会互相挤兑,每个被压到只剩 46-53 tok/s,于是同样 30k 的窗口,批处理要 164-326 秒,分拆运行则要 569-645 秒。解码本身几乎打平,每会话 5.7 对 5.3 tok/s。真正让 --parallel 3 用不到一半的内存、三分之二的墙钟时间,还多生成 4% token 的,正是预填充。表中的有效解码速度是生成 token 数除以墙钟时间,那才是你实际要熬过去的时间。后续轮次同样偏向它,优势约 1.7 倍,不过那组数据是在上一个 llama.cpp 版本上测的。

所以反对它的理由只剩最后两行。上下文是切分,不是共享:在关闭统一 KV 的情况下,n_ctx_seq = n_ctx / n_parallel,也就是说 -c 131072 --parallel 3 只给每个会话留下 43,776 个 token,而不是 128k。打开 --kv-unified 能在不额外占用内存的前提下把完整窗口还给每个会话,但我实测时三槽位的冷启动轮次耗时多了 66%,所以我还是保持关闭。另外,推理力度是服务器级标志,一次 --parallel 3 启动会让每个会话都用同一种思考模式——这正是上文那套配置的核心意义。命名启动是我用来让 xhighmedium 两档都能随时调用的做法,而想在同一预设下跑多个会话时,我就会选 --parallel

还有一点值得知道:槽位亲和只是一种启发式策略,并非硬性绑定,所以请求到达时如果自己的槽位正被占用,就会落到另一个会话的槽位上,并清掉对方的缓存。

⚠️ 在采信这些结论之前,先升级你的 llama.cpp。在 b10803 上,--parallel 那几组不只是慢,而是彻底坏了:三个会话同时冷预填充 30k,分别只生成 2、586 和 36 个 token 就返回了,草稿接受率为 0.000;而独立启动时每个都能干净利落地跑满 1024 个。这是输出错误,不是单纯变慢。到了 b10888,同样的测试在每条流上都给出健康的接受率,也就是上面那张表的数据。独立启动那几组在两个版本之间几乎没有变化(815 秒对 797 秒)。

注意事项:表中每个单元格只跑了一次,一台机器、一个模型、llama.cpp b10888。上游正在积极改动这一块,所以版本更新后请重新测量,别直接照搬这张表。

几组基准测试

看表之前先提醒一句。这些数据来自大约三周内、不同版本上的三次独立测量,所以请把每张表当作独立结果来读,不要跨表比较单元格。所有测试都在同一台 Strix Halo 笔记本上完成,接交流电运行,电源模式锁定为 performance,采用贪心采样,解码与预填充耗时取自 llama.cpp 自带的 timings 块,而非墙钟时间。

先看 27b 在短提示词、空窗口下的表现。这是最优情况的数据,MTP 的效果简直像变魔法。

构建与量化 解码(MTP 关) 解码(MTP 开) 预填充(4k 提示词) 草稿接受率
原生 ROCm,Q8_0(27 GB) 7.3 t/s 22.4 t/s(n=5) 270 t/s 73%
原生 Vulkan,Q8_0(27 GB) 7.4 t/s 22.6 t/s(n=5) 201 t/s 73%
ROCmFP4 分支,FAST(14 GB) 13.0 t/s 29.9 t/s(n=6) 259 t/s 84%

在 Q8_0 上,MTP 带来了 3.1 倍的提速;ROCmFP4 构建上也有 2.3 倍。在我测试的每个上下文长度下,草稿长度设为 5 都胜过后端默认值 3,全程没有出现反转。

接下来是窗口真正填满时的同样测试——对智能体编程来说,这个数字才真正重要。下表每一行都开启了 MTP。

上下文 Q8_0 预填充 Q8_0 解码 ROCmFP4 预填充 ROCmFP4 解码
270 t/s 22.4 t/s 259 t/s 29.9 t/s
32k 210 t/s 15.6 t/s 193 t/s 19.6 t/s
64k 164 t/s 14.2 t/s 124 t/s 16.6 t/s
128k 115 t/s 11.3 t/s 66 t/s 13.2 t/s
256k 71 t/s 5.4 t/s 失败 失败

MTP 的收益会随着窗口填满而缩水:空窗口时是 3.1 倍,到 256k 装满时只剩 1.15 倍——因为 KV 缓存越大,验证一遍的成本就越高,尽管接受率本身一直稳得住。而 ROCmFP4 分支的优势在解码,不在预填充:到了 128k,它在提示词处理上已经落后于原版 Q8_0。这一点,再加上预填充的耗时,才是我最终把窗口上限卡在 128k、而不跑原生 256k 的真正原因。

下面是我日常使用的 Q6_K 跑一轮真实 Pi 对话时的样子,直接从服务器日志里截出来的。

prompt eval: 181633 ms / 31410 tokens  (172.9 t/s)
eval:          6231 ms /    89 tokens  ( 14.1 t/s)
draft acceptance = 0.835 (71 accepted / 85 generated), mean len = 5.18

对一份 31k token 的对话记录,预填充花了三分钟,随后解码速度为 14 tok/s。到了下一轮,只需预填充新增的 4,770 个 token,45 秒内就返回了结果。冷会话与热会话之间的这种差距,是决定这些模型用起来体验如何的最关键因素。

接下来是 27b 与 Flash Next 在五个真实编码任务上的对决,生成的代码会在隐藏测试上运行验证。

模型 正确性 Token 数 耗时
Qwen3.8-Flash-Next 5/5 2,320 76.5 秒
Qwen3.8-27B ROCmFP4 FAST 5/5 4,223 289.8 秒

两个模型全部答对。区别只在于 Flash Next 用少 45% 的 token 说完了同样的话。其中一个任务,27b 花了 1,784 个 token,Flash Next 只花了 424 个。不过五个任务谈不上正确性上限,它衡量的其实是啰嗦程度;想在能力上一较高下,还得靠更难的测试集。

无济于事的尝试

这些反面发现和前面的收获一样有价值——它们让我免得把其中几项写进配置:

  • Qwen 官方采样设置。慢了 2.8 倍,前面已经提到。
  • 在 ROCmFP4 上对 V 缓存启用 turbo410k 上下文下慢了 49%,还改变了模型的生成结果:思考变多,回答变短。
  • --reasoning-budget完全不起作用。把它从 8192 降到 2000,输出逐字节完全一致——反正模型停下来时远远用不满这个预算。真正起约束作用的是客户端的 maxTokens
  • repeat-penalty 1.05唯一一个在回答中出现事实错误的配置项。贪心解码的输出是确定性的,所以这是该设置可复现的固有缺陷,不是偶然失误。上游警告惩罚项"可能在长文本生成时催生生僻 token 造成的胡言乱语",于是我保持 1.0 不变。
  • 锁定 GPU 时钟。power_dpm_force_performance_level 写入 high,大约 25 秒后机器就悄无声息地彻底死机,只能断电重启。Strix Halo 上千万别试。反正自动模式下有负载时本来就能提速到 1900-2500 MHz。

真正物有所值的只有两个配置:--ubatch-size 512(而非 1024),冷预填充提速约 4%,且多轮测试均能复现;以及在 Vulkan0 而非 ROCm0 上运行 ROCmFP4 分支,解码提速 24%。

注意事项

以下是目前使用这些模型过程中遇到的问题和一些心得体会。

免责声明:我的很多编码测试并不是在理想条件下进行的。我现在正在休假,没带上能为笔记本提供 180W 峰值功率的原装电源适配器,手头只有一个 100W PD 氮化镓充电器,撑不住 GPU 满载,因此出现了 GPU 重置和电池耗尽关机的情况,进而导致模型重启。我相信整体体验会比我的情况好得多。等我回去后,会用正规电源适配器重新测试这套方案,并把测试结果更新到本文中。

  • 在我看来,最烦人的问题是预填充耗时。冷启动后(会话开始、模型重启、上下文压缩之后等)的第一个提示词需要很长时间处理。在我的配置下,一份 31k token 的对话记录大约要 3 分钟;如果真正填满 128k 窗口,按上表所示的 115 tok/s 计算,耗时接近 18 分钟。得益于缓存,后续提示词几乎立刻就能处理,解码速度为 10 到 15 tok/s,这已经完全不算差了——能看到内容持续生成,感觉并不会太慢。
  • 在 Pi 的模型定义里,把上下文长度设置为与启动时相同,避免突然触发压缩。上下文长度设置得当,Pi 的压缩效率会更高,损失的上下文也更少。
  • 把客户端的 maxTokens 至少设为 8192。这是影响最大的单项设置,而且由客户端控制,不在服务端预设里。一旦低于这个值,模型会把全部 token 预算耗在思考上,然后返回 finish_reason: length,让你苦等 8 分钟后只拿到一个空字符串。我为此折腾了整整一个晚上,才弄清楚问题出在哪里。
  • 思考内容占生成 token 的 90% 到 95%。一个 40k 上下文的问题,思考内容有 29,006 个字符,回答却只有 1,426 个字符。真正决定任务耗时的其实是这个比例,而不是解码速度。这正是 mediumxhigh 快得多的原因,也是我大多数任务默认使用 medium 的原因。
  • ROCmFP4 FAST 版本没有提示词缓存。每个请求都报告 cache_n: 0,因此重复的提示词每次都得完整跑一遍预填充。原版 llama.cpp 是会缓存前缀的。在一个主要靠往对话记录里追加内容的智能体循环中,这一点会让解码最快的版本反而成为实际完成最慢的一个。正因如此,FAST 版本只适合处理一次性任务这种特殊情况,而不能作为默认选择。
  • 这个 fork 的投机解码路径默认并不是严格的贪心模式。它会打出 Qwen MTP strict verification is disabled; greedy output may diverge 的日志,而且同一个提示词跑三次,补全长度各不相同(分别是 152、158 和 160 个 token)。打开 --spec-mtp-strict-qwen 几乎没有任何可测量的代价——1135 秒对 1136 秒——所以完全没理由不开。
  • 严格来说这不算注意事项:对这些模型而言,Strix Halo 的瓶颈在内存带宽,而不在 GPU 频率。这直接决定了哪些参数值得去调。解码(decode)速度已经跑到内存总线理论峰值的 83% 左右,所以对功耗调整几乎无感;提示词处理(prefill)那部分才是吃算力的,对功耗确实敏感。实测扫描笔记本的功耗档位发现:从 55W 拉到 90W,prefill 提升了 12.7%,decode 却只涨了 4.2%,而且其中大头来自 55W 到 70W 这第一步。过了 70W 收益就趋于平缓,我的功耗也就停在这个档位。这一轮测试是在 Qwen3.6-27B-Q6_K 上测的,所以请看比例,别盯着绝对数值。

| 功耗档位 | 预填充 (pp4096) | 解码 (tg256) |
| ------------- | ---------------: | -------------: |
| 55W | 284.4 t/s | 8.78 t/s |
| 70W | 307.6 t/s | 8.89 t/s |
| 90W | 320.6 t/s | 9.15 t/s |

它到底可行吗

那么,在笔记本上跑 Qwen 3.8,真能在 Agentic 编程中取代 Claude Opus 吗?只要你有耐心,答案是百分百可以。如果你追求速度,那它多半不适合你;但如果你不介意它比顶级云端模型多花两三倍时间完成任务,也愿意花点时间做配置,那答案是肯定的——无论是 Agentic 编程,还是搭配 Hermes 这类工具使用,它都足以取代 Claude Opus 4.6 到 4.8。我还打算让 Hermes 和 Pi 一起跑。在下一个更强的本地模型出现之前,我就用它们当主力编程模型了。已经迫不及待等 Qwen 4 发布了,我有种预感:届时会诞生一个能在消费级 GPU 上流畅运行的 Opus 5 级别模型(当然,Kimi K3 现在也能跑,但对大多数人来说并不现实)。等它一出来我就会立刻上手测试,并把结果分享在这里。


如果你喜欢这篇文章,欢迎点赞或留言。

你可以在 BlueskyMastodonLinkedIn 上关注我。

——

🧑‍💻

zhirenhun

一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。

ai llamacpp localllm qwen38