CAMEL schemas 结构化输出转换器实战指南:从 OpenAI 到 Outlines 的 Schema 转换全解析
2026/9/13 20:48:16 网站建设 项目流程

CAMEL schemas 结构化输出转换器实战指南:从 OpenAI 到 Outlines 的 Schema 转换全解析

【免费下载链接】camel🐫 CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org项目地址: https://gitcode.com/GitHub_Trending/ca/camel

结构化输出(Structured Output)是构建可靠 Agent 应用的关键能力。CAMEL 框架在camel/schemas模块中提供了统一、可插拔的 Schema 转换器(Schema Converter)体系:无论是闭源的 OpenAI 模型,还是通过 Outlines 约束解码的本地开源模型,都能把大模型的自由文本稳定转换为符合 Pydantic 模型、JSON Schema 或正则约束的结构化结果。本文以 docs/camel.schemas.rst 对应的模块为骨架,结合源码、示例与测试,完整讲解BaseConverterOpenAISchemaConverterOutlinesConverter的设计、参数、底层原理与实战用法,读完即可在自己的 Agent 流程中落地可靠的 Schema 化输出。

模块总览:schemas 在 CAMEL 中的定位

camel/schemas是 CAMEL 的"响应格式管理"层,它把"让模型输出符合指定 Schema"这一能力抽象成可替换的转换器对象。从源码看,该包的对外导出非常精简(camel/schemas/init.py):

from .openai_converter import OpenAISchemaConverter from .outlines_converter import OutlinesConverter __all__ = ["OpenAISchemaConverter", "OutlinesConverter"]

包内共有 4 个文件,对应 RST 文档列出的子模块结构:

子模块文件路径核心类职责
camel.schemas.basecamel/schemas/base.pyBaseConverter定义转换器的抽象接口
camel.schemas.openai_convertercamel/schemas/openai_converter.pyOpenAISchemaConverter基于 OpenAI 模型的原生结构化输出
camel.schemas.outlines_convertercamel/schemas/outlines_converter.pyOutlinesConverter基于 Outlines 库的约束解码转换
camel.schemas(模块内容)camel/schemas/init.py统一导出与命名空间

该模块是整个框架"结构化响应"能力的底层基础设施:上层的ChatAgent在调用step(..., response_format=...)时即依赖这类转换机制,test/schema_outputsexamples/structured_response中的用例都直接或间接建立在它之上。因此,理解 schemas 模块,就等于理解了 CAMEL 中"如何让模型输出严格符合 Schema"的完整链路。

BaseConverter:所有转换器的统一抽象

BaseConverter定义在 camel/schemas/base.py,它继承abc.ABC,是整个模块的"协议契约"。其核心职责是管理响应格式(response format),并声明唯一一个抽象方法:

class BaseConverter(ABC): @abstractmethod def convert(self, content: str, *args: Any, **kwargs: Dict[str, Any]) -> Any: """Structures the input text into the expected response format."""

