Eval bug: deepseek4 produces garbled output when parallel processing is enabled and speculation is in use

该报错是 DeepSeek-V4 模型在并行处理( -np > 1 )与投机解码(MTP/DSpark)同时启用时触发的 KV 缓存回滚重放 bug,导致长程注意力失效并输出乱码。优先排查是否同时启用了并行槽位和投机解码,并尝试暂时禁用投机解码或仅使用单槽位验证。

快速结论:该报错是 DeepSeek-V4 模型在并行处理(-np > 1)与投机解码(MTP/DSpark)同时启用时触发的 KV 缓存回滚重放 bug,导致长程注意力失效并输出乱码。优先排查是否同时启用了并行槽位和投机解码,并尝试暂时禁用投机解码或仅使用单槽位验证。

适用环境:llama.cpp(版本 10326,基于 commit ceebfc910);Linux x86_64;CUDA 后端;AMD 9950X CPU + NVIDIA RTX 6000 GPU;模型为 unsloth/DeepSeek-V4-Flash-0731-GGUF(UD-IQ1_S、UD-IQ2_M 量化版本)。

最快修复方案:Issue 中暂无确认的一步修复方案。可优先尝试禁用投机解码(去掉 --spec-type/--model-draft 相关参数),或将 -np 设置为 1 以绕过该 bug。

注意事项:提交者尝试了 PR #26756 的补丁但模型无法加载,报错 compress_ratios has wrong array length; expected 43, got 46,该补丁可能不兼容当前模型格式。上述绕行方案会牺牲投机解码的加速收益,但能保证输出正确性。

问题场景

用户在 llama.cpp 的 llama-clillama-server 中运行 DeepSeek-V4-Flash-0731 模型,同时启用多个并行处理槽位(-np > 1)和投机解码(如 --spec-type draft-dspark--spec-type mtp)。触发条件严格依赖这两个选项同时开启:单独启用投机解码(单槽位)或单独启用并行(禁用投机)时,推理都正常。用户观察到投机解码确实生效(速度提升约 2 倍),但在运行一段时间后输出变得“看似连贯但长期上下文不对”,工具调用功能受影响最严重。

报错原文

Eval bug: deepseek4 produces garbled output when parallel processing is enabled and speculation is in use

(尝试补丁时出现的关联加载错误:

error loading model hyperparameters: key deepseek4.attention.compress_ratios has wrong array length; expected 43, got 46

原因分析

根据 Issue 中引用 Fable 5 的分析,这是 DeepSeek-V4 稀疏注意力机制中的一个真实代码 bug,发生在投机解码与多序列并行同时启用时。具体机制如下:

DeepSeek-V4 的稀疏注意力为每个序列维护一个小型“压缩器状态”环,以及用于撤销被拒绝投机草稿的回滚快照平面(rollback snapshot planes)。关键问题出在 per-ubatch 图计划的构建方式上:

  • DSv4 KV 缓存上下文构造函数会针对一个批次的所有 ubatch 预先构建压缩器计划,且只从一次 pending-rollback 数组快照中读取状态。
  • 每个计划都会为包含的每个序列发出“还原 plane[rollback] → plane[0]”的拷贝操作,并在每个 ubatch 的图开始时执行。
  • -np = 2 时,DSv4 缓存强制使用 split_equal ubatch 拆分,两个序列按锁步展开,较短的序列结束后停止。当两个槽位贡献的 token 数不等(例如接受的草稿长度不同,或一个槽位解码而另一个处理提示块)时,较长的序列会跨越两个 ubatch。
  • ubatch A 正确应用回滚并推进环状态,而 ubatch B 会再次应用相同的回滚,将 ubatch A 刚写入的环行还原。此后每个提交的压缩块,只要其窗口回溯跨过 ubatch 边界,就会基于过期状态计算,并永久写入 CSA/HCA 缓存及索引器 key 缓存。

因此,原始滑动窗口缓存未被破坏,短程注意力仍然精确,文本在局部保持连贯;损坏的是长程召回(压缩 key)和索引器的 top-k 选择。工具调用受影响最严重,因为它依赖对工具 schema 的精确长程召回,而多轮工具流程(提示缓存重用、部分草稿接受)恰恰会在每一步触发回滚。

单槽位(-np = 1)之所以正常,是因为单个序列的批次只占一个 ubatch,还原操作只执行一次。该 bug 与量化或 CUDA 后端无关,纯粹是 index-plan 逻辑错误,属于后端无关性问题。

环境排查

  • 确认 llama.cpp 版本:10326(commit ceebfc910),以及影响范围包含 1269cb1f 之后多个构建版本。
  • 确认模型:unsloth/DeepSeek-V4-Flash-0731-GGUF 的 UD-IQ1_S、UD-IQ2_M 量化版本。
  • 确认投机解码类型:MTP、DSpark、DFlash、EAGLE3 任一启用即可触发。
  • 确认并行槽位数:-np 大于 1 时触发,等于 1 时不触发。
  • CPU/GPU 环境:9950X CPU + RTX 6000 GPU,Linux x86_64 系统。

解决步骤

  1. 临时绕行方案(已验证有效)
    • 禁用投机解码:移除 --spec-type--model-draft--spec-draft-n-max 等相关参数,只保留主流模型。此时并行推理(-np > 1)可正常工作。
    • 或将 -np 设置为 1(单槽位),保留投机解码。此时投机加速有效,输出正确。
  2. 等待官方修复:Issue 已标记为 bug 并关闭,且存在关联 PR #26756。但该 PR 在当前环境使用 DSpark 草稿模型时会导致加载失败,报错 compress_ratios has wrong array length; expected 43, got 46。建议关注上游修复进展,或在官方确认适配后再尝试升级版本。
  3. 若尝试补丁:如果升级到包含修复的版本,请先验证模型可以正常加载(注意 deepseek4.attention.compress_ratios 数组长度一致),再结合业务场景进行回归测试。

验证方法

分别运行以下三组配置,对比输出质量:

  • 启用 -np 2 + 投机解码:应能复现乱码/长程上下文错误。
  • 仅启用 -np 2(禁用投机):输出应保持正确。
  • 仅启用投机(-np 1):输出应保持正确。

如果并行 + 投机场景下的输出与后两种配置一致且自然连贯,说明问题已解决。此外,可以针对工具调用场景(多轮 function calling)做专门测试,因为该场景对长程召回依赖最强,最容易暴露问题。

参考来源

ggml-org/llama.cpp #26741

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 19822

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注