構造化テキスト解析における正規表現 vs LLM
構造化テキスト(クイズ、フォーム、請求書、ドキュメント)を解析するための実用的な意思決定フレームワーク。核心的な洞察:正規表現は低コストかつ決定論的に95〜98%のケースを処理できる。コストのかかるLLM呼び出しは残りのエッジケースに留める。
使用場面
- 繰り返しパターンを持つ構造化テキスト(設問、フォーム、表)の解析
- テキスト抽出に正規表現とLLMのどちらを使うかの判断
- 両方のアプローチを組み合わせたハイブリッドパイプラインの構築
- テキスト処理におけるコスト/精度のトレードオフの最適化
意思決定フレームワーク
テキスト形式は一貫していて繰り返しがあるか?
├── はい (>90% が何らかのパターンに従う) → 正規表現から始める
│ ├── 正規表現が 95%+ を処理 → 完了、LLM は不要
│ └── 正規表現が <95% を処理 → エッジケースのみ LLM を追加
└── いいえ (自由形式、高度に可変) → LLM を直接使用
アーキテクチャパターン
[正規表現パーサー] ─── 構造を抽出(95〜98% の精度)
│
▼
[テキストクリーナー] ─── ノイズを除去(マーカー、ページ番号、アーティファクト)
│
▼
[信頼度スコアラー] ─── 信頼度の低い抽出結果にフラグを立てる
│
├── 高信頼度(≥0.95)→ 直接出力
│
└── 低信頼度(<0.95)→ [LLM バリデーター] → 出力
実装
1. 正規表現パーサー(大半のケースを処理)
import re
from dataclasses import dataclass
@dataclass(frozen=True)
class ParsedItem:
id: str
text: str
choices: tuple[str, ...]
answer: str
confidence: float = 1.0
def parse_structured_text(content: str) -> list[ParsedItem]:
"""Parse structured text using regex patterns."""
pattern = re.compile(
r"(?P<id>\d+)\.\s*(?P<text>.+?)\n"
r"(?P<choices>(?:[A-D]\..+?\n)+)"
r"Answer:\s…