ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Qwen-Agent Schema 详解:基于 Pydantic 的多模态消息、函数调用与推理链数据结构

Qwen-Agent Schema 详解:基于 Pydantic 的多模态消息、函数调用与推理链数据结构 Qwen-Agent Schema 详解基于 Pydantic 的多模态消息、函数调用与推理链数据结构【免费下载链接】Qwen-AgentAgent framework and applications built upon Qwen3.0, featuring Function Calling, MCP, Code Interpreter, RAG, Chrome extension, etc.项目地址: https://gitcode.com/GitHub_Trending/qw/Qwen-Agent本篇技术指南围绕 Qwen-Agent 的消息与数据模型qwen_agent/llm/schema.py展开系统讲解其类型安全设计、Message/ContentItem/FunctionCall三大核心类的字段语义、校验规则与序列化行为并结合仓库源码与测试用例说明消息如何被转换为 OpenAI 兼容格式供各类模型服务消费。读完本文你将掌握在多模态对话、Function Calling 与带思维链reasoning场景下如何正确构造、读写和序列化 Qwen-Agent 消息对象。Overview为什么需要一套结构化消息 Schemaqwen-agent的 schema 为消息系统提供了结构化、类型安全的建模能力用于支撑多模态对话、函数调用Function Calling与推理链reasoning chain等高级能力。整套模型建立在 Pydantic 之上在构造、校验与序列化阶段保证数据完整性同时允许灵活表达异构的多模态内容文本、图片、文件、音频与视频。设计目标Type Safety类型安全通过 Pydantic 模型强制执行字段类型与取值约束。Multimodal Support多模态支持消息可携带异构媒体类型文本、图片、文件、音频、视频。Compatibility兼容性对齐 OpenAI 风格的消息格式同时通过extra字段支持任意扩展元数据。Developer Experience开发者体验提供字典式访问__getitem__、.get()、序列化时自动排除None字段以及直观的调试输出表示。以上设计与官方文档 qwen-agent-docs/website/content/en/guide/core_moduls/schema.md 完全对应而文档所描述的每一条行为都能在 qwen_agent/llm/schema.py 中找到一一对应的实现。核心常量角色、内容类型与字段名schema 首先以模块级常量定义了消息的角色role、内容类型content type与字段名避免在代码中散落魔法字符串# Role types SYSTEM system USER user ASSISTANT assistant FUNCTION function # Content types (used in ContentItem) TEXT text IMAGE image FILE file AUDIO audio VIDEO video # Message field names ROLE role CONTENT content REASONING_CONTENT reasoning_content NAME name在源码 qwen_agent/llm/schema.py 中上述常量定义于DEFAULT_SYSTEM_MESSAGE 之后该空系统消息默认值被 qwen_agent/llm/base.py 用于在首条消息非system时自动补一条空 system 消息。仓库内的 Agent 实现大量复用这些常量例如 qwen_agent/agent.py 与 qwen_agent/agents/assistant.py 均通过from qwen_agent.llm.schema import CONTENT, ROLE, SYSTEM, ContentItem, Message导入后组织对话逻辑。基类BaseModelCompatibleDict让 Pydantic 模型像字典一样好用所有 schema 类都继承自BaseModelCompatibleDict它在pydantic.BaseModel之上叠加了字典式行为。其完整实现位于 qwen_agent/llm/schema.py字典式访问与安全读取msg Message(roleuser, contentHello) print(msg[role]) # → user__getitem__委托给getattr(self, item)__setitem__委托给setattr。.get()在键不存在或取值为空None、空串等 falsy 值时返回默认值msg.get(non_existent_key, default) # → default注意实现细节get()内部先getattr(self, key)捕获AttributeError返回default同时对None等 falsy 取值也回落到default因此与 Python 字典的.get()语义略有差异——字段存在但为空时同样返回默认值。干净的序列化默认排除Nonemsg.model_dump() # fields with valueNone are excluded by default基类重写了model_dump与model_dump_json若调用方未显式传入exclude_none则自动置为True。这意味着一个ContentItem(textNone, image...)序列化后只会输出{image: ...}保证下游 JSON 的干净与紧凑。可读的字符串表示str(msg)返回model_dump()的结果即f{self.model_dump()}同时各子类还实现了各自的__repr__如FunctionCall({...})、ContentItem({...})、Message({...})便于在日志与 REPL 中直观调试。FunctionCall模型提议或执行的函数调用FunctionCall表示模型提议或已执行的某次函数调用class FunctionCall(BaseModelCompatibleDict): name: str arguments: str # JSON-encoded string在 qwen_agent/llm/schema.py 中name为函数名arguments为JSON 编码的字符串不是 dict这一点与 OpenAItool_calls[].function.arguments的表示一致。fc FunctionCall(nameget_weather, arguments{city: Beijing}) print(fc.name) # → get_weather print(fc.arguments) # → {city: Beijing}ContentItem单条多模态内容单元ContentItem表示一条多模态内容其五个字段text、image、file、audio、video中恰好只能提供一个class ContentItem(BaseModelCompatibleDict): text: Optional[str] None image: Optional[str] None # e.g., base64-encoded data or URL file: Optional[str] None # file path or URL audio: Optional[Union[str, dict]] None video: Optional[Union[str, list]] None字段类型说明字段类型取值示例textOptional[str]任意文本内容imageOptional[str]base64 编码数据或图片 URL如data:image/png;base64,...fileOptional[str]文件路径或 URLaudioOptional[Union[str, dict]]音频 URL/路径或携带音频元数据的 dictvideoOptional[Union[str, list]]视频 URL/路径或多个视频/帧组成的 list属性.type与.value.type→text | image | file | audio | video.value→ 对应的取值base64、URL、文件路径等实现上二者都依赖私有方法get_type_and_value()qwen_agent/llm/schema.py它先对self.model_dump()取唯一键值对并断言键名属于五种内容类型之一。由于model_dump()默认排除了None字段互斥校验通过后恰好只剩一个字段因此该断言在合法对象上必然成立。type与value这两个 property 在 qwen_agent/llm/base.py 的停用词后处理、qwen_agent/llm/function_calling.py 的函数结果提取等底层流程中被频繁使用。互斥校验恰好一个字段通过model_validator(modeafter)实现qwen_agent/llm/schema.py依次统计text判is not None与image、file、audio、video判 truthy中被提供的字段数若provided_fields ! 1则抛出ValueError(Exactly one of text, image, file, audio, or video must be provided.)注意text的空字符串仍视为“已提供”因为is not None而其余字段空值视为未提供。# Valid txt ContentItem(textHello) img ContentItem(imagehttps://example.jpg) img ContentItem(imagedata:image/png;base64,...) # Invalid (raises ValueError) bad ContentItem(textHi, image...) # ❌ Exactly one ... must be providedMessage对话中的单条消息Message表示对话中的一条消息同时支持多模态内容与函数调用class Message(BaseModelCompatibleDict): role: Literal[system, user, assistant, function] content: Union[str, List[ContentItem]] reasoning_content: Optional[Union[str, List[ContentItem]]] None name: Optional[str] None function_call: Optional[FunctionCall] None extra: Optional[dict] None字段说明字段类型描述rolestr必须为system、user、assistant、function之一contentstr或List[ContentItem]主要消息内容——纯文本或多模态条目列表reasoning_contentOptional保存模型的推理痕迹如 chain-of-thought格式与content相同nameOptionalstr当role function时标识被调用的函数名function_callOptionalFunctionCall当role assistant时表示模型建议调用的函数extraOptionaldict任意元数据如 token 数、日志、自定义注解构造注意点若传入contentNone构造器会自动将其置为空字符串见 qwen_agent/llm/schema.py。role字段通过field_validator(role)校验qwen_agent/llm/schema.py非法取值抛出ValueError。文档中字段注解写为Literal[...]源码实际以str注解 运行时 validator 的方式实现二者等价地保证取值约束。构造示例纯文本消息msg Message(roleuser, contentWhat is the weather in Tokyo?)多模态输入文本 图片content [ ContentItem(textDescribe this image:), ContentItem(imagehttps://example.com/cat.jpg) ] msg Message(roleuser, contentcontent)Assistant 发起函数调用msg Message( roleassistant, content, function_callFunctionCall(nameget_weather, arguments{city: Tokyo}) )函数响应msg Message( rolefunction, nameget_weather, content{temperature: 25, unit: Celsius} )带推理痕迹的响应注意reasoning_content与最终回答会拆成两条独立的assistant消息msgs [Message( roleassistant, content, reasoning_contentStep 1: Identify the city. Step 2: Fetch weather data... ), Message( roleassistant, contentIt is 25 degrees Celsius, )]源码中的实际调用消息如何贯穿 Agent 全链路schema 并非孤立的数据结构而是 Agent 与 LLM 交互的统一中间表示输入统一BaseChatModel.chat()qwen_agent/llm/base.py接受List[Union[Message, Dict]]对 dict 输入自动执行Message(**msg)转换同时记录首个输入类型决定返回值是 dict 列表还是Message列表_return_message_type即“如果输入是 dict返回也是 dict输入是 pydantic 模型返回也是 pydantic 模型”。系统消息补全当DEFAULT_SYSTEM_MESSAGE非空且首条消息不是system时自动在头部插入Message(roleSYSTEM, ...)。超长截断_truncate_input_messages_roughly按 user 轮次对多模态内容逐条ContentItem截断且严格要求 system 消息不超过一条且必须位于首位。函数调用流程qwen_agent/llm/function_calling.py 导入ASSISTANT, FUNCTION, USER, ContentItem, Message在_remove_fncall_messages中将function消息与function_call消息改写为 user 文本validate_num_fncall_results校验函数调用与函数结果消息的数量与顺序必须一一对应。模型服务适配以 DashScope 实现为例qwen_agent/llm/qwen_dashscope.py非流式输出被包装为Message(roleASSISTANT, content..., reasoning_content..., extra{model_service_info: response})extra字段用于携带原始模型服务信息流式输出则由_full_stream_output逐 chunk 拼接content、reasoning_content与tool_calls。兼容性说明与 OpenAI 消息格式的双向转换文档明确指出三条兼容性约定源码中均有对应实现Qwen Agent 接收与返回消息列表响应中的reasoning_content、content与function_call存放在不同的消息中——这也是上文“带推理痕迹的响应”示例拆分为两条 assistant 消息的原因。调用模型服务时Agent 会把数据转换成对应格式如 OpenAI Chat Completions 格式。具体转换逻辑位于BaseChatModel._conv_qwen_agent_messages_to_oaiqwen_agent/llm/base.py连续多条assistant消息被合并为一条function_call被放入tool_calls数组并携带id默认取自extra.function_idrolefunction消息被改写为roletool并带上对应的id反向转换则由quick_chat_oai中的_convert_to_qwen_agent_messages完成tool→function、tool_calls→function_call。以 JSON 格式访问时返回 JSON以 pydantic 模型访问时返回 pydantic 模型——即上文提到的_return_message_type机制qwen_agent/llm/base.py。实战验证从示例与测试看消息的构造习惯仓库中的示例与测试提供了贴近实战的用法参考examples/function_calling.py 展示了纯 dict 形式的完整 Function Calling 闭环以{role: user, content: ...}发起对话 → 检查last_response.get(function_call)→json.loads解析arguments→ 追加{role: function, name: ..., content: ...}返回给模型。由于输入为 dictllm.chat的返回值同样是 dict可.get(function_call)。examples/assistant_weather_bot.py 与 examples/assistant_rag.py 则使用Message/ContentItem对象在 Agent 层传递结构化内容。tests/llm/test_oai.py 用Message(user, draw a cute cat)构造输入并断言传入 functions 时response[-1].function_call.name image_gen不传 functions 时response[-1].function_call is None同时验证了content为字符串、max_retries默认值等细节。tests/agents/test_assistant.py 展示了多模态消息Message(user, [ContentItem(text...), ContentItem(image...)])以及本地文件通过ContentItem(filestr(Path(...)))传入tests/memory/test_memory.py。tests/llm/test_continue.py 验证了“assistant 续写”场景下连续两条 assistant 消息的输入形态。小结Qwen-Agent 的 schema 层以 Pydantic 为基石通过BaseModelCompatibleDict、FunctionCall、ContentItem与Message四个核心构件为多模态对话、Function Calling 与推理链提供了统一、类型安全且兼容 OpenAI 的消息表示。理解这套 schema是深入阅读 Agent 实现如 qwen_agent/agent.py、qwen_agent/agents/fncall_agent.py与二次开发的基础构造消息时遵循“ContentItem恰好一个字段、Message.role四选一、函数调用用function_callname消息配对、推理链拆分独立 assistant 消息”这几条规则即可稳定地驱动 Qwen 系列模型完成各类 Agent 任务。【免费下载链接】Qwen-AgentAgent framework and applications built upon Qwen3.0, featuring Function Calling, MCP, Code Interpreter, RAG, Chrome extension, etc.项目地址: https://gitcode.com/GitHub_Trending/qw/Qwen-Agent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表