hidden states、routed experts 与旁路返回语义#
执行模型前面的章节已经把 token generation、sampling、finish、output processor 和非生成路径讲得比较完整了,但还有一类很容易被误读成“只是调试附加项”的返回语义没有单独讲清:
return_hidden_statesreturn_routed_experts
这两个开关不会改写主执行循环的骨架,却会显著改变输出对象携带的信息密度,也会把执行层的一部分内部证据旁路带回调用方。它们既不是纯 API 装饰,也不是另开一条独立执行路径,而是挂在主执行链上的正式返回语义。
先把“旁路返回”放回主执行链#
很多读者第一次看到 hidden states 或 routed experts 时,会自然把它们想成“独立输出流”。更稳的理解方式是:主执行链仍然照常跑,只是 execution layer 把一部分本来就已经存在的中间证据附着到了同一条输出对象链上。
下面这张图的职责,就是把这种关系明确画出来:
flowchart LR
Fwd["forward / logits processor"] --> Main["main output semantics"]
Fwd --> Hidden["hidden states capture"]
Fwd --> Experts["routed experts capture"]
Main --> Proc["scheduler_output_processor_mixin"]
Hidden --> Proc
Experts --> Proc
Proc --> Tok["BatchTokenIDOutput"]
Tok --> Str["BatchStrOutput / meta_info"]这张图最重要的不是“有三条箭头”,而是它明确告诉你:这不是另开一条 IPC 或另跑一遍模型,而是把附加证据附着进同一条输出对象链。
return_hidden_states 其实是 execution-side 的正式能力#
从 io_struct.py、engine.py 和 OpenAI utils 一侧都能看出来,return_hidden_states 不是本地调试专用变量,而是正式请求字段。这一点很关键,因为它说明上游明确承认:
- hidden states 是可以被正式请求、正式返回的运行时证据
但它又不是纯 surface feature。因为真正决定它怎样被收集和怎样重新回到结果里的,仍然是 execution 后半段。这种位置特别值得系统书强调:它让读者知道哪些能力属于“从请求参数进入 execution 语义,再折返回输出”的正式运行时能力。
hidden states 不是事后拼出来的,而是从 execution 后半段顺路取出来的#
从 layers/logits_processor.py 相关路径可以看出,hidden states 并不是在 detokenizer 或 API 层临时构造的,而是在 logits processor 与后续输出整理阶段决定:
- 要不要保存
- 保存哪一部分
- 以什么形式放进输出对象
这非常重要,因为它说明 hidden states 返回的本质不是“再跑一遍模型拿中间层”,而是复用主 forward 已经自然产生的中间表示。也正因为这样,它才更像旁路返回语义,而不是另一条独立执行链。
对外通常只返最后一层或最后位置,本质上是一次再压缩#
OpenAI-compatible utils 里的 process_hidden_states_from_ret(...) 很值得注意:
- 如果
request.return_hidden_states没开,直接返回None - 如果开了,就从
meta_info["hidden_states"]再进一步取最后一项
这说明 hidden states 即使在内部被保存得更丰富,对外 surface 往往仍然会再做一次收缩。这样的设计非常合理:
- 内部可以保留足够多的执行证据
- 对外返回时要控制体积、语义复杂度和兼容性
因此,hidden states 在 runtime 内部往往比在 API 返回里更“厚”。如果读者只看 surface,很容易低估这层旁路语义在 execution 内部真正长什么样。
return_routed_experts 和它属于同一类问题#
它和 hidden states 的位置非常像:
- 执行层本来就自然知道一部分专家路由信息
- 请求开关决定要不要暴露这些信息
- 这些信息最终再附着进输出对象 /
meta_info
不同点只在于它暴露的不是表示向量,而是专家路由轨迹。从 scheduler_output_processor_mixin.py 看,当 req.return_routed_experts 为真时,系统会把 req.routed_experts 放进输出对象;BatchStrOutput 与相关 OpenAI utils 又会继续把它折回调用方可消费的形式。
因此它不是 observability 旁路日志,而是 execution model 正式输出语义的一部分。
为什么 routed experts 不是直接回一坨数组#
layers/moe/routed_experts_capturer.py 和相关 helper 里最值得技术书强调的一点是:专家 id 不会被天真地直接塞成一个大 JSON 数组,而会考虑更节制的序列化方式,例如 base64 编码后再由需要的调用方自行恢复。
这说明返回 routed experts 这件事本身就带着明确工程代价:
- 信息量大
- 序列化开销高
- 不能把它当成免费附加字段
也正因为这样,它才更像一条需要被认真设计的旁路证据返回链,而不是“顺手把内部数组也带出去”。
scheduler_output_processor_mixin.py 是这两类旁路语义真正的收口点#
前面的 output-processing 章节已经讲过,它会把 output ids、finish reasons、logprobs、reasoning tokens 等内容整理进 BatchTokenIDOutput。这一章要补的关键点是:它也会在条件满足时把:
req.hidden_statesreq.routed_experts
一起塞进输出对象。
这意味着 output processor 的角色远不只是“把 token 变成可回包对象”,而是“把 execution layer 允许暴露的一切返回语义统一折叠进输出对象”。读懂这一点,前面的主执行链和这里的旁路语义就会自然接起来。
这章和 5.9 不重复,它补的是“挂到输出链上的证据”#
5.9 输出处理、reasoning token 与 streaming 边界 讲的是输出链本身:
BatchTokenIDOutputBatchStrOutput- streaming chunk
- logprobs 增量
而这一章补的是另一层问题:
- execution 内部有哪些附加证据会旁路挂到这条输出链上
- 为什么它们不会改写主执行链,却会改变返回语义的厚度
换句话说,5.9 讲“输出边界本身”,这章讲“有哪些执行证据会搭这条边界一起出去”。
最容易出现的三种误判#
第一,误以为 hidden states / routed experts 是 API 层随手拼出来的。
更准确地说,真正的保存和拼接都发生在 execution 后半段。
第二,误以为打开这些开关会让模型另跑一遍。
它们主要复用主执行链已经产生的中间证据。
第三,误以为它们只是 debug 日志,不是正式返回语义。
源码已经把它们做成了正式请求开关和正式输出字段。
真正顺着源码读这条旁路返回链时,推荐的顺序#
建议按下面顺序:
engine.py/ request object 里的return_hidden_states、return_routed_expertslayers/logits_processor.py里 hidden states 的保存点scheduler_output_processor_mixin.py里附着到输出对象的逻辑io_struct.py里BatchTokenIDOutput/BatchStrOutput对应字段- OpenAI utils 或 routed experts helper 里最终怎样对外暴露
这样读,你会得到一条完整的“从请求开关到返回证据”的 execution 旁路,而不是几处零散字段。
工程收益与代价#
收益很明确:
- 给调试、分析和研究场景提供了正式证据出口
- 不需要为这些能力重写主执行链
- 与现有输出对象链天然兼容
代价也同样真实:
- 返回对象会更重
- 序列化成本会升高,尤其是 routed experts
- 对外 surface 往往还要再做一次压缩或转换,防止返回语义过厚
这正是系统书应该帮读者看清的那类 tradeoff:不是“能不能做”,而是“以什么代价正式支持”。
小结#
hidden states 与 routed experts 真正值得单独成章的地方,不在于它们多返回了一点信息,而在于它们揭示了 execution model 里另一条很重要的设计线:主执行链负责“生成什么”,旁路返回语义负责“额外暴露什么证据”。
读懂这一层之后,execution model 就不再只讲 token 怎样被生成,也开始讲 execution layer 还能怎样正式把内部证据带回来。
叶王 © 2013-2026 版权所有。如果本文档对你有所帮助,可以请作者喝饮料。