# PR #53071 完整报告

- 仓库：`vllm-project/vllm`
- 标题：[Bugfix] Return HTTP 400 instead of 501 for unknown chat roles in DeepSeek encoders
- 合并时间：2026-08-20 17:23
- 原文链接：http://prhub.com.cn/vllm-project/vllm/pull/53071

---

# 执行摘要

- 一句话：DeepSeek 未知角色返回 400 而非 501
- 推荐动作：该 PR 值得精读，因为它展示了如何处理客户端输入错误与 HTTP 状态码的映射，以及如何通过测试保证行为一致性。值得关注的设计决策是异常类型与错误码的对应关系，以及参数化测试覆盖多个模块的做法。

# 功能与动机

PR body 指出：DeepSeek V3.2/V4 chat-template 编码器对未知角色（如大写 SYSTEM）抛出 NotImplementedError，OpenAI serving 层将其映射为 HTTP 501，而未知角色属于客户端输入错误，应返回 HTTP 400。V3.2 路径自 #29837 引入，V4 路径自 #40860 引入，本次统一行为。

# 实现拆解

1. **修改异常类型**：在 `vllm/tokenizers/deepseek_v32_encoding.py` 和 `vllm/tokenizers/deepseek_v4_encoding.py` 的 `render_message()` 函数中，将 else 分支的 `raise NotImplementedError(f"Unknown role: {role}")` 改为 `raise ValueError(f"Invalid role: {role}")`。
2. **调整错误消息措辞**：根据 reviewer DarkLight1337 建议，将错误消息从 "Unknown role" 改为 "Invalid role"，使语义更准确。
3. **新增测试覆盖**：
 - `tests/test_request_input_bounds.py` 新增 `test_encode_messages_unknown_role_raises_value_error`，参数化覆盖 `deepseek_v32` 和 `deepseek_v4` 编码模块，断言抛出 ValueError 且消息匹配 "Invalid role: SYSTEM"。
 - `tests/tokenizers_/test_deepseek_v4.py` 新增 `test_deepseek_v4_unknown_role_raises_value_error`，通过 `apply_chat_template` 包装验证同样行为。
4. **测试验证**：PR body 中手动验证了两个编码模块 standalone 均通过，且正常编码与 lowercase system 角色行为不受影响。

关键文件：
- `tests/test_request_input_bounds.py`（模块 测试；类别 test；类型 test-coverage；符号 test_encode_messages_unknown_role_raises_value_error）: 新增参数化测试覆盖 deepseek_v32 和 deepseek_v4 编码模块，验证未知角色抛出 ValueError，是行为验证的关键。
- `tests/tokenizers_/test_deepseek_v4.py`（模块 测试；类别 test；类型 test-coverage；符号 test_deepseek_v4_unknown_role_raises_value_error）: 新增测试通过 apply_chat_template 包装验证未知角色抛出 ValueError，覆盖了更深层调用链。
- `vllm/tokenizers/deepseek_v32_encoding.py`（模块 编码器；类别 source；类型 core-logic）: 核心源码变更：将未知角色的异常从 NotImplementedError 改为 ValueError，并调整消息。
- `vllm/tokenizers/deepseek_v4_encoding.py`（模块 编码器；类别 source；类型 core-logic）: 核心源码变更：与 v32 相同，将未知角色异常改为 ValueError。

关键符号：render_message

## 关键源码片段

### `tests/test_request_input_bounds.py`

新增参数化测试覆盖 deepseek_v32 和 deepseek_v4 编码模块，验证未知角色抛出 ValueError，是行为验证的关键。

```python
# tests/test_request_input_bounds.py
@pytest.mark.parametrize(
    "encoding_module",
    ENCODING_MODULES,
    ids=["deepseek_v32", "deepseek_v4"],
)
def test_encode_messages_unknown_role_raises_value_error(encoding_module):
    # 非法角色（如大写 SYSTEM）属于客户端错误，应抛出 ValueError
    # 以便 OpenAI serving 层映射为 HTTP 400，而不是 NotImplementedError（HTTP 501）。
    with pytest.raises(ValueError, match="Invalid role: SYSTEM"):
        encoding_module.encode_messages(
            [{"role": "SYSTEM", "content": "Hello"}],
            thinking_mode="chat",
        )

```

### `tests/tokenizers_/test_deepseek_v4.py`

新增测试通过 apply_chat_template 包装验证未知角色抛出 ValueError，覆盖了更深层调用链。

```python
# tests/tokenizers_/test_deepseek_v4.py
def test_deepseek_v4_unknown_role_raises_value_error():
    # 非法角色属于客户端错误：必须以 ValueError 形式抛出（OpenAI serving 层映射为 HTTP 400），
    # 而不是 NotImplementedError（映射为 HTTP 501）。
    with pytest.raises(ValueError, match="Invalid role: SYSTEM"):
        _tokenizer().apply_chat_template(
            [{"role": "SYSTEM", "content": "Hello"}],
            tokenize=False,
        )

```

### `vllm/tokenizers/deepseek_v32_encoding.py`

核心源码变更：将未知角色的异常从 NotImplementedError 改为 ValueError，并调整消息。

```python
# vllm/tokenizers/deepseek_v32_encoding.py
def render_message(
    msg: dict[str, Any],
    index: int,
    messages: list[dict[str, Any]],
    thinking_mode: str,
    drop_thinking: bool,
    add_default_bos_token: bool,
    is_prefix: bool,
    last_user_idx: int,
) -> str:
    role = msg.get("role")
    # ... 省略其他分支处理逻辑 ...
    else:
        # 未知角色属于客户端输入错误，抛出 ValueError 让 serving 层返回 HTTP 400
        raise ValueError(f"Invalid role: {role}")

```

# 评论区精华

评审中 DarkLight1337 建议将错误消息从 "Unknown role" 改为 "Invalid role"，作者 JC-ut0 同意并修改。其他评论为合并触发 CI 和 bot 辅助，无重大争议。

- 错误消息措辞建议 (style): 作者同意并修改，消息改为 "Invalid role"。

# 风险与影响

- 风险：变更仅影响 `render_message()` 中对未知角色的异常类型，属于边缘路径修改，风险低。但需注意：此改动可能影响依赖异常类型的行为，例如调用方捕获 NotImplementedError 或依赖异常消息的测试或监控，需检查项目内是否有其他对 "Unknown role" 字符串的引用。
- 影响：影响范围限于 DeepSeek V3.2/V4 编码器，对用户而言，发送未知角色请求时错误码从 501 变为 400，更符合语义；对系统而言，无性能或安全影响。团队需注意错误消息变更可能影响依赖字符串匹配的日志或监控。
- 风险标记：错误消息变更可能影响依赖字符串的监控或日志

# 关联脉络

- PR #29837 DeepSeek V3.2 encoding module introduction: PR body 提及 V3.2 路径自该 PR 引入，本次修改其异常行为。
- PR #40860 DeepSeek V4 encoding module introduction: PR body 提及 V4 路径自该 PR 引入，本次修改其异常行为。