Prhub

#22702 Support defer_loading field at function level for Chat Completions API

原始 PR 作者 zRzRzRzRzRzRzR 合并时间 2026-04-23 01:09 文件变更 5 提交数 17 评论 15 代码增减 +145 / -28

执行摘要

为 Chat Completions API 添加函数级 defer_loading 字段支持,实现工具延迟加载和 GLM 特定扩展。

根据PR body,添加defer_loading支持是为了让标记为defer_loading: true的工具从模型的工具列表中隐藏,并通过chat template(如GLM-5.1)处理过滤。这是一个GLM特定的扩展,用于实现工具的动态加载和跨轮次解锁,而非OpenAI API的标准功能。

建议精读此PR,特别是protocol.py中的Pydantic模型扩展和序列化逻辑,以学习如何优雅地添加可选字段并控制序列化行为。同时关注serving.py中的Anthropic集成方式,理解跨API协议映射的设计权衡。对于涉及协议扩展的项目,此PR提供了处理厂商特定扩展的实用模式。

讨论亮点

Review中,JustinTong0323指出了关键bug:在anthropic/serving.py中,item.get("name")应改为item.get("tool_name")以匹配Anthropic SDK v0.93.0的ToolReferenceBlockParam,否则tool_reference解锁路径无效。此外,讨论了测试覆盖不足、建议添加日志以便调试过滤逻辑,以及tool_choice处理中当工具被过滤时应返回错误而非静默降级。结论是bug被修复,但测试和日志建议未完全实现,且设计上明确此为GLM扩展而非OpenAI标准。

实现拆解

  1. 扩展OpenAI协议模型:在python/sglang/srt/entrypoints/openai/protocol.py中,为Function类添加defer_loading: Optional[bool]字段和自定义序列化器_serialize,确保字段仅在设置时序列化;为Tool类添加defer_loading字段和_propagate_defer_loading验证器,以从工具级别传播值到函数级别。同时新增ChatCompletionMessageContentToolReferenceBlock内容类型,用于GLM的tool_reference扩展。
  2. 集成Anthropic端点逻辑:在python/sglang/srt/entrypoints/anthropic/serving.py中,修改工具转换逻辑以传递defer_loading字段,并添加tool_reference内容类型的处理,将Anthropic的tool_name字段映射为name以匹配聊天模板。同时调整tool_choice处理,确保当工具被过滤时正确处理。
  3. 更新Anthropic协议定义:在python/sglang/srt/entrypoints/anthropic/protocol.py中,为AnthropicContentBlock添加tool_reference类型,并为AnthropicTool添加defer_loading字段,以支持请求解析。
  4. 传递tool_reference到模板:在python/sglang/srt/parser/jinja_template_utils.py中,添加对tool_reference内容类型的处理,使其能通过模板路径传递,供聊天模板使用。
  5. 添加测试覆盖:在test/registered/unit/entrypoints/openai/test_protocol.py中,新增TestFunctionDeferLoading测试类,验证defer_loading字段的序列化、传播和tool_reference内容类型的接受性。
文件 模块 状态 重要度
python/sglang/srt/entrypoints/openai/protocol.py 协议模型 modified 7.66
test/registered/unit/entrypoints/openai/test_protocol.py 协议测试 modified 6.39
python/sglang/srt/entrypoints/anthropic/serving.py Anthropic 服务 modified 6.82
python/sglang/srt/entrypoints/anthropic/protocol.py Anthropic 协议 modified 4.91
python/sglang/srt/parser/jinja_template_utils.py 模板解析 modified 4.73

关键符号

_serialize _propagate_defer_loading

关键源码片段

python/sglang/srt/entrypoints/openai/protocol.py core-logic

核心协议模型变更,添加 defer_loading 字段、tool_reference 内容类型及序列化逻辑,是功能实现的基础。

