跳转至

schemas.py — verl/tools/schemas.py

文件路径

verl/tools/schemas.py

文件概述

这个文件定义了 verl 工具系统中所有的数据模式(Schema),使用 Pydantic 的 BaseModel 来做数据验证和序列化。这些 Schema 遵循 OpenAI 的 Function Calling 格式,是工具系统的"数据契约"——所有工具的输入输出都必须符合这些格式。

为什么需要这个文件? 在强化学习中,模型(LLM)需要调用外部工具(如搜索、代码执行等)。OpenAI 定义了一套标准的 tool calling 格式,verl 按照这个格式来描述工具的名称、参数、返回值等信息,这样 LLM 就知道有哪些工具可用、每个工具接受什么参数。

关键代码讲解

1. 工具参数的属性定义

class OpenAIFunctionPropertySchema(BaseModel):
    """The schema of a parameter in OpenAI format."""
    type: str
    description: str | None = None
    enum: list[str] | None = None

描述工具函数某一个参数的类型信息。例如一个搜索工具的 query 参数可以表示为:

{"type": "string", "description": "搜索关键词"}

2. 工具参数集合定义

class OpenAIFunctionParametersSchema(BaseModel):
    """The schema of parameters in OpenAI format."""
    type: str
    properties: dict[str, OpenAIFunctionPropertySchema]
    required: list[str]

将多个参数组合在一起。properties 是参数名到参数定义的映射,required 列出必填参数。

3. 函数定义

class OpenAIFunctionSchema(BaseModel):
    """The schema of a function in OpenAI format."""
    name: str
    description: str
    parameters: OpenAIFunctionParametersSchema = Field(
        default_factory=lambda: OpenAIFunctionParametersSchema(
            type="object", properties={}, required=[]
        )
    )
    strict: bool = False

描述一个完整的函数:名称、描述、参数列表。strict=False 表示不强制要求参数严格匹配。

4. 完整的工具 Schema

class OpenAIFunctionToolSchema(BaseModel):
    """The schema of a tool in OpenAI format."""
    type: str
    function: OpenAIFunctionSchema

这是最外层的工具描述,type 通常为 "function",function 字段包含函数的详细定义。一个完整的工具 schema 长这样:

{
    "type": "function",
    "function": {
        "name": "search",
        "description": "搜索相关信息",
        "parameters": {
            "type": "object",
            "properties": {"query": {"type": "string"}},
            "required": ["query"]
        }
    }
}

5. 函数调用解析

class OpenAIFunctionCallSchema(BaseModel):
    """The parsed schema of a tool in OpenAI format."""
    name: str
    arguments: dict[str, Any]

    @staticmethod
    def from_openai_function_parsed_schema(
        parsed_schema: OpenAIFunctionParsedSchema,
    ) -> tuple["OpenAIFunctionCallSchema", bool]:
        has_decode_error = False
        try:
            arguments = json.loads(parsed_schema.arguments)
        except json.JSONDecodeError:
            arguments = {}
            has_decode_error = True
        if not isinstance(arguments, dict):
            arguments = {}
            has_decode_error = True
        return OpenAIFunctionCallSchema(name=parsed_schema.name, arguments=arguments), has_decode_error

LLM 生成的函数调用中,arguments 是一个 JSON 字符串。这个方法负责将其解析为 Python 字典,并处理 JSON 解析失败的情况(返回空字典并标记错误)。

6. 工具响应

class ToolResponse(BaseModel):
    """The response from a tool execution."""
    text: str | None = None
    image: list[Any] | None = None
    video: list[Any] | None = None

    @model_validator(mode="before")
    @classmethod
    def initialize_request(cls, values):
        if "image" in values and not isinstance(values["image"], list):
            raise ValueError(...)
        if "video" in values and not isinstance(values["video"], list):
            raise ValueError(...)
        return values

    def is_empty(self) -> bool:
        return not self.text and not self.image and not self.video

    def is_text_only(self) -> bool:
        return self.text and not self.image and not self.video

工具执行后返回的结果,支持三种类型:文本、图片列表、视频列表。验证器确保 image 和 video 字段必须是列表类型。

核心类/函数列表

类名 作用
OpenAIFunctionPropertySchema 描述单个参数的类型/描述
OpenAIFunctionParametersSchema 描述参数集合
OpenAIFunctionSchema 描述一个函数(名称+描述+参数)
OpenAIFunctionToolSchema 最外层工具描述
OpenAIFunctionParsedSchema LLM 输出的原始函数调用(arguments 为字符串)
OpenAIFunctionCallSchema 解析后的函数调用(arguments 为字典)
OpenAIFunctionToolCall 完整的工具调用(含 id 和 type)
ToolResponse 工具执行的返回结果

与其他模块的关系

  • 被所有工具类使用:BaseTool、SandboxFusionTool、SearchTool 等都依赖这些 Schema。
  • 被 tool_registry.py 使用:从配置文件加载工具时,会将配置转换为 OpenAIFunctionToolSchema。
  • 与 LLM 推理对接:rollout 过程中,LLM 的输出会被解析为 OpenAIFunctionCallSchema,然后传递给工具执行。

小结

schemas.py 是工具系统的数据层,定义了工具描述、函数调用、工具响应等所有数据格式。它遵循 OpenAI 的 Function Calling 规范,使得 verl 的工具系统与 OpenAI 兼容的 LLM 可以无缝对接。