接口要点:

  • 入参content是待结构化的原始文本;*args/**kwargs用于传递output_schema(期望的响应格式,通常是 PydanticBaseModel类型)以及可选的自定义prompt
  • 返回Any,即转换后的结构化结果,具体类型由实现类决定(可能是BaseModel实例、dict或普通str)。

从设计上看,BaseConverter只约定"输入文本 + 输出 Schema → 结构化结果"这一最小语义,把"用什么模型、用什么解码策略"完全交给子类实现。这为上层提供了一致的调用入口,同时允许在 OpenAI 结构化输出与本地约束解码之间自由切换。

OpenAISchemaConverter:基于 OpenAI 模型的原生结构化输出

OpenAISchemaConverter(camel/schemas/openai_converter.py)是把"字符串或函数"转换为BaseModelSchema 的实现,适用于通过 OpenAI 平台(或兼容平台)获得可靠 JSON 结构化输出的场景。

构造参数

类构造器签名如下(源码 L61-L75):

def __init__( self, model_type: ModelType = ModelType.GPT_4O_MINI, model_config_dict: Optional[Dict[str, Any]] = None, api_key: Optional[str] = None, ):
参数类型默认值说明
model_typeModelTypeModelType.GPT_4O_MINI使用的模型类型,来自 camel/types/enums.py 的枚举
model_config_dictOptional[Dict]None会透传给openai.ChatCompletion.create()的附加配置字典(如temperaturemax_tokens等);为None时内部使用空字典
api_keyOptional[str]NoneOpenAI API Key;为None时自动从环境变量OPENAI_API_KEY读取

值得注意的底层实现细节:

  1. API Key 强制校验:构造器上装饰了@api_keys_required([("api_key", "OPENAI_API_KEY")])(源码 L56-L60),即既允许显式传api_key,也允许设置环境变量OPENAI_API_KEY,两者都没有时会在初始化阶段报错拦截,避免运行时才发现凭据缺失;
  2. 客户端复用框架工厂:内部通过ModelFactory.create(ModelPlatformType.OPENAI, model_type, api_key=api_key)._client(源码 L70-L74)构建 OpenAI 客户端,而不是自己 new 一个裸客户端——这意味着它与 CAMEL 的 ModelFactory 模型管理体系完全打通;
  3. 默认转换 Prompt:模块级常量DEFAULT_CONVERTER_PROMPTS(源码 L30-L33)定义了默认系统提示词:"从用户文本中提取关键实体与属性,并转换为结构化 JSON 格式",用于引导模型聚焦于结构化抽取。

convert 方法与三种 Schema 输入形态

核心方法convert(content, output_schema, prompt)定义在 源码 L77-L120:

def convert( self, content: str, output_schema: Union[Type[BaseModel], str, Callable], prompt: Optional[str] = DEFAULT_CONVERTER_PROMPTS, ) -> BaseModel:

output_schema支持三种形态,统一由 camel/utils/response_format.py 的get_pydantic_model归一化为 Pydantic 模型类:

输入形态说明处理逻辑
Type[BaseModel]直接传入 Pydantic 模型类校验必须是BaseModel子类,否则抛出ValueError
strJSON 编码的字符串模板json.loads解析为字典,再通过 Pydantic 的create_model动态创建TemporaryModel
Callable一个普通函数将其参数签名转换为BaseModel(函数装饰器语义),函数即 Schema 描述

转换流程中还有两处显式的防御性校验:

  • output_schemaNone,直接抛出ValueError("Expected an output schema, got None.")(源码 L94-L95);
  • 若传入的不是BaseModel子类,抛出ValueError(f"Expected a BaseModel, got {type(output_schema)}")(源码 L98-L101)。

底层原理:Structured Outputs 解析

OpenAISchemaConverter并未使用传统的 JSON 模式,而是直接调用 OpenAI 的Structured Outputs接口(源码 L103-L111):

self.model_config_dict["response_format"] = output_schema response = self._client.beta.chat.completions.parse( messages=[ {'role': 'system', 'content': prompt}, {'role': 'user', 'content': content}, ], model=self.model_type, **self.model_config_dict, )

关键点:

  1. output_schema直接写入response_format,交给服务端做 Schema 约束;
  2. 使用beta.chat.completions.parse端点,返回结果带.parsed字段,即已解析为 Pydantic 对象的响应;
  3. 返回前还有一次类型兜底校验(源码 L115-L118):若message.parsed不是预期的output_schema类型则报错,保证返回对象的类型安全。

三种 Schema 输入的测试验证

仓库测试 test/schema_outputs/test_openai_converter.py 用同一个"天气信息抽取"场景,完整验证了三种输入形态等价可用:

  • test_openai_converter_with_str_template(L30-L46):传入 JSON 字符串模板'{"location": "Beijing", "date": "2023-09-01", "temperature": 30.0}',对 "Today is 2023-09-01, the temperature in Beijing is 30 degrees." 抽取结果断言为{"location": "Beijing", "date": "2023-09-01", "temperature": 30.0}
  • test_openai_converter_with_function(L49-L61):传入get_temperature(location, date, temperature)函数,函数签名即 Schema;
  • test_openai_converter_with_model(L64-L76):传入TemperaturePydantic 模型类,字段为location: strdate: strtemperature: float

测试断言统一使用structured_output.model_dump()比较字典,说明无论以何种形态定义 Schema,转换结果最终都以标准 Pydantic 模型对象返回,接口行为完全一致。

OutlinesConverter:基于 Outlines 的本地约束解码转换

OutlinesConverter(camel/schemas/outlines_converter.py)面向另一类场景:不依赖云端结构化输出 API,而是在本地通过 Outlines 库对模型生成过程施加硬约束(正则、JSON Schema、类型、枚举、文法),从解码层面保证输出合法。

构造参数与平台支持

def __init__( self, model_type: str, platform: Literal[ "vllm", "transformers", "mamba", "llamacpp", "mlx" ] = "transformers", **kwargs: Any, ):
参数说明
model_type本地模型的名称/标识,例如 HuggingFace 模型名或本地模型路径
platform模型加载平台,默认"transformers",可选值有vllmtransformersmamballamacppmlx
**kwargs透传给 Outlinesmodels模块的额外参数

平台分发的实现(源码 L51-L65)使用 Python 3.10+ 的match语句:vllm对应models.vllm(...)transformers对应models.transformers(...)mamba对应models.mamba(...)llamacpp对应models.llamacpp(...)mlx对应models.mlxlm(...),其余值抛出ValueError(f"Unsupported platform: {platform}")。Outlines 的模型对象在构造阶段创建,后续所有转换方法复用它。

六类约束转换方法

OutlinesConverter没有把能力塞进一个convert,而是拆分为 6 个语义明确的专用方法,每种对应 Outlines 的一种约束解码策略:

方法对应 Outlines API用途返回类型
convert_regex(content, regex_pattern)outlines.generate.regex输出匹配指定正则str
convert_json(content, output_schema)outlines.generate.json按 JSON Schema(字符串或可调用对象)输出dict
convert_pydantic(content, output_schema)outlines.generate.json按 Pydantic 模型约束输出BaseModel
convert_type(content, type_name)outlines.generate.format输出为指定类型(int/float/bool/datetime.date等)str
convert_choice(content, choices)outlines.generate.choice输出必须是给定候选列表之一str
convert_grammar(content, grammar)outlines.generate.cfg按上下文无关文法(CFG)约束输出str

其中convert_type支持的类型(源码 L129-L153)包括intfloatbooldatetime.datedatetime.timedatetime.datetime以及 Outlines 文档中列出的自定义类型。

统一入口 convert

除各专用方法外,convert(源码 L189-L249)提供了按名称分发的统一入口:

def convert(self, content: str, type: Literal["regex", "json", "type", "choice", "grammar"], **kwargs) -> Any:

type参数取值为regex/pydantic/json/type/choice/grammar,对应分发到上表六个方法;**kwargs中按类型传入对应参数(如regex_patternoutput_schematype_namechoicesgrammar)。不支持的取值抛出ValueError("Unsupported output schema type")

两种 Converter 的对比小结:

维度OpenAISchemaConverterOutlinesConverter
依赖模型平台OpenAI(云端 API)本地模型(transformers/vllm/mamba/llamacpp/mlx)
约束方式服务端 Structured Outputs(parse端点)本地解码期约束(Outlines 库)
Schema 输入Pydantic 类 / JSON 字符串 / 函数Pydantic 类 / JSON Schema / 正则 / 类型 / 枚举 / 文法
返回类型BaseModelstr/dict/BaseModel,视方法而定
典型场景追求易用性与云端能力本地部署、数据不出域、强解码约束

实战:在 ChatAgent 中让响应严格符合 Schema

虽然schemas模块本身只负责"转换",但它在实际项目中最常见的用法是配合ChatAgentresponse_format参数使用。仓库示例 examples/structured_response/json_format_response.py 展示了最小可用闭环:

from pydantic import BaseModel, Field from camel.agents import ChatAgent from camel.models import ModelFactory from camel.types import ModelPlatformType, ModelType assistant_sys_msg = "You are a helpful assistant." model = ModelFactory.create( model_platform=ModelPlatformType.DEFAULT, model_type=ModelType.DEFAULT, ) camel_agent = ChatAgent(assistant_sys_msg, model=model) # pydantic basemodel as input params format class JokeResponse(BaseModel): joke: str = Field(description="a joke") funny_level: str = Field(description="Funny level, from 1 to 10") response = camel_agent.step("Tell me a joke.", response_format=JokeResponse) print(response.msgs[0].content) # {'joke': "Why couldn't the bicycle find its way home? It lost its bearings!", 'funny_level': '8'}

实战要点:

  1. 用 Pydantic 定义 SchemaField(description=...)中的描述会作为模型的提示信息,帮助模型理解每个字段的语义,建议始终填写;
  2. 直接传入模型类step(..., response_format=JokeResponse),返回的response.msgs[0].content即为可安全解析的结构化 JSON 字符串;
  3. 与工具调用结合:示例 examples/structured_response/json_format_reponse_with_tools.py 展示了给ChatAgent挂载MathToolkitSearchToolkit等工具的同时使用response_format=Schema,让 Agent 在完成"估算牛津大学校龄并加 10 年"这类需要推理+检索的任务后,输出仍能严格落在{'current_age': ..., 'calculated_age': ...}的 Schema 里;
  4. Prompt 工程辅助:同目录的 examples/structured_response/structure_response_prompt_engineering.py 说明,在复杂任务中还可以通过精心设计系统提示词进一步稳定输出格式。

使用建议与限制

  • 优先使用 OpenAISchemaConverter:当你的模型来自 OpenAI 平台且网络环境允许时,它是成本最低、体验最顺滑的方案——只需要定义 Pydantic 模型,其余交给服务端;
  • 本地部署选择 OutlinesConverter:当数据敏感、需要本地推理时,OutlinesConverter的约束解码从机制上保证了格式合法(非法输出在解码期就不可能产生),但它要求正确安装 Outlines 及对应平台依赖(transformers/vllm 等),并需结合本仓库 pyproject.toml 中的依赖声明确认环境;
  • 两类转换器都要求类型安全OpenAISchemaConverter在解析后校验parsed类型,OutlinesConverter在平台与type取值上做显式校验,错误会在调用点尽早暴露;
  • API Key 前置条件:使用OpenAISchemaConverter前务必配置OPENAI_API_KEY环境变量或显式传入api_key,否则初始化即失败。

总结

camel/schemas是 CAMEL 结构化输出能力的统一抽象层:BaseConverter定义了"文本 → 结构"的契约;OpenAISchemaConverter借助 OpenAI Structured Outputs 为云端模型提供开箱即用的 Pydantic 解析;OutlinesConverter借助约束解码为本地模型提供正则、JSON、类型、枚举、文法六种细粒度约束。二者通过ChatAgent.response_format与上层 Agent 流程无缝衔接,并得到 test/schema_outputs/test_openai_converter.py 与 examples/structured_response 的完整验证。在构建需要可靠结构化输出的多智能体应用时,根据模型部署形态在两种转换器之间选择,即可让 Agent 的输出始终"有章可循"。

【免费下载链接】camel🐫 CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org项目地址: https://gitcode.com/GitHub_Trending/ca/camel

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询