Qwen 系列模型评测格式正确率从 74% 到 100%:一次本地 vLLM 评测问题复盘

重点放在前面

使用 “enable_thinking”: false参数配置,不然思维链输出可能会超出max_token限制。

背景

这次任务是对几个大模型做本地或 OpenAI 兼容接口评测,数据集包括两大类:

  • CyberCertBench:客观选择题,要求模型输出选项字母。
  • 电力行业问答:开放问答,需要模型给出完整回答,再由裁判模型和 embedding 计算得分。

评测工具会输出一个很关键的指标:format_valid_rate,也就是格式有效率。这个指标尤其影响 CyberCertBench,因为选择题的答案必须能被程序抽取成合法选项,例如 ABAC答案: B。如果模型长篇解释、输出思考过程,或者最终没有给出可解析的选项,即使它“看起来理解了题目”,程序也会判为格式无效。

一开始,qwen3.5-9b-awq 的旧结果不理想:

数据集题数旧格式有效率旧准确率
CyberMetric808090.00%78.75%
mmlu_Computer_Security10074.00%57.00%

后来重新调整推理配置并重跑后,格式正确率达到了 100%:

数据集题数新格式有效率新准确率
CyberMetric8080100.00%95.00%
mmlu_Computer_Security100100.00%79.00%

这篇文章记录这次问题的前因后果,以及具体是怎么处理的。

现象:模型不是不会答,而是输出格式不稳定

旧结果里,格式无效的样例有一个共同点:模型没有直接输出选项,而是先开始解释。

例如某些 Cyber 选择题只需要输出 答案: A,但模型会输出类似下面这种内容:

要计算二进制数之间的按位异或结果,我们需要逐位进行比较……

或者:

Google hacking involves using advanced search operators...

再比如:

RAID 0 does not provide redundancy...

答案:

这些回答对人来说可能还能猜出模型想说什么,但对自动评测程序来说是有问题的:程序要从回答中抽取 A-J 之间的选项字母。如果输出是一大段解释,里面可能有很多普通英文字母 A、B、C、D;如果最后的答案又被截断,程序就无法可靠抽取最终选项,于是 format_valid=false

所以问题不是简单的“模型能力差”,而是“模型输出行为和评测格式要求不匹配”。

评测工具如何判定格式有效

Cyber 选择题的格式判定逻辑大致是:

  1. 优先匹配 答案: Xanswer is X 这类明确答案格式。
  2. 如果整段内容几乎只有选项字母,也会尝试抽取。
  3. 如果是一大段自然语言解释,无法明确定位最终选项,就判为格式无效。

也就是说,评测工具并不要求模型一定只输出一个字母,但它必须能明确抽取出最终选项。最稳的输出就是:

答案: B

或者:

B

但如果输出变成:

这个问题考察的是访问控制模型。首先我们分析 A 选项……

这种内容很容易让解析器失败。

为什么之前不行

旧配置里,其实已经有比较严格的选择题 prompt,例如要求模型只输出最终选项,不要解释。但是对 Qwen 系列模型来说,仅靠提示词并不总是够。

原因主要有三个。

第一,Qwen 系列模型有 thinking / reasoning 输出倾向。
即使 prompt 写了“不要解释”,模型仍可能进入思考模式,先生成推理过程,再给答案。

第二,Cyber 选择题的 max_tokens 设置较短。
我们把选择题输出限制得比较短,本意是防止模型输出太多废话。但如果模型一开始就进入解释模式,短 token 反而会把解释截断在中间,导致最后的 答案: X 根本没有生成出来。旧结果中很多无效样例就是这种情况:输出了一段解释,但没有出现可解析的答案。

第三,旧配置缺少对 Qwen chat template 的显式控制。
OpenAI 兼容接口虽然形式一样,但不同模型服务对 Qwen 的 thinking 控制参数支持不完全一样。只在 prompt 中写 /no_think 有时不够,最好在请求体里同时传递禁用 thinking 的参数。

为什么 Kimi、DeepSeek、GLM 的格式问题少很多

