使用 OpenRouter 的结构化输出,附带 Instructor 的完整指南¶
OpenRouter 提供了一个统一的 API,用于访问多个 LLM 提供商,让您可以在不同模型之间轻松切换。本指南将向您展示如何将 Instructor 与 OpenRouter 结合使用,以实现跨各种 LLM 提供商的类型安全、已验证响应。
要在 openai
客户端上设置特定于提供商的配置,请务必使用 extra_body
kwarg。
快速入门¶
⚠️ 重要:请确保您使用的模型在 OpenRouter 模型列表 中支持 Tool Calling
和/或 Structured Outputs
Instructor 通过 OpenAI 客户端与 OpenRouter 协作,因此您无需安装基础软件包之外的任何额外内容。
简单用户示例 (同步)¶
我们支持使用此进行简单的工具调用
from openai import OpenAI
import os
import instructor
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY"),
)
client = instructor.from_openai(client, mode=instructor.Mode.TOOLS)
resp = client.chat.completions.create(
model="google/gemini-2.0-flash-lite-001",
messages=[
{
"role": "user",
"content": "Ivan is 28 years old",
},
],
response_model=User,
extra_body={"provider": {"require_parameters": True}},
)
print(resp)
#> name='Ivan' age=20
简单用户示例 (异步)¶
from openai import AsyncOpenAI
import os
import instructor
from pydantic import BaseModel
import asyncio
class User(BaseModel):
name: str
age: int
client = AsyncOpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY"),
)
client = instructor.from_openai(client, mode=instructor.Mode.TOOLS)
async def extract_user():
user = await client.chat.completions.create(
model="google/gemini-2.0-flash-lite-001",
messages=[
{"role": "user", "content": "Extract: Jason is 25 years old"},
],
response_model=User,
extra_body={"provider": {"require_parameters": True}},
)
return user
# Run async function
user = asyncio.run(extract_user())
print(user)
嵌套对象示例 (同步)¶
from pydantic import BaseModel
import os
from openai import OpenAI
import instructor
from pydantic import BaseModel
class Address(BaseModel):
street: str
city: str
country: str
class User(BaseModel):
name: str
age: int
addresses: list[Address]
# Initialize with API key
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY"),
)
# Enable instructor patches for OpenAI client
client = instructor.from_openai(client, mode=instructor.Mode.TOOLS)
# Create structured output with nested objects
user = client.chat.completions.create(
model="anthropic/claude-3.7-sonnet",
messages=[
{
"role": "user",
"content": """
Extract: Jason is 25 years old.
He lives at 123 Main St, New York, USA
and has a summer house at 456 Beach Rd, Miami, USA
""",
},
],
extra_body={"provider": {"require_parameters": True}},
response_model=User,
)
print(user)
#> name='Jason' age=25 addresses=[Address(street='123 Main St', city='New York', country='USA'), Address(street='456 Beach Rd', city='Miami', country='USA')]
结构化输出 (同步)¶
⚠️ 重要:请检查您选择的模型是否在 OpenRouter 模型列表 中支持 Structured Outputs
。结构化输出是工具调用的一个子集,它限制模型的输出以匹配您的 schema,从而生成有效的 JSON Schema。
Instructor 也支持 OpenRouter 的结构化输出,如其 API 文档 此处 所述。请注意,如果我们使用 OpenAI 的 GPT-4o 模型(例如 openai/gpt-4o-2024-11-20
),以下 User 模型将抛出错误,因为 OpenAI 不支持在其结构化输出 schema 中使用 regex 模式。
from pydantic import BaseModel, Field
import os
from openai import OpenAI
import instructor
class User(BaseModel):
name: str
age: int
phone_number: str = Field(
pattern=r"^\+?1?\s*\(?(\d{3})\)?[-.\s]*(\d{3})[-.\s]*(\d{4})$"
)
# Initialize with API key
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY"),
)
# Enable instructor patches for OpenAI client
client = instructor.from_openai(
client, mode=instructor.Mode.OPENROUTER_STRUCTURED_OUTPUTS
)
# Create structured output with nested objects
user = client.chat.completions.create(
model="google/gemini-2.0-flash-001",
messages=[
{
"role": "user",
"content": """
Extract: Jason is 25 years old and his number is 1-212-456-7890
""",
},
],
response_model=User,
extra_body={"provider": {"require_parameters": True}},
)
print(user)
# > name='Jason' age=25 phone_number='+1 (212) 456-7890'
JSON 模式¶
如果您的模型不支持工具调用,当您尝试使用 mode.TOOLS
时,您将看到以下错误:
instructor.exceptions.InstructorRetryException: Error code: 404 - {'error': {'message': '未找到支持工具调用的端点。要了解更多关于提供商路由的信息,请访问:https://openrouter.ai/docs/provider-routing', 'code': 404}}
在这种情况下,我们建议改为使用 JSON
模式,如下所示。
from pydantic import BaseModel, Field
import os
from openai import OpenAI
import instructor
class User(BaseModel):
name: str
age: int
phone_number: str = Field(
pattern=r"^\+?1?\s*\(?(\d{3})\)?[-.\s]*(\d{3})[-.\s]*(\d{4})$"
)
# Initialize with API key
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY"),
)
# Enable instructor patches for OpenAI client
client = instructor.from_openai(client, mode=instructor.Mode.JSON)
# Create structured output with nested objects
user = client.chat.completions.create(
model="openai/chatgpt-4o-latest",
messages=[
{
"role": "user",
"content": """
Extract: Jason is 25 years old and his number is 1-212-456-7890
""",
},
],
response_model=User,
)
print(user)
流式传输¶
您还可以使用流式传输,如下所示,使用 create_partial
方法。虽然我们这里使用的是 JSON 模式,但这应该也适用于工具调用和结构化输出。
from pydantic import BaseModel, Field
import os
from openai import OpenAI
import instructor
class User(BaseModel):
name: str
age: int
# Initialize with API key
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY"),
)
# Enable instructor patches for OpenAI client
client = instructor.from_openai(client, mode=instructor.Mode.JSON)
# Create structured output with nested objects
user = client.chat.completions.create_partial(
model="openai/chatgpt-4o-latest",
messages=[
{
"role": "user",
"content": """
Extract: Jason is 25 years old and his number is 1-212-456-7890
""",
},
],
response_model=User,
)
for chunk in user:
print(chunk)
# > name=None age=None
# > name='Jason' age=None
# > name='Jason' age=25