Prhub

#20930 feat(multimodal_gen): plumb max_sequence_length via diffusers_kwargs

原始 PR 作者 Religious-J 合并时间 2026-05-13 16:32 文件变更 8 提交数 11 评论 12 代码增减 +42 / -4

执行摘要

通过 diffusers_kwargs 传递 max_sequence_length 控制文本编码长度

Image generation requests sometimes need to control text tokenizer sequence length (e.g. via Diffusers-style kwargs or API extensions). Previously, diffusers_kwargs was dropped when building SamplingParams, and several pipelines hard-coded max_length for chat-template / tokenizer calls, so callers could not align tokenization with encoder capacity or downstream expectations.

值得精读,特别是如何通过 is_flux_v1() 方法将模型特殊逻辑封装到 PipelineConfig 中,避免在核心编码阶段做 model-specific 判断。设计决策平衡了通用性和正确性。建议添加测试覆盖主要 pipeline 的 max_sequence_length 路径。

讨论亮点
  1. Flux v1 CLIP context 覆盖风险:review 指出直接对所有 encoder 设置 max_length 会破坏 Flux v1 的 CLIP(固定 77 tokens)。通过添加 is_flux_v1() 方法并跳过 encoder 0 解决。
  2. is_flux_v1 方法设计争议:DefTruth 认为将模型特定方法放入基类 PipelineConfig 不通用,mickqian 回应应避免按模型命名,但可以按语义命名。最终保留了 is_flux_v1
  3. QwenImage padding 模式变更:自动将 padding 从 True 改为 max_length,可能导致小 prompt 场景下的性能回归,但功能正确。

实现拆解

  1. SamplingParams 保留 diffusers_kwargs:在 sampling_params.py 中添加 diffusers_kwargs 字段,不再在合并用户 kwargs 时丢弃。
  2. OpenAI image API 传递 diffusers_kwargs:在 image_api.py 中将 request.diffusers_kwargs 传入 build_sampling_params
  3. prepare_request 提取 max_sequence_length:在 utils.py 中,当 diffusers_kwargs 包含 max_sequence_length 时,将其设置到 req.max_sequence_length
  4. TextEncodingStage 使用 max_length:在 text_encoding.pyforward 中从 batch 获取 max_sequence_length,传递给 encode_text;在 encode_text 内部根据 max_length 设置 tok_kwargs,并针对 Flux v1 的 CLIP encoder (index 0) 跳过覆盖,以避免固定 77 token 上下文被破坏。
  5. 各 pipeline config 适配 tokenize_prompt
    • base.py 添加默认 is_flux_v1() 返回 False。
    • flux.pyFluxPipelineConfigFlux2PipelineConfig 分别覆盖 is_flux_v1() 返回 True/False;Flux2PipelineConfig.tokenize_prompt 使用 tok_kwargs.pop("max_length", 512) 替换硬编码值。
    • qwen_image.py 重写 tokenize_prompt 方法,根据 max_length 设置 padding 模式,默认 1024。
    • zimage.py 类似适配。
文件 模块 状态 重要度
python/sglang/multimodal_gen/configs/pipeline_configs/qwen_image.py 模型配置 modified 6.45
python/sglang/multimodal_gen/runtime/pipelines_core/stages/text_encoding.py 编码流水线 modified 6.13
python/sglang/multimodal_gen/configs/pipeline_configs/flux.py 模型配置 modified 6.16
python/sglang/multimodal_gen/configs/pipeline_configs/base.py 模型配置 modified 6.05
python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py API modified 5.61
python/sglang/multimodal_gen/runtime/entrypoints/utils.py 请求处理 modified 5.26
python/sglang/multimodal_gen/configs/pipeline_configs/zimage.py 模型配置 modified 5.11
python/sglang/multimodal_gen/configs/sample/sampling_params.py 采样参数 modified 4.58

关键符号

tokenize_prompt encode_text is_flux_v1 prepare_request build_sampling_params forward (TextEncodingStage)

关键源码片段

python/sglang/multimodal_gen/configs/pipeline_configs/qwen_image.py core-logic

新增 tokenize_prompt 方法,根据 max_length 切换 padding 模式并设定默认值 1024,是核心实现之一。

def tokenize_prompt(self, prompts: list[str], tokenizer, tok_kwargs) -> dict:
    # 总是开启截断
    tok_kwargs.setdefault("truncation", True)
​
    if tok_kwargs.get("max_length") is not None:
        # 如果外部指定了 max_length,使用固定长度 padding
        tok_kwargs["padding"] = "max_length"
    else:
        # 否则使用默认 1024,并保持原有 padding 为 True(动态 padding)
        tok_kwargs.setdefault("max_length", 1024)
        tok_kwargs["padding"] = True
    return tokenizer(prompts, **tok_kwargs)
