资讯动态

为 Pydantic AI 添加 Provider API 能力:跨 Provider 抽象、默认值策略与能力门控的完整工程指南

发布时间:2026/9/13 21:29:51 来源:尧图企业网站定制
为 Pydantic AI 添加 Provider API 能力跨 Provider 抽象、默认值策略与能力门控的完整工程指南【免费下载链接】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-aiPydantic AI 是一个类型安全、端到端的 Python AI 框架屏蔽了数十家模型提供商的差异。当需要为它新增一项Provider API 能力提示词缓存、strict/结构化工具调用、思考/推理强度、服务等级 service tier、安全设置、logprobs、缓存断点等时如何设计出的 API 与既有抽象一致、默认值深思熟虑、并以能力标志capability flag做门控是一门有明确方法论可循的工程学问。本指南基于仓库中.agents/skills/adding-a-provider-api-feature/SKILL.md这份维护者技能文档展开并结合pydantic_ai_slim包中的源码实现与测试用例完整还原从设计决策到落地验证的六步流程。本指南不适用于新增模型 id那是另一条add-new-model流程、修复 bug 或纯重构。它只针对把某个 provider 已有的 API 能力以正确的方式透传到 Pydantic AI 用户面前这一场景。防止返工的唯一铁律先找到治理该能力的既有跨 Provider 抽象在开始设计任何东西之前先找出代码库中已经存在的、管辖该能力的跨 Provider 抽象让它的形状替你决定 API。这是最能在早期避免返工的一条规则也是维护者在评审中拒绝改动的最常见原因——我该怎样暴露这个功能这个问题十有八九已被代码库里的某个抽象回答过了当现有抽象存在时再去设计一个 provider 专属的新开关几乎必然被拒。判定你是否跳过此步的征兆很直接当你发现自己正在列出 2-3 个用户如何控制这个功能的候选方案时——如果其中一个方案与既有跨 Provider 控件重复那它就不是真正的选项既有抽象胜出。Pydantic AI 中管辖各能力的既有抽象共五类SKILL.md 逐一给出了落点抽象形态代表实现用途per-tool 标志ToolDefinition.strict: bool | Nonetools.py在 models/init.py 的_customize_tool_def中解析strict 工具调用共享ModelSettings字段thinking、service_tiersettings.py各带 per-model 解析器映射到原生概念思考、服务等级{Provider}ModelSettings前缀字段anthropic_cache、openai_prompt_cache_key、groq_reasoning_effort无法用共享枚举表达的 provider 原生值消息流标记message-stream markerCachePointmessages.py 的UserPromptPart.content中缓存断点ModelProfile能力标志openai_supports_strict_tool_definition、bedrock_supports_prompt_caching模型/家族级能力事实Step 0 — 枚举兄弟 Provider 的先例对你要新增的能力先列出每个已有同类能力的 provider 是如何暴露它的并点明管辖它的既有抽象。历史上跳过这一步的贡献者都被评审打了回票有人直接上原始google_tool_config被要求改用共享的strict对应 issue #5366 的评审意见有人用字符串前缀做模型检测被要求改用 profile 标志对应 PR #4604 的评审讨论。因此在动笔设计前应当实际阅读兄弟 provider 的实现并翻阅引入它们的 PR 评审线程gh pr view n --comments。只有当没有任何既有抽象覆盖该能力时才允许打开一个设计分叉。Step 1 — 选择 API 形态按优先级排列共有六条决策准则既有跨 Provider 抽象已覆盖 → 直接复用。新增一个 provider 映射_translate_*解析器、JsonSchemaTransformer子类、CachePoint翻译。对于共享抽象已经表达的语义不要再加 provider 前缀的旋钮。无共享抽象但 ≥3 个 provider 已有该概念 → 提升为共享ModelSettings字段。采用刻意收窄的通用词汇表 per-model 解析器把 per-provider 字段保留在下面作为优先级更高的逃生舱口service_tier的提升即此范例见 PR #4926。不要删除provider 旋钮只对确实命名不当的做废弃并留TODO(v3)注释。provider 原生值无法用共享枚举表达家族间取值集合不相交、或纯平台侧请求塑形→ 此时{provider}_*旋钮才合理且它与统一字段共存并优先于它groq_reasoning_effort即此范例见 PR #5797。按用户能否自然地指向它选择落点边界在消息流内部→ 用标记CachePoint是结构性区域system prompt、工具定义、整请求设置→ 用 setting见 PR #3363 的评审讨论。把能力接进 provider 的每一条请求路径chat API 和 responses API 都要跨 provider API 共享的设置放到基础 settings 类上见 PR #3678 的评审讨论。类型化。尽量复用 provider SDK 自带的类型旋钮一律用Literal类型化绝不用extra_body或未类型化的**kwargs。这正是 models/AGENTS.md 与核心维护者 DouweM 反复强调的kwargs 是大忌……我宁愿重复也要类型安全PR #3457 评审。源码佐证strict与_customize_tool_def以 strict 工具调用为例看这条链路在仓库中的真实落点。ToolDefinition定义在 tools.py 第 550 行附近strict: bool | None None文档明确说明False时绝不启用 strict 模式在 Google 上任何strictFalse的函数或输出工具会把整个请求留在AUTO模式因为 Gemini 的模式是请求级的而非工具级None默认时按 provider 推断——OpenAI 在 schema 严格兼容时启用Google 在受支持模型Gemini 2.5上默认VALIDATEDAnthropic 与 Bedrock 则保持关闭除非显式strictTrue。解析发生在 models/init.py 的_customize_tool_def第 1847-1858 行def _customize_tool_def(transformer: type[JsonSchemaTransformer], tool_def: ToolDefinition) - ToolDefinition: schema_transformer transformer(tool_def.parameters_json_schema, stricttool_def.strict) parameters_json_schema schema_transformer.walk() return replace( tool_def, parameters_json_schemaparameters_json_schema, strictschema_transformer.is_strict_compatible if tool_def.strict is None else tool_def.strict, )可见当strict is None时最终值由JsonSchemaTransformer.is_strict_compatible推断显式设置则原样保留。这与 SKILL.md 中per-tool 标志 per-schema 兼容性信号的门控分层完全一致。JsonSchemaTransformer的基类定义在 _json_schema.py第 16-60 行它遍历 JSON schema 并在每层应用转换is_strict_compatible字段默认置True用于在strict is None时回填ToolDefinition.strict或OutputObjectDefinition.strict。不同 provider 的子类会按自己的 schema 方言收窄该信号。Step 2 — 默认值默认开启静默vs 显式 opt-in默认值决策是这份技能文档的第二个重点。规则是只有当下述条件同时成立时才默认开启——启用该功能不会改变可观察行为、也不会让用户多花钱即一个纯向后兼容的改进例如缓存只会降低成本一个无需重写 schema、也不会拒绝此前合法请求的校验模式。纯受益且向后兼容的默认值受欢迎无需 opt-in。反之以下情形必须保持opt-in会改变可观察的输出或线上行为是preview预览功能provider 可能更改语义可能提高成本——且要小心选择默认值让共享字段永不静默把用户升级到更贵档位service_tier用auto而非default见 PR #4926在规模化时可能撞上 provider 限制曾有人自动提升 strict 模式结果静默弄坏了工具数 20 的 agent随后在 PR #5580 回滚涉及有损的 schema 重写OpenAI/Anthropic 的 strict 转换。当默认值不明朗时用真实探针live probe决策而不是凭观点。PR #5897 就把一个默认值从 0/5 恢复率翻成 5/5。另外要警惕文档里的automatic措辞——需要核实它指的是 Pydantic AI 侧的默认值还是只是 provider 侧对某个 opt-in 功能的托管。源码佐证service_tier与thinking的默认语义settings.py 中service_tier的取值集合文档写明per-provider settingsopenai_service_tier、anthropic_service_tier、bedrock_service_tier、google_cloud_service_tier总是优先于这个统一字段。这正是共享字段 下层逃生舱口结构的运行体现——共享枚举只表达交叉词汇如auto/default原生值交给前缀字段。thinking: ThinkingLevel同样在 settings.pyTrue用 provider 默认强度、False关闭在永远思考的模型上被静默忽略、minimal/low/medium/high/xhigh指定强度省略时用模型默认行为。provider 专属设置如anthropic_thinking在设置后覆盖统一字段。Step 3 — 能力门控Capability gating检测能力支持度要用ModelProfile上的 provider 前缀标志在Provider.model_profile()中设置——绝不要在代码里内联isinstance或模型名判断见 profiles/AGENTS.md 的明确要求。门控要放在实际发生变化的那一层模型/家族级→ profile 标志google_supports_strict_tool_definition、bedrock_supports_prompt_cachingper-schema 级→JsonSchemaTransformer.is_strict_compatible信号除非该模式无需重写否则默认保守SDK 版本级→ 探测 SDK 形态退化并用UserWarning提示PR #5580botocore 的 strict 参数即此案例客户端侧无法得知→ 交由运行时 API 错误兜底。不支持 → 静默忽略该设置best-effort让尽可能多的请求成功并在 docstring 中说明——绝不硬报错。用户设置冲突 → 用UserWarning而非UserError。Profile 是分层的开发者 key 的基座 按家族解析的薄 provider 覆盖层且provider 覆盖层最后叠加见 issue #5934 与 PR #6231。源码佐证ModelProfile的字段语义ModelProfile定义在 profiles/init.py第 47 行起是一个totalFalse的 TypedDict所有字段可选缺省键表示用文档化默认值。与本文主题直接相关的能力字段包括supports_thinking: bool——模型是否支持思考/推理配置False时统一thinking设置被静默忽略thinking_always_enabled: bool——模型是否总是思考OpenAI o-series、DeepSeek R1True时thinkingFalse被静默忽略并蕴含supports_thinkingTruejson_schema_transformer: type[JsonSchemaTransformer] | None——使工具/结构化输出 schema 与模型兼容的转换器。子类如OpenAIModelProfile、AnthropicModelProfile追加 provider 专属键跨类合并走 dict-spread。实际例子在 profiles/google.pygoogle_supports_strict_tool_definition is_thinking_model and not is_image_modelgoogle_supports_thinking_level is_3_or_newer——能力事实完全以标志形式沉淀而非散落的模型名判断。Step 4 — 测试录制线上 wire-contract cassette测试策略是以真实线上录制的wire-contract cassette为准断言精确的出站请求体——受支持模型会发出该 mode/字段不受支持模型则缺失或被忽略再加一个实际行使新设置的测试。优先用基于 case 的参数化 VCR而不是 mock但当要断言 cassette 匹配器抓不到的内部请求形状时单元测试仍然适用这也是反驳评审机器人这会失败论断的方式直接附上一份录制好的 cassette 作为证据。在 tests/models 目录下可以找到大量此类 cassette 测试例如 test_model_settings_support.py详见下一节以及各 provider 的 cassettes 目录中的上千份 YAML 录制文件都是这一测试理念的仓库级体现。Step 5 — 文档与技能更新新公开符号的 docstring 必须列出哪些 provider 支持它、以及各自如何解释该值。随后新增/刷新 docs 下的对应.md章节更新那些现在宣称不足的兄弟 docstring比如only OpenAI要改成完整 provider 列表机制描述只写到 provider 文档所声明的程度——provider 文档没写明的机制不要替它断言更新相关的 agent skill本 SKILL.md 自身就是这一环节的产物。源码佐证Supported by:清单是被测试强制执行的ModelSettings每个字段的Supported by:清单不是手写注释而是被强制校验的tests/models/test_model_settings_support.py会逐个探测每个 model 类的出站请求断言清单里列出的类恰好就是实际发送该字段的类。这意味着转发一个新设置 → 必须同步编辑它的清单新增一个Model类 → 必须在那个测试里新增一个Casetool_choice与thinking通过HAND_MAINTAINED豁免继续人工维护。源码佐证CachePoint的受支持列表写法以CachePoint标记为例messages.py 第 789-817 行它可插入UserPromptPart.content标记缓存边界不支持的模型会过滤掉它docstring 的Supported by:列出 Anthropic、Amazon BedrockConverse API、OpenAIGPT-5.6 系列、OpenRouter。ttl字段取值5m | 1h并逐行说明每个 provider 对 TTL 的差异化处理如 OpenAI 忽略 per-marker 值、改用请求级openai_prompt_cache_options[ttl]OpenRouter 对 Gemini 模型自动省略显式 TTL。这正是 Step 5列出支持者 说明各自解释方式的示范写法。维护者反复强调的九条原则引述跨 Provider 抽象优先于 provider 旋钮——这映射到 Anthropic 与 OpenAI API 里的strict……它已经表示在ToolDefinition上了……一个更完整、更一致、不要求用户做特殊处理的实现应该自动使用这个模式。issue #5366一旦多个 provider 都有该概念就提升为共享设置per-provider 覆盖保留在底层。PR #4926Best-effort——静默忽略不支持的设置不要报错——我们通常做 best effort好让尽可能多的请求成功。PR #3438隐藏 provider 复杂性——功能应该对不想成为该 provider 限制专家的用户同样可用。能力事实属于ModelProfile标志基座 覆盖分层。issue #5934类型安全优于重复不要未类型化的 kwargs。PR #3457共享字段放在基础 settings 类上覆盖所有 API 表面。PR #3678对照真实 API 验证把校验推迟到运行时——如果 SDK 类型允许、我们试了不失败我就没问题。PR #3678即使推迟统一也要命名它——今天的{provider}_*旋钮可以注明未来应折叠进的Caching/Thinking风格能力。PR #4604先例地图七项能力的完整决策档案能力复用的抽象默认值门控关键 PR/issueservice tier跨 provider提升为ModelSettings.service_tieropt-in绝不静默升级map-and-drop#4926strict — OpenAI起源ToolDefinition.strict按兼容 schema 自动提升per-schemais_strict_compatible#1304strict — Anthropic复用strict保守 opt-intransformer profile 标志#3457strict — Bedrock含修复复用strictopt-in自动提升已回滚transformer profile SDK 探测#4237、#5580strict — GeminiVALIDATED复用strict拒绝原始google_tool_config默认开启该模式无需 schema 重写profile 标志is_strict_compatible True#6353thinking跨 providerModelSettings.thinking per-provider 映射opt-in优雅降级supports_thinking标志#4640reasoning effort — Groqprovider 旋钮与thinking共存并优先opt-inper-family profile 标志#5797、#6231prompt caching — Anthropic → Bedrock/OpenRouterCachePoint标记 settingsopt-in{provider}_supports_prompt_caching#3363、#3438、#4604结语一套可复用的新增能力清单把 SKILL.md 浓缩成一份可执行的 checklist任何 provider API 能力的新增都可照此走完先枚举列出每个已有同类能力的 provider 如何暴露它命名管辖它的既有抽象只在一处开口共享抽象覆盖 → 复用≥3 provider 有该概念 → 提升共享字段值集不相交 → 才允许{provider}_*旋钮且共存并优先接通所有请求路径chat 与 responses API 都要接线共享设置放基础 settings 类类型化Literal拒绝extra_body与裸**kwargs定默认值纯向后兼容且不增成本才默认开启否则 opt-in不确定就用真实探针验证能力门控ModelProfile标志provider 前缀、分层叠加、最后覆盖不支持就静默忽略并写进 docstring测试wire-contract cassette 断言出站请求体 参数化 VCR文档docstring 列出支持者与各自语义同步Supported by:清单有测试强制、docs 章节与相关 skill。这套方法论的价值在于它不是一份按步照做的模板而是一套用既有抽象的形状预决 API 表面的设计纪律——遵守它你的改动会天然与 Pydantic AI 现有的 30 个 provider 保持一致也最容易被维护者接受。【免费下载链接】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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价