Prhub

#32981 bump dynamo-tokenizers to 1.7.0

原始 PR 作者 rainj-me 合并时间 2026-08-01 06:02 文件变更 4 提交数 2 评论 1 代码增减 +946 / -133

执行摘要

升级 dynamo-tokenizers 至 1.7.0 并适配 JSON 键序变化

PR body 仅说明目标是 bump dynamo-tokenizers 到 1.7.0。从原 Cargo.toml 注释可见此前 pin 在 =1.5.3 的原因:1.7.0 会传递启用 serde_json/preserve_order,从而重排每个 JSON 对象的键序。本次升级需要同步适配这一行为变化,包括调整依赖锁文件位置和内部测试的等价性断言方式。

值得快速精读 frame.rs 的测试调整和 finish_reason.rs 的 Box 化两处改动,它们展示了依赖升级时如何识别并适配隐性行为变化(键序、枚举大小)。对维护 rust server 的工程师有参考价值;对只关注模型性能的读者可跳过。

讨论亮点

PR 没有任何实质性的 review 评论,仅 ishandhanani 直接 approve。issue 评论是 Gemini Code Assist 自动公告(停止服务),与本次变更无关。因此没有可提炼的技术交锋;设计权衡主要沉淀在代码注释中:原 pin 注释解释了为何避免 1.7.0,升级后测试策略从字节级等价放宽为文档级等价。

实现拆解

  1. 解除版本钉死并升级依赖rust/sglang-server/Cargo.tomldynamo-tokenizers=1.5.3 改为 1.7.0,并移除旧注释;新注释说明 dynamo-tokenizers 依赖 hf-hub,需要一起升级版本。
  2. 适配 preserve_order 对 JSON 键序的影响rust/sglang-server/src/api_server/frame.rs 中,cumulative_frame_json 的等价性测试不再断言字节级一致,而是新增 as_json 辅助函数把 frame 解析为 serde_json::Value 后按 JSON 文档语义比较;相应注释从强调 BTreeMap 字母序改为说明『按约定排序』,避免 preserve_order 下键序不稳定导致测试失败。
  3. 控制 FinishReason 枚举大小rust/sglang-server/src/message/finish_reason.rsFinishReason::Unknownserde_json::Map<String, serde_json::Value> 改为 Box<...>,因为 preserve_order 使 serde_json::Map 内存占用增大,直接内嵌会撑大每个 ChunkEvent(原注释提到 chunk_event_frame_stays_small 的约束)。
  4. Cargo.lock 移入 workspace 根目录:第二个 commit 把 rust/sglang-server/Cargo.lock 重命名为 rust/Cargo.lock,统一管理包含 sglang-server 在内的多个 crate 的依赖树;lock 文件新增大量传递依赖(如 basetenkenizer、chrono、axum 0.7 等),并同步 hf-hub 版本。
  5. 测试配套:没有新增独立测试文件,但 frame.rs 内嵌测试从字节比较改为文档比较,并补了 println! 调试输出(可能为临时遗留);Cargo.lock 的大幅变更本身反映了新依赖图的解析结果。
文件 模块 状态 重要度
rust/sglang-server/Cargo.toml 构建配置 modified 4.11
rust/sglang-server/src/api_server/frame.rs 帧组装 modified 6.91
rust/sglang-server/src/message/finish_reason.rs 消息模型 modified 4.32
rust/Cargo.lock 依赖锁定 renamed 5.22

关键符号

as_json cumulative_frame_json

关键源码片段

rust/sglang-server/Cargo.toml configuration

依赖升级的入口:解除 dynamo-tokenizers 的精确 pin,升级到 1.7.0,并更新了说明注释。

# rust/sglang-server/Cargo.toml — 依赖段
[dependencies]
# 此前为了规避 1.7.0 传递启用 serde_json/preserve_order 导致 JSON 键序重排,
# 这里被钉死在 =1.5.3;本次 PR 解除钉死并升级到 1.7.0。
# dynamo-tokenizers 依赖 hf-hub,两个版本需要一起升级。
dynamo-tokenizers = "1.7.0"
hf-hub = { version = "0.4", default-features = false }
rust/sglang-server/src/api_server/frame.rs test-coverage

