--- name: regex-vs-llm-structured-text description: 解析結構化文字時,選擇使用正規表示式 (Regex) 或大型語言模型 (LLM) 的決策框架 — 优先使用 Regex,僅針對低信心度的邊緣案例引入 LLM。 --- # 結構化文字解析:Regex 與 LLM 之爭 這是一個在解析結構化文字(如測驗、表單、發票、文件)時的實踐決策框架。核心洞察在於:正規表示式 (Regex) 能以極低成本且具備確定性地處理 95-98% 的案例。應將昂貴的 LLM 呼叫保留給剩餘的邊緣案例 (Edge cases)。 ## 何時啟用 - 解析包含重複模式的結構化文字(題目、表單、表格)。 - 在文字擷取任務中抉擇應使用 Regex 還是 LLM。 - 建構同時結合兩者優點的混合處理管線 (Hybrid Pipelines)。 - 優化文字處理過程中的成本與準確度權衡。 ## 決策框架 ``` 文字格式是否具備一致性且重複出現? ├── 是 (>90% 遵循特定規律) → 優先使用 Regex │ ├── Regex 能處理 95% 以上案例 → 完成,不需要 LLM │ └── Regex 能處理比例 < 95% → 僅針對邊緣案例添加 LLM └── 否 (非結構化、高度變動) → 直接使用 LLM ``` ## 架構模式 ``` 原始文字內容 │ ▼ [Regex 解析器] ─── 擷取結構化數據 (95-98% 準確度) │ ▼ [文字清理器] ─── 移除噪音(標記、頁碼、人工痕跡) │ ▼ [信心度評分器] ─── 標記低信心度的擷取結果 │ ├── 高信心度 (≥0.95) → 直接輸出 │ └── 低信心度 (<0.95) → [LLM 驗證器] → 最終輸出 ``` ## 實作範例 ### 1. Regex 解析器 (處理絕大部分案例) ```python 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]: """使用 Regex 模式解析結構化文字。""" pattern = re.compile( r"(?P\d+)\.\s*(?P.+?)\n" r"(?P(?:[A-D]\..+?\n)+)" r"答案:\s*(?P[A-D])", re.MULTILINE | re.DOTALL, ) items = [] for match in pattern.finditer(content): choices = tuple( c.strip() for c in re.findall(r"[A-D]\.\s*(.+)", match.group("choices")) ) items.append(ParsedItem( id=match.group("id"), text=match.group("text").strip(), choices=choices, answer=match.group("answer"), )) return items ``` ### 2. 信心度評分 (Confidence Scoring) 標記需要 LLM 介入審查的項目: ```python @dataclass(frozen=True) class ConfidenceFlag: item_id: str score: float reasons: tuple[str, ...] def score_confidence(item: ParsedItem) -> ConfidenceFlag: """評估擷取信心度並標記潛在問題。""" reasons = [] score = 1.0 if len(item.choices) < 3: reasons.append("選項過少") score -= 0.3 if not item.answer: reasons.append("缺少答案") score -= 0.5 if len(item.text) < 10: reasons.append("題目過短") score -= 0.2 return ConfidenceFlag( item_id=item.id, score=max(0.0, score), reasons=tuple(reasons), ) ``` ### 3. LLM 驗證器 (僅針對邊緣案例) ```python def validate_with_llm( item: ParsedItem, original_text: str, client, ) -> ParsedItem: """利用 LLM 修正低信心度的擷取結果。""" response = client.messages.create( model="claude-haiku-4-5-20251001", # 選用最便宜的模型進行驗證 max_tokens=500, messages=[{ "role": "user", "content": ( f"請從以下文字中擷取問題、選項與答案。\n\n" f"原始文字:{original_text}\n\n" f"目前擷取結果:{item}\n\n" f"如果需要請回傳修正後的 JSON,若正確無誤請回傳 'CORRECT'。" ), }], ) # 解析 LLM 回應並回傳修正後的項目... return corrected_item ``` ### 4. 混合管線 (Hybrid Pipeline) ```python def process_document( content: str, *, llm_client=None, confidence_threshold: float = 0.95, ) -> list[ParsedItem]: """完整管線:Regex -> 信心度檢查 -> 針對邊緣案例使用 LLM。""" # 步驟 1:Regex 擷取 (處理 95-98% 的情況) items = parse_structured_text(content) # 步驟 2:信心度評分 low_confidence = identify_low_confidence(items, confidence_threshold) if not low_confidence or llm_client is None: return items # 步驟 3:僅針對標記為低信心度的項目進行 LLM 驗證 result = [] for item in items: if item.id in {f.item_id for f in low_confidence}: result.append(validate_with_llm(item, content, llm_client)) else: result.append(item) return result ``` ## 實踐之最佳實踐 - **從 Regex 開始**:即便是未臻完美的 Regex,也能為你提供優化的基準線。 - **使用信心度評分**:透過程式化方式識別哪些部分真正需要 LLM 的協助。 - **選用最廉價的 LLM**:驗證任務通常使用輕量級模型(如 Haiku 系列)即已足夠。 - **不可變性 (Immutability)**:在清理或驗證步驟中始終回傳新的實例。 - **測試驅動開發 (TDD)**:優先為已知模式編寫測試,再逐步加入邊緣案例。 - **記錄指標**:追蹤 Regex 成功率與 LLM 呼叫次數,以監控管線的健康狀況。 ## 應避免的反模式 - 在 Regex 能處理 95% 以上案例時,依然將所有文字傳送給 LLM(既昂貴又緩慢)。 - 對於非結構化、變動極大的文字強行使用 Regex。 - 跳過信心度評估,一味寄望 Regex「總是有效」。 - 在清理或驗證過程中直接修改原始解析物件。 - 未測試邊緣案例(如格式錯誤的輸入、缺失欄位、編碼問題)。 ## 適用情境 - 測驗/考試題目解析。 - 表單數據擷取。 - 發票/收據處理。 - 文件結構解析(標題、章節、表格)。 - 任何具有重複模式且對成本敏感的結構化文字處理。