
Instructor 结构化输出核心用 Pydantic Response Model 定义 LLM 输出模式【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor本文以 Instructor 的 Models 概念文档 为核心骨架结合仓库源码instructor/v2/core/schema.py、instructor/v2/providers/openai/schema.py、instructor/v2/core/client.py与配套教程Response Models 教程、Fields 概念、Optional Fields 教程展开。读者将掌握如何用pydantic.BaseModel定义 LLM 输出结构、如何通过response_model让模型自动校验并返回类型化实例、如何利用 docstring 与字段注解进行提示词工程、如何处理可选字段、如何在运行时动态创建模型以及如何给模型挂载业务方法。什么是 Response ModelInstructor 的核心理念是用 Pydantic 模型定义你要什么让语言模型照着输出。在 Instructor 中这个用于描述输出结构的 Pydantic 模型就被称为Response Model。定义一个 Response Model 极其简单——它就是一个普通的pydantic.BaseModel子类from pydantic import BaseModel, Field class User(BaseModel): name: str Field(descriptionThe name of the user.) age: int Field(descriptionThe age of the user.)定义完成后把它作为response_model参数传给客户端例如client.create(...)Instructor 会在背后完成三件事定义 schema 与提示词把你的模型编译成 JSON Schema 并注入 prompt / 工具定义告诉语言模型应该输出什么形状的数据校验 API 返回对语言模型的原始输出进行解析与 Pydantic 校验类型不符或缺失字段都会触发重试详见 Retrying 概念返回模型实例最终交付的是一个已经通过校验的User实例而不是一坨需要手动解析的 JSON 字符串。对应到仓库源码响应处理的核心管线位于 instructor/v2/core/client.py其中create的签名里response_model: type[T]或None直接决定了本次调用是否走结构化输出分支而把模型变成发给 LLM 的 schema这一步在 v2 架构中按供应商拆分统一由 instructor/v2/core/schema.py 导出generate_openai_schema、generate_anthropic_schema、generate_gemini_schema三个兼容入口实际实现在各供应商目录下如 instructor/v2/providers/openai/schema.py。一个最小可用示例import instructor from pydantic import BaseModel, Field class User(BaseModel): name: str Field(descriptionThe name of the user.) age: int Field(descriptionThe age of the user.) client instructor.from_provider(openai/gpt-4o-mini) user client.create( response_modelUser, messages[{role: user, content: Extract: John is 30 years old}], ) print(user.name) # John print(user.age) # 30from_provider(openai/gpt-4o-mini)是 Instructor 提供的统一客户端创建接口支持 OpenAI、Anthropic、Gemini、Mistral、Cohere、Groq 等大量供应商完整列表见 Integrations 索引 与 from_provider 概念。用 docstring 与字段注解驱动提示词Response Model 不仅定义结构它本身还承载着提示词工程。Instructor 约定类的 docstring 就是发给语言模型的指令每个字段的类型注解与Field(description...)就是对该字段的说明。from pydantic import BaseModel, Field import instructor class User(BaseModel): This is the prompt that will be used to generate the response. Any instructions here will be passed to the language model. name: str Field(descriptionThe name of the user.) age: int Field(descriptionThe age of the user.) client instructor.from_provider(openai/gpt-4o-mini) user client.create( response_modelUser, messages[{role: user, content: Extract: John is 30 years old}], )源码层面的证据在 instructor/v2/providers/openai/schema.pygenerate_openai_schema用docstring_parser.parse(model.__doc__)解析类 docstring把其中的参数说明:param xxx: ...补进 JSON Schema 对应字段的description若整个模型没有 description则自动生成Correctly extracted \{model.name} with all the required parameters with correct types 作为工具描述。也就是说你写下的 docstring 与字段描述会被直接编译进发给 LLM 的 tool/function schema这就是用 Python 类型系统做提示词工程的原理。此外Pydantic 的Field还提供了更多可用于提示词工程的元数据详见 Fields 概念description字段语义说明title字段标题examples字段示例值可显著提升抽取准确性json_schema_extra向 JSON Schema 追加任意额外属性。这些都会进入model.model_json_schema()生成的 schema进而影响 LLM 的输出质量。让字段可选Optional 与默认值现实中的抽取任务经常遇到原文里没有这个信息的情况。此时可以把字段声明为Optional并给出默认值from pydantic import BaseModel, Field from typing import Optional import instructor class User(BaseModel): name: str Field(descriptionThe name of the user.) age: int Field(descriptionThe age of the user.) email: Optional[str] Field(descriptionThe email of the user., defaultNone) client instructor.from_provider(openai/gpt-4o-mini) user client.create( response_modelUser, messages[{role: user, content: Extract: John is 30 years old}], ) # user.email None需要注意两个关键点Optional[str]本身不产生默认值即使类型写成Optional[str]字段依然会被视为必填required。必须显式给出defaultNone或default_factory字段才会在发给 LLM 的 schema 中标记为可选。这一点在 Fields 概念 中也有明确提示。JSON Schema 层面可选字段意味着该字段允许为null同时Optional不改变类型的描述LLM 在信息缺失时倾向于返回null而不是凭空编造。关于可选值还有两套进阶工具Maybe[T]类型用于表达模型也不确定的字段返回值包裹在Maybe容器中可通过is_uncertain判断置信度详见 Maybe 概念 与 Optional Fields 教程SkipJsonSchema注解如果某个字段例如private_field、scratch_pad不想让语言模型看到可以用 Pydantic 的SkipJsonSchema[...]把它从发给 LLM 的 schema 中剔除并配合默认值使用见 Fields 概念中的对应小节。从源码看可选字段不进入 required 集合的行为是有意为之在 instructor/v2/providers/openai/schema.py 的注释中明确说明parameters[required]直接复用 Pydantic 自己计算出的schema.get(required, [])而 Pydantic 的 required 集合天然排除了带默认值无论是default还是default_factory的字段——这也解释了为什么只写Optional而不给默认值不生效。运行时动态创建模型当输出结构在编码期无法预知例如由数据库配置、用户配置或动态业务规则决定时可以使用 Pydantic 的create_model在运行时构造模型。基础用法from pydantic import BaseModel, create_model class FooModel(BaseModel): foo: str bar: int 123 BarModel create_model( BarModel, apple(str, russet), banana(str, yellow), __base__FooModel, ) print(BarModel) # class __main__.BarModel print(BarModel.model_fields.keys()) # dict_keys([foo, bar, apple, banana])create_model的字段参数形式为(类型, 默认值或 Field)同时可以用__base__继承已有模型实现字段的合并与复用。典型场景从数据库配置构建模型文档给出的典型场景是模型的结构保存在数据库中例如一张prompt表存有每个model_name对应的property_name / property_type / descriptionSELECT property_name, property_type, description FROM prompt WHERE model_name {model_name}拿到查询结果后用create_model一行代码完成模型构建from pydantic import BaseModel, create_model, Field from typing import List types { string: str, integer: int, boolean: bool, number: float, List[str]: List[str], } # Mocked cursor.fetchall() cursor [ (name, string, The name of the user.), (age, integer, The age of the user.), (email, string, The email of the user.), ] BarModel create_model( User, **{ property_name: (types[property_type], Field(descriptiondescription)) for property_name, property_type, description in cursor }, __base__BaseModel, ) print(BarModel.model_json_schema())输出正是标准 JSON Schema可作为response_model直接使用{ properties: { name: {description: The name of the user., title: Name, type: string}, age: {description: The age of the user., title: Age, type: integer}, email: {description: The email of the user., title: Email, type: string} }, required: [name, age, email], title: User, type: object }这套模式的价值在于同一个代码库可以为不同用户/场景生成字段相同、描述不同的模型——字段描述即提示词因此等于实现了同一结构、个性化 prompt。关于 JSON Schema 生成的更多细节Optional 允许 null、Decimal 序列化为字符串、子模型进入$defs等见 Fields 概念文档的附录。给模型添加行为让抽取结果会做事Pydantic 模型本质是 Python 类因此可以像普通类一样定义方法为抽取结果附加业务逻辑from pydantic import BaseModel from typing import Literal import instructor client instructor.from_provider(openai/gpt-4.1-mini) class SearchQuery(BaseModel): query: str query_type: Literal[web, image, video] def execute(self): print(fSearching for {self.query} of type {self.query_type}) # Searching for cat of type image return Results for cat query client.create( modelgpt-4.1-mini, messages[{role: user, content: Search for a picture of a cat}], response_modelSearchQuery, ) results query.execute() print(results) # Results for cat在这里Literal[web, image, video]让 LLM 的输出被约束到枚举取值内详见 Enums 概念而execute()方法则在抽取完成后原地执行后续动作。这种结构 行为一体的模式非常适合将 RAG 检索、SQL 执行、API 调用等副作用封装在模型内部——官方博客 RAG is more than embeddings 中有更多此模式的实际案例。类似地Pydantic 还支持用field_validator/model_validator挂载自定义校验逻辑使模型内部即可校验、失败则自动重试参考 Validation 概念 与 Custom Validators 教程。组合进阶从简单模型到复杂结构Response Model 的能力可以自由组合覆盖从简单到复杂的各类抽取需求详见 Response Models 教程嵌套模型addresses: List[Address]实现分层数据结构抽取列表字段tags: List[str]一次抽取多个同类条目字段校验price: float Field(gt0)、name: str Field(min_length3)让 Pydantic 在解析时完成边界校验文档即提示为模型写 docstring、为字段写 description让 LLM 与同事都能理解模型语义。一个综合示例结合 Simple Object Extraction 与 Nested Structure 教程from typing import List, Optional from pydantic import BaseModel, Field class Address(BaseModel): street: str city: str country: str class User(BaseModel): A user record extracted from unstructured text. name: str Field(descriptionFull name of the user.) age: Optional[int] Field(defaultNone, descriptionAge if mentioned.) addresses: List[Address] Field(descriptionAll known addresses.) # 作为 response_model 使用 # user client.create(response_modelUser, messages[...])常见问题与排查要点字段声明了Optional却仍被要求必填Optional不自动产生默认值请补上 None或default_factory。不想让 LLM 看到/生成某字段用SkipJsonSchema[...]从 schema 中剔除并给出默认值避免校验失败。抽取结果字段总是错误或缺失优先检查 docstring 与Field(description...)是否准确——它们直接编译进发给 LLM 的 schema源码见 instructor/v2/providers/openai/schema.py。结构在编码期未知用create_model从配置/数据库动态构建字段描述按需生成。希望失败自动重试Instructor 默认在响应校验失败时携带错误信息向 LLM 重试可参考 Retrying 概念 调整max_retries。参考与延伸阅读Response Models 教程创建响应模型的分步指南Simple Object Extraction基础抽取模式Nested Structures复杂层级模型Optional Fields可选数据的处理Types各类数据类型的使用Fields字段高级配置与 JSON Schema 定制Maybe 概念表达不确定的字段Fields 文档中的相关小节SkipJsonSchema用法【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考