Qwen3.8-27B 的 reasoning_effort 三档:模板里只有两档有分支

2026-08-16

翻 Hugging Face 上 Qwen/Qwen3.8-27B 这个权重仓的时候,有一处值得单独拎出来说:model card 用三个并列的条目介绍 reasoning_effort,而随仓的 chat_template.jinja 里,只有其中两档会走到「设置提示词」的分支上。

下面把这两处的原文位置、逐行内容,以及你自己怎么在仓库副本里核对,一次说清楚。本文所有事实都来自 2026-08-16 采集的快照 1d4bf0f,那天之后上游有更新的话,请以仓库最新内容为准。

先说清楚这是个什么仓

Qwen/Qwen3.8-27B模型权重仓,不是代码工程。没有 src/,没有测试,没有可读的推理实现。跟「推理行为控制」有关的线索,我们能核到的都落在这 8 个文本文件里(也是本次采集下来的全部文本文件):README.md(也就是 model card 正文)、config.jsongeneration_config.jsonpreprocessor_config.jsonvideo_preprocessor_config.jsontokenizer_config.jsonchat_template.jinjaLICENSE

我们采集时实读的体量是:README.md 65,012 字节 / 583 行,chat_template.jinja 8,952 字节 / 170 行,tokenizer_config.json 17,928 字节 / 306 行,generation_config.json 只有 202 字节 / 13 行。

这个前提很重要:当 model card 的描述和模板文件的分支条件不一样时,你没有第三份材料可以去仲裁,只能把两处都摊开、各自标好位置。本文就是这么做的,不做谁对谁错的判断。

model card 那三行

README.md:258 起是这么写的:Qwen3.8 官方支持 reasoning_effort,用于调节推理深度与控制成本,随后三个并列条目:

  • xhigh(默认):for complex tasks demanding thorough analysisREADME.md:259
  • mediumbalancing accuracy and speedREADME.md:260
  • lowefficient reasoning optimizing for speed and costREADME.md:261

三条在版式上完全对等——同一层级、同样的一句话说明。这是 model card 自述的描述,我们没有验证过其中任何一句。

同一节往下几行,README.md:266-267 还有一个 > [!Tip],原文说:在多轮 agentic 任务里,更低的推理档位不一定缩短总完成时间——单轮响应可能更快,但也可能导致分析不充分、失败更多、反复重试,从而增加总时延与 token 消耗。同样是 model card 自述,我们没有做过任何验证,这里只作转述。

模板第 45 到 56 行

现在看 chat_template.jinja。档位解析全部集中在 45 到 56 行这一块,原样贴出:

{%- set reasoning_instructions = '' %}
{%- if enable_thinking is undefined or enable_thinking is true %}
    {%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %}
    {%- if resolved_reasoning_effort not in ('xhigh', 'medium', 'low') %}
        {{- raise_exception('Unexpected reasoning effort ' ~ reasoning_effort ~ '. Supported types are xhigh (default), medium, and low.') }}
    {%- endif %}
    {%- if resolved_reasoning_effort == 'xhigh' %}
        {%- set reasoning_instructions = 'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.' %}
    {%- elif resolved_reasoning_effort == 'low' %}
        {%- set reasoning_instructions = 'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.' %}
    {%- endif %}
{%- endif %}

逐行拆开来看,一共四件事:

第一,默认值在这里。 47 行的 reasoning_effort|default('xhigh') 给出默认档位 xhigh,与 README.md:259 括号里的「(default)」是一致的。这一处两边对得上。

第二,合法值集合是三个。 48 行的判定是 resolved_reasoning_effort not in ('xhigh', 'medium', 'low')medium 明确在集合里。所以传 medium 不会触发 49 行的异常——那条异常的文案原文是 Unexpected reasoning effort ... Supported types are xhigh (default), medium, and low.,它自己也把 medium 列为受支持的类型。

第三,只有两个分支会赋值。 51 行判 xhigh、53 行判 low,各自把一段英文提示词写进 reasoning_instructionsmedium 没有对应的 elif 分支。变量在 45 行被初始化成空串,走 medium 这条路时它保持空串。

第四,整块被思考开关包住。 46 行的条件是 enable_thinking is undefined or enable_thinking is true。也就是说 enable_thinking 显式传 false 时,47 到 55 行整段都不执行——档位的合法性校验不做,提示词也不注入。

差异在哪里,以及只能说到哪一步

把两处并排:

位置写的是什么
README.md:259-261xhigh / medium / low 三条并列,各配一句描述
chat_template.jinja:48合法值集合 ('xhigh', 'medium', 'low'),三个都在
chat_template.jinja:51-55只有 xhighlow 两个分支设置 reasoning_instructions

差异就在最后一行:README 把三档写成对等的三个选项,模板的提示词注入只覆盖其中两个。以我们实读的仓库快照 1d4bf0f 为准,这两处的字面内容就是上表所列。

这里必须打住。我们不推断哪一处「是对的」,不推断为什么会这样,也不拿这个差异去评价这个模型或这个仓库。往下只剩一件能做的事:告诉你怎么自己核。

自己核的三步

第一步,确认你手上的模板和仓库里的一致。 模板内容在这个仓里存了两份:一份是独立文件 chat_template.jinja,另一份是 tokenizer_config.json 第 285 行的 "chat_template" 字段。我们按字节比对过,两者长度同为 8,952、md5 同为 519239a4908bb1f805bbce5fa8c8a242,内容完全一致,且都不以换行结尾。你在自己的副本上跑一遍同样的比对,就知道有没有被中间环节改过:

