当你指示GPT返回用户信息的JSON格式时,它可能返回带有三层markdown代码框的内容:
{
"name": "张三"
}
当你需要一个简单的评分数字时,它可能回复“高”;当你索要一个列表时,它却遗漏了几个必要字段。
这并非模型本身能力有限,而是缺乏合适的约束工具。Instructor正是为此类问题而生——仅需几行代码,即可让LLM的输出严格符合你的Pydantic数据模型定义。
为何需要Instructor
传统的JSON模式存在三大痛点:
1. 输出格式难以掌控
# 你想要的
{"score": 0.85}
# GPT实际给出的
```json
{"score": "很高", "confidence": "非常确定"}
\```
2. 字段经常遗漏或多余
模型时常自由发挥,随意增减字段,导致后续代码处理时报错。
3. 缺少自动纠错机制
验证一旦失败就终止,需要开发者手动编写重试逻辑。
Instructor的策略很清晰:利用Pydantic定义数据结构,自动执行验证,失败时自动发起重试,直至获得合规数据或达到重试上限。
快速入门(5分钟)
pip install instructor openai pydantic
基础用法——抽取个人信息:
import instructor
from openai import OpenAI
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
occupation: str
client = instructor.from_openai(OpenAI())
person = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "Extract: John is 30, works as an engineer"}
],
response_model=Person,
max_retries=3
)
print(person.name) # John
print(person.age) # 30
其工作原理是:
- 定义Pydantic数据模型
- 用
from_openai()方法包装客户端 - 在请求中传入
response_model参数 - 直接获得经过验证的Python对象
如果验证不通过,系统会自动重试;类型不符也会触发重试,直到成功或达到max_retries上限。
高级应用:处理嵌套结构与自定义校验
真实的业务场景通常更复杂。下面是一个工单分类系统的例子:
from pydantic import BaseModel, Field, field_validator
from typing import List, Optional
from enum import Enum
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class Tag(BaseModel):
name: str = Field(..., min_length=2, max_length=20)
confidence: float = Field(..., ge=0.0, le=1.0)
class Ticket(BaseModel):
title: str = Field(..., min_length=10)
priority: Priority
tags: List[Tag] = Field(..., min_items=1, max_items=5)
estimated_hours: Optional[float] = Field(None, gt=0, le=100)
@field_validator('estimated_hours')
@classmethod
def validate_hours(cls, v):
if v is not None and v % 0.5 != 0:
raise ValueError('工时必须为0.5的整数倍')
return v
ticket = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": "分类工单:生产环境Redis崩溃,导致所有用户登录功能受影响"
}],
response_model=Ticket,
max_retries=3
)
print(ticket.priority) # Priority.CRITICAL
print(ticket.tags[0].name) # redis
print(ticket.estimated_hours) # 2.0(符合0.5倍数规则)
该示例集成了以下功能:
- 枚举类型(Priority)
- 嵌套对象(List[Tag])
- 字段限制(最小长度、数值范围等)
- 自定义校验逻辑(工时需为0.5的整数倍)
当任何字段不符合预设规则时,Instructor 会将具体的验证错误信息反馈给模型,引导其重新生成,直至满足要求或达到最大重试次数。
流式处理:实时生成与获取
对于大型数据列表或复杂对象,等待模型一次性完成生成会拖慢效率。Instructor 提供了部分流式(Partial streaming)功能,支持一边生成一边处理:
from instructor import Partial
class UserList(BaseModel):
users: List[Person]
stream = client.chat.completions.create_partial(
model="gpt-4o",
messages=[{
"role": "user",
"content": "提取:张三30岁工程师,李四25岁设计师,王五35岁产品"
}],
response_model=Partial[UserList],
stream=True
)
for partial_result in stream:
if partial_result.users:
print(f"已提取 {len(partial_result.users)} 个用户")
for user in partial_result.users:
if user.name: # Partial 对象字段可能为 None
print(f" - {user.name}")
输出结果将是:
已提取 1 个用户
- 张三
已提取 2 个用户
- 张三
- 李四
已提取 3 个用户
- 张三
- 李四
- 王五
使用 Partial[T] 会将模型中的所有字段变为可选(Optional),这样你就可以实时处理已生成的部分内容,无需等待全部完成。
注意:在流式模式下无法使用 @field_validator,因为中间状态可能暂时不符合验证规则。
多平台支持:一套代码适配多种模型
Instructor 2026版本现已兼容超过15家服务商,API接口保持统一:
# OpenAI
client = instructor.from_openai(OpenAI())
# Anthropic Claude
from anthropic import Anthropic
client = instructor.from_anthropic(Anthropic())
# Google Gemini
import google.generativeai as genai
client = instructor.from_gemini(genai.GenerativeModel("gemini-2.0-flash-001"))
# 本地模型 (Ollama)
from openai import OpenAI
client = instructor.from_openai(
OpenAI(base_url="http://localhost:11434/v1", api_key="ollama"),
mode=instructor.Mode.JSON
)
切换服务商时只需修改初始化代码,原有的response_model定义和业务逻辑完全不用变动。
对于本地模型部署,推荐优先使用Mode.JSON模式而非Mode.TOOLS,因为开源模型在函数调用方面的支持参差不齐。
三个实用技巧与注意事项
1. 不宜将重试次数设得过高
# ❌ 这样写会急剧增加token消耗
response = client.create(
response_model=ComplexModel,
max_retries=10 # 验证失败将重试10次,每次都会消耗token
)
# ✅ 建议重试3次即可,验证失败通常说明prompt需要优化
max_retries=3
每次重试都会将错误信息追加到prompt中再次调用API。若复杂模型验证失败10次,token消耗量可能是正常情况的3-5倍。
2. 过深的嵌套可能导致上下文溢出
class DeepNested(BaseModel):
level1: List['DeepNested'] # 递归嵌套结构
# 当模型生成过深嵌套结构时,验证错误信息会异常冗长
# 重试时prompt可能超出上下文窗口限制
解决办法:通过限制嵌套深度或使用max_items约束列表长度来避免此问题。
3. 流式传输不支持同步验证器
class User(BaseModel):
email: str
@field_validator('email')
@classmethod
def validate_email(cls, v):
# ❌ 在 create_partial(stream=True) 模式下不会被执行
if '@' not in v:
raise ValueError('邮箱格式无效')
return v
流式传输模式返回的是Partial对象,期间验证器会被跳过。需要在获取最终结果后另行执行完整验证。
Instructor与PydanticAI的场景选择
Instructor更适合单次数据抽取任务:
- 从文本中提取结构化数据
- 内容分类与标签标注
- 数据格式转换
PydanticAI则更适用于多轮智能体交互场景:
- 需要调用外部工具(如搜索引擎、数据库查询)
- 多步骤推理任务
- 需要完整执行历史记录与可观测性
两者均出自Pydantic官方团队:Instructor专注基于Schema的数据抽取,而PydanticAI是完整的智能体运行时框架。
简单选择原则:仅需JSON抽取用Instructor,需要动态交互用PydanticAI。
生产部署检查清单
在生产环境中使用 Instructor 前,请确保以下几点:
- 将
max_retries设为 2-3 次,不宜超过 5 次 - 嵌套层级建议不超过 3 层
- 所有 List 字段均需设置
max_items限制 - 流式处理场景中未使用
field_validator - 已核算 token 成本(重试操作会加倍消耗)
随时随地看视频