Prhub

#33173 docs: rewrite the runtime-context skill for the namespace-bag config model

原始 PR 作者 ch-wan 合并时间 2026-08-02 00:00 文件变更 1 提交数 1 评论 31 代码增减 +158 / -69

执行摘要

重写 runtime-context 技能文档,适配 namespace-bag 配置模型

PR body 明确指出:".claude/skills/sglang-runtime-context skill still described the retired resolve-at-end contract (a single resolved ServerArgs as the source of truth, ServerArgs.override as the mutation entry) — actively misleading for anyone touching config now." 即旧的技能文档描述的是已被迁移淘汰的配置契约,会对任何接触配置代码的开发者(包括 Claude Code agent)产生误导。本 PR 作为 RFC #30696 follow-up stack 的最后一块拼图,需要把文档对齐到已落地的 namespace-bag 模型。

值得精读。这份 PR 是理解 SGLang 新配置架构(RuntimeContext + namespace bags)最直接的入口,尤其适合配置系统维护者和经常被 agent 改动波及的模块 owner。重点看三处:tier 表中 raw config seed 与 resolved config 的职责切分、"Reads that legitimately stay on a ServerArgs instance" 章节(per-runner / per-instance 边界)、以及护栏清单(writer ratchet、namespace-coverage lint、migration-deferral ratchet)。整个 review 交锋过程本身就是一份"配置模型迁移边界情况清单",比正文更有学习价值。

讨论亮点

Review 由 Codex 机器审阅与作者自审构成,围绕"文档表述不能比实现更乐观"展开,核心交锋如下:

  • raw config 生命周期:Codex 指出 RuntimeContext.set_server_args() 明确允许覆盖,多 Engine / tokenizer 构建会再发布,文档写 publish-once 会误导。作者答复:"Fixed — the tier table now states the actual lifecycle: published at process entry, re-publish is last-publish-wins (in-process tokenizer build, multi-Engine) and re-projects the bags."
  • draft 配置隔离范围:Codex 指出只有 build_draft_tp_worker() 会安装私有 draft bags,EAGLE/Frozen-KV/MultiLayer/Standalone 直接构造 TpModelWorker(is_draft_worker=True) 时跳过 publish、共享目标进程 bags,draft 侧声明会污染目标配置。作者两次修正(declare 小节与 pitfall 小节)后才闭合。
  • strict mutation 守卫的真实行为:Codex 指出 SGLANG_STRICT_CONFIG_MUTATION 已不再是控制开关,ServerArgs.__setattr__ 在物化后无条件拒绝写入,环境变量只是遗留 harness 标志。作者确认并改为无条件描述。
  • mid-resolution 小节被删后恢复:作者自审发现重写后丢掉了 resolved_view / self._resolved() 的中段读取契约;随后恢复 "Mid-resolution reads (inside the pipeline only)" 小节,并接受 Codex 意见补回 adaptive_spec_params 例外(pipeline 调用的 helper 可用 resolved_view)。
  • live-shadowed sizes 的 fail-loud 过宽:作者自审指出 attn-CP / moe-DP 在 dist init 后总是安装(size=1 别名),只有 DCP 可选;Codex 又补充 attn_dcp_size / attn_dcp_rank 在未初始化时通过 get_dcp_group_no_assert() 返回合成值 1/0。最终收窄为:config-intent 读 server_args.X,fail-loud 只针对 DCP 与 pre-dist-init。
  • detokenizer / launcher 例外:Codex 指出 detokenizer 进程从不 publish,launcher 在 Rust-server / 非零 rank / multi-tokenizer 模式下也不一定 publish。作者修复了 detokenizer 例外并限定描述范围;launcher 未见明确闭合回复,但 r3 disposition 判定 clean。
  • mm processor 残留漏洞:Codex 指出 BaseMultimodalProcessor.process_mm_data() 仍通过 get_server_args()base_gpu_id / rl_on_policy_target,多 Engine 共进程时存在 last-publish-wins 问题。作者选择在文档中将其标注为已知漏洞而非推广模式。

实现拆解

