
深入理解 Instructor 中的字段元数据用 Pydantic Field 精调 LLM 结构化输出【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructorpydantic.Field是 Instructor 结构化输出体系的控制面板通过它定义默认值、排除敏感中间字段、裁剪发送给语言模型的 Schema并用title/description/examples/json_schema_extra把提示词工程直接注入 JSON Schema。本文将完整讲解Field的全部核心用法并结合仓库源码instructor/v2/providers/openai/schema.py、instructor/v2/core/function_calls.py等剖析这些元数据最终如何被转换成 OpenAI / Anthropic / Gemini 等各家的工具定义与提示词读完即可在真实抽取任务中熟练运用字段级定制。为什么字段元数据是提示词工程的关键一环在 Instructor 中response_model里的 Pydantic 模型承担双重角色它既是输出结构的校验器又是发送给语言模型的提示词来源。正如 Response Models 文档所述模型的 docstring、字段类型与字段注解会被一起用于构造 promptcreate方法据此生成响应。而Field正是字段级元数据的统一入口。Instructor 在各 provider 的 handler 中都直接依赖 Pydantic 的model_json_schema()来生成工具定义例如 bedrock/handlers.py、openai/handlers.py、cohere/handlers.py 等均通过response_model.model_json_schema()取值。这意味着你在Field中写下的每一个参数最终都会进入模型看到的 Schema 与提示词。理解Field就是理解如何用元数据编程语言模型的输出行为。默认值default与default_factorydefault参数用于为字段定义静态默认值from pydantic import BaseModel, Field class User(BaseModel): name: str Field(defaultJohn Doe) user User() print(user) # nameJohn Doedefault_factory则接收一个可调用对象在实例化时才生成默认值——适合每次都需要新鲜默认值的场景如生成唯一 IDfrom uuid import uuid4 from pydantic import BaseModel, Field class User(BaseModel): id: str Field(default_factorylambda: uuid4().hex)两个使用要点互斥default与default_factory不能同时使用Optional不等于默认值使用typing.Optional只是声明字段可以是None并不会自动赋予None默认值必须显式使用default或default_factory定义默认值字段才会在发送给语言模型时被判定为not required非必填。这一required 判定逻辑在源码中得到了精确实现。在 instructor/v2/providers/openai/schema.py#L26-L31 中generate_openai_schema直接复用 Pydantic 的required集合# Reuse Pydantics own required set, which excludes any field that has a # default -- whether that default is a plain value (default) or a # default_factory. Deriving it from the presence of a default # key in each property missed default_factory fields (whose defaults are # never emitted into the JSON schema) and wrongly marked them required. parameters[required] sorted(schema.get(required, []))从源码注释可以推断如果单纯检查 JSON Schema 中是否存在default键会漏掉default_factory字段其默认值不会写入 JSON Schema从而被错误标记为必填。因此 Instructor 选择信任 Pydantic 自身的 required 推导结果保证default_factory字段同样不会被强制要求模型输出。用Annotated组合FieldField也可以与类型标注Annotated一起使用把默认值等元数据直接贴在类型上便于复用类型别名from uuid import uuid4 from typing_extensions import Annotated from pydantic import BaseModel, Field class User(BaseModel): id: Annotated[str, Field(default_factorylambda: uuid4().hex)]这种写法在 Instructor 的简单类型输出中同样成立如 Types 概念 所示可以直接把Annotated[bool, Field(descriptionSample Description)]传给response_modelInstructor 内部会用create_model将其包装为BaseModel后再生成 Schema。exclude导出模型时剔除无关字段exclude用于控制字段在模型导出如model_dump_json()时是否被剔除。这对结构化输出尤其有价值像scratch_pad草稿纸或chain_of_thought思维链这类仅供模型推理、不该出现在最终结果里的字段可以放心保留在模型中导出时自动隐藏from pydantic import BaseModel, Field from datetime import date class DateRange(BaseModel): chain_of_thought: str Field( descriptionReasoning behind the date range., excludeTrue ) start_date: date end_date: date date_range DateRange( chain_of_thought I want to find the date range for the last 30 days. Today is 2021-01-30 therefore the start date should be 2021-01-01 and the end date is 2021-01-30, start_datedate(2021, 1, 1), end_datedate(2021, 1, 30), ) print(date_range.model_dump_json()) # {start_date:2021-01-01,end_date:2021-01-30}注意exclude只影响导出序列化字段仍保留在模型实例中date_range.chain_of_thought仍可访问适合思考过程仅用于内部、结果交付给下游的推理型任务。SkipJsonSchema从发送给 LLM 的 Schema 中彻底移除字段与exclude导出阶段不同有些场景希望语言模型完全看不到某个字段——即从 Instructor 构造提示词与工具定义所依据的 JSON Schema 中整体移除。这时使用 Pydantic 的SkipJsonSchema注解from pydantic import BaseModel from pydantic.json_schema import SkipJsonSchema from typing import Union class Response(BaseModel): question: str answer: str private_field: SkipJsonSchema[Union[str, None]] None assert private_field not in Response.model_json_schema()[properties]由于模型永远不会为该字段返回值你必须为它提供默认值可以是defaultNone也可以通过 PydanticField声明default_factory。这一点与 Response Models 中使用SkipJsonSchema将字段从发给 LLM 的 Schema 中省略的用法相互呼应是内部元数据如内部 ID、缓存键、校验辅助字段与外部 Schema 解耦的标准手段。定制 JSON Schema把提示词工程写进字段以下参数专用于定制生成的 JSON Schema也是 Instructor 提示词工程最常用的武器参数作用title字段的标题description字段的描述对模型的指令examples字段的示例值json_schema_extra向字段追加任意额外的 JSON Schema 属性它们都是在 Schema 中注入更多信息的机会直接影响模型对字段的理解。看一个综合示例from pydantic import BaseModel, Field, SecretStr class User(BaseModel): age: int Field(descriptionAge of the user) name: str Field(titleUsername) password: SecretStr Field( json_schema_extra{ title: Password, description: Password of the user, examples: [123456], } ) print(User.model_json_schema()) { properties: { age: {description: Age of the user, title: Age, type: integer}, name: {title: Username, type: string}, password: { description: Password of the user, examples: [123456], format: password, title: Password, type: string, writeOnly: True, }, }, required: [age, name, password], title: User, type: object, } 可以看到SecretStr类型会自动带来format: password与writeOnly: True而json_schema_extra允许你把title、description、examples一次性整体注入适合在复用已有配置时批量定制。为什么description如此重要在 instructor/v2/providers/openai/schema.py#L19-L37 中generate_openai_schema会解析模型 docstring对每个docstring.params如果属性尚未有description就用 docstring 参数说明回填模型本身若无description则回退到 docstring 的short_description再兜底使用Correctly extracted \{model.name} with all the required parameters with correct types。这解释了为什么给Field(description...)、类 docstring 写清楚说明能显著提升抽取质量——它们最终会成为语言模型看到的工具描述。description约束型参数如min_length、pattern、ge、le等也值得联动使用详见 Field Validation 教程 中的约束表与field_validator示例验证失败时 Instructor 会捕获错误、将错误信息拼入上下文并自动重试。JSON Schema 生成的通用规则原文档最后给出了一组关于 JSON Schema 生成的通用规则理解它们能避免许多模型输出与预期不符的坑Optional字段的 JSON Schema 会明确表示该字段允许为nullDecimal类型在 JSON Schema 中以及序列化时以字符串形式暴露JSON Schema不保留 namedtuple 的命名元组身份会退化为普通结构当校验输入与序列化输出不一致时可以指定 JSON Schema 到底表示校验输入还是序列化输出子模型会被放入 JSON Schema 的$defs属性中并按规范引用通过Field做了修改如自定义 title、description 或默认值的子模型会递归内联而不是引用模型的description取自类的 docstring或Field的参数描述。最后一条在源码中同样得到印证ResponseSchema基类的 docstring 明确提示开发者务必为类添加 docstring 说明如何使用它会进入 description 属性并成为 prompt 的一部分见 instructor/v2/core/function_calls.py#L119-L136。源码视角字段元数据如何变成各家工具定义Instructor 将Pydantic 模型 → 厂商工具 Schema的转换收敛到统一的 schema helper 上instructor/v2/core/schema.py 对外导出generate_openai_schema、generate_anthropic_schema、generate_gemini_schema三个兼容入口OpenAI 版本instructor/v2/providers/openai/schema.py以model.model_json_schema()为基底剔除title/description得到parameters再用 docstring 回填字段描述最终返回{name, description, parameters}结构Anthropic 版本instructor/v2/providers/anthropic/schema.py#L13-L21复用 OpenAI 的 name/description但把完整model.model_json_schema()直接作为input_schemaGemini 与其余 providerbedrock、cohere、mistral、perplexity、vertexai、writer、xai 等的 handler 同样以model_json_schema()为最终 Schema 来源。因此你在Field里写的default、description、examples、json_schema_extra会经由这条链路进入 OpenAI 函数参数、Anthropicinput_schema、Gemini 工具声明等各家格式——字段元数据即跨厂商一致的提示词载体。综合实战一个带内部思考与公开输出的抽取模型把上述能力组合起来一个典型的隐藏思维链 只暴露结论的抽取模型可以这样写from typing import Union from datetime import date from pydantic import BaseModel, Field from pydantic.json_schema import SkipJsonSchema import instructor client instructor.from_provider(openai/gpt-4o-mini) class Booking(BaseModel): Extract booking details from user messages. chain_of_thought: str Field( descriptionReasoning behind the extraction., excludeTrue ) hotel: str Field(descriptionName of the hotel, examples[Grand Hotel]) check_in: date Field(descriptionCheck-in date (YYYY-MM-DD)) check_out: date Field(descriptionCheck-out date (YYYY-MM-DD)) internal_id: SkipJsonSchema[Union[str, None]] None # 仅内部使用LLM 不可见 booking client.create( response_modelBooking, messages[{role: user, content: Book Grand Hotel from 2026-05-01 to 2026-05-03}], ) print(booking.model_dump_json()) # 输出中不包含 chain_of_thought 与 internal_id其中excludeTrue保证导出时隐藏思维链SkipJsonSchema保证内部 ID 根本不进入模型可见的 Schemadescription/examples则负责引导模型正确取值——这就是字段元数据在 Instructor 中的完整闭环用法。延伸阅读Response Models —— 用 Pydantic 模型定义输出结构Field Validation —— 字段级约束与校验模式Types —— 各种字段类型与Annotated用法Optional Fields —— 处理缺失/可选数据Enums 与 Unions —— 枚举与联合类型字段【免费下载链接】instructorstructured outputs for llms项目地址: https://gitcode.com/GitHub_Trending/in/instructor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考