核心适配点:把累计帧 JSON 的等价性测试从字节级比较改为文档级比较,新增 as_json 辅助函数,并更新相关注释。

// rust/sglang-server/src/api_server/frame.rs — 测试辅助与等价性断言// 新增辅助函数:把 frame 字符串解析成 JSON 文档再比较,
// 不再要求字节级一致(preserve_order 后键序不再固定为字母序)。
fn as_json(frame: &str) -> serde_json::Value {
    serde_json::from_str(frame).expect("a frame must be valid JSON")
}#[test]
fn cumulative_frame_json_matches_serde() {
    // ... 构造 deltas 的代码省略 ...
    for index in [None, Some(3usize)] {
        let mut acc = OutputAccumulator::default();
        for d in &deltas {
            acc.fold(d);
            let fast = cumulative_frame_json(&acc, "7", index).expect("no extras → fast path");
            let slow = tag_value(frame_value(acc.snapshot(), "7"), index);
            // 字节比较改为文档等价比较:键序变化不再导致断言失败
            assert_eq!(
                as_json(&fast),
                as_json(&slow),
                "index={index:?} text={:?}",
                acc.snapshot().text
            );
        }
    }
}
rust/sglang-server/src/message/finish_reason.rs core-logic

FinishReason::Unknown 变体从内嵌 Map 改为 Box<Map>,避免 preserve_order 使 Map 变大后撑大每个 ChunkEvent。

// rust/sglang-server/src/message/finish_reason.rs
/// 终止原因枚举。外层 untagged,保证遇到 Python 侧新增的 type 时
/// 不会让整个 header 解码失败(那会拖垮整个 batch)。
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum FinishReason {
    Known(FinishKind),
    /// 未知类型保留原始 map 原样回显。
    /// Box 化:preserve_order 使 serde_json::Map 内存变大,
    /// 避免撑大每个 ChunkEvent(参考 chunk_event_frame_stays_small)。
    Unknown(Box<serde_json::Map<String, serde_json::Value>>),
}

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  1. JSON 键序行为变化:serde_json 启用 preserve_order 后,meta_info 及各 logprob 字段的键不再按字母序输出。若 Python 侧或外部客户端依赖固定键序(如字节级签名、顺序敏感解析),可能出现兼容性问题;不过 JSON 语义解析通常不依赖键序。
  2. 测试强度下降:frame.rs 的等价性断言从字节级放宽为文档级,虽然语义更稳健,但会掩盖键序或转义格式上的回归;且测试中遗留了 println! 调试输出,应清理。
  3. 依赖锁定策略变化:dynamo-tokenizers 从精确版本 =1.5.3 改为 semver 范围 1.7.0,后续小版本升级可能自动引入新行为,失去原先的钉死保护。
  4. 构建影响:Cargo.lock 移入 workspace 并引入大量新传递依赖(basetenkenizer、chrono 等),会增加 rust server 的编译时间和二进制体积;hf-hub 版本联动变化也可能影响模型加载行为。

对使用 rust server(如 --enable-rust-server 部署)的用户,tokenizer 升级到 1.7.0,输出 JSON 的键顺序不再固定为字母序,但内容语义不变,大多数客户端无感;对 SGLang 团队,需要知晓 serde_json preserve_order 的全局影响,未来写字节级断言时需改用文档比较;对构建系统,workspace 级 lock 统一了依赖解析,影响所有链接 dynamo-tokenizers 的 crate。整体影响局限在 rust server 模块,不涉及 Python 调度核心与模型 forward 逻辑。

JSON 键顺序行为变化 依赖锁定策略调整 Cargo.lock 移入 workspace 测试强度从字节级降为文档级

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论