纯文档变更,只改一个文件 .claude/skills/sglang-runtime-context/SKILL.md,按以下步骤完成重写:

  1. 重写 frontmatter 与 tier 总表:description 更新为 "publish + namespace config bags",把原来单一 config 层拆成 raw config seed(get_server_args())与 resolved config(get_exec()/get_memory()/.../get_device() 等 11 个命名空间 bag)两层,并分别标注生命周期:seed 在进程入口发布、last-publish-wins、只读;bag 只在 publish 时投影、变更仅限 get_context().override。
  2. 以 "Config: publish + namespace bags" 章节替换 "resolve-at-end" 章节:说明 ServerArgs 是 pristine 种子,业务代码不读它做决策;publish(server_args, role=...) 按进程入口逐角色发布;SGLANG_ROLE_NAMESPACES=record/enforce 记录并限制各角色可读的命名空间;嵌套发布用 get_context().preserve_config() 包裹(如 draft-worker 构建)。
  3. 新增 "Reads that legitimately stay on a ServerArgs instance" 章节:区分 per-runner fork 字段(draft-worker deepcopy 重写的 attention_backend、load_format 等)、per-instance 边界(tokenizer-manager 家族、mm processor)、整体对象传递;并说明 get_parallel() 的 dual 语义:live 拓扑属性(@property)优先于 config bag 叶子,live-shadowed sizes 的读取规则单独成段。
  4. 重写测试惯用语与护栏清单:从旧的 override_server_args 改为 publish-seeding(测试通过真正发布注入配置,而不是伪造 accessor 或 SimpleNamespace);强调 per-file 测试运行避免 leaked-publish 掩盖问题;护栏扩展为 writer ratchet(ServerArgs.override 逐步退役)、namespace-coverage lint(test_server_args_namespaces.py 双向校验)、migration-deferral ratchet,以及 strict mutation 无条件守卫。
  5. 按 review 迭代修正:把 publish-once 改为 last-publish-wins;恢复被删掉的 mid-resolution(resolved_view/self._resolved())小节并注明 adaptive_spec_params 例外;将 live-shadowed fail-loud 收窄到 DCP 与 pre-dist-init;补 detokenizer 进程不 publish 的例外;把 mm processor 的 last-publish-wins 残留标记为已知漏洞;为 SGLANG_ROLE_NAMESPACES=record 补充 torch.compile 追踪代码内的读取不被观测的说明。
文件 模块 状态 重要度
.claude/skills/sglang-runtime-context/SKILL.md 技能库 modified 4.93

关键符号

RuntimeContext.publish RuntimeContext.preserve_config RuntimeContext.override declare_load_time_override resolved_view

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

评论区精华

raw config 生命周期应为 last-publish-wins 正确性

Codex P2 评论:`RuntimeContext.set_server_args()` 明确允许覆盖,多 Engine / tokenizer 构建会再发布;文档写 publish-once 会让依赖该技能的代码保留或依赖陈旧的进程全局配置。

结论:作者改为:published at process entry; re-publish is last-publish-wins(in-process tokenizer build、multi-Engine)并重新投影 bags。 · 已解决

draft 配置隔离仅限 preserve_config 构建 正确性

Codex 指出只有 `build_draft_tp_worker()` 安装私有 draft bags;EAGLE/Frozen-KV/MultiLayer/Standalone 直接构造 `TpModelWorker(is_draft_worker=True)` 时跳过 publish,draft 侧 `declare_load_time_override()` 会写到当前已发布的目标 bags 并持续存在。

结论:作者两次修正(declare 小节与 pitfall 小节),将隔离保证限定在 preserve_config 路径;跳过 publish 的 draft 加载共享进程 bags,声明必须 draft-safe。 · 已解决

严格 mutation 守卫实际上无条件生效 正确性

Codex 指出 guardrail 仍把守卫描述为 `SGLANG_STRICT_CONFIG_MUTATION=1` 控制,但 `ServerArgs.__setattr__` 在物化后已无条件拒绝写入且不再读环境变量,环境变量只是遗留 harness 标志。

结论:文档改为 " 物化后无条件生效 ",bag 密封一并说明;环境变量仅作为 legacy 标志提及。 · 已解决

mid-resolution(resolved_view)小节被删后恢复 设计

