instructor について
InstructorでLLMの応答を型付きの構造化データに変換し、検証するためのスキルです。開発者はPydanticスキーマ、無効出力の再試行、部分結果のストリーミング、複数プロバイダー向けの共通APIを活用できます。
主な機能
- 01Pydanticスキーマ検証
- 02無効な出力の自動再試行
- 03部分結果のストリーミング
- 04ネスト型とオプション項目
- 05プロバイダー共通API
活用シーン
- 01テキストからレコードを抽出
- 02スキーマに照らして生成JSONを検証
- 03構造化結果をリアルタイムで配信
- 04無効な抽出応答に対処
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kalarislabs/ research-agent-skills --skill instructorインストール後、Claude Code で/instructorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/advanced-features.mdcommon-patterns.mderror-handling.mdexamples.mdprovider-configuration.mdproviders.mdvalidation.md詳細
Instructor:LLM の構造化出力
このスキルを使用する場面
次のような場合に Instructor を使用してください。
- LLM の応答から構造化データを確実に抽出する
- Pydantic スキーマに対して出力を自動的に検証する
- エラーを自動処理して、抽出の失敗を再試行する
- 型安全性と検証機能を備えて、複雑な JSON を解析する
- リアルタイム処理用に部分的な結果をストリーミングする
- 一貫した API で複数の LLM プロバイダーに対応する
インストール
# Base installation
pip install instructor
# With specific providers
pip install "instructor[anthropic]" # Anthropic Claude
pip install "instructor[openai]" # OpenAI
pip install "instructor[all]" # All providers
クイックスタート
基本例:ユーザーデータの抽出
import instructor
from pydantic import BaseModel
from anthropic import Anthropic
# Define output structure
class User(BaseModel):
name: str
age: int
email: str
# Create instructor client
client = instructor.from_anthropic(Anthropic())
# Extract structured data
user = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "John Doe is 30 years old. His email is [email protected]"
}],
response_model=User
)
print(user.name) # "John Doe"
print(user.age) # 30
print(user.email) # "[email protected]"
OpenAI を使用する
from openai import OpenAI
client = instructor.from_openai(OpenAI())
user = client.chat.completions.create(
model="gpt-4o-mini",
response_model=User,
messages=[{"role": "user", "content": "Extract: Alice, 25, [email protected]"}]
)
基本概念
1. レスポンスモデル(Pydantic)
レスポンスモデルでは、LLM の出力の構造と検証ルールを定義します。
基本モデル
from pydantic import BaseModel, Field
class Article(BaseModel):
title: str = Field(description="Article title")
author: str = Field(description="Author name")
word_count: int = Field(description="Number of words", gt=0)
tags: list[str] = Field(description="List of relevant tags")
article = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "Analyze this article: [article text]"
}],
response_model=Article
)
利点:
- Python の型ヒントによる型安全性
- 自動検証(word_count > 0)
- Field の説明による自己文書化
- IDE の自動補完に対応
ネストされたモデル
class Address(BaseModel):
street: str
city: str
country: str
class Person(BaseModel):
name: str
age: int
address: Address # Nested model
person = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "John lives at 123 Main St, Boston, USA"
}],
response_model=Person
)
print(person.address.city) # "Boston"
オプションフィールド
from typing import Optional
class Product(BaseModel):
name: str
price: float
discount: Optional[float] = None # Optional
description: str = Field(default="No description") # Default value
# LLM doesn't need to provide discount or description
制約に Enum を使用する
from enum import Enum
class Sentiment(str, Enum):
POSITIVE = "positive"
NEGATIVE = "negative"
NEUTRAL = "neutral"
class Review(BaseModel):
text: str
sentiment: Sentiment # Only these 3 values allowed
review = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "This product is amazing!"
}],
response_model=Review
)
print(review.sentiment) # Sentiment.POSITIVE
2. 検証
Pydantic は LLM の出力を自動的に検証します。検証に失敗すると、Instructor が再試行します。
組み込みバリデーター
from pydantic import Field, EmailStr, HttpUrl
class Contact(BaseModel):
name: str = Field(min_length=2, max_length=100)
age: int = Field(ge=0, le=120) # 0 <= age <= 120
email: EmailStr # Validates email format
website: HttpUrl # Validates URL format
# If LLM provides invalid data, Instructor retries automatically
カスタムバリデーター
from pydantic import field_validator
class Event(BaseModel):
name: str
date: str
attendees: int
@field_validator('date')
def validate_date(cls, v):
"""Ensure date is in YYYY-MM-DD format."""
import re
if not re.match(r'\d{4}-\d{2}-\d{2}', v):
raise ValueError('Date must be YYYY-MM-DD format')
return v
@field_validator('attendees')
def validate_attendees(cls, v):
"""Ensure positive attendees."""
if v < 1:
raise ValueError('Must have at least 1 attendee')
return v
モデルレベルの検証
from pydantic import model_validator
class DateRange(BaseModel):
start_date: str
end_date: str
@model_validator(mode='after')
def check_dates(self):
"""Ensure end_date is after start_date."""
from datetime import datetime
start = datetime.strptime(self.start_date, '%Y-%m-%d')
end = datetime.strptime(self.end_date, '%Y-%m-%d')
if end < start:
raise ValueError('end_date must be after start_date')
return self
3. 自動再試行
検証に失敗すると、Instructor は LLM にエラーのフィードバックを返して自動的に再試行します。
# Retries up to 3 times if validation fails
user = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "Extract user from: John, age unknown"
}],
response_model=User,
max_retries=3 # Default is 3
)
# If age can't be extracted, Instructor tells the LLM:
# "Validation error: age - field required"
# LLM tries again with better extraction
仕組み:
- LLM が出力を生成します
- Pydantic が検証します
- 無効な場合:エラーメッセージが LLM に返されます
- LLM はエラーのフィードバックを基に再試行します
- max_retries の回数まで繰り返します
4. ストリーミング
リアルタイム処理用に部分的な結果をストリーミングします。
部分オブジェクトのストリーミング
from instructor import Partial
class Story(BaseModel):
title: str
content: str
tags: list[str]
# Stream partial updates as LLM generates
for partial_story in client.messages.create_partial(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "Write a short sci-fi story"
}],
response_model=Story
):
print(f"Title: {partial_story.title}")
print(f"Content so far: {partial_story.content[:100]}...")
# Update UI in real-time
イテラブルのストリーミング
class Task(BaseModel):
title: str
priority: str
# Stream list items as they're generated
tasks = client.messages.create_iterable(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[{
"role": "user",
"content": "Generate 10 project tasks"
}],
response_model=Task
)
for task in tasks:
print(f"- {task.title} ({task.priority})")
# Process each task as it arrives
プロバイダーの設定
詳細、コード例、パラメーター表については、references/provider-configuration.md を参照してください。この手順が該当する場合にお読みください。
よく使われるパターン
詳細、コード例、パラメーター表については、references/common-patterns.md を参照してください。この手順が該当する場合にお読みください。
高度な機能
詳細、コード例、パラメーター表については、references/advanced-features.md を参照してください。この手順が該当する場合にお読みください。
エラー処理
詳細、コード例、パラメーター表については、references/error-handling.md を参照してください。この手順が該当する場合にお読みください。
ベストプラクティス
1. フィールドの説明を明確にする
# ❌ Bad: Vague
class Product(BaseModel):
name: str
price: float
# ✅ Good: Descriptive
class Product(BaseModel):
name: str = Field(description="Product name from the text")
price: float = Field(description="Price in USD, without currency symbol")
2. 適切な検証を使用する
# ✅ Good: Constrain values
class Rating(BaseModel):
score: int = Field(ge=1, le=5, description="Rating from 1 to 5 stars")
review: str = Field(min_length=10, description="Review text, at least 10 chars")
3. プロンプトに例を含める
messages = [{
"role": "user",
"content": """Extract person info from: "John, 30, engineer"
Example format:
{
"name": "John Doe",
"age": 30,
"occupation": "engineer"
}"""
}]
4. 固定カテゴリには Enum を使用する
# ✅ Good: Enum ensures valid values
class Status(str, Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"
class Application(BaseModel):
status: Status # LLM must choose from enum
5. 欠損データを適切に処理する
class PartialData(BaseModel):
required_field: str
optional_field: Optional[str] = None
default_field: str = "default_value"
# LLM only needs to provide required_field
他の選択肢との比較
| 機能 | Instructor | 手動 JSON | LangChain | DSPy |
|---|---|---|---|---|
| 型安全性 | ✅ あり | ❌ なし | ⚠️ 一部対応 | ✅ あり |
| 自動検証 | ✅ あり | ❌ なし | ❌ なし | ⚠️ 制限あり |
| 自動再試行 | ✅ あり | ❌ なし | ❌ なし | ✅ あり |
| ストリーミング | ✅ あり | ❌ なし | ✅ あり | ❌ なし |
| 複数プロバイダー | ✅ あり | ⚠️ 手動 | ✅ あり | ✅ あり |
| 学習曲線 | 低い | 低い | 中程度 | 高い |
Instructor を選ぶ場合:
- 構造化され、検証済みの出力が必要な場合
- 型安全性と IDE のサポートが必要な場合
- 自動再試行が必要な場合
- データ抽出システムを構築する場合
他の選択肢を選ぶ場合:
- DSPy:プロンプトを最適化したい場合
- LangChain:複雑なチェーンを構築する場合
- 手動:単純な単発の抽出を行う場合
リソース
- ドキュメント:https://python.useinstructor.com
- GitHub:https://github.com/jxnl/instructor
- クックブック:https://python.useinstructor.com/examples
- Discord:コミュニティによるサポートを利用できます
関連項目
references/validation.md- 高度な検証パターンreferences/providers.md- プロバイダー固有の設定references/examples.md- 実際のユースケース
エージェントの運用手順
- 環境を確認します。 フレームワークのバージョン、モデルプロバイダー、API キー、レート制限を確認します。
- 入力を明確にします。 データまたはユーザーから、形式、識別子、パラメーターを確認します。結果を左右する値は推測せず、質問してください。
- まず小規模に実行します。 既知の入力で単一の呼び出しまたはチェーンをテストし、生の出力を確認します。
- 上記の指示と参考情報を使用して、タスク全体を実行します。
- 結果を検証します。 小規模なラベル付きデータセットで評価し、構造化出力をスキーマと照合して、プロンプトと応答をログに記録します。
- 報告します。 実行した内容(バージョン、コマンド、パラメーター)、確認した内容、未確認の事項を明示します。
| このような場合 | 対応 |
|---|---|
| 出力が想定されたスキーマと一致しない | 検証と再試行を追加し、スキーマを厳密にするか、プロンプトを簡素化します。 |
| この手順に記載された関数、フラグ、エンドポイントがインストール済みのバージョンにない | インストール済みバージョンのドキュメント(help()、--help、公式ドキュメント)を確認して対応し、ユーザーに伝えます。API を捏造してはいけません。 |
| 必須の入力、識別子、パラメーターが曖昧である | ユーザーに確認するか、実行前に仮定を明示します。 |
誠実性に関するルール
- 結果、パラメーター、識別子、引用、統計を捏造してはいけません。実行または検証できない場合は、その旨を明確に伝えます。
- ユーザーの同意なしに、個人情報や機密データを外部 API に送信してはいけません。
- ここに記載されたバージョン固有の詳細は古くなっている可能性があるため、インストール済みバージョンの公式ドキュメントで確認します。
- 費用が発生する操作、共有 GPU やクラウドのクォータを消費する操作、個人データや患者データに触れる操作、取り消せない操作を行う前に確認します。