Prhub

#34097 docs(skill): record where config is read now that the seed is off limits

原始 PR 作者 ch-wan 合并时间 2026-08-10 05:46 文件变更 1 提交数 1 评论 55 代码增减 +171 / -29

执行摘要

技能文档落定 config 种子禁读规则与分形状读取入口

PR body 说明:原 tier 表把 get_server_args() 描述为 “debugging, dumps, per-runner fork copies”,但 reader-convergence 之后它同时是业务代码“永远不得读取字段”的种子——“it is now also the thing business code must never read a field off”。文档需要记录每种配置形态现在该去哪里读:resolved leaf 到其 bag、live topology 到 get_parallel()、由实例推导的值到 runtime_context 具名访问器、被遮蔽的配置尺寸到 configured_*_size()、runner 解析值到 runner。同时修正两处过期引用:已被删除的 writer ratchet 与 declare_load_time_override。另因 #34086 因 force-push 事故被 GitHub 误关(“a bad force-push on my side briefly pointed several member branches at the same commit”),本 PR 取代它继续承载同一份内容与原评审线程。

值得精读,尤其关注三点:1)分形状读取的决策映射(bag / get_parallel() / 具名访问器 / configured_*_size() / runner stamp),这是理解 SGLang 配置架构的钥匙;2)读棘轮测试(test_global_config_read_ratchet.py)如何用 AST 收集器把架构约束钉死,以及词法作用域遮蔽的处理;3)“文档评审反哺代码质量”的流程——纯文档 PR 的评审催生了 sarvam_moe.py 与收集器的真实修复。若只关心运行时行为,可跳过。

讨论亮点