后来又看了 ds-kimi-glm 这一批结果,这里面同时测了 Kimi、DeepSeek、GLM、Qwen3.6-27B 和 Nex-N2-Pro。这个对照很有价值,因为它们用的是同一套评测 prompt 和运行参数:

  • temperature=0
  • cyber_max_tokens=64
  • workers=1
  • 没有额外传 enable_thinking=false
  • 没有给 Qwen chat template 单独传 thinking 控制

结果很明显:Kimi、DeepSeek、GLM 的格式确实没出大问题,但并不是完全没有问题。

模型CyberMetric80 格式率mmlu_Computer_Security 格式率电力问答最低格式率典型问题
Kimi-K2.698.75%99.00%100.00%偶发输出推导过程,最后停在 Result:,没有给出选项
DeepSeek-V4-Pro98.75%100.00%98.61%偶发中文解释过长,被截断前没有输出最终选项
GLM-5.1100.00%97.00%97.22%偶发长篇中文解释,没有在可截取范围内给出答案
Qwen3.6-27B 旧配置0.00%0.00%100.00%Cyber 选择题大量空响应或不可解析响应
Nex-N2-Pro 旧配置58.75%30.00%100.00%大量空响应,部分题输出类似思考过程的长文本

这说明两个问题。

第一,Kimi、DeepSeek、GLM 更容易遵守“只输出答案”的指令。
这些托管模型在当前接口下,默认可见输出更接近普通 chat completion:收到严格格式要求后,大多数时候会直接给出答案。它们偶发失败时,主要是又开始解释,或者输出被 cyber_max_tokens=64 截断。

第二,Qwen 的问题更像是模型模板和输出协议没有对齐。
同一套旧配置下,Qwen3.6-27B 在 Cyber 上是 0% 格式率;后来在新配置中增加:

{
  "enable_thinking": false,
  "chat_template_kwargs": {
    "enable_thinking": false
  }
}

再把 Cyber 输出长度放宽到 256 后,Qwen3.6-27B 的两个 Cyber 数据集格式率都恢复到 100%。这说明旧结果不能简单理解成“Qwen 不会答题”,更合理的解释是:请求没有正确关闭 Qwen 相关的 thinking / chat-template 行为,导致评测程序拿到的可见输出不是稳定的最终答案。

所以,Kimi、DeepSeek、GLM 之所以看起来“格式没问题”,不是因为 prompt 本身已经完美,而是它们在这个接口下默认就更贴近评测工具想要的输出协议。Qwen 系列则需要显式控制 thinking,才能稳定进入同样的答题模式。

这次怎么处理

这次不是换了模型权重,也不是靠后处理硬修结果,而是从“生成行为”入手,重新配置了 Qwen 系列的推理参数。

核心处理有四点。

1. 明确关闭 Qwen thinking

对 Qwen 系列模型,在请求体里加入:

{
  "extra_body": {
    "enable_thinking": false,
    "chat_template_kwargs": {
      "enable_thinking": false
    }
  }
}

这里同时写 enable_thinkingchat_template_kwargs.enable_thinking 是为了兼容不同服务实现:

  • 有些 OpenAI 兼容服务识别顶层 enable_thinking
  • 有些 vLLM / tokenizer chat template 更依赖 chat_template_kwargs.enable_thinking

这一步是关键。它让模型直接进入“答题模式”,而不是先输出 reasoning。

2. 继续使用严格的选择题 prompt

Cyber 选择题 prompt 保持强约束:

/no_think
请回答下面的客观选择题。
强制要求:只能输出一行,格式必须是 `答案: X`,其中 X 是一个或多个选项字母,例如 A 或 AC。
不要解释,不要推理,不要复述题目,不要输出任何其他文字。

注意:prompt 是必要条件,但不是充分条件。
之前不稳定,说明仅靠 prompt 不能完全压住 Qwen 的解释倾向;这次真正稳定,是因为 prompt 和 enable_thinking=false 一起生效了。

3. 给选择题设置更短的输出长度

Cyber 选择题只需要输出选项,所以设置:

{
  "run": {
    "temperature": 0,
    "cyber_max_tokens": 64,
    "elec_max_tokens": 2048
  }
}