作者自审:替换为 publish + bags 后丢掉了中段解析契约(`resolved_view` / `self._resolved()`、pipeline-only、materialize-at-end),编辑 hooks/passes 的 agent 失去 in-flight 读取指引。

结论:恢复 "Mid-resolution reads (inside the pipeline only)" 小节;并接受 Codex 意见补回 `adaptive_spec_params` 例外(pipeline 调用的 helper 可用 `resolved_view`)。 · 已解决

live-shadowed sizes 的 fail-loud 说明过宽 正确性

作者自审:attn-CP / moe-DP 在 dist init 后总是安装(size=1 别名),只有 DCP 可选;Codex 补充 `attn_dcp_size` / `attn_dcp_rank` 在未初始化时经 `get_dcp_group_no_assert()` 返回合成值 1/0,不能用 fail-loud 当初始化检查。

结论:规则保留 config-intent → `server_args.X`(property 总是胜出);fail-loud 收窄为 DCP + pre-dist-init,并叫出合成默认值。 · 已解决

detokenizer / launcher 进程不 publish 的例外 正确性

Codex 两条评论:`run_detokenizer_process` 从不调用 publish(detokenizer_manager.py:515-537);launcher 在 Rust-server、非零 rank、multi-tokenizer 模式下也不 publish(Engine._launch_subprocesses 提前返回)。

结论:作者修复 detokenizer 例外并限定描述为 publishing process entries;launcher 未见明确回复,r3 disposition 判定 clean,但该分支仍建议后续验证。 · 已解决

multimodal processor 的 last-publish-wins 漏洞 正确性

Codex 指出 `BaseMultimodalProcessor.process_mm_data()` 仍通过 `get_server_args()` 读 `base_gpu_id` / `rl_on_policy_target`(base_processor.py:538-544),多 Engine 共享进程时会读到最新发布的值。

结论:作者在 per-instance 边界小节中将其标注为已知 last-publish-wins hole,不作为可复制模式;代码层未改。 · 已解决

namespace 记录的编译盲区与 parallel 例外 设计

Codex 指出 `SGLANG_ROLE_NAMESPACES=record` 在 torch.compile 追踪代码内跳过读取记录,会产出不完整的 ROLE_NAMESPACE_SETS;且 `ParallelContext.__getattr__` 直读 bag、parallel 不在 ROLE_NAMESPACE_SETS 中,审计与强制都覆盖不到。

结论:record 模式说明补充 "audit with compilation disabled";parallel 审计例外未见明确闭合记录,文档以 dual semantics 方式另行说明。 · 已解决

风险与影响

本 PR 不触碰任何运行时代码,但存在以下风险:

  • 文档与实现同步风险(主要):SKILL.md 描述的是迁移中期状态——ServerArgs.override 正在被 writer ratchet 逐步淘汰、launcher 等进程的发布行为尚未完全收敛。后续 PR 一旦完成 writer 迁移或改变 launcher 行为,这份文档会再次失真;纯文档没有 CI 测试保护,只能靠人工 review 维持。
  • 误导迁移风险:若读者按文档把 detokenizer / launcher 侧代码迁移到 bag 访问器,会直接触发 ValueError: config namespace ... not published。文档已尽力标注例外,但 launcher 分支的闭合情况在 review 中未见明确记录。
  • 已知残留BaseMultimodalProcessor.process_mm_data() 的 last-publish-wins 漏洞被文档标记为已知,但这属于代码层问题,文档只能减轻影响、不能根治。
  • 无回归/性能/安全风险:不涉及任何运行时逻辑。

SKILL.md 是 Claude Code 编写 SGLang 代码时的必读指南,本次重写直接影响后续所有接触 server_args / 配置相关代码的开发者与 AI agent 的行为:

  • 对团队:确保新贡献不再按已废弃的 resolve-at-end 契约往 ServerArgs.override 上写,减少配置模型迁移的返工成本。
  • 对系统:零运行时影响。
  • 对迁移栈:作为 RFC #30696 的 4/4 收尾,补齐了文档债,使配置命名空间迁移形成闭环。
纯文档变更无代码防护 描述易随迁移推进失真 launcher 发布例外未完全闭合 mm processor 已知 last-publish-wins 漏洞

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论