pydantic-ai output 模块深度解析:从 ToolOutput 到 NativeOutput 的 Agent 输出类型体系
【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai
pydantic_ai.output是 pydantic-ai 中定义 Agent 输出契约的核心模块,它决定了一次 Agent 运行(run)的最终返回内容——是纯文本、结构化数据、图片,还是由模型提供参数后调用某个函数的返回值。本篇指南以pydantic_ai.output模块的公开 API(OutputDataT、ToolOutput、NativeOutput、PromptedOutput、TextOutput、StructuredDict、DeferredToolRequests、OutputObjectDefinition)为主线,结合模块源码与官方使用文档,系统讲解每种输出类型的适用场景、参数含义、底层原理与代码示例,帮助你在实际项目中精准选择并配置 Agent 的输出方式。
阅读本文前建议先了解 Agent 的运行方式 与 结构化输出总览。
一、模块总览:output_type 与 OutputSpec
在 pydantic-ai 中,所有输出配置都汇聚到Agent构造函数的output_type参数上,其类型为OutputSpec。根据 pydantic_ai_slim/pydantic_ai/output.py 中的定义,OutputSpec可以是:
- 单个类型(如
MyModel、int、str); - 单个输出函数(或绑定方法);
- 类型/函数的序列(list,用于表达多个候选输出);
- 上述内容的任意嵌套组合;
- 或上述四种输出模式标记类(Marker Class)之一的实例:
ToolOutput、NativeOutput、PromptedOutput、TextOutput。
模块还导出了两个辅助类型:
OutputDataT:一个默认值为str的协变 TypeVar,描述一次运行输出数据的类型,Agent、AgentRunResult与StreamedRunResult均以它为泛型参数,从而保证类型信息在结果对象上传递。OutputMode:全部输出模式的字面量联合'text' | 'tool' | 'native' | 'prompted' | 'tool_or_text' | 'image' | 'auto'。其中tool_or_text已废弃不再使用;auto表示由模型根据ModelProfile.default_structured_output_mode自动选择结构化输出模式。结构化输出可用的模式是StructuredOutputMode = Literal['tool', 'native', 'prompted']。
输出数据被包裹在运行结果中
无论哪种输出类型,输出数据都会被包裹在AgentRunResult或StreamedRunResult中,以便访问运行的 usage 用量与消息历史。两者都以其包裹的数据为泛型参数,因此类型检查器能保留输出数据的类型信息。
一次运行在模型返回下列内容之一时结束:某个输出类型对应的结构化数据、输出函数调用结果、纯文本(当未指定输出类型或str在允许范围内时)、图片,或DeferredToolRequests(当模型调用了延迟工具时)。若超出了 Usage Limits 运行也会被取消。
最基本的用法——用 Pydantic 模型作为output_type,强制模型返回符合规范的字段:
from pydantic import BaseModel from pydantic_ai import Agent class CityLocation(BaseModel): city: str country: str agent = Agent('google:gemini-3-flash-preview', output_type=CityLocation) result = agent.run_sync('Where were the olympics held in 2012?') print(result.output) #> city='London' country='United Kingdom'二、ToolOutput:默认的工具调用输出模式
ToolOutput是一个标记类,用于"使用一个工具来产出输出,并可选地定制该工具"。它是 pydantic-ai 的默认结构化输出方式:每个输出类型(或函数)的 JSON Schema 被提供给模型,作为某个特殊"输出工具"的参数 Schema;模型通过发起一次工具调用来"提交"最终结果。这种模式被几乎所有模型支持,并被验证在广泛的模型上表现良好。
其字段定义如下(见 output.py):
| 字段 | 类型 | 含义 |
|---|---|---|
output | OutputTypeOrFunction | 输出类型或输出函数(必填) |
name | str \| None | 传给模型的工具名。若未指定且只有一个输出,使用final_result;若有多个输出,会在类型/函数名基础上拼接生成工具名 |
description | str \| None | 传给模型的工具描述。默认取类型或函数的 docstring |
max_retries | int \| None | 该输出工具的单工具重试上限,会覆盖 Agent 输出侧重试预算;未设置时使用 Agent 级默认值(必须>= 0,否则抛出UserError) |
strict | bool \| None | 是否对该工具启用严格模式 |
sequential | bool | 该输出工具是否必须作为"屏障"串行执行(默认False)。仅在end_strategy='exhaustive'下有意义:此时工具本可并行,sequential=True的输出工具会单独运行,等模型先前发出的函数工具执行完毕后它才执行 |
底层实现中(见 pydantic_ai_slim/pydantic_ai/_output.py),OutputToolset.build()会为每个输出工具构造ToolDefinition:默认工具名为常量DEFAULT_OUTPUT_TOOL_NAME = 'final_result',默认描述为'The final response which ends this conversation'。当存在多个输出且未指定名称时,工具名会被清洗后追加类型名(如final_result_Fruit),重复名称自动加序号去重;描述则取object_def.description,缺失时使用默认描述。
from pydantic import BaseModel from pydantic_ai import Agent, ToolOutput class Fruit(BaseModel): name: str color: str class Vehicle(BaseModel): name: str wheels: int agent = Agent( 'openai:gpt-5.2', output_type=[ ToolOutput(Fruit, name='return_fruit'), ToolOutput(Vehicle, name='return_vehicle'), ], ) result = agent.run_sync('What is a banana?') print(repr(result.output)) #> Fruit(name='banana', color='yellow')注意:由于ToolOutput是对象而非类型,多个输出必须用 list 传递,不能写成Fruit | Vehicle联合。
输出工具的重试与动态过滤
使用输出工具时,每个工具拥有独立的重试计数器:Agent 输出侧的重试预算(通过Agent(retries={'output': N})或agent.run(retries={'output': N})设置)是所有输出工具的默认单工具上限;若想覆盖某个工具,可在ToolOutput上直接传max_retries,例如ToolOutput(Fruit, max_retries=2)。
若需要在运行过程中动态修改或过滤可用输出工具,可以定义 Agent 级的prepare_output_tools函数(类型为ToolsPrepareFunc),它在运行的每一步之前被调用,接收RunContext与ToolDefinition列表,返回该步要暴露的输出工具定义;返回[]表示不暴露任何输出工具。这与普通工具的prepare_tools机制类似。
三、NativeOutput:模型原生的结构化输出
NativeOutput标记类用于启用模型的原生 "Structured Outputs"(JSON Schema response format)能力:模型被强制只输出符合给定 JSON Schema 的文本。注意并非所有模型都支持该能力,部分模型还有使用限制(例如部分 Gemini 模型不能将 Native Output 与函数工具同时使用),因此选择前需确认目标模型的ModelProfile.default_structured_output_mode。
from pydantic_ai import Agent, NativeOutput from tool_output import Fruit, Vehicle agent = Agent( 'openai:gpt-5.2', output_type=NativeOutput( [Fruit, Vehicle], name='Fruit or vehicle', description='Return a fruit or vehicle.' ), ) result = agent.run_sync('What is a Ford Explorer?') print(repr(result.output)) #> Vehicle(name='Ford Explorer', wheels=4)字段说明:
| 字段 | 类型 | 含义 |
|---|---|---|
outputs | 单个输出类型/函数 或 其序列 | 要输出的类型或函数 |
name | str \| None | 传给模型的结构化输出名;默认取类型/函数名 |
description | str \| None | 描述;默认取 docstring |
strict | bool \| None | 是否使用严格模式(若模型支持) |
template | str \| Literal[False] \| None | 传给模型的提示词模板。'{schema}'占位符会被替换为输出 JSON Schema;未指定但模型 profile 表明需要把 Schema 作为提示词发送时,使用 profile 上的默认模板;设为False则完全禁用 Schema 提示词 |
从源码看,NativeOutputSchema继承自StructuredTextOutputSchema,其mode属性返回'native'。StructuredTextOutputSchema.build_instructions()会复制object_def.json_schema,注入title/description,若模板中没有{schema}占位符则自动追加\n\n{schema},最终用json.dumps(schema)填充模板——这解释了模板的可定制机制。
四、PromptedOutput:通过指令提示的输出
PromptedOutput标记类通过模型的 instructions(指令)提示模型输出符合 JSON Schema 的文本,并尝试解析模型的纯文本响应。它适用于所有模型,但通常是最不可靠的方式,因为模型并不被强制匹配 Schema。
虽然一般建议优先使用 Tool 或 Native 输出,但某些场景下该模式可能产出更高质量的结果;对于不支持原生工具调用或结构化输出的模型,它是产生结构化输出的唯一选择。若模型 API 支持 "JSON Mode"(强制输出合法 JSON),该能力会被启用,但模型仍需自行遵循 Schema;Pydantic AI 会验证返回的结构化数据,验证失败时要求模型重试。
from pydantic import BaseModel from pydantic_ai import Agent, PromptedOutput from tool_output import Vehicle class Device(BaseModel): name: str kind: str agent = Agent( 'openai:gpt-5.2', output_type=PromptedOutput( [Vehicle, Device], name='Vehicle or device', description='Return a vehicle or device.' ), ) result = agent.run_sync('What is a MacBook?') print(repr(result.output)) #> Device(name='MacBook', kind='laptop') agent = Agent( 'openai:gpt-5.2', output_type=PromptedOutput( [Vehicle, Device], template='Gimme some JSON: {schema}' ), ) result = agent.run_sync('What is a Ford Explorer?') print(repr(result.output)) #> Vehicle(name='Ford Explorer', wheels=4)字段与NativeOutput基本一致(outputs、name、description、template),区别在于其mode为'prompted',且template未指定时使用模型 profile 上的prompted_output_template默认模板。
五、TextOutput:让文本经过一个函数处理
TextOutput标记类将"输出函数"与纯文本输出结合:模型以纯文本(而非输出工具调用)提供字符串,该字符串被作为唯一参数传入你提供的函数,函数的返回值成为 Agent 运行的最终输出。如果不加TextOutput包装,Pydantic AI 默认会为任何输出函数(包括接收字符串的)创建一个输出工具;包装后则改为纯文本路径。
from pydantic_ai import Agent, TextOutput def split_into_words(text: str) -> list[str]: return text.split() agent = Agent( 'openai:gpt-5.2', output_type=TextOutput(split_into_words), ) result = agent.run_sync('Who was Albert Einstein?') print(result.output) #> ['Albert', 'Einstein', 'was', 'a', 'German-born', 'theoretical', 'physicist.']TextOutput可与一个或多个ToolOutput(或未标记的类型/函数)同时出现在output_type列表中。与其他输出函数一样,文本输出函数可选的第一个参数可以是RunContext,并可通过抛出ModelRetry请求模型用修正后的参数(或换一种输出类型)重试。
输出函数的一般规则
输出函数与函数工具类似,但有三个关键区别:模型被强制调用其中之一;该调用会结束本次运行;函数返回值不会回传给模型。函数参数由 Pydantic 校验(可带 validation context),支持RunContext作为第一个参数,可抛出ModelRetry请求重试。输出函数不支持ToolFailed(那是函数工具失败的专用异常),在这里ToolFailed被当作普通异常处理:可由on_output_process_errorhook 恢复,否则中止运行。
一个典型的"路由 + 交接"示例(完整示例见 docs/output.md):外层路由 Agent 的输出类型为[hand_off_to_sql_agent, RouterFailure],其中hand_off_to_sql_agent是一个接收RunContext与查询字符串的异步函数,它内部把查询转成 SQL 并调用另一个 SQL Agent,成功则返回list[Row],失败则抛出ModelRetry让外层模型换一种方式处理。
流式场景下的部分输出处理
使用run_stream()/run_stream_sync()流式运行时,输出函数会被调用多次——每次模型产生部分输出时调用一次,最终完整输出时再调用一次。若输出函数有副作用(发送通知、写日志、更新数据库等),应检查RunContext.partial_output标志:流式时部分输出为True、最终输出为False;其他运行方法中该标志恒为False。
from pydantic import BaseModel from pydantic_ai import Agent, RunContext class DatabaseRecord(BaseModel): name: str value: int | None = None # Make optional to allow partial output def save_to_database(ctx: RunContext, record: DatabaseRecord) -> DatabaseRecord: """Output function with side effect - only save final output to database.""" if ctx.partial_output: # Skip side effects for partial outputs return record # Only execute side effect for the final output print(f'Saving to database: {record.name} = {record.value}') return record agent = Agent('openai:gpt-5.2', output_type=save_to_database)流式文本与 TextOutput 的注意事项
使用stream_text()时不会应用TextOutput包装的函数:delta=False时它对每个累积文本快照应用输出验证器,delta=True时直接产出原始文本增量并跳过验证器。要流式获取TextOutput函数产生的结果,应改用stream_output()。另外,使用.stream_text(delta=True)时最终输出消息不会加入结果消息历史。
六、StructuredDict:附加自定义 JSON Schema 的字典输出
当使用BaseModel、dataclass 或TypedDict定义结构化输出不可行时——例如从外部来源拿到 JSON Schema,或 Schema 需要动态生成——可以用StructuredDict(json_schema, name, description)函数生成一个带有 JSON Schema 附件的dict[str, Any]子类,Pydantic AI 会把这个 Schema 传给模型。
from pydantic_ai import Agent, StructuredDict schema = { 'type': 'object', 'properties': { 'name': {'type': 'string'}, 'age': {'type': 'integer'} }, 'required': ['name', 'age'] } agent = Agent('openai:gpt-5.2', output_type=StructuredDict(schema)) result = agent.run_sync('Create a person') print(result.output) #> {'name': 'John Doe', 'age': 30}参数说明:
json_schema:必须是type: 'object'的 JSON Schema,用于定义字典内容的结构;name:结构化输出的名称;未提供时使用 Schema 中的title字段(如有);description:描述;未提供时使用 Schema 中的description字段(如有)。
实现细节(见 output.py 中StructuredDict定义):该函数首先调用_utils.check_object_json_schema校验 Schema 类型;若 Schema 含$defs,会用InlineDefsJsonSchemaTransformer将其内联(因为 Pydantic 的TypeAdapter在__get_pydantic_json_schema__返回$defs时会失败),若内联后仍有$defs则抛出UserError——即当前StructuredDict不支持递归$ref/$defs;随后把name/description写入 Schema 的title/description字段,最后返回一个实现了__get_pydantic_core_schema__(dict[str, Any]的dict_schema)与__get_pydantic_json_schema__(返回附着的 Schema)的_StructuredDict类。
需要明确的是:Pydantic AI不会对收到的 JSON 对象做任何校验,是否正确解释 Schema 中的约束(必填字段、整数范围等)完全取决于模型。输出类型是dict[str, Any],你的代码应防御性地读取内容;可以配合输出验证器把校验错误反馈给模型并让它重试。
七、DeferredToolRequests:把延迟工具请求作为输出
DeferredToolRequests是一个 dataclass(源码位于 pydantic_ai_slim/pydantic_ai/_deferred.py),可作为output_type使用:当模型在本次运行中调用了延迟工具(deferred tools)时,该对象成为运行的输出。它有三个字段:
calls:list[ToolCallPart],需要外部执行的工具调用;approvals:list[ToolCallPart],需要人工审批(human-in-the-loop)的工具调用;metadata:dict[str, dict[str, Any]],以tool_call_id为键的工具调用元数据。
结果可以通过build_results()方法构造DeferredToolResults传给下一次 Agent 运行(tool_call_id必须匹配):approvals键对应审批类调用,calls键对应外部执行类调用,metadata为逐调用元数据;approve_all=True时未显式列出的审批调用默认以ToolApproved()通过。remaining()方法返回应用结果后仍未解决的请求(全部解决则返回None)。
# 使用 DeferredToolRequests 作为输出类型的示例 from pydantic_ai import Agent, DeferredToolRequests agent = Agent( 'openai:gpt-5.2', output_type=[DeferredToolRequests, ...], # 与其他输出类型并列 )在OutputSchema.build()中(见 pydantic_ai_slim/pydantic_ai/_output.py),DeferredToolRequests会被识别并设置allows_deferred_tools=True,且要求至少再提供一个其他输出类型。更详细的用法参见 deferred-tools 文档。
八、OutputObjectDefinition 与输出上下文/钩子
OutputObjectDefinition是结构化输出生成的输出对象定义,一个 dataclass,包含四个字段:
json_schema:ObjectJsonSchema,输出对象的 JSON Schema;name:输出对象名称;description:输出对象描述;strict:是否启用严格模式。
它在模块内部由ObjectOutputProcessor.__init__构造:名称优先取显式传入的name,否则取 JSON Schema 的title或输出对象自身的__name__;描述优先取显式传入的description,否则取 docstring 生成的描述(两者都有时拼接)。
与之配套的还有OutputContext(虽然未在__all__中列出,但在模块内定义),它描述"正在处理的输出"的上下文信息,传给输出钩子使用:mode(配置的模式,注意它反映的是配置而非本次响应的实际格式,例如混合模式下ToolOutputSchema报告'tool',需结合tool_call判断)、output_type、object_def、has_function、function_name、tool_call、tool_def、allows_text、allows_image、allows_deferred_tools。
输出钩子(hooks)的编排在_output.py的run_output_validate_hooks/run_output_process_hooks中实现:validate 钩子(before_output_validate、wrap_output_validate、on_output_validate_error、after_output_validate)只对需要解析的结构化输出触发;process 钩子(before_output_process、wrap_output_process、on_output_process_error、after_output_process)对所有输出类型(文本、结构化、图片)都触发,包括工具输出模式。任一钩子抛出的ValidationError或ModelRetry,在wrap_validation_errors=True时会被转换为ToolRetryError(构造RetryPromptPart回传给模型重试);流式场景(wrap_validation_errors=False)则原样传播。@agent.output_validator装饰器注册的输出验证器运行在 process 钩子内部,因此会被wrap_output_process完整包裹。
九、Optional Output:允许None作为输出
有些 Agent 完全通过工具调用完成工作,不需要最终输出。默认情况下(output_type含str),模型被要求以文本结束最后一轮;若它认为工作已结束且无话可说,会返回空响应或仅含 thinking 内容的响应,Pydantic AI 仍会要求它产出文本。
把None加入output_type即可接受"无最终消息"作为合法结局:
from pydantic_ai import Agent agent = Agent('anthropic:claude-opus-4-6', output_type=str | None) @agent.tool_plain def mark_task_done(task_id: int) -> str: """Mark the task as done.""" return f'Task {task_id} marked done.' result = agent.run_sync('Mark task 1 as done, then stop without saying anything.') print(result.output) #> Nonestr | None是最典型的情况:模型只能通过"无文本输出"的响应(空响应、文本部分全为空串、或仅含 thinking 内容)来表态None,没有输出工具或结构化 Schema 参与。None也支持其他输出模式:
- 工具模式的裸联合(如
output_type=int | None、output_type=[int, float, None]):会额外暴露一个final_result_NoneType输出工具,让模型通过工具调用提交None;空响应仍同样被视为None。 - 显式模式标记(如
ToolOutput(int | None)、NativeOutput([int, None])):None作为包装器生成的判别式 Schema 的一个分支存在(ToolOutput以null提交,NativeOutput/PromptedOutput选择NoneType分支);此时空响应不被接受,模型必须通过 Schema 提交。
约束:output_type=None单独使用不合法,必须至少再提供一个其他输出类型。输出验证器仍会以None为参数运行,因此可通过抛ModelRetry拒绝None。流式场景下,stream_output()对空响应会产出空迭代器,应改用get_output()获取最终的None。
十、输出模式的选择与 end_strategy
三种结构化输出模式可概括为:
| 模式 | 机制 | 适用性 |
|---|---|---|
| Tool Output(默认) | 输出 Schema 作为特殊输出工具的参数 Schema,模型通过工具调用提交结果 | 几乎所有模型,稳定性好 |
| Native Output | 使用模型原生 Structured Outputs,强制输出符合 JSON Schema 的文本 | 需模型支持,部分模型有功能限制 |
| Prompted Output | 把 JSON Schema 注入 instructions 提示模型按 Schema 输出文本 | 所有模型可用,可靠性最低 |
当模型在同一响应中既产出最终结果又发出其他工具调用时,end_strategy决定这些调用的命运(默认'graceful'):
'graceful'(默认):输出工具按发出顺序执行,首个成功者即为最终结果,后续输出工具跳过;同时请求的函数工具仍会执行(副作用发生、结果在运行继续时对模型可用)。'early':输出工具一旦成功立即结束运行,同响应请求的函数工具完全跳过——最快,适合"拿到结果就不再需要函数工具"的场景。'exhaustive':所有工具(包括结果不会被使用的额外输出工具)都执行并并行化;首个按发出顺序通过校验的结果胜出。
当所有输出工具都失败时,三种策略下函数工具都会执行且运行继续:没有结果可结束,输出失败会作为重试回传给模型,函数工具结果让模型在下一轮同时做出反应。在'exhaustive'策略下,可用ToolOutput(sequential=True)把某个输出工具变成屏障,确保响应中的函数工具全部先执行完——这是函数工具sequential=True标志在输出工具上的对应物。
十一、源码视角:OutputSchema.build 的分发逻辑
理解整个输出体系最直观的方式是看 pydantic_ai_slim/pydantic_ai/_output.py 中OutputSchema.build()的分发流程:
_flatten_output_spec()递归展平output_spec(序列会被展开,PEP 604 联合通过get_union_args拆开),得到扁平的项目列表;- 检测特殊类型:
NoneType/None→allows_none;DeferredToolRequests→allows_deferred_tools;BinaryImage→allows_image(各要求至少再提供一个其他类型); - 若存在
NativeOutput标记 → 返回NativeOutputSchema(要求它必须是唯一输出类型,内部再展平其outputs构建处理器); - 若存在
PromptedOutput标记 → 返回PromptedOutputSchema(同样要求唯一); - 否则按成员分类:
str/TextOutput归入文本输出(最多一个),ToolOutput归入工具输出,其余归入普通类型/函数; - 文本与工具并存 →
ToolOutputSchema(混合模式,可同时接受文本与工具输出);纯文本 →TextOutputSchema;有ToolOutput→ToolOutputSchema;有其他类型/函数 →AutoOutputSchema(mode='auto',最终由模型 profile 决定具体结构化模式);仅图片 →ImageOutputSchema;否则抛出UserError('At least one output type must be provided.')。
单输出类型由ObjectOutputProcessor处理,多个输出由UnionOutputProcessor处理——后者为每个成员注册一个kind判别键,构造包含kind/data的判别式 JSON Schema(result.anyOf),并约束kind必须命中已注册键,未知值会以普通ValidationError失败。非对象 Schema(如int、list[int])会被包装进单元素对象({'response': value}),保证所有注册给模型的工具都是对象 Schema——这一点解释了 docs/output.md 中的说明。
十二、输出验证器(Output Validators)
@agent.output_validator装饰器注册的验证函数用于补充 Pydantic 校验器难以/无法完成的验证,尤其是涉及异步 IO 的场景。验证器可带可不带RunContext参数,同步异步皆可(OutputValidator会通过inspect.signature判断是否接收上下文,通过is_async_callable判断是否异步)。
每次验证器抛出ModelRetry会消耗 1 单位运行输出重试预算(默认 1,可通过Agent(retries={'output': N})、agent.run(retries={'output': N})或ToolOutput(max_retries=N)调整)。验证器内部,ctx.max_retries反映实际限制你的上限(文本路径的全局预算或工具路径的单工具上限),ctx.retry是全局重试计数器,在单次运行内切换输出工具时保持一致。验证器不支持ToolFailed——请用ModelRetry请求模型重新输出。若要对不同输出类型实现不同的验证逻辑,推荐改用输出函数,避免在验证器里做isinstance分支。
流式场景下验证器同样会被多次调用,应检查ctx.partial_output以只校验完整结果:
from pydantic_ai import Agent, ModelRetry, RunContext agent = Agent('openai:gpt-5.2') @agent.output_validator def validate_output(ctx: RunContext, output: str) -> str: if ctx.partial_output: return output if len(output) < 50: raise ModelRetry('Output is too short.') return output结语
pydantic_ai.output模块以output_type为唯一入口,通过ToolOutput、NativeOutput、PromptedOutput、TextOutput四个标记类 +StructuredDict助手函数 +DeferredToolRequests/BinaryImage/None等特殊类型,覆盖了从纯文本、结构化数据、函数调用结果到图片、延迟工具请求的全部输出形态。理解OutputSpec的展平与分发逻辑、OutputObjectDefinition的构造规则、输出钩子与验证器的执行时机,以及end_strategy对并发工具调用的影响,是写出健壮、可预测的 pydantic-ai Agent 的关键。更多配套内容可参考 结构化输出总览、StreamedRunResult 流式结果 与 Agent 运行文档。
【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考