这里要注意一个细节:cyber_max_tokens=64 本身不是万能解法。
如果没有先关闭 thinking,模型可能在 64 个 token 内只输出解释,最后答案被截断,格式反而更差。正确顺序应该是:

  1. 先禁用 thinking,让模型直接答题。
  2. 再缩短选择题输出长度,减少尾部废话。

4. 增加 stop token,减少模型继续生成

对 Qwen 系列加入:

{
  "stop": [
    "<|im_end|>",
    "<|endoftext|>"
  ]
}

这能减少模型在答案后继续输出模板结束符、额外解释或其他无关内容。

推荐的 Qwen 评测配置片段

下面是脱敏后的配置示例。实际使用时把 base_urlapi_key、模型名改成自己的即可。

{
  "api": {
    "base_url": "http://127.0.0.1:8000/v1",
    "api_key": "YOUR_API_KEY",
    "timeout": 180,
    "retries": 2,
    "extra_body": {
      "enable_thinking": false,
      "top_p": 0.9,
      "repetition_penalty": 1.08,
      "chat_template_kwargs": {
        "enable_thinking": false
      },
      "stop": [
        "<|im_end|>",
        "<|endoftext|>"
      ]
    }
  },
  "models": [
    "Qwen/Qwen3-8B"
  ],
  "run": {
    "datasets": [
      "cyber",
      "elec"
    ],
    "workers": 3,
    "temperature": 0,
    "cyber_max_tokens": 64,
    "elec_max_tokens": 2048,
    "seed": 42
  }
}

如果是远端 AWQ 模型,服务端并发能力不确定,可以先把 workers 设置为 1,确保格式稳定后再逐步提高。

vLLM 部署中的一个插曲

本地部署 Qwen3-8B 时使用的是 vLLM 的 OpenAI API 服务。为了让输出更可控,我使用了:

--generation-config vllm

这样可以避免模型仓库自带的 generation config 覆盖我们评测时需要的确定性设置。

另外,在 WSL 环境中,vLLM 的 V2 runner 曾经遇到过 UVA is not available 问题,因此切换为:

export VLLM_USE_V2_MODEL_RUNNER=0

这个问题和格式正确率不是一回事,但它影响模型能否稳定启动。

重跑后的结果

最终结果如下:

模型Cyber 格式有效率Elec 格式有效率Cyber 得分Elec judge 得分加权 judge 得分
Foundation-Sec-8B-Instruct100%100%0.69440.65870.6730
Qwen3-0.6B100%100%0.60560.62010.6143
Qwen3-8B100%100%0.77220.75420.7614
qwen3.5-9b-awq 重跑100%100%0.86110.76150.8013

其中 qwen3.5-9b-awq 的 Cyber 格式有效率变化最明显:

数据集旧格式有效率新格式有效率
CyberMetric8090.00%100.00%
mmlu_Computer_Security74.00%100.00%

准确率也同步提升:

数据集旧准确率新准确率
CyberMetric8078.75%95.00%
mmlu_Computer_Security57.00%79.00%

这并不代表模型突然“变聪明”了,而是原先很多题因为格式无效无法抽取答案,被直接记成 0 分。格式稳定后,模型的真实答题能力才被更准确地统计出来。

经验总结

这次问题的核心经验是:评测大模型时,不能只看模型能力,还要看输出协议是否和评测程序一致。

对于 Qwen 这类带 thinking 能力的模型,建议按下面顺序排查:

  1. 先确认 prompt 是否明确要求输出格式。
  2. 再确认服务端是否真的关闭了 thinking。
  3. 对选择题设置较短的 max_tokens,但前提是模型已经不会先输出长篇解释。
  4. 加 stop token,减少答案后继续生成。
  5. temperature 设为 0,保证评测可复现。
  6. 并发不要一开始拉满,先稳定格式,再提高 workers。

如果只改 prompt,不改 Qwen 的 chat template / thinking 参数,格式问题可能仍然反复出现。
如果只缩短 max_tokens,但模型仍先解释,答案可能被截断,格式反而更差。
所以这次能从 74%/90% 提升到 100%,关键不是单点技巧,而是把 prompt、thinking 控制、输出长度和 stop token 配套处理了。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