ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Instructor Patching 机制深度解析:如何为 LLM 客户端注入结构化输出能力

Instructor Patching 机制深度解析:如何为 LLM 客户端注入结构化输出能力 Instructor Patching 机制深度解析如何为 LLM 客户端注入结构化输出能力【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructorPatching 是 Instructor 的核心机制之一它不修改 LLM SDK 的原始代码而是通过包装完成方法为客户端注入结构化输出能力——新增response_model等参数、基于 Pydantic 的校验、失败重试与类型化返回。本文将围绕 docs/concepts/patching.md 展开结合当前仓库的 v2 源码实现instructor/v2/core/patch.py、instructor/v2/core/mode.py、instructor/v2/core/registry.py讲清 Patching 的工作原理、各种 Mode 的适用场景、各提供商的默认模式以及手动 Patching 与from_provider的取舍读完即可在自己的项目中安全地使用或调试 Patching。Patching 是什么给客户端加装结构化输出Patching 的英文原意是打补丁。在 Instructor 的语境中它指的是在不动 LLM 客户端原始代码的前提下为其对象附加新功能。当你对 OpenAI、Anthropic、Google 等任意 SDK 客户端执行 patch 之后该客户端会获得一套新的能力新参数create()或chat.completions.create()方法新增response_model、max_retries、context等参数校验自动将 LLM 返回内容与 Pydantic 模型比对不合格则拦截重试校验失败时携带错误反馈自动重试兼容性被 patch 的客户端原有方法全部保留你依然可以使用 SDK 的全部原生功能。当前仓库中instructor.core.patch仅是兼容导出层见 instructor/core/patch.py真正的实现位于 v2 体系instructor/v2/core/patch.py。这意味着 Patching 机制已统一收敛到 v2 的 handler 注册表架构中这也解释了为什么文档推荐所有用户优先使用from_provider——它会自动完成 patch 并选择正确的 Mode。Patching 的工作流程五步走从 instructor/v2/core/patch.py 的同步包装器_create_sync_wrapper异步版本_create_async_wrapper与之对称见同文件 L309-L428可以看出patch 后的create方法执行流程如下包装完成方法patch()拦截客户端的chat.completions.create或传入的任意create函数用functools.wraps包装成新函数并回写到客户端对象上解析响应模型调用prepare_response_model处理response_modelresponse_model is not None and mode not in Mode.parallel_modes()时执行见 patch.py L227-L228转换为提供商格式通过注册表mode_registry.get_handlers(provider, mode)拿到该提供商对应 Mode 的request_handler将 Pydantic 模型转换为 JSON Schema、工具定义等提供商可理解的格式见 registry.py L159发送并校验重试将加工后的请求交给retry_sync_v2/retry_async_v2instructor/v2/core/retry.py其中内置了校验失败后的重试reask逻辑返回类型化对象校验通过后把 JSON 反序列化为 Pydantic 模型实例返回而不是原始响应。包装器还额外处理了几件隐藏事项autodetect_images图像自动检测、cache/cache_namespace/cache_ttl响应缓存、handle_templating模板注入instructor/v2/core/templating.py以及token_budget预算校验instructor/v2/core/budget.py。这些能力都是锦上添花——即使你不显式使用它们patch 依旧正常工作。从测试也能佐证这套流程的稳定性tests/llm/test_openai/test_patch.py 同时覆盖了同步与异步客户端的多 Mode 场景tests/core/test_patch.py 验证了最基本的instructor.patch(client)用法。手动 Patching最小可用示例文档提供了最直接的用法——先创建原生客户端再手动 patchimport openai import instructor from pydantic import BaseModel class YourModel(BaseModel): message: str # 创建基础客户端 openai_client openai.OpenAI() # 手动 patch 它 client instructor.patch(openai_client, modeinstructor.Mode.TOOLS) # 现在可以用了 response client.chat.completions.create( response_modelYourModel, messages[{role: user, content: Say hello}], )从源码看instructor.patch的完整签名是instructor/v2/core/patch.py L147-L168def patch( client: OpenAI | AsyncOpenAI | None None, create: Callable[..., T_Retval] | None None, mode: Mode Mode.TOOLS, provider: Provider Provider.OPENAI, ) - OpenAI | AsyncOpenAI | InstructorChatCompletionCreate:值得注意的细节默认modeMode.TOOLS、providerProvider.OPENAI如果你用的是非 OpenAI 客户端必须显式传入正确的provider否则注册表会因 Mode 未注册而抛出RegistryErrorpatch 前会调用RegistryValidationMixin.validate_mode_registration校验见 patch.py L106。支持create参数除了传客户端你也可以直接传一个函数instructor.patch(createmy_create_fn, ...)这为自定义客户端实现提供了入口。apatch已弃用异步场景直接使用同一个patch即可patch.py L171-L182 会抛出DeprecationWarning。包装器签名patch.py L195-L204patch 后的create接受response_model、context、max_retries、strict、hooks、token_budget。其中max_retries的类型是int | Retrying既可以是次数也可以是 tenacity 的Retrying实例——当前 v2 实现中默认值为1旧版文档记载为0以当前仓库源码为准。为什么推荐from_provider而非手动 Patching文档反复强调99% 的场景下from_provider是更优选择。对比两种写法import instructor from pydantic import BaseModel # 更简单的方式 class YourModel(BaseModel): message: str client instructor.from_provider(openai/gpt-4o-mini) _response client.create( response_modelYourModel, messages[{role: user, content: Say hello}], )手动 Patching 与from_provider的核心差异维度手动 Patchingfrom_provider提供商识别需要自己传provider枚举从provider/model字符串自动识别Mode 选择需要自己传mode按提供商应用推荐默认 Mode客户端创建自己 new SDK 客户端再 patch一行代码创建并完成全部配置切换提供商需重写初始化代码改一行字符串即可适用场景自定义客户端、调试 patch 行为绝大多数生产场景from_provider的完整用法API Key、Mode 覆盖、缓存、异步客户端、错误处理、提供商切换参见 docs/concepts/from_provider.md从旧的手动 Patching 模式迁移的详细步骤参见 docs/concepts/migration.md。在底层from_provider也复用了同样的注册表分发逻辑并通过get_provider(base_url)instructor/v2/core/providers.py L84-L126根据 base URL 的关键字如azure、anthropic、ollama、localhost:11434、x.ai等自动推断Provider枚举随后再确定合适的 Mode。Patching 的三种核心 Mode 与适用场景文档将 Mode 划分为三大类核心差异在于如何让模型返回结构化内容Tool CallingMode.TOOLS利用提供商原生的函数/工具调用 API把 Pydantic 模型转换成工具定义让模型以工具参数的形式输出结构化 JSON。OpenAI 的默认模式函数调用支持方OpenAI、Anthropic、Google、Ollama针对支持工具调用的模型。在源码中Mode.tool_modes()返回全部工具类 Mode 的集合instructor/v2/core/mode.py L80-L105包含TOOLS、PARALLEL_TOOLS、ANTHROPIC_TOOLS、GEMINI_TOOLS、MISTRAL_TOOLS、VERTEXAI_TOOLS、CEREBRAS_TOOLS、WRITER_TOOLS、BEDROCK_TOOLS、RESPONSES_TOOLS等。JSON ModeMode.JSON在提示词中直接要求模型返回 JSON然后从响应中解析并校验。对大部分提供商可用且通常更省 token。支持方OpenAI、Anthropic、Google、Ollama 及大多数提供商。Mode.json_modes()mode.py L108-L127列出了全部 JSON 类 Mode包括JSON、JSON_O1、JSON_SCHEMA、ANTHROPIC_JSON、GEMINI_JSON、BEDROCK_JSON、PERPLEXITY_JSON、XAI_JSON等。Markdown JSONMode.MD_JSON要求模型返回包裹在 markdown 代码块中的 JSON之后从文本/代码块中提取。支持方Databricks、部分视觉模型适用场景工具调用不可用或输出结构简单时的回退方案。值得注意的是当前仓库中许多提供商的旧模式如BEDROCK_JSON、FIREWORKS_JSON、WRITER_JSON、PERPLEXITY_JSON在 v2 中都会映射到MD_JSON见DEPRECATED_TO_CORE映射表mode.py L203-L250。各提供商的默认 Mode文档与from_provider文档docs/concepts/from_provider.md共同给出的默认模式如下提供商默认 Mode说明OpenAIMode.TOOLS函数调用支持流式结构化输出AnthropicMode.TOOLSClaude 原生 tool use APIGoogle GeminiMode.TOOLS函数调用需要jsonref包Union 类型除Optional外不受支持OllamaMode.TOOLS或Mode.JSONllama3.1、llama3.2、mistral-nemo 等支持工具旧模型回退到 JSON从源码角度v2 对过时提供商专属 Mode的处理是自动降级并警告normalize_mode_for_providerinstructor/v2/core/providers.py L76-L81会在 Mode 出现在DEPRECATED_TO_CORE中时先通过Mode.warn_deprecated_mode发出DeprecationWarning再将其替换为核心 Mode。例如ANTHROPIC_TOOLS → TOOLSANTHROPIC_JSON → MD_JSONBEDROCK_JSON → MD_JSONVERTEXAI_PARALLEL_TOOLS → PARALLEL_TOOLS因此无论你传的是新旧哪种 Mode最终都会收敛到TOOLS、JSON、JSON_SCHEMA、MD_JSON、PARALLEL_TOOLS、RESPONSES_TOOLS这几个核心 Mode 之一。完整的 Mode 对比、选型建议与各提供商兼容性清单参见 docs/modes-comparison.md 和 docs/concepts/mode-migration.md。使用from_provider时这些默认值会被自动应用如需覆盖可通过mode参数指定import instructor client instructor.from_provider( openai/gpt-4o-mini, modeinstructor.Mode.JSON, # 覆盖默认的 TOOLS 模式 )Patching 究竟给客户端加了什么文档明确了 patch 注入的功能清单我们逐一对照源码确认新增参数response_modelPydantic 模型或类型定义期望的输出结构。包装器接收后由prepare_response_model规范化再交给 handler 转成 schema。max_retries校验失败时的重试次数。当前 v2 包装器签名默认1且支持传入 tenacity 的Retrying对象进行精细控制patch.py L198。context校验钩子hooks使用的附加上下文会随请求一起传递给handle_templating与重试逻辑。此外还有strict默认True用于 schema 严格模式、hooksinstructor/v2/core/hooks.py、token_budget等参数。增强的方法行为patch 后的create()方法接受response_model参数自动校验响应是否符合 Pydantic 模型校验失败时自动重试并携带错误信息reask返回类型化的 Pydantic 对象而非原始响应原有全部参数照常透传SDK 原生功能不受影响。提供商特定的注意事项OpenAI默认Mode.TOOLS函数调用流式场景同样支持结构化输出相关测试见 tests/v2/test_openai_streaming.py通过Mode.RESPONSES_TOOLS支持新的 Responses API 工具调用见 mode.py L29-L30。Anthropic默认Mode.TOOLStool use使用 Claude 原生工具调用 APIANTHROPIC_REASONING_TOOLS已弃用现在建议用Mode.ANTHROPIC_TOOLS配合thinking{type: enabled, budget_tokens: ...}参数实现扩展思考见 mode.py L156-L175 的弃用说明。Google Gemini默认Mode.TOOLS函数调用工具调用依赖jsonref包需额外安装Union 类型除Optional外不受支持设计 schema 时需注意。Ollama本地模型默认Mode.TOOLS模型支持时或Mode.JSONllama3.1、llama3.2、mistral-nemo 等模型支持工具调用旧模型自动回退到 JSON 模式。什么时候才需要手动 Patching文档给出的结论非常明确绝大多数场景都不需要手动 Patching。仅在以下情况才考虑需要对 patch 过程做细粒度控制例如自定义create函数、精确指定provider与mode正在使用自定义客户端实现可借助patch(create...)传入任意函数调试 Patching 行为本身。此外如果你的需求是多工具并行一个响应中多次工具调用可关注Mode.PARALLEL_TOOLS及其别名parallel_modes()见 mode.py L129-L136。深入阅读docs/concepts/from_provider.md —— 推荐方式一行代码创建已 patch 的客户端docs/concepts/migration.md —— 从手动 Patching 迁移到from_providerdocs/modes-comparison.md —— 各 Mode 的详细对比与选型建议docs/concepts/mode-migration.md —— 旧 Mode 到核心 Mode 的映射说明docs/integrations/index.md —— 各提供商的专属文档核心实现instructor/v2/core/patch.py、instructor/v2/core/mode.py、instructor/v2/core/registry.py、instructor/v2/core/providers.py测试参考tests/core/test_patch.py、tests/llm/test_openai/test_patch.py、tests/v2/test_issue_2374.py演示了Mode.MD_JSON Provider.GEMINI的手动组合【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表