AI・機械学習
上級

スキーマ駆動抽出(スキーマクドウチュウシュツ)

PydanticやZod等の型定義ライブラリでデータスキーマを事前定義し、LLMにそのスキーマに準拠した構造化データを返させる開発手法。instructorやoutlinesなどのライブラリがスキーマ定義からプロンプト生成・バリデーション・リトライを自動化し、型安全なLLMデータ抽出を実現する。

0 回閲覧
0 いいね

スキーマ駆動抽出とは

スキーマ駆動抽出とは、Pydantic(Python)やZod(TypeScript)などの型定義ライブラリでデータの構造・型・制約を事前に定義し、LLMにそのスキーマに厳密に準拠した構造化データを出力させる開発手法である。従来のLLMデータ抽出では出力JSONの形式が保証されず、パース失敗やフィールド欠損が頻発していたが、2024-2025年にinstructor・outlines・guidance等のライブラリが成熟したことで、コンパイル時型チェックからランタイムバリデーションまで一貫した型安全性が実現可能になった。

主要ライブラリ詳細比較

ライブラリ開発元言語アプローチ対応LLMGitHubスター
instructorJason LiuPythonパッチ方式OpenAI/Anthropic/Google/Mistral/Ollama/LiteLLM9,200+
outlines.txt (dottxt)Python文法制約デコーディングHF Transformers/vLLM/llama.cpp/ExLlamaV28,500+
guidanceMicrosoft ResearchPythonテンプレート + 制約OpenAI/HF Transformers/llama.cpp19,000+
MarvinPrefectPythonデコレータ方式OpenAI5,000+
zod-to-json-schema個人開発TypeScriptスキーマ変換全JSON Schema対応LLM1,200+
TypeChatMicrosoftTypeScript型推論 + バリデーションOpenAI8,300+

instructor の実装パターン

instructorはPythonのデファクトスタンダードで、Pydanticモデルを定義するだけでLLMから型安全なデータを取得できる:

  • パッチ方式: OpenAI/Anthropic等のクライアントをinstructor.from_openai()でラップ
  • 自動リトライ: バリデーション失敗時にエラーメッセージをLLMにフィードバックし自動修正(最大3回)
  • ストリーミング: Partial[Model]型でパーシャルオブジェクトの逐次受信
  • バリデーション: Pydanticのfield_validatorでビジネスロジックレベルの制約を定義
  • マルチモーダル: 画像入力に対応(OpenAI Vision/Anthropic Vision/Google Vision)
  • キャッシュ: instructor.cacheで同一入力の結果をキャッシュし、APIコスト削減
  • バッチ処理: Iterableレスポンスで複数レコードの一括抽出
  • コスト: ライブラリ自体はOSS無料、LLM APIコストのみ

outlines の文法制約デコーディング

outlinesはローカルLLMでスキーマ準拠出力を実現する:

  • CFG(文脈自由文法): JSON Schemaを文脈自由文法に変換し、トークン生成時に文法違反を防止
  • 正規表現制約: 出力を正規表現パターンに完全に制約(例: メールアドレス形式のみ許可)
  • FSM(有限状態機械): 状態遷移に基づく効率的な制約付きデコーディング
  • 対応ランタイム: HF Transformers/vLLM/llama.cpp/ExLlamaV2/MLX
  • 速度: 制約なしの生成と比較してオーバーヘッドは5-15%程度
  • 型サポート: Pydantic BaseModel/dataclass/TypedDictに対応

Pydantic × instructor 実践パターン

スキーマ駆動抽出の典型的なワークフロー:

  • Step 1: Pydanticモデルで抽出スキーマを定義(フィールド名・型・説明・制約)
  • Step 2: instructor.from_openai()でクライアントをパッチ
  • Step 3: client.chat.completions.create(response_model=MyModel)で型安全な抽出を実行
  • Step 4: バリデーション失敗時は自動リトライ(エラーメッセージがプロンプトに追加される)
  • Step 5: 成功した結果はPydanticオブジェクトとして利用(.model_dump()でJSON化)

ベストプラクティスとして、各フィールドのField(description=...)に具体的な抽出指示を書くことが精度向上の鍵。例えばprice: float = Field(description="税込価格を数値で抽出。通貨記号は除去。見つからない場合は0.0")のように指定する。

TypeScript(Zod)での実装

TypeScript環境ではZodスキーマを中心としたエコシステムが確立:

  • zod-to-json-schema: ZodスキーマをJSON Schemaに変換し、OpenAI Structured Outputsに渡す
  • AI SDK (Vercel): generateObject()でZodスキーマ指定の構造化出力を取得
  • TypeChat: Microsoft製。TypeScriptの型定義から直接抽出スキーマを生成
  • LangChain.js: StructuredOutputParser.fromZodSchema()でZod統合

設計上の注意点

  • スキーマの粒度: フィールド数が多すぎると抽出精度が低下。20フィールド以下が推奨
  • オプショナルフィールド: Optional[str] = Noneで未発見時のnull許容を明示
  • 列挙型の活用: カテゴリ分類にはLiteral["A", "B", "C"]で候補を制約
  • ネストの深さ: 3階層以内が推奨。深いネストはフラット化を検討
  • 配列サイズ: Field(min_length=1, max_length=10)で配列要素数を制約
  • バリデーション: @field_validatorでビジネスルール(日付範囲・金額上限等)を定義

よくある質問(FAQ)

Q1: instructorとoutlinesの使い分けは? A: クラウドLLM(OpenAI/Anthropic/Google)を使う場合はinstructorが最適。ローカルLLM(Llama 3.1/Mistral/Qwen)でスキーマ準拠出力が必要な場合はoutlinesを選択する。併用も可能で、instructorからoutlines対応バックエンドを呼び出せる。

Q2: バリデーション失敗時のリトライ回数は何回が適切ですか? A: instructorのデフォルトは3回で、実運用でも3回が最適。GPT-4oクラスのモデルでは1回目で95%以上成功し、3回以内に99%以上が解決する。3回失敗した場合はスキーマ設計の見直しが必要。

Q3: スキーマが頻繁に変わる場合はどう対応しますか? A: Pydanticのモデル継承を活用し、基底スキーマに共通フィールド、派生スキーマに文書種別固有のフィールドを定義する。スキーマのバージョニングにはPydantic v2のmodel_configでスキーマバージョンをメタデータとして管理する。

まとめ

  • スキーマ駆動抽出はPydantic/Zodで型定義→LLMが型安全データを返す手法
  • instructorがPythonデファクト、outlines がローカルLLM向けの選択肢
  • 自動リトライ・バリデーション・ストリーミングが実用性の鍵
  • フィールド説明の具体性が抽出精度を大きく左右する
  • TypeScript環境ではZod + Vercel AI SDK / TypeChat が主流