import json,io,hashlib
ct=json.load(io.open('tokenizer_config.json',encoding='utf-8'))['chat_template']
f=io.open('chat_template.jinja',encoding='utf-8').read()
print(len(ct), len(f), ct==f, hashlib.md5(ct.encode()).hexdigest(), hashlib.md5(f.encode()).hexdigest())

第二步,直接看 45 到 56 行。 不用通读 170 行,档位逻辑全在这一段里。数一下 {%- if resolved_reasoning_effort =={%- elif resolved_reasoning_effort == 一共几个分支,各自判的是哪个字符串。

第三步,确认这个参数在本仓没有别的落点。 对上面列的 8 个文本文件逐词统计,reasoning_effort 的命中情况是:tokenizer_config.json 6 次、chat_template.jinja 6 次,其余文件全部 0 次。而这两处命中实际是同一份模板内容(第一步已经比对过了)。enable_thinking 是各 4 次、preserve_thinking 是各 2 次,分布相同。

也就是说:在这个权重仓里,reasoning_effort 的唯一落点是 chat template。 generation_config.jsonconfig.jsonpreprocessor_config.jsonvideo_preprocessor_config.json 里都没有这个字段——generation_config.json 全文只有 13 行,键就是 bos_token_iddo_sampleeos_token_idpad_token_idtemperaturetop_ktop_p 这几个,跟推理档位无关。

顺带说清楚提示词是怎么进 prompt 的

既然 reasoning_instructions 是这段逻辑唯一的产物,那它拼到哪儿去了,就决定了这个变量的影响面。模板 57 到 87 行给了答案,它分两种情况:

  • tools(57 行判 tools and tools is iterable and tools is not mapping):先开 <|im_start|>system\n,若 reasoning_instructions 非空就先输出它再加两个换行(59-61 行),然后才是 # Tools 那段固定文案与 <tools>...</tools> 序列化。档位提示词排在工具说明前面。
  • 没有 tools(76-87 行):如果首条是 system 且正文非空,输出格式是 <|im_start|>system\n + 提示词 + 两个换行 + 正文;如果首条是 system 但正文为空、或者首条压根不是 system,而 reasoning_instructions 非空,模板会单独插一条只含这段提示词的 system 消息(前者在 81-82 行,后者在 84-85 行)。

两条路径都有同一个前提:reasoning_instructions 非空。空串时,上面这些插入动作都不发生。

这里有一个结构性的事实值得记住:推理档位是以 system 消息的形式注入到 prompt 文本里的,不是模型内部的什么开关。它最终就是几行英文,跟你自己写的 system prompt 排在一起。

传参那一层还有一个岔路

reasoning_effort 到底怎么传,README 里的 Text-Only 示例(README.md:284-303)给了写法,而且三个控制项的位置并不一样:

completion = client.chat.completions.create(
    model="Qwen/Qwen3.8-27B",
    messages=messages,
    extra_body={
        "chat_template_kwargs": {
            "enable_thinking": True,  # on by default
            "preserve_thinking": True, # on by default
        },
    },
    reasoning_effort="xhigh",  # xhigh by default; supported levels are xhigh, medium, and low
    stream=True,
    stream_options={"include_usage": True},
)

这段代码是从 model card 里原样抄下来的,我们没有部署过这个模型,也没有运行过这段示例,只按字面转述它的写法;实际可用的参数以官方最新说明与你所用推理框架的文档为准。

enable_thinkingpreserve_thinkingextra_body.chat_template_kwargs 里,reasoning_effort 却是 create() 的顶层参数(README.md:300)。另外 README.md:466README.md:493 两处 Note 说明,用 Qwen Cloud 的 API 时,enable_thinking / preserve_thinking 要直接传、不要包在 chat_template_kwargs 里——同一个参数在不同服务端有两套传法。顺带一提,model card 里提到的 Qwen3.8-27B 官方托管版本,README.md:16 原文写的是 coming soon,按 README 自述尚未上线。

至于顶层的 reasoning_effort 在 vLLM、SGLang、TokenSpeed 这些框架里具体怎么映射到模板变量 reasoning_effort本仓的文件里没有任何说明,README 只给了 OpenAI SDK 侧的写法。我们没有查阅这些框架的源码,所以这一段照实留白:核不出来就是核不出来。

medium 该不该用

这个问题我们没有依据回答。model card 把它描述为 balancing accuracy and speed,模板里它是合法值、不抛异常、不注入提示词——这两句是我们能确认的全部。选哪一档取决于你的用法,项目没有给出通用值,我们也没有做过任何对比。

真正能带走的是方法:这个仓里凡是涉及推理行为的参数,先在 chat_template.jinja 里 grep 一遍它出现在第几行、被哪个条件包着、赋值分支覆盖了哪些取值,再回头看 model card 怎么描述。两处对得上就按描述理解,对不上就把两处位置都记下来——模板的 9 处 raise_exception(行号 10、21、33、39、43、49、100、106、160)也可以用同样的方式扫一遍,它们是这份模板里少数几个把约束写死了的地方。

延伸阅读


本文依据 Hugging Face 仓库 Qwen/Qwen3.8-27B 的 model card 与随仓配置文件 (config.jsongeneration_config.jsonpreprocessor_config.jsonchat_template.jinja 等)整理, 核对日 2026-08-16,对应仓库快照 1d4bf0f。 本文内容为 model card 与配置文件口径,我们没有下载权重、没有部署、也没有推理过这个模型, 因此不涉及生成质量、推理速度与显存占用的任何描述;文中所有评测数字均为 model card 自述,我们没有复现。 模型仓库内容随上游更新而变动,请以官方最新说明为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。