Prhub

#40339 [Bugfix] Normalize malformed dict prompts that carry token IDs in `prompt`

原始 PR 作者 Alchuang22-dev 合并时间 2026-04-21 15:44 文件变更 3 提交数 3 评论 5 代码增减 +57 / -2

执行摘要

修复渲染器路径中格式错误的字典提示处理,避免 tokenizer 内部异常。

根据 issue #40292,在 embedding 端点中观察到 TypeError: TextEncodeInput must be Union[TextInputSequence, Tuple[InputSequence, InputSequence]] 错误,原因是请求传递了包含 token IDs 的字典提示。PR body 指出,这些格式错误的输入会绕过提示解析,导致 Hugging Face tokenization 错误,本修复旨在在预处理边界捕获此类问题。

该 PR 值得精读,尤其是预处理边界验证的设计决策,展示了如何在早期阶段捕获非法输入以避免深层错误,同时强调了代码鲁棒性和错误处理的重要性。

讨论亮点

review 中,gemini-code-assist[bot] 建议使用更高效的字典操作进行规范化,但 DarkLight1337 提议直接拒绝输入以避免不必要的复杂性和潜在错误。最终,作者 Alchuang22-dev 决定拒绝并返回 TypeError,这一决策简化了实现并明确了错误处理边界。

实现拆解

  1. 添加验证函数:在 vllm/renderers/inputs/preprocess.py 中新增 _validate_prompt_dict 函数,检查字典中 "prompt" 字段是否为字符串,若不是则抛出 TypeError,确保早期验证。
  2. 集成到解析函数:在 parse_dec_only_prompt_parse_enc_prompt_parse_dec_prompt 中调用 _validate_prompt_dict,覆盖所有字典提示解析路径,防止非法输入进入下游。
  3. 防御性检查:在 vllm/renderers/base.py_tokenize_singleton_prompt 和异步版本中添加检查,如果 "prompt" 字段存在且非字符串,抛出清晰错误,增强渲染器路径的鲁棒性。
  4. 测试配套:在 tests/renderers/inputs/test_preprocess.py 中添加三个测试用例(如 test_parse_dec_only_prompt_rejects_non_string_prompt_field),覆盖非字符串 prompt 字段的拒绝场景,确保修复的正确性和覆盖率。
文件 模块 状态 重要度
vllm/renderers/inputs/preprocess.py 渲染器预处理 modified 6.83
vllm/renderers/base.py 渲染器基础 modified 5.91
tests/renderers/inputs/test_preprocess.py 测试覆盖 modified 5.86

关键符号

_validate_prompt_dict parse_dec_only_prompt _parse_enc_prompt _parse_dec_prompt _tokenize_singleton_prompt

关键源码片段

vllm/renderers/inputs/preprocess.py core-logic

核心逻辑文件,新增验证函数并集成到解析流程,直接影响输入预处理边界。

def _validate_prompt_dict(prompt: Mapping[str, object]) -> None:
    """Reject malformed dict prompts before renderer tokenization."""
    if (
        "prompt" not in prompt
        or "prompt_token_ids" in prompt
        or "prompt_embeds" in prompt
    ):
        return # 如果 prompt 字段不存在,或已有 token IDs 或 embeds,则跳过验证
    if not isinstance(prompt["prompt"], str):
        raise TypeError("Prompt text should be a string") # 确保 prompt 字段是字符串,否则抛出错误
vllm/renderers/base.py core-logic

渲染器基础层,添加防御性检查,确保在 tokenization 前验证输入格式。

def _tokenize_singleton_prompt(
    self,
    prompt: SingletonDictPrompt,
    params: TokenizeParams,
) -> SingletonTokPrompt:
    if "prompt_token_ids" not in prompt and "prompt_embeds" not in prompt:
        if not isinstance(prompt.get("prompt"), str):
            raise TypeError(
                "Expected prompt['prompt'] to be a string before tokenization; "
                "use 'prompt_token_ids' for token ID inputs" # 提供更明确的错误消息,指导用户正确输入
            )
        prompt = params.apply_pre_tokenization(self.tokenizer, prompt)
        prompt = self._tokenize_prompt(prompt, params)
    # 其余逻辑保持不变

评论区精华

规范化 vs 拒绝格式错误的提示 设计

gemini-code-assist[bot] 建议优化规范化逻辑,但 DarkLight1337 提议直接拒绝输入以避免复杂性和潜在错误。

结论:最终决定拒绝输入并抛出 TypeError,简化实现并明确错误处理边界。 · 已解决

风险与影响

风险较低:变更主要添加验证逻辑,不改变合法输入的行为。唯一潜在风险是,如果现有代码依赖于格式错误的输入(如 {"prompt": [1, 2, 3]}),现在会抛出错误,但这正是修复的目的,且合法字符串 prompt 不受影响,确保了向后兼容性。

对用户:提供更清晰的错误消息,避免难以理解的 tokenizer 内部异常,提升调试体验。对系统:增强鲁棒性,防止格式错误输入导致崩溃或未定义行为。对团队:增加测试覆盖,提高代码质量,并为类似输入验证场景提供参考。

输入验证增强 向后兼容性风险低

关联 Issue

#40292 [Bug] TypeError: TextEncodeInput must be Union[TextInputSequence, Tuple[InputSequence, InputSequence]] on embedding endpoint (v0.19.0)

完整报告

参与讨论