Prhub

#42396 [Feature] Add structured output and effort support to Anthropic Messages API

原始 PR 作者 chaunceyjiang 合并时间 2026-05-28 20:06 文件变更 3 提交数 2 评论 12 代码增减 +78 / -0

执行摘要

为 Anthropic API 添加结构化输出和 effort 参数支持

用户需求(关联 Issue #8907)希望在 vLLM 的 Anthropic 兼容 API 中支持结构化输出和 effort 参数,以更好地控制推理行为和输出格式,参考 Anthropic 官方文档(https://platform.claude.com/docs/en/build-with-claude/structured-outputs 和 https://platform.claude.com/docs/en/build-with-claude/effort)。

该 PR 可以精读以了解如何扩展 Anthropic API 入口,特别关注 _handle_output_config 的转换模式。设计决策方面,注意 effort 被放在 output_config 内而非顶层,与官方规范略有偏离,但保持了内部一致性。测试用例提供了良好的参考。

讨论亮点
  • effort 参数设计争议:gemini-code-assist[bot] 指出 Anthropic 官方 API 中 effort 应为顶层参数而非嵌套于 output_config,且有效值仅为 low/medium/high。作者未采纳建议,合并者 DarkLight1337 批准合并,设计保持不变。
  • 功能范围讨论:DarkLight1337 询问 effort 与结构化输出是否属同一功能,作者解释是一并实现的,DarkLight1337 要求更新 PR 标题描述,作者照做。
  • 空检查健壮性:gemini-code-assist[bot] 建议使用 is not None 而非 if json_schema: 以避免空字典误跳过,此建议未被采纳。

实现拆解

  1. 协议模型扩展vllm/entrypoints/anthropic/protocol.py):新增 AnthropicJsonOutputFormat(包含 json_schematype)和 AnthropicOutputConfig(包含 effortformat)两个 BaseModel,并在 AnthropicMessagesRequest 中添加可选字段 output_config: AnthropicOutputConfig | None
  2. 请求转换逻辑vllm/entrypoints/anthropic/serving.py):在 _convert_anthropic_to_openai_request 中调用新方法 _handle_output_config。该方法提取 output_config.formatoutput_config.effort,分别映射到 OpenAI 的 ResponseFormat(含 JsonSchemaResponseFormat)和 reasoning_effort;对 AnthropicCountTokensRequest 类型直接返回。
  3. 端到端测试tests/entrypoints/anthropic/test_messages.py):新增 test_anthropic_structured_output,通过 Anthropic 客户端发送含 output_config 的请求,验证返回 JSON 包含所需字段。
文件 模块 状态 重要度
vllm/entrypoints/anthropic/serving.py API 入口 modified 6.89
vllm/entrypoints/anthropic/protocol.py 数据模型 modified 6.5
tests/entrypoints/anthropic/test_messages.py 测试 modified 5.5

关键符号

_handle_output_config test_anthropic_structured_output

关键源码片段

vllm/entrypoints/anthropic/serving.py core-logic

核心业务逻辑,新增 `_handle_output_config` 方法转换 output_config 和 effort 到 OpenAI 请求格式。

# vllm/entrypoints/anthropic/serving.py (partial)@classmethod
def _handle_output_config(
    cls,
    req: ChatCompletionRequest,
    anthropic_request: AnthropicMessagesRequest | AnthropicCountTokensRequest,
) -> None:
    """处理输出配置,如输出格式(JSON Schema)和推理努力程度"""
    # 计数 token 请求不需要输出配置
    if isinstance(anthropic_request, AnthropicCountTokensRequest):
        return
​
    output_config: AnthropicOutputConfig | None = anthropic_request.output_config
    # 检查是否有 JSON Schema 格式配置
    if output_config and output_config.format and output_config.format.json_schema:
        req.response_format = ResponseFormat(
            type=output_config.format.type,
            json_schema=JsonSchemaResponseFormat(
                schema=output_config.format.json_schema,
                name=output_config.format.type, # 使用 "json_schema" 作为默认名称
            ),
        )
    # 检查是否有推理努力程度配置
    if output_config and output_config.effort is not None:
        req.reasoning_effort = output_config.effort
vllm/entrypoints/anthropic/protocol.py core-logic

新增 `AnthropicJsonOutputFormat` 和 `AnthropicOutputConfig` 模型,扩展 `AnthropicMessagesRequest` 包含 `output_config` 字段。

# vllm/entrypoints/anthropic/protocol.py (partial)class AnthropicJsonOutputFormat(BaseModel):
    """JSON 输出格式配置"""
    json_schema: dict[str, Any] | None = Field(default=None, alias="schema")
    type: Literal["json_schema"] = "json_schema"
​
​
class AnthropicOutputConfig(BaseModel):
    """模型输出配置,包含输出格式和推理努力程度"""
    # 注意:官方 Anthropic API 仅支持 low/medium/high,此处额外包含 xhigh/max
    effort: Literal["low", "medium", "high", "xhigh", "max"] | None = None
    format: AnthropicJsonOutputFormat | None = None
​
​
class AnthropicMessagesRequest(BaseModel):
    # ... 其他字段 ...
    output_config: AnthropicOutputConfig | None = None # 新增字段

评论区精华

effort 参数置于 output_config 内部与官方规范不符 设计

gemini-code-assist[bot] 指出 Anthropic API 中 effort 是顶层参数,不应嵌套在 output_config 中,且有效值仅为 low/medium/high。

结论:作者未修改,合并者 DarkLight1337 批准,按现有设计合并。 · 已解决

reasoning effort 与结构化输出是否为同一功能 question

DarkLight1337 询问为何将 effort 与结构化输出合并在同一 PR 中。

结论:作者解释是一并实现的,DarkLight1337 要求更新 PR 标题描述,作者照做。 · 已解决

json_schema 空字典检查应使用 is not None 正确性

gemini-code-assist[bot] 建议使用 is not None 而非 truthy 检查,以避免空字典被跳过。

结论:未被采纳。 · 已解决

风险与影响

  • 兼容性风险effort 支持 xhighmax,但 Anthropic 官方仅定义 lowmediumhigh,使用非标准值可能导致未来行为不确定。
  • 转换逻辑风险output_config.format.json_schema 使用 truthy 检查,空字典 {} 会被跳过,可能使用户意图未生效。
  • 交互风险output_configtool_choice/tools 的交互未经测试,同时使用时可能出现冲突。
  • 影响范围:仅 Anthropic API 入口,不影响核心引擎或其他 API,风险可控。
  • 用户:使用 vLLM Anthropic API 的用户现在可以指定 output_config 参数,包括 format(JSON Schema)和 effort(推理努力程度),扩展了功能性。
  • 系统:对核心引擎无影响,仅在 API 入口层进行参数映射,性能开销可忽略。
  • 团队:为后续 Anthropic API 的扩展(如其他输出格式)奠定了基础。
非标准 effort 值 空 json_schema 潜在问题 与 tool calls 交互未测试

关联 Issue

#8907 [Usage]: claude code+vllm-ascend+deepseek-v4-flash,how to enable thinking mode with "high" or "max"?

完整报告

参与讨论