评审主体是作者自审(ch-wan,借 #34087 作为 stack review 载体)与 Codex bot 的 P2 建议。核心交锋有三条线:其一,自审发现未修改的 get_parallel() 段落仍指引 server_args.X,与新版 configured_*_size() 指引直接矛盾,属于 blocker,作者在 PR 内改写段落并交叉链接;其二,Codex 连续指出多个“instance-only”访问器(attention_backends()cutedsl_moe_max_num_tokens()max_speculative_num_draft_tokens()configured_*_size())的实际输入都是已发布叶节点,读种子会错过 post-publish override,作者逐一确认并改为从 bags 派生;其三,读棘轮的形态覆盖边界成为拉锯战——module-level/annotated/属性挂载/条件绑定别名、整对象交接、调用点登记粒度,作者的选择是“扩展收集器 + 修真实代码”(sarvam_moe.py 被实地修复)而不是收窄声明。最终 fresh re-review 报 bugs: 0、suggestions: 3、nits: 3。

实现拆解

  1. 重写 tier 总览表get_server_args() 一行从“调试、dump、per-runner fork 副本”改为“启动记录 + 业务代码禁读”,并标注读棘轮(read ratchet)把 get_server_args().field、别名绑定、getattr(..., "field") 等可识别形式钉死在 0;运行时计算的名字与整对象交接为构造性豁免。这是全文的纲领,后续所有读取指引都以此为前提。
  2. 新增 “Reading config: the seed is off limits” 决策映射:按数据形状给出五类入口——已解析叶节点走命名空间 bag(get_exec()get_schedule() 等)、实时拓扑走 get_parallel()、由发布叶节点推导的值走 runtime_context 具名访问器(如 attention_backends()get_exec().kernel 派生,保留 post-publish override 可见性)、被 live 属性遮蔽的配置尺寸走 configured_{tp,pp,moe_dp,attn_cp}_size()(DCP 无 configured 访问器,未装组时 attn_dcp_size/dcp_enabled 安全返回 1/False 但只报有效拓扑)、runner 解析值走 runner 属性或构造参数。
  3. 重写 “Reads that legitimately stay on a ServerArgs instance”:删除 “per-runner fork 字段” 段落(draft-worker 配置深拷贝已不存在,所有 worker 共享同一发布实例);保留 handed-instance 边界(tokenizer 家族、entrypoints/、tokenizer 进程 MM 处理器、MMEncoderGrammarManager);新增测试双重规则 “a double publishes its config, it does not inject one on a stand-in”;补上 ModelRunner._load_format_scope 有界 override 作为唯一受认可的对共享 bag 的临时写入。
  4. 同步修正 get_parallel() 小节与 Guardrails:shadowed 尺寸的 config-intent 读取从 server_args.X 改指 configured_*_size(),并说明 DCP 未装组时的安全降级语义;Guardrails 新增第 5 条全局 config 读棘轮(基线 0、豁免按 owner module、_CONFIGURED_SIZE_CALL_SITES 登记表),重写第 4 条使“决策的替代物”明确为 bag 叶节点 / 具名访问器 / runner stamp,而非 get_server_args().field
  5. 配套与验证:本 PR 无代码与测试改动(单提交仅改 SKILL.md)。评审回复中声称的棘轮收集器扩展(module-level/annotated/instance-attribute/条件绑定/参数名遮蔽、module-qualified 识别)与 sarvam_moe.py 修复不在本 diff 内,应位于 reader-convergence 配套栈的其他 PR,基于可见材料无法最终确认其合并顺序。
文件 模块 状态 重要度
.claude/skills/sglang-runtime-context/SKILL.md 技能文档 modified 4.89

关键符号

get_server_args get_parallel configured_tp_size configured_pp_size configured_moe_dp_size configured_attn_cp_size attention_backends max_speculative_num_draft_tokens preserve_config

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

相邻 get_parallel() 段落仍指引 server_args.X,与新规则自相矛盾 正确性

ch-wan 自审 blocker:未修改的 get_parallel() 小节(约 115-116 行)仍说 shadowed 尺寸的 config-intent 读取要走 server_args.X,与新增的 configured_*_size() 指引及生产调用点相反;Codex 另给出同质 P2:按照旧段落会重新引入棘轮失败的读取。

结论:本 PR 内改写该段落指向 configured_tp_size()/configured_pp_size()/configured_moe_dp_size()/configured_attn_cp_size()(DCP 走 get_parallel().attn_dcp_size/.dcp_enabled),并交叉链接 “Reading config” 节,两处不再互相矛盾。 · 已解决

attention_backends() 被归为 instance-only,但输入全是 exec.kernel 叶节点 正确性

Codex 指出三个输入(attention_backend、prefill/decode_attention_backend)都是已发布的 exec.kernel 叶节点,实例读法会错过 get_context().override(...),与“由叶节点可表达的推导必须用 bag”的规则相悖。

结论:ch-wan 确认属实:改为从 get_exec().kernel 派生 (kernel.prefill_attention_backend or base, kernel.decode_attention_backend or base),文档移入 bag 派生组。 · 已解决

max_speculative_num_draft_tokens / cutedsl_moe_max_num_tokens 读种子会拿到过期边界 正确性

Codex 连续两条指出这两个访问器输入均为 schedule/exec.graph/spec 叶节点,override 后按种子读取会给出过期值——前者影响 KV pool 与 mamba 投机 buffer 尺寸,后者影响 CuteDSL wrapper 的 token 预算。

结论:两者均改为从 bags 派生(max_spec 含 adaptive 分支);instance-only 组收缩为 mamba_cache_chunk_size、uses_mla_backend、process_model_config。 · 已解决

configured_*_size() 实为 bag-backed,文档原先描述相反 正确性

Codex:_configured_parallel() 读 config_bag("parallel") 而非 get_server_args(),post-publish override 对 configured_*_size() 可见;ch-wan 自审还复现了同类缺陷:override("audit", pp_size=4) 移动 bag 叶节点后访问器仍答 1。

结论:configured_*_size() 改为读 parallel bag 自身叶节点(绕过 live property 遮蔽),文档两处表述同步更正:只有 bag 支撑的读取(含 configured_*_size())看到 override,实例派生访问器看不到。 · 已解决

读棘轮对别名形态的覆盖盲区:module-level、属性挂载、条件绑定、改名导入 正确性

Codex 多轮指出 _collect 只认直接 ast.Name 绑定和字面 get_server_args:sa: ServerArgs = ...、self._sa = ...(SarvamMoEMLAAttention 实际命中)、if True: sa = ...、cfg = sa 链式拷贝、from ... import get_server_args as get_args 均能绕过基线。

结论:收集器按词法作用域扩展(module-level/annotated/instance-attribute/ 嵌套语句,参数名遮蔽按作用域处理),并反向验证;sarvam_moe.py 实修(改读 attention_backends() 与 get_memory().disable_radix_cache),基线保持 0。alias 链拷贝与改名导入未见修复回复,可能仍有盲区。 · 已解决

整对象交接 f(get_server_args()) 是否违反零读取基线 question

Codex:kimi_k3.py:1929 的 require_mlp_sync(get_server_args()) 最终在 utils/common.py:3586/3612 读 server_args.tp_size,棘轮保持绿色,“business code does not read fields off it” 的顶层声明被证伪。

结论:文档明示两类构造性豁免并点名为豁免:运行时计算的名字(getattr(sa, name))与整对象交接(f(get_server_args()) 视为调用者选择实例,callee 读属 supplied-instance 契约),census 工具负责审计这些形态。 · 已解决

DCP 的 config-intent 读取指引:无 configured 访问器 正确性

Codex:把 config-intent 读者指向 get_parallel().attn_dcp_size/.dcp_enabled 是错的——它们需要分布式组且只报有效拓扑;随后又指出未装组时两者安全降级(dcp_enabled→False、attn_dcp_size→1,test_attn_dcp_defaults_when_group_is_uninitialized 钉死),“需要 dist init” 的说法也不准确。

结论:文档改为:当前不存在 config-intent DCP 调用点(访问器随上游 #33925 删除);live 成员未装组时安全返回 1/False 但报有效拓扑;未来需要 requested size 须自建 configured_dcp_size() 并登记调用点。 · 已解决

“每个调用点都登记” 的保证过强 测试

Codex:census 以 (file, accessor) 为单元,同文件重复调用坍缩,且只认裸 ast.Name;新增调用点可能不触发任何失败。

结论:收集器补上 module-qualified 调用识别;文档明确 (file, accessor) 粒度与“抓新文件 / 新访问器”的真实保证,并说明不做逐行追踪是刻意取舍(避免 map 因换行抖动)。 · 已解决

MMEncoder 的 per-worker 配置豁免理由不成立 设计

Codex:MMEncoder.__init__ 立即 publish 传入的同一实例,per-worker 设备经独立 gpu_id 参数传递,config 字段并非 per-worker,因此 self.server_args.encoder_transfer_backend 等读取缺乏豁免依据。

结论:重写为 construction-path 约定而非语义豁免:self.server_args 读取今天与 bags 一致只因是同一对象,post-publish override 不会到达它;per-runner 段落同步删除 draft deepcopy 表述,并补上 _load_format_scope 有界 override。 · 已解决

“没有任何测试 stub 访问器” 与现存测试冲突 测试

Codex:test_fp8_utils.py:102 patch get_exec、test_tokenspeed_mla_dcp_metadata.py:37 与 test_kimi_k25.py:380 patch get_parallel,绝对化声明不成立;且与“绝不 monkeypatch import 绑定”的 testing idioms 相矛盾。

结论:声明收窄为“本次 sweep 转化的两个测试”;访问器级 stub 例外与全局禁令在文档中互相限定。 · 已解决

风险与影响

纯文档改动,无运行时风险。主要风险:1)文档-实现漂移——文中承诺的 configured_*_size() 读 parallel bag 语义、_CONFIGURED_SIZE_CALL_SITES 登记表、棘轮覆盖形态均以配套栈当前实现为准,后续若新增 DCP 的 config-intent 调用点或扩展别名形态,文档会过期;2)棘轮声明边界——alias-to-alias 链式拷贝与 import ... as 改名导入两类盲区在可见回复中未见确认修复,“baselines are 0” 的表述可能仍过强;3)误导 agent——该 skill 是 AI agent 修改 runtime_context 相关代码时的首选参考,作者自审即承认旧段落会导致 agent 做出错误重构,任何残留矛盾都会被放大为错误代码;4)配套依赖——文档若先于配套代码合并,会短暂出现“文档声称收集器已扩展而代码未包含”的窗口。

对用户与运行时无任何影响。对开发者与 AI agent 工作流影响显著:该 skill 是 .claude/skills 中面向 runtime_context 改动的治理文档,后续所有涉及配置读取的新代码、重构与测试编写都会以其为指南;新增的“测试双重必须 publish 配置”规则改变组件测试的写法;团队层面为 reader-convergence 架构提供了可执行约束,降低误读种子配置的概率。影响面广但程度温和。

文档与实现易漂移 依赖 reader-convergence 配套栈 棘轮覆盖声明可能仍过强 指导性文档影响 agent 重构

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论