非構造化テキストからのデータ抽出
メール、領収書、記事などの生テキストを読み込み、型、デフォルト値、検証を備えた構造化フィールドを返す情報抽出パイプラインを構築します。
「非構造化テキストからのデータ抽出」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。
情報抽出の課題
組織は、メール、サポートチケット、契約書、請求書、ニュース記事、医療記録、ソーシャルメディアへの投稿など、構造化されていないテキストに埋もれています。価値のある構造化データがこうしたテキストの中に埋もれていますが、手作業での抽出は時間とコストがかかり、ミスも起こりやすいものです。構造化出力に対応したLLMはこの状況を変えます。あらゆるテキストを読み取り、妥当な精度で、関連するフィールドを定義済みのスキーマに大規模に入力できるためです。
情報抽出(IE)とは、構造化されていないテキストから構造化された事実を自動的に特定して取り出すプロセスです。LLMベースのIEは、従来のルールベースや古典的なNLPアプローチを大幅に上回ります。LLMは文脈、同義語、暗黙的な情報を理解できるため、表現のバリエーションごとに手作業で正規表現パターンを用意する必要がありません。
よくある抽出のユースケース
情報抽出は、さまざまな価値あるビジネス用途を支えています。
- 請求書処理:買掛金業務を自動化するため、PDF請求書から仕入先、明細、金額、支払期日を抽出します
- 契約書分析:法務文書から契約当事者、発効日、支払条件、解除条項を抽出します
- 履歴書解析:ATSで利用するため、履歴書からスキル、職歴、学歴、連絡先情報を抽出します
- サポートチケットの振り分け:チケットを自動的に振り分けるため、カテゴリ、重大度、影響を受ける製品、顧客ランクを抽出します
- ニュースモニタリング:競合情報分析のため、ニュース記事からエンティティ、イベント、感情を抽出します
メール抽出パイプラインの構築
顧客のメールを読み取り、対応に役立つ構造化データを抽出する実用的な抽出パイプラインを構築してみましょう。このパイプラインでは、Pydanticスキーマで各メールから取得したい情報を正確に定義し、その後メールをバッチ処理します。
import openai
from pydantic import BaseModel
from typing import List, Optional
from enum import Enum
client = openai.OpenAI()
class Priority(str, Enum):
urgent = 'urgent'
high = 'high'
normal = 'normal'
low = 'low'
class EmailExtraction(BaseModel):
subject_summary: str
sender_intent: str
product_mentioned: Optional[str]
issue_category: str # billing / technical / general / feedback
priority: Priority
action_required: bool
action_description: Optional[str]
customer_sentiment: str # positive / negative / neutral / frustrated
def extract_from_email(email_body: str) -> EmailExtraction:
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'You are an expert at analyzing customer emails and extracting structured information for a support team.'},
{'role': 'user', 'content': f'Analyze this customer email:\n\n{email_body}'}
],
response_format=EmailExtraction
)
return result.choices[0].message.parsedLLMによる固有表現認識
固有表現認識(NER)は、古典的なIEタスクの一つです。テキスト内の固有表現(人物、組織、場所、日付、金額など)を特定し、分類します。LLMを使うと、抽出したいエンティティを説明するだけで、専用のNERモデルを学習させなくても抽出できるため、NERが大幅に簡単になります。
import openai
from pydantic import BaseModel
from typing import List, Optional
client = openai.OpenAI()
class NamedEntity(BaseModel):
text: str # The exact text as it appears
entity_type: str # PERSON / ORG / LOCATION / DATE / MONEY / PRODUCT
normalized: Optional[str] # Standardized form where applicable
class NERResult(BaseModel):
entities: List[NamedEntity]
text = '''
Apple Inc. CEO Tim Cook announced yesterday that the company will invest $1.2 billion
in a new manufacturing facility in Austin, Texas, expected to open in Q3 2026.
'''
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract all named entities from the text. Classify each as PERSON, ORG, LOCATION, DATE, MONEY, or PRODUCT.'},
{'role': 'user', 'content': text}
],
response_format=NERResult
)
for entity in result.choices[0].message.parsed.entities:
print(f'[{entity.entity_type}] {entity.text}')大規模なドキュメントからの抽出
数千件のドキュメントを処理する本番用の抽出パイプラインでは、非同期処理とレート制限への対応が必要です。一般的なパターンでは、asyncioとセマフォを使い、APIのレート制限を守りながらドキュメントを並列処理します。
import asyncio
import openai
from pydantic import BaseModel
from typing import List, Optional
async_client = openai.AsyncOpenAI()
class InvoiceExtraction(BaseModel):
vendor: str
total_amount: Optional[float]
currency: str
invoice_date: Optional[str]
async def extract_invoice(doc_text: str, semaphore: asyncio.Semaphore) -> InvoiceExtraction:
async with semaphore: # Limit concurrent requests
result = await async_client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract invoice data.'},
{'role': 'user', 'content': doc_text}
],
response_format=InvoiceExtraction
)
return result.choices[0].message.parsed
async def process_invoices(documents: List[str]):
sem = asyncio.Semaphore(5) # Max 5 concurrent requests
tasks = [extract_invoice(doc, sem) for doc in documents]
return await asyncio.gather(*tasks, return_exceptions=True)
# results = asyncio.run(process_invoices(invoice_texts))
print('Async pipeline defined - handles rate limits via semaphore')暗黙的・推測された情報への対応
LLMは、明示的に記載された情報だけでなく、推測された情報や暗黙的な情報も抽出できます。「これを1か月間毎日使っていますが、今でも問題なく動作します」とレビューに書かれている場合、モデルは「耐久性」という語が一度も登場しなくても、耐久性が高いという肯定的な属性を推測できます。これは、明示的に存在する情報しか見つけられない正規表現ベースの抽出に対する大きな優位性です。
ただし、この能力にはリスクもあります。モデルが過剰に推測し、事実ではなく推測でフィールドを埋める可能性があるためです。法務、金融、医療など重要性の高い抽出では、スキーマにconfidenceフィールドを追加し、モデルに確信度を評価させてください。確信度の低い抽出には、人による確認のためのフラグを付けます。
抽出プロンプトの設計
抽出の品質は、プロンプトの設計に大きく左右されます。抽出プロンプトの主な原則は次のとおりです。
- 曖昧なフィールドを定義する:「日付」が請求日、支払期日、受領日のいずれを意味するのか曖昧な場合は、どれを求めるのか正確に指定します
- 一般的でない形式には例を示す:「価格は数値のみを返してください。例:$29.99ではなく29.99」
- 正規化の方法を指定する:「国名をISO 3166-1 alpha-2コードに正規化してください」
- 抽出元を指定する:「メール本文ではなく、件名からのみ抽出してください」
抽出プロンプトは、人間のデータ入力担当者に向けた正確な仕様書だと考えてください。プロンプトに残した曖昧さはすべて、モデルが一貫性なく判断する原因になります。
複雑なドキュメントに対するマルチパス抽出
ドキュメントによっては、スキーマ全体が大きい、セクションごとに異なる専門知識が必要、ドキュメント構造のばらつきが大きいといった理由から、1回の処理では抽出しきれません。マルチパス抽出では、タスクを順番に実行する複数のステップに分割します。まずドキュメントの種類を分類し、次にその種類に適したスキーマを抽出します。
import openai
from pydantic import BaseModel
from typing import Optional
client = openai.OpenAI()
class DocumentType(BaseModel):
doc_type: str # invoice / contract / resume / report
confidence: float
def classify_document(text: str) -> str:
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Classify the document type.'},
{'role': 'user', 'content': text[:500]} # Use only the beginning for classification
],
response_format=DocumentType
)
return result.choices[0].message.parsed.doc_type
# Then route to the appropriate extraction schema
EXTRACTION_SCHEMAS = {
'invoice': 'InvoiceSchema', # Replace with actual Pydantic classes
'contract': 'ContractSchema',
'resume': 'ResumeSchema',
}
print('Multi-pass: classify first, then extract with the right schema')抽出後のエンリッチメント
抽出したデータには、初回の抽出後にエンリッチメントが必要になることがよくあります。たとえば、企業データベースに問い合わせて抽出した会社名を正式名称に変換する、抽出した郵便番号を検索して市区町村や都道府県を補完する、抽出した日付を標準形式に変換するといった処理です。このエンリッチメントはLLMの呼び出し中ではなく、抽出後にアプリケーションコードで実行してください。
抽出とエンリッチメントを分離すると、パイプラインのテストと保守が容易になります。エンリッチメントのロジックを独立して単体テストでき、エンリッチメントコードを変更せずに抽出モデルを入れ替えることもできます。
抽出精度の測定
本番用の抽出パイプラインでは、ラベル付きテストセットに対して精度を体系的に測定してください。主な指標は次のとおりです。
- フィールド精度:ドキュメントごとに正しく抽出されたフィールドの割合
- 完全一致:フィールドの値が正解データと完全に一致すること
- 正規化後の一致:正規化後にフィールドの値が一致すること(例:'$1,234.00' == '1234.0')
- 偽陽性率:nullであるべきフィールドをモデルが抽出してしまう頻度
- 偽陰性率:存在するフィールドに対してモデルがnullを返す頻度
モデルを変更したとき、プロンプトを更新したとき、またはパイプラインに新しいドキュメントソースを追加したときは、必ずこの評価を実行してください。数千件のドキュメントを処理する場合、わずかな精度低下でも、ビジネスに大きな影響が連鎖的に生じる可能性があります。
継続的改善のための抽出ログ
本番環境で得られるすべての抽出結果は、パイプラインを改善するためのデータポイントです。入力ドキュメント、抽出結果、検証エラーがあれば、そのすべてをデータベースに記録してください。定期的に本番ログからサンプルを抽出し、よくある失敗パターンを特定します。たとえば、モデルが苦手とする特定のドキュメント形式、本来nullであるべきでないのに頻繁にnullになるフィールド、プロンプトのドリフトを示す異常な値などです。
このログデータは、抽出タスクに特化したモデルを将来ファインチューニングしたい場合の学習データセットにもなります。構造化抽出において、汎用LLMよりも高精度かつ低コストな選択肢を得られます。
理解度チェック
このレッスンで学んだAIエンジニアリングの概念を確認しましょう。
レッスンのまとめ
このレッスンでは、Pydanticスキーマを使ったLLMにより、構造化されていないあらゆるテキストソースから構造化データを安定して抽出できること、セマフォを使った非同期処理により、レート制限を守りながら数千件のドキュメントをバッチ抽出できること、そしてマルチパス抽出により、まずドキュメントを分類し、その種類に適したスキーマを適用できることを学びました。次は、抽出データがビジネスルールに違反した場合に対応するための検証と自動再試行のロジックを構築します。
よくある質問
「非構造化テキストからのデータ抽出」レッスンは無料ですか?
はい。「非構造化テキストからのデータ抽出」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。
「非構造化テキストからのデータ抽出」で何を学びますか?
メール、領収書、記事などの生テキストを読み込み、型、デフォルト値、検証を備えた構造化フィールドを返す情報抽出パイプラインを構築します。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Engineering Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「非構造化テキストからのデータ抽出」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Engineering Academyレッスンでコードを書いて実行できますか?
はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- JSONモードとresponse_format
- Pydanticによる構造化出力
- 非構造化テキストからのデータ抽出
- 不正な出力の検証と再試行