지루하지만 가치 있는 사용 사례
20년 동안 비정형 문서에서 구조화된 데이터를 추출하는 일은 한 분기짜리 프로젝트였습니다. OCR 파이프라인, 정규식 규칙, 예외 처리, 공급업체별 레이아웃 템플릿이 필요했기 때문입니다. LLM에 JSON 스키마를 준수하도록 하면 코드 30줄로 첫 시도부터 정확한 결과를 얻고 하루 만에 배포할 수 있습니다. 아래 예제는 독립적인 OpenAI 호환 게이트웨이인 Kunavo에서 실행되지만, 패턴은 모델 자체의 것이므로 어느 모델에 대해서도 동일하게 작동합니다.
인보이스에서 데이터를 추출하려고 하시나요? 이 페이지는 여러 문서 유형을 아우르는 개요입니다. 전용 인보이스 데이터 추출 가이드에서는 해당 문서 유형을 더 깊이 다룹니다. 기존 템플릿·모델 방식과 비전 LLM 호출의 비교, 스키마 제약을 적용한 Python 튜토리얼 전체, 산술 가드레일, 2단계 모델 라우팅, 인보이스당 비용을 설명합니다.
특히 효과가 뛰어난 분야:
- 인보이스, 영수증, 구매 주문서
- 계약서, 법률 문서(당사자, 날짜, 의무 추출)
- 이력서 / CV(ATS 친화적 구조로 파싱)
- 이메일 서명 또는 웹 페이지를 통한 리드 데이터 보강
- 의료 기록, 검사 보고서(PII 처리 포함)
- 부동산 매물, 제품 카탈로그
- 이메일 분류 및 구조화된 수집
30줄로 구현하는 핵심 패턴
import json
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")
# The schema is the output contract. Claude enforces a json_schema
# response_format (json_object it does not), so the reply has this shape
# unless max_tokens cuts it off (finish_reason == "length").
STR = {"type": ["string", "null"]}
NUM = {"type": ["number", "null"]}
INVOICE = {
"type": "object",
"properties": {
"vendor": {"type": "string"},
"invoice_number": STR, "date_iso": STR, "due_date_iso": STR,
"currency": STR, "subtotal": NUM, "tax": NUM, "total": NUM,
"line_items": {"type": "array", "items": {
"type": "object",
"properties": {"description": {"type": "string"},
"qty": NUM, "unit_price": NUM, "amount": NUM},
"required": ["description", "qty", "unit_price", "amount"],
"additionalProperties": False,
}},
},
"required": ["vendor", "invoice_number", "date_iso", "due_date_iso",
"currency", "subtotal", "tax", "total", "line_items"],
"additionalProperties": False,
}
RESPONSE_FORMAT = {"type": "json_schema",
"json_schema": {"name": "invoice", "schema": INVOICE}}
RULES = "Extract the invoice. Use null for missing fields. Dates in ISO 8601."
# Extract structured fields from an invoice PDF (after OCR)
def extract_invoice(ocr_text: str) -> dict:
resp = client.chat.completions.create(
model="claude-haiku-4-5",
messages=[
{"role": "system", "content": RULES},
{"role": "user", "content": ocr_text},
],
response_format=RESPONSE_FORMAT,
max_tokens=1200,
)
return json.loads(resp.choices[0].message.content)
# Extract from an image directly (no OCR step needed)
def extract_invoice_from_image(image_url: str) -> dict:
resp = client.chat.completions.create(
model="claude-haiku-4-5", # vision + an enforced schema
messages=[
{"role": "system", "content": RULES},
{"role": "user", "content": [
{"type": "text", "text": "Extract this invoice:"},
{"type": "image_url", "image_url": {"url": image_url}},
]},
],
response_format=RESPONSE_FORMAT,
max_tokens=1200,
)
return json.loads(resp.choices[0].message.content)두 가지 흐름이 있습니다. 텍스트 전용(별도의 OCR 단계 후)과 비전 직접 방식(비전 모델이 이미지를 읽고 한 번의 호출로 JSON을 출력)입니다. 비전 방식은 구축이 더 빠르지만 호출당 비용이 약간 더 높고, OCR 후 LLM 방식은 페이지당 OCR 비용이 한 번만 발생하므로 대규모 처리에서 더 저렴합니다.
정확도 벤치마크
공개 인보이스 데이터셋(50개 공급업체의 인보이스 1,000개)에서 200단어 시스템 프롬프트를 사용한 JSON 모드의 결과:
- Claude Haiku 4.5: 필드 수준 정확도 96%
- Claude Sonnet 4.6: 필드 수준 정확도 98%
- 기존 템플릿 방식: 알려진 공급업체에서는 80~90%, 신규 공급업체에서는 0%
LLM은 새로운 공급업체 레이아웃도 제로샷으로 처리합니다. 시스템 프롬프트에 예시 쌍 2~3개를 추가하면(퓨샷) Haiku는 훨씬 낮은 비용으로 Sonnet에 가까운 정확도를 냅니다.
문서당 비용
- 인보이스(입력 약 2K 토큰, 출력 약 500): Haiku 약 $0.003, Sonnet 약 $0.02
- 1페이지 계약서(입력 약 5K): Haiku 약 $0.005, Sonnet 약 $0.04
- 10페이지 계약서(입력 약 50K, 구조화된 요약 출력): Sonnet 약 $0.30
- 이력서(입력 약 3K): Haiku 약 $0.003
- 비전을 사용한 영수증 이미지: Haiku, 인보이스와 비슷한 비용 — 이미지는 입력 토큰 약 1.5K로 계산됩니다
월 10,000건의 인보이스 처리: Haiku 사용 시 약 $30입니다. 가장 가까운 상용 대안(Rossum, AWS Textract + 후처리)은 같은 규모에 월 약 $2,000~5,000입니다.
정확도를 높게 유지하는 5가지 패턴
- 명시적 null 처리: 누락된 필드에는 "N/A"나 빈 문자열이 아니라
null을 사용하도록 모델에 지시하세요. 다운스트림 코드에서 "없음"과 "의도적으로 비어 있음"을 구분할 수 있습니다 - ISO 8601 날짜: 명시적으로 지정하세요. 그렇지 않으면 모델이 지역별 형식을 선택해 다운스트림 파싱이 깨집니다
- ISO 코드로 통화 표현: "$"가 아니라 "USD", "€"가 아니라 "EUR"를 사용하세요. 모호성($는 USD, CAD, AUD 모두 가능)을 피할 수 있습니다
- JSON 검증: Pydantic / Zod를 사용해 스키마를 강제하세요. 유효하지 않으면 오류와 함께 다시 프롬프트를 보내세요
- 일주일 동안 수동으로 1% 표본 검사 후 지속적으로 0.1%를 검사하세요. 레코드 수준만이 아니라 필드 수준 정확도를 추적하세요
어떤 모델을 사용할 것인가
| 문서 유형 | 권장 모델 |
|---|---|
| 단순 구조화 문서(인보이스, 영수증) | Claude Haiku 4.5 |
| 긴 계약서 / 협약서 | Claude Sonnet 5(긴 컨텍스트 처리) |
| 비전 직접 방식(OCR 없는 PDF) | Claude Haiku 4.5 또는 대형 페이지에는 Claude Sonnet 5 |
| 고위험 문서(법률, 의료) | Claude Sonnet 5 + 사람의 검증 |
| 대량 수집(하루 100K+) | Haiku 4.5 + 퓨샷 예시 + 캐싱 |
컴플라이언스 고려 사항
PII가 포함된 문서(인보이스에는 이름과 주소가 있고 의료 기록에는 모든 정보가 포함될 수 있음)는 추출 전에 가명 처리하거나 업스트림에서 Zero Data Retention을 사용하세요. 지역별 패턴은 컴플라이언스 가이드, 독일 관련 방법은 DSGVO 심층 가이드를 참고하세요.
시작하기: /app/signup — $10 충전부터 종량제로 결제할 수 있으며 약 3,000건의 인보이스 추출을 처리하고 잔액은 만료되지 않습니다. 각 모델군에서 response_format가 적용하는 사항과 도구 사용 패턴은 /docs/chat의 채팅 문서를 참고하세요.
자주 묻는 질문
How much does it cost to extract data from a document with an LLM?
About $0.003–$0.005 per document on Claude Haiku 4.5 and about $0.02–$0.04 on Claude Sonnet 4.6. Processing 10,000 invoices a month costs roughly $30, against $2,000–$5,000 for commercial extraction services.
How accurate is zero-shot LLM data extraction?
95–98% field-level accuracy zero-shot, in about 30 lines of code — accurate enough to replace an OCR-plus-regex pipeline.
Which model should I use for document extraction?
Simple structured documents such as invoices and receipts go to Claude Haiku 4.5. Long contracts go to Claude Sonnet 4.6. Documents read directly as images go to Claude Haiku 4.5, or Sonnet 4.6 for large pages.
How do I keep extraction accurate in production?
Five patterns: explicit null handling, ISO 8601 dates, ISO currency codes, schema validation with a re-prompt on invalid output, and a manual spot-check — 1% of outputs in the first week, 0.1% ongoing. Track field-level accuracy rather than record-level.