python/sglang/multimodal_gen/runtime/pipelines_core/stages/text_encoding.py core-logic

文本编码核心阶段,读取 batch.max_sequence_length 并传递给 encode_text,以及在 encode_text 中根据 max_length 注入 tok_kwargs 并跳过 Flux v1 CLIP。

# 在 forward 方法中
max_seq_length = getattr(batch, "max_sequence_length", None)
(
    prompt_embeds_list,
    prompt_masks_list,
    pooler_embeds_list,
    prompt_embeds_masks_list,
    prompt_seq_lens_list,
) = self.encode_text(
    prompt_text,
    server_args,
    encoder_index=all_indices,
    return_attention_mask=True,
    max_length=max_seq_length, # 传入请求指定的 max_length
)# 在 encode_text 方法内部遍历 encoder 时
# 准备 tokenizer 参数
# 如果指定了 max_length 且当前 encoder 不是 Flux v1 的 CLIP(索引 0),则覆盖 max_length
is_flux_v1 = server_args.pipeline_config.is_flux_v1()
if max_length is not None and not (is_flux_v1 and i == 0):
    tok_kwargs["max_length"] = max_length
python/sglang/multimodal_gen/configs/pipeline_configs/flux.py core-logic

Flux 和 Flux2 pipeline 的 is_flux_v1 方法定义,以及 Flux2 tokenize_prompt 对 effective_max_length 的支持。

# FluxPipelineConfig (Flux v1)
def is_flux_v1(self) -> bool:
    return True# Flux2PipelineConfig
def is_flux_v1(self) -> bool:
    return Falsedef tokenize_prompt(self, prompts: list[str], tokenizer, tok_kwargs) -> dict:
    messages = build_flux2_text_messages(prompts)
    # 从 tok_kwargs 中提取 max_length,不存在则使用默认 512
    effective_max_length = tok_kwargs.pop("max_length", 512)
    inputs = tokenizer.apply_chat_template(
        messages,
        add_generation_prompt=False,
        tokenize=True,
        return_dict=True,
        return_tensors="pt",
        padding="max_length",
        truncation=True,
        # 2048 from official github repo, 512 from diffusers
        max_length=effective_max_length,
    )
    return inputs

评论区精华

Flux v1 CLIP context 被覆盖风险 正确性

chatgpt-codex-connector[bot] 指出在 Flux 模型上对 CLIP encoder 设置 max_sequence_length 会导致崩溃,因为 CLIP 固定 77 tokens。

结论:通过添加 is_flux_v1() 方法并在 encode_text 中跳过 encoder 0 解决。 · 已解决

is_flux_v1 方法设计争议 设计

DefTruth 认为将 is_flux_v1 放在基类 PipelineConfig 不通用,mickqian 认为应避免按模型命名但应按语义命名。

结论:最终保留了 is_flux_v1 方法,声明返回 bool。 · 已解决

QwenImage padding 模式变更导致性能潜在回归 性能

chatgpt-codex-connector[bot] 指出将 padding 从 True 改为 max_length 会导致短 prompt 也按固定长度 padding,增加额外计算。

结论:当前实现保持功能正确,但未优化默认路径的性能。review 建议恢复动态 padding 但此 PR 未采用。 · unresolved

风险与影响

  1. Flux v1 兼容性:如果用户设置了 max_sequence_length,CLIP encoder 可能被传递过大的 max_length 导致异常。当前通过 is_flux_v1() 跳过索引 0 缓解,但其他模型类似问题未全覆盖。
  2. QwenImage 性能回归:默认情况下的 padding 从动态变为固定 max_length,对于短 prompt 会增加计算和内存开销。
  3. 缺少测试覆盖:此 PR 没有添加测试用例,特别是涉及 max_sequence_length 路径的自动化测试(包括 Flux、QwenImage、ZImage)。
  4. SamplingParams 接口变化:新增 diffusers_kwargs 字段,若其他模块直接构造 SamplingParams 可能遗漏。

用户可以通过 API 的 diffusers_kwargs.max_sequence_length 控制文本编码序列长度,便于适配不同模型能力。默认行为无变化。对系统而言,文本编码阶段增加了动态长度路径,但只会在显式传入时触发。团队需要关注后续 pipeline 实现是否统一使用 tok_kwargs 中的 max_length,以及 is_flux_v1 这种模型特定方法是否会扩散。

核心路径变更 缺少测试覆盖 兼容性风险

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论