🧠

LangExtractでLLMによる構造化抽出を最速で立ち上げる

に公開

LangExtractとは

LangExtractはGoogleが公開したオープンソースのPythonライブラリで、LLMの応答を人手によるポストプロセスなしで構造化データに落とし込むことを目的に設計されています。Gemini 2.5 Flashなどのクラウドモデルはもちろん、OpenAIやOllama経由のローカルモデルにも対応し、少数の例示(few-shot)から信頼性の高い抽出パイプラインを構築できます。

本記事ではLangExtract 1.0系の内部構造を覗きつつ、プロダクションで役立つ使い方とベストプラクティスを整理します。

特徴ハイライト

  • 出典トレーサビリティ: langextract.core.data.Extraction は抽出テキストと文字範囲を保持し、元文書を正確にハイライト可能。
  • Few-shot駆動のスキーマ生成: 例示データからプロバイダ固有のレスポンス制約を自動生成し、JSON/YAMLの形崩れを防止。
  • 長文対応: chunking.ChunkIterator による文書分割と並列推論 (batch_length, max_workers) で十万文字クラスの文書にも対応。
  • プロンプト検証: prompt_validation がFew-shot例と抽出結果のアラインメントを事前チェックし、曖昧な例示を警告。
  • 可視化ツール: lx.visualize がスタンドアロンHTML/Notebookでのハイライト表示を提供し、レビューが高速。
  • プラグイン可能なモデルプロバイダ: Gemini/OpenAI/Ollamaが同梱され、カスタムプロバイダはエントリポイント経由で追加。

クイックスタート

インストール

pip install langextract
# OpenAI連携も使う場合
pip install "langextract[openai]"

Geminiを使う場合は GEMINI_API_KEY または LANGEXTRACT_API_KEY を、OpenAIなら OPENAI_API_KEY を環境変数で設定します。Ollama利用時は OLLAMA_BASE_URL(未設定なら http://localhost:11434)が自動で参照されます。

最小コード例

import os
import langextract as lx
from langextract.core import data

examples = [
    data.ExampleData(
        text="田中花子さんは毎朝5mgのアムロジピンを服用している。",
        extractions=[
            data.Extraction(
                extraction_class="服薬情報",
                extraction_text="アムロジピン",
                attributes={"用量": "5mg", "服用頻度": "毎朝"},
            )
        ],
    )
]

result = lx.extract(
    text_or_documents="山田太郎さんは就寝前に10mgのアムロジピンを飲んでいる。",
    prompt_description="文中から薬剤名と用量、服用頻度を抽出してください。",
    examples=examples,
    model_id="gemini-2.5-flash",
    api_key=os.environ["GEMINI_API_KEY"],
)

for extraction in result.extractions:
    print(extraction.extraction_class, extraction.extraction_text, extraction.attributes)

lx.extract は単一文字列の場合 AnnotatedDocument を、複数文書(data.Document のイテラブル)を渡すとジェネレータを返します。Gemini以外のモデルを使う場合は model_idgpt-4o-minigemma2:2b に変更するだけです。

出力の可視化

annotated = result  # 上記の戻り値
lx.visualize(annotated)

Notebook環境ではハイライト付きのインタラクティブビューが表示され、スクリプト環境ではHTML文字列が返るので任意に保存できます。長文レビュー時に便利です。


パイプラインの仕組み

LangExtractの抽出パイプラインは大きく以下のステップで構成されています。

  1. ドキュメント分割: chunking.ChunkIterator がトークン長の上限 (max_char_buffer) を守りつつチャンク化。
  2. プロンプト生成: prompting.PromptTemplateStructuredQAPromptGenerator がFew-shot例を組み込み、必要に応じてコードフェンスを付与。
  3. LLM推論: factory.create_model 経由でGemini/OpenAI/Ollamaなどの BaseLanguageModel を生成し、並列推論 (max_workers) を実行。
  4. レスポンス解析: resolver.Resolver がフェンス有無を吸収し、JSON/YAMLを data.Extraction のリストへデコード。
  5. 追試統合: annotation.Annotatorextraction_passes > 1 の場合に非重複抽出をマージしてリコールを向上。

Geminiのようにフォーマット制約APIが使える場合、Few-shot例から自動生成されたスキーマをプロバイダに渡し、余計なポストプロセスを省けます。


Few-shot例とプロンプトバリデーション

examples 引数は必須です。例示が曖昧なまま本番投入すると、想定外のフォーマット崩れや漏れが発生します。LangExtract 1.0では prompt_validation が標準で有効(警告モード)になっており、整合しない抽出があるとアラートを出します。

import langextract as lx
from langextract import prompt_validation as pv

report = pv.validate_prompt_alignment(
    examples=examples,
    aligner=lx.resolver.WordAligner(),
)

if report.has_failed or report.has_non_exact:
    for issue in report.issues:
        print(issue.short_msg())

prompt_validation_level="error"lx.extract に渡すと、整合性が取れるまで実行が失敗するため、デプロイ前のデータドリブンな品質担保に役立ちます。


モデルプロバイダの選択

LangExtractは langextract.providers 配下にGemini/OpenAI/Ollamaの実装を持ち、factory.ModelConfig を通じて柔軟に切り替えられます。

from langextract import factory

config = factory.ModelConfig(
    model_id="gpt-4o-mini",
    provider_kwargs={
        "api_key": os.environ["OPENAI_API_KEY"],
        "temperature": 0.2,
    },
)

result = lx.extract(
    text_or_documents=doc,
    prompt_description=desc,
    examples=examples,
    config=config,
)

Ollamaを使う場合は model_id="gemma2:2b" のようにモデル名を書くと、自動的にOllamaプロバイダが選択され、model_url でエンドポイントを指定できます。独自LLMへの接続は[エントリポイント langextract.providers] にプロバイダを登録することで拡張可能です。


長文・大量ドキュメントへの対応戦略

  • max_char_buffer: チャンクサイズ(文字数)を制御。Geminiのトークン上限に合わせて調整。
  • batch_lengthmax_workers: 並列度を司るパラメータ。batch_length >= max_workers が推奨値。
  • extraction_passes: 2以上にすると独立した再抽出を行い、重複しない結果だけをマージすることでリコールを向上。コストはその分増えるので検証しながら調整。
  • additional_context: Document ごとに補足情報を与えられるため、テンプレート化されたメタデータを添付可能。

大量文書を処理する際は、progress.ProgressBar がデフォルトで標準出力に進捗を表示します。ロギングを細かく追いたい場合は debug=Truecore.debug_utils による詳細ログ出力が有効化されます。


可視化とレビュー体験

lx.visualizeAnnotatedDocument あるいはそのリストを受け取り、以下を自動生成します。

  • クラスごとの色分けハイライト
  • 属性のツールチップ表示
  • ページ内ミニマップ・スライダーによるジャンプ

生成されるHTMLは単一ファイルなので、Slackやメールで共有しても依存関係がなくレビューが容易です。Notebook外では戻り値のHTML文字列をファイルに書き出すだけでOKです。

from pathlib import Path

html = lx.visualize(result)
Path("report.html").write_text(html, encoding="utf-8")

使いどころのアイデア

  • 医療・金融など監査が必要な領域でのエンティティ抽出と根拠提示
  • 顧客サポートログやSLA違反の兆候を抽出する監視基盤
  • 特許・契約書からの条文サマリー化と相互比較
  • LLM生成テキストからの構造化ログ生成(resolver と組み合わせた静的解析)
  • 社内LLMガバナンスのためのプロンプト監査

ヘルスケア用途での利用にはGoogleのHealth AI Developer Foundations Termsが適用される点にも留意してください。


ベストプラクティスまとめ

  • Few-shot例は文字範囲が特定できるよう正確に抜粋する。曖昧な例は prompt_validation が検出。
  • GeminiのStructured Outputを活かすなら use_schema_constraints=True のまま、OpenAIのJSONモードを使うなら format_type=data.FormatType.JSON を明示。
  • まずは短文でmax_char_bufferbatch_lengthをチューニングし、トークンコストとスループットを可視化してから本番に適用。
  • resolver_params={"fence_output": False} などを渡して、モデルの出力仕様に合わせたパース設定を行う。
  • 失敗した抽出は exceptions モジュールの例外で分類されるため、再試行ロジックやモニタリングに活用できる。

さいごに

LangExtractは「LLMの出力を正確に構造化したい」という、LLM導入現場で最もハードな課題を解くための実装が詰まっています。唯一必要なのは良質なFew-shot例と明確な抽出要件です。まずは小規模なドキュメントからPoCを回し、visualizeprompt_validation を確認しながら本番に耐えるプロンプトとスキーマを磨いてみてください。

良い抽出ライフを!

GitHubで編集を提案

Discussion