class Function(BaseModel):
    """Function descriptions."""
    description: Optional[str] = Field(default=None, examples=[None])
    name: str
    parameters: Optional[object] = None
    strict: bool = False # 保持默认值以确保下游代码(如 function_call_parser)看到预期形状
    defer_loading: Optional[bool] = None # 新增字段,用于标记工具是否延迟加载
​
    @model_serializer(mode="wrap")
    def _serialize(self, handler):
        data = handler(self)
        if self.defer_loading is None:
            data.pop("defer_loading", None) # 当 defer_loading 为 None 时,从序列化输出中移除该字段,避免污染 JSON
        return dataclass Tool(BaseModel):
    """Function wrapper."""
    type: str = Field(default="function", examples=["function"])
    function: Function
    defer_loading: Optional[bool] = None # 工具级别的 defer_loading 字段,可作为 function 级别的快捷设置
​
    @model_validator(mode="after")
    def _propagate_defer_loading(self) -> "Tool":
        if self.defer_loading is not None and self.function.defer_loading is None:
            self.function.defer_loading = self.defer_loading # 将工具级别的值传播到函数级别,便于统一处理
        return self
python/sglang/srt/entrypoints/anthropic/serving.py core-logic

Anthropic 端点实现,集成 defer_loading 过滤和 tool_reference 解锁逻辑,是关键的业务逻辑变更点。

def _convert_tool_result_content(content):
    if isinstance(content, list):
        tool_content_parts = []
        for item in content:
            item_type = item.get("type")
            if item_type == "tool_reference":
                # Anthropic SDK 使用 `tool_name` 字段,但 SGLang 聊天模板匹配 `name`,在此转换
                ref_name = item.get("tool_name") or item.get("name")
                if ref_name:
                    tool_content_parts.append({"type": "tool_reference", "name": ref_name})
            # 其他类型处理(如 text、image)省略
        return tool_content_parts
    # 简化示例,实际函数更复杂

评论区精华

Anthropic 端点中 tool_reference 字段名错误 正确性

JustinTong0323 指出在 anthropic/serving.py 中,item.get('name') 应改为 item.get('tool_name') 以匹配 Anthropic SDK v0.93.0 的 ToolReferenceBlockParam,否则 tool_reference 解锁路径无效。

结论:Bug 被修复,确保 tool_reference 能正确解锁延迟工具。 · 已解决

测试覆盖和日志建议 测试

Review 中提到测试覆盖不足,且建议添加日志以帮助调试工具过滤逻辑,避免用户困惑。

结论:测试已部分添加,但日志建议未实现,可能影响可调试性。 · partially_resolved

tool_choice 处理逻辑改进 设计

讨论了 tool_choice 处理中当工具被过滤时应返回错误而非静默降级,以及 tool_choice: 'none' 应始终转发。

结论:逻辑已调整,但具体实现细节未在 review 中完全确认。 · 已解决

风险与影响

  1. 协议兼容性风险:在protocol.py中新增defer_loading字段和序列化逻辑可能影响现有API客户端,特别是strict字段的默认值处理需保持向后兼容。
  2. Anthropic集成错误serving.py中的tool_reference解锁逻辑若错误使用字段名,会导致延迟工具无法解锁,影响功能可用性。
  3. 测试覆盖不足:测试文件虽新增,但未覆盖Anthropic端点的过滤和解锁场景,可能引入回归问题。
  4. 设计混淆风险defer_loading为GLM特定扩展,与OpenAI API标准不一致,可能导致用户误解或集成困难。

对用户:GLM模型用户现在可以利用defer_loading功能实现工具的动态隐藏和通过tool_reference解锁,增强多步工具调用的灵活性。对系统:扩展了Chat Completions API协议,新增字段和内容类型,影响OpenAI和Anthropic端点的请求处理流程。对团队:需要维护新的协议逻辑和确保与下游聊天模板(如GLM-5.1)的集成,增加了代码复杂性和测试负担。

协议扩展风险 测试覆盖不足 Anthropic 集成错误

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论