LangExtractは、Googleが2025年7月に公開したPythonの情報抽出ライブラリです。LLMに「何を抜き出すか」の指示と例を渡すと、薬剤名や契約日のような項目を構造化データで返し、各項目に原文の何文字目から何文字目かという位置を付けます。ライセンスはApache-2.0、2026年11月8日時点の最新版はPyPIの1.7.2(2026年11月7日公開)で、Python 3.10以上が必要です。
この記事は1.7.2のソースとローカルでの実行結果をもとに、インストールから基本コード、Gemini・Ollama・OpenAIの切り替え、PDFの扱い、API費用の見積もり方までを順に説明します。日本語で使うときに既定設定のままだと出典位置が取れない問題も、実測した結果を載せています。
まとめ:LangExtractを使う前に押さえる要点
pip install langextractで入り、lx.extract()に指示文・例(ExampleData)・モデルIDを渡すだけで動きます。既定モデルはgemini-3.5-flashです。- 日本語のテキストでは
tokenizer=UnicodeTokenizer()を必ず渡します。既定のRegexTokenizerでは、抽出語の位置が取れなかったり途中で切れたりします。1.7.2でも挙動は同じでした(実測は後述)。 - モデルIDの先頭で接続先が自動で決まります。
geminiはGemini、gpt-4・gpt-5・gpt-6はOpenAI、gemma・llama・qwenなどはOllamaです。gpt-6系が自動判定になったのは1.7.2からで、1.7.1以前はModelConfigで接続先を明示します。 - ライブラリの利用料は無料で、クラウドのモデルではAPI料金がかかります。LLMに送るプロンプトの数は「分割数×
extraction_passes」が基本で、10,500字の日本語文書(UnicodeTokenizer・分割1000字)では1パスで11件、3パスで33件でした。 - 1.3.0以降はURLを渡しても本文を取りに行きません。取得させるときは
fetch_urls=Trueを付けます。PDFの読み込み機能は無いので、PyMuPDFなどで先にテキストへ変換します。
LangExtractで何ができるか:出典位置つきの抽出とHTML表示
LangExtractは2025年7月30日にGoogle Developers Blogで発表されました。GitHubのREADMEには「Googleの公式サポート製品ではない」と書かれています。GitHub APIで確認したスター数は、2026年11月8日時点で39,277です。
抽出結果の1件は Extraction オブジェクトで、次の情報を持ちます。
extraction_class:項目の種類(例:medication)extraction_text:抜き出した文字列attributes:用量などの付加情報(辞書)char_interval:原文での開始位置と終了位置alignment_status:原文との一致の度合い(完全一致・部分一致・あいまい一致)
LLMの構造化出力(JSON Schemaで形式を固定する機能)でも項目は取れますが、原文との照合による位置の検証は別途必要です。位置を出力項目として指定することはできますが、スキーマへの適合だけで位置の正しさは保証されません。LangExtractはLLMの出力を原文に照合し直して位置を付けるので、監査やレビューのときに、抽出結果に対応する原文の範囲をそのまま確認できます。長文の分割と並列実行、結果をハイライト表示するHTMLの生成も付いています。形式の保証だけでよい場合は、LLM構造化出力の仕組みで足ります。
| 手段 | 出典位置 | 長文の分割 | 向く用途 |
|---|---|---|---|
| 正規表現 | あり | 不要 | 書式が決まった番号・日付 |
| LLMの構造化出力 | 自前で指定・照合 | 自前で実装 | 形式だけ保証したい抽出 |
| LangExtract | あり | 標準で実装済み | 表記ゆれのある文章からの抽出 |
向く用途:抽出結果を原文で確かめる業務
発表記事が想定している入力は、臨床記録、長文の法的文書、顧客フィードバック、ニュース記事です。READMEの例も、服薬記録からの薬剤抽出、放射線科レポートの構造化(RadExtract)、『ロミオとジュリエット』全文からの人物抽出で構成されています。共通するのは、抜き出した項目が原文のどこにあるかを人が後で確かめる必要があることです。契約書の解約条項や問い合わせメールの製品名・注文日のように、「原文に書いてある語」をそのまま取り出して一覧にする作業に向きます。
インストールとAPIキーの設定(Python 3.10以上)
仮想環境を作ってからインストールします。本記事と同じ版で再現する場合は python -m pip install "langextract==1.7.2" を使います。OpenAIのモデルを使う場合は、追加の依存を含む langextract[openai] が必要です。これを入れずにOpenAIのモデルを指定すると、1.7.2では「OpenAI provider requires openai package」で止まります。
python3 -m venv .venv
source .venv/bin/activate
pip install langextract
# OpenAIも使う場合
pip install "langextract[openai]"
# Gemini APIキー(Google AI Studioで発行)
export LANGEXTRACT_API_KEY="your-api-key"
APIキーは環境変数から自動で読まれます。1.7.2のソース(factory.py)では、Geminiのモデルは GEMINI_API_KEY、LANGEXTRACT_API_KEY の順に探し、OpenAIのモデルは OPENAI_API_KEY、LANGEXTRACT_API_KEY の順に探します。両方が設定されていると警告を出したうえで前者を使います。キーを書き換えたのに反映されないときは、もう一方の変数が残っていないかを確認してください。
1.7.2は、Googleの公式SDK google-genai の3.0に対応しました(1.7.2のリリースノート)。3.0は通信ライブラリが httpx から httpx2 に替わっており、1.7.1以前と組み合わせるとGeminiへの通信エラー時に再試行が効きません。新しい環境に入れると3.0が選ばれるので、LangExtractも1.7.2に上げておきます。SDKの変更点はgoogle-genai 3.0でのGemini APIの使い方にまとめています。
基本の使い方:指示文・例・lx.extractの3点
必要なのは、何を抜き出すかを書いた指示文、出力の見本となる例、入力テキストの3つです。次のコードは、服薬の記録から薬剤名と用法を抜き出します。
import langextract as lx
from langextract.core import tokenizer
text = "患者は2026年9月1日からアムロジピン5mgを1日1回服用している。"
prompt = "薬剤名と用法を、原文の表記のまま出現順に抜き出す。言い換えない。"
examples = [
lx.data.ExampleData(
text="田中さんはロキソプロフェン60mgを頓服で使う。",
extractions=[
lx.data.Extraction(
extraction_class="medication",
extraction_text="ロキソプロフェン",
attributes={"dose": "60mg"},
),
lx.data.Extraction(extraction_class="dosage", extraction_text="頓服"),
],
)
]
result = lx.extract(
text_or_documents=text,
prompt_description=prompt,
examples=examples,
model_id="gemini-3.5-flash",
tokenizer=tokenizer.UnicodeTokenizer(), # 日本語では必須
)
for e in result.extractions:
if e.char_interval is None:
continue # 原文に位置が見つからない抽出は捨てる
s, t = e.char_interval.start_pos, e.char_interval.end_pos
print(e.extraction_class, text[s:t], e.alignment_status, e.attributes)
例(ExampleData)の書き方
extraction_text には、例文に含まれる文字列をそのまま書き、出現順に並べます。例文に無い語や言い換えた語を書くと、実行前の検査(prompt validation)が「Prompt alignment」の警告を出します。例は抽出結果の形を決める一番強い手がかりで、例に書いた attributes のキーは出力形式を示す手がかりになります。キーを制約できる範囲は、接続先とスキーマ制約の設定によって異なります。例の選び方はfew-shotプロンプトの例示の選び方も参考になります。
出力のぶれを抑えたいときは lx.extract(temperature=0.0) を指定します。1.7.2から、この引数は language_model_params や ModelConfig 側の温度より優先されるようになりました。作成済みのモデルを model= で渡した場合だけは無視され、警告が出ます。
結果の保存とHTMLでの確認
抽出結果はJSONL形式で保存でき、そのファイルからハイライト付きのHTMLを作れます。
lx.io.save_annotated_documents([result], output_dir=".", output_name="result.jsonl")
html = lx.visualize("result.jsonl")
with open("result.html", "w", encoding="utf-8") as f:
f.write(html.data if hasattr(html, "data") else html)
Jupyterでは lx.visualize() がHTMLオブジェクトを返すので .data を取り出します。保存したJSONLの各行には、抽出ごとの char_interval と alignment_status が入ります。1.7.2からは生成されるHTMLの先頭に <meta charset="UTF-8"> が付くようになり、手元の1.7.2でも出力の1行目がこの宣言でした。1.7.1以前で作ったHTMLは文字コードの宣言が無いため、日本語が文字化けしたらブラウザの文字エンコーディングをUTF-8に切り替えて開きます。
日本語で出典位置がずれる問題とUnicodeTokenizer
lx.extract() の既定のトークナイザーはRegexTokenizerです。空白や記号、文字種の切り替わりで単語を区切る前提の分割器なので、単語の間に空白が無い日本語では、かなと漢字・カタカナが続く部分が1つの塊になります。例文「患者は2026年9月1日からアムロジピン5mgを1日1回服用している。」は、「日からアムロジピン」「回服用している」がそれぞれ1トークンになりました。LangExtractは抽出語をトークン単位で原文に照合するため、塊の途中にある「アムロジピン」は位置を特定できません。UnicodeTokenizerは日本語を1文字ずつに分けるので、この問題が起きません。公式の日本語サンプル(docs/examples/japanese_extraction.md)にも、日本語ではUnicodeTokenizerを使うよう注記があります。
位置照合の差を、2026年10月4日にLangExtract 1.7.0で、2026年11月8日に1.7.2で検証しました(どちらもPython 3.11)。結果は2つの版で同じでした。以下は掲載した1文についての結果で、日本語全般の抽出精度を測ったものではありません。モデルの性能差が混ざらないよう、APIを呼ばずに決まったJSONを返すだけのダミーモデルを作り、同じ抽出結果(アムロジピン、1日1回)を原文に照合させています。
| トークナイザー | アムロジピン | 1日1回 | 例の事前検査 |
|---|---|---|---|
| RegexTokenizer(既定) | 位置なし(None) | 「1日1」で部分一致 | 2件とも FAILED |
| UnicodeTokenizer | 15〜20文字目・完全一致 | 25〜28文字目・完全一致 | 警告なし |
既定のままだと、抽出そのものは返ってきても、薬剤名は位置が取れず、用法は「回」が欠けた範囲を指します。HTML表示のハイライトも同じ範囲になるので、原文で確かめるというLangExtractの利点がほぼ失われます。エラーにならない点が厄介で、出力だけ見ていると気づきません。
日本語・中国語・韓国語の文章では、例の事前検査に「FAILED to align」が出ていないかを最初に確認し、出ていればトークナイザーの指定漏れを疑ってください。UnicodeTokenizerは1.1.1(2025年11月27日)で追加された機能で、それ以前の0.x〜1.0系を前提に書かれた日本語の解説記事には出てきません。
モデル別の設定:Gemini・Ollama・OpenAI
接続先は model_id の先頭の文字列で自動的に決まります。1.7.2のpatterns.pyでの振り分けは次のとおりです。表のIDはAPI通信を行わず、選択されるプロバイダを確認したものです。各APIでの抽出成功を示すものではありません。
| model_idの先頭 | 接続先 | 確認したID |
|---|---|---|
| gemini | Gemini API | gemini-3.5-flash |
| gpt-3.5・gpt-4・gpt4.・gpt-5・gpt5.・gpt-6・o1〜o9 | OpenAI | gpt-5.6、gpt-6-astra |
| gemma・llama・qwen・mistral・gpt-oss など | Ollama | gemma3:4b、gpt-oss:20b |
| 上記以外 | エラー | ModelConfigで明示 |
Gemini(既定はgemini-3.5-flash)
既定のモデルは1.5.0(2026年5月20日)で gemini-3.5-flash に変わりました。READMEは大量処理や費用を抑えたい場合に gemini-3.1-flash-lite を挙げています。Geminiのモデルには廃止日が決まっているとREADMEにも注記があり、旧版の解説に出てくる gemini-2.5-flash などのIDは、Gemini APIのモデル一覧と廃止予定の見分け方で現役かを確かめてから使います。
思考の量を指定する thinking_config は、1.7.0では渡しても無視されていました。1.7.1(2026年10月8日)から実際にAPIへ送られるので、以前から指定していたコードは、版を上げると出力・応答時間・費用が変わることがあります。サービスアカウントで認証する場合は、language_model_params に vertexai=True・project・location を渡すとVertex AI経由になり、batch 設定を足せばVertex AIのバッチAPIで処理できます。1.7.1からは、バッチの中でブロックされた項目や MAX_TOKENS で途切れた項目が空の結果ではなく InferenceRuntimeError になります。止めずに先へ進めたいときは ignore_item_errors=True を指定します。
Ollama(ローカル実行・APIキー不要)
Ollamaで動かすモデルを使えば、テキストを外部のAPIへ送らずに抽出できます。先に ollama pull gemma3:4b でモデルを取得しておきます。
result = lx.extract(
text_or_documents=text,
prompt_description=prompt,
examples=examples,
model_id="gemma3:4b",
model_url="http://localhost:11434",
tokenizer=tokenizer.UnicodeTokenizer(),
)
READMEは、Ollamaでは fence_output と use_schema_constraints を指定せず自動設定に任せるよう書いています。後述の output_schema もOllamaでは使えません。切り替える前に、人手で正解を付けた同じ文書でGeminiとOllamaを比較します。抽出件数だけでなく、正解項目の取りこぼし、誤抽出、出典位置の一致も確認します。Ollama自体の導入はローカルLLMの構築手順で解説しています。
OpenAI(langextract[openai]とgpt-6の自動判定)
gpt-5.6 や gpt-6-astra のようにパターンに当たるIDは、model_id を書くだけでOpenAIに振り分けられます。キーは OPENAI_API_KEY から読まれます。gpt-6 で始まるIDがパターンに入ったのは1.7.2で、1.7.0では gpt-6-astra が「No provider registered」で止まることを確認しています。1.7.1以前を使い続ける場合や、パターンに当たらないIDを使う場合は、ModelConfigで接続先を指定します。
from langextract.factory import ModelConfig
result = lx.extract(
text_or_documents=text,
prompt_description=prompt,
examples=examples,
config=ModelConfig(model_id="gpt-6-astra", provider="openai"),
tokenizer=tokenizer.UnicodeTokenizer(),
)
OpenAI互換のAPIを持つ他社のサービスも、provider_kwargs={"base_url": "..."} を足せば同じ方法で使えます。1.7.2からは、api.openai.com へのリクエストでは出力上限を max_completion_tokens として送り、それ以外の base_url には従来どおり max_tokens で送ります。互換APIで出力上限が効かないときは、接続先がどちらの名前を受け付けるかを確認してください。
API費用の見積もり:プロンプト数の数え方
LangExtract自体の利用料は無料です。この章では、クラウドのLLMを使う場合のAPI料金を見積もります(Ollamaでのローカル実行なら、代わりに計算機と電力の費用がかかります)。トークン課金のAPIでは「入力トークン数×入力単価+出力トークン数×出力単価」が料金の基本で、単価はモデルごとに違います。使用量を見積もる材料になるのが、LLMに送るプロンプトの数です。LangExtractは本文を max_char_buffer の文字数を目安に分割し、分割した単位ごとに1件のプロンプトを送ります。extraction_passes を増やすと、この処理を文書全体に対して繰り返します。
1.7.2で、日本語の文書をAPIを呼ばない計数用のモデルに通し、モデルに渡されたプロンプトの件数を数えました(トークナイザーはUnicodeTokenizer)。再試行やバッチAPIを使うと、実際のAPIリクエスト数はこの件数と一致しないことがあります。
| 文書 | max_char_buffer | extraction_passes | プロンプト数 |
|---|---|---|---|
| 35字の文×300=10,500字 | 1000(既定) | 1(既定) | 11件 |
| 35字の文×300=10,500字 | 1000(既定) | 3 | 33件 |
| 35字の文×300=10,500字 | 2000 | 1(既定) | 6件 |
| 35字の文×300=10,500字 | 2000 | 3 | 18件 |
| 300字の文×40=12,000字 | 1000(既定) | 1(既定) | 14件 |
| 600字の文×20=12,000字 | 1000(既定) | 1(既定) | 20件 |
短い文が並ぶ文書なら、件数は「文字数÷max_char_buffer(切り上げ)×extraction_passes」に近くなります。ただし分割は文の切れ目を優先するため、1文が長い文書ほど概算から外れます。600字の文が並ぶ12,000字では、概算の12件に対して実際は20件でした。見積もりには、対象の文書で実際に生じる分割数を使います。毎回の入力には本文の分割単位に加えて指示文と例が付くため、例を長くするほど1回あたりの入力トークンも増えます。数千件の文書を流す前に、10件ほどで実際の請求額を確かめてから全体を見積もると外しにくくなります。
本文はクラウドのAPIへ送られます。Gemini APIは、無料枠のプロジェクトから送った内容がGoogleの製品改善に使われる規約です(課金が有効なプロジェクト経由なら原則として使われません)。個人情報や社外秘の文書を扱うなら課金済みのプロジェクトかVertex AIを使うか、Ollamaでローカル実行します。規約の違いはGemini APIに学習させない設定で整理しています。
長文・PDF・URLの扱い
長文で効く引数(max_char_buffer・extraction_passes)
長い文書は自動で分割され、並列にLLMへ送られます。調整する主な引数は次のとおりです。
max_char_buffer(既定1000):入力本文を分割する文字数の目安。指示文・例・追加コンテキストを含むプロンプト全体の上限ではありません。また、1つのトークンが設定値より長い場合は、そのトークンだけで1つの分割単位になります。小さくするとプロンプトの件数が増え、文脈の分断で精度が下がる場合もあります。extraction_passes(既定1):同じ文書を何回抽出するか。3にすると同じ入力を3回処理し、重ならない抽出結果を統合します。拾い漏れの改善を狙えますが、改善は保証されません。プロンプトの件数は前章の実測どおり3倍になります。max_workers(既定10)とbatch_length(既定10):並列数は両者の小さい方で決まります。batch_lengthをmax_workers未満にすると警告が出ます。context_window_chars(既定なし):前の分割単位の末尾を何文字含めるか。指示語が分割の境目をまたぐ文書で使います。
PDFから抽出する手順
LangExtractにはPDFを読む機能がありません。先にテキストへ変換して渡します。ページ単位で Document にすると、結果がどのページのものかを document_id で追えます。
この例にはPyMuPDFが必要です。同じ仮想環境で python -m pip install pymupdf を実行し、対象ファイルを report.pdf として用意してください。前の基本例で定義した変数を引き続き使用します。
import pymupdf
pages = [p.get_text() for p in pymupdf.open("report.pdf")]
docs = [lx.data.Document(text=t, document_id=f"page-{i + 1}") for i, t in enumerate(pages)]
results = lx.extract(
text_or_documents=docs,
prompt_description=prompt,
examples=examples,
model_id="gemini-3.5-flash",
tokenizer=tokenizer.UnicodeTokenizer(),
)
for r in results:
for e in r.extractions:
print(r.document_id, e.extraction_text, e.char_interval)
このとき char_interval は各ページのテキスト内での位置で、PDF上の座標ではありません。固定応答モデルを使った2ページのPDFの検証(1.7.2・PyMuPDF 1.28.2)では、両ページの請求書番号に開始12・終了16の範囲が返りました。0始まり・終了位置を含まないため、通常の数え方では13〜16文字目です。ページ内の位置を図や画面で示したい場合は、PyMuPDFの search_for() などで座標を引き直します。変換ツールはPyMuPDFの使い方、段組みや表の多いPDFならMarker(marker-pdf)で検討できます。
URL入力の自動取得設定(1.3.0以降)
1.3.0(2026年4月29日)で、URLの自動取得は初期状態で無効になりました。1.7.2でもProject GutenbergのURLだけを text_or_documents に渡すと、URLの文字列47文字そのものが抽出対象になります。エラーは出ません。
本文を取得させるには fetch_urls=True を付けます。ソースの説明には、取得したURLを検査しないため内部ネットワークへの不正なアクセス(SSRF)の危険があり、URLが信頼できる場合に限って隔離環境で使うよう書かれています。利用者が入力したURLを渡すシステムでは、自前で取得と検査をしてから本文を渡す方が安全です。
v1.0から1.7.2までの変更点:古い解説記事と違う箇所
2025年夏の公開直後に書かれた解説の多くは1.0系が前提です。その後の変更で、コードの書き方や既定値が次のように変わりました(各版の詳細はGitHubのリリースノート)。
| 版 | 公開日 | 主な変更 |
|---|---|---|
| 1.0.0 | 2025-07-22 | 初の正式版 |
| 1.0.3/1.0.4 | 2025-08-03/08-05 | OpenAI対応/Ollama対応 |
| 1.0.6 | 2025-08-13 | 外部プロバイダのプラグイン機能 |
| 1.1.0 | 2025-11-14 | Vertex AIのバッチAPI対応 |
| 1.1.1 | 2025-11-27 | UnicodeTokenizer追加(日本語の分割を改善) |
| 1.2.0 | 2026-03-22 | 分割単位の解析エラーを既定で無視 |
| 1.3.0 | 2026-04-29 | URL自動取得を無効化・Geminiの再試行 |
| 1.4.0/1.5.0 | 2026-05-15/05-20 | OpenAIのスキーマ制約/OpenAIバッチ・既定モデル変更 |
| 1.6.0 | 2026-07-02 | output_schemaの指定 |
| 1.7.0 | 2026-09-13 | 拒否・ブロック・本文欠落をエラー化 |
| 1.7.1 | 2026-10-08 | thinking_configの送信・バッチ失敗のエラー化 |
| 1.7.2 | 2026-11-07 | gpt-6の自動判定・google-genai 3.0・HTMLのcharset |
1.2.0で既定になった解析エラーの無視は、壊れたJSONを返した分割単位があっても文書全体を止めないための変更です。裏を返すと、抽出件数が少ないときに例外が出ないまま一部の分割単位が抜けている可能性があります。件数が想定より少ないときは debug=True でログを確認してください。1.6.0の output_schema を使うと、属性の値を列挙型に限定するといった、例だけでは伝えにくい制約をGeminiとOpenAIに課せます。
1.7.2では、空白だけの値など原文に照合できない空の抽出を結果から外すようになりました。CSVのデータセットを読み込むときは「NA」「NULL」や空欄を欠損値(NaN)にせず文字列のまま残します。旧版の出力件数と比べて数が減った、あるいは欠損値の扱いが変わったときは、この2点を疑ってください。
LangExtractが向かない場面と失敗パターン
LangExtractの価値は「原文に書いてある語を、位置付きで抜く」ことにあります。要約や分類ラベルの生成だけが目的なら、まずLLMを直接呼ぶ構成を検討します。
- 原文にない値を作らせる用途:要約、感情の判定、「重要度:高」のような分類ラベルは原文中に位置を持ちません。属性(attributes)に入れれば出力はできますが、出典位置で検証するという利点は使えません。
- 書式が固定された項目だけを取る用途:郵便番号、注文番号、日付のように形が決まっている項目は、正規表現の方が速く、費用もかかりません。
- 表の数値の集計:PDFの表をテキスト化すると行と列の関係が崩れます。表はpandasなどで表として読み込みます。
- 医療の判断に使う用途:READMEの服薬抽出の例には「診断や治療の提案に使うものではない」との免責があり、健康関連の利用にはHealth AI Developer Foundationsの利用規約も適用されます。
導入時によくある失敗は、日本語なのにトークナイザーを指定しないこと、char_interval が None の抽出をそのまま使うことの2つです。後者は、LLMが入力文でなく例の文から語を拾ってしまった場合にも起きます。READMEも [e for e in result.extractions if e.char_interval] で位置のある結果だけを残すよう勧めています。抽出をシステムに組み込む設計や、どの業務から始めるかの判断に迷う場合は、生成AIの導入支援で相談を受け付けています。
よくある質問
LangExtractはGoogleの公式製品ですか?
GoogleのGitHub組織(google/langextract)で公開され、Google Developers Blogでも発表されましたが、READMEには「公式サポート製品ではない」と明記されています。ライセンスはApache-2.0で、商用利用もできます。
LangExtractはOllamaで使えますか?
使えます。model_id に gemma3:4b などOllamaのモデル名を書き、model_url にOllamaの待ち受けアドレス(既定は http://localhost:11434)を渡します。APIキーは要りません。ただし output_schema には対応していません。
LangExtractでPDFを読み込めますか?
直接は読めません。PyMuPDFなどでページごとにテキストを取り出し、lx.data.Document にして渡します。返ってくる位置は各ページのテキスト内の文字位置です。
OpenAIのモデルを使うには何が必要ですか?
pip install "langextract[openai]" で追加の依存を入れ、OPENAI_API_KEY を設定します。1.7.2ではgpt-3.5・gpt-4・gpt4.・gpt-5・gpt5.・gpt-6・o1〜o9で始まるIDが自動で振り分けられ、それ以外のOpenAI向けIDは ModelConfig(provider="openai") で指定します。
LangExtractは日本語に対応していますか?
対応しています。ただし tokenizer=UnicodeTokenizer() の指定が前提で、既定のままでは出典位置が取れなかったり途中で切れたりします。