# task-937.1: OpenDataLoader PDF 심층 분석 + 기존 PDF 스킬 비교 + 업그레이드 방안

- **작성자**: 오딘 (개발2팀장)
- **팀원**: 토르(백엔드), 프레이야(프론트), 미미르(UX/UI), 헤임달(테스터)
- **작성일**: 2026-03-25
- **분석 대상**: https://github.com/opendataloader-project/opendataloader-pdf
- **분석 범위**: GitHub 레포 전체 (334파일), 기존 PDF 스킬 전수

---

## Phase 1: OpenDataLoader PDF 심층 분석

### 1.1 아키텍처 개요

OpenDataLoader PDF(이하 ODL)는 **Java 코어 엔진 + 다국어 SDK 래퍼** 구조이다.

```
opendataloader-pdf
├── java/     → Java 코어 엔진 (veraPDF 기반, PDF 파싱/변환 로직 전부)
├── python/   → Python SDK (Java JAR의 thin wrapper, subprocess 호출)
├── node/     → Node.js SDK (Java JAR의 thin wrapper, child_process.spawn)
├── content/  → 문서 사이트
├── docs/     → 하이브리드 모드 설계/실험 문서
├── samples/  → 샘플 PDF/JSON
├── examples/ → 배치 처리, RAG, LangChain 예제
└── options.json → CLI 옵션 단일 진실 소스 (SDK 자동 생성)
```

**핵심 설계 원칙**: Python/Node.js SDK는 Java CLI의 얇은 래퍼(thin wrapper)이다. 실제 PDF 파싱/변환 로직은 전부 Java JAR(`opendataloader-pdf-cli.jar`) 안에 있으며, Python 레이어는 인자를 CLI 인수로 조립해서 `subprocess`로 JAR를 호출한다.

### 1.2 Java 코어 프로세싱 파이프라인

```
PDF Input
  ↓
veraPDF 파싱 (preprocessing)
  ↓
문서 메타데이터 추출 (calculateDocumentInfo)
  ↓
처리 경로 분기:
  ├── TaggedDocumentProcessor  (--use-struct-tree 시, PDF 태그 구조 직접 활용)
  ├── HybridDocumentProcessor  (--hybrid 시, 트리아지 → Java/AI 분기)
  └── DocumentProcessor        (기본, Java 전용 경로)
  ↓
XY-Cut++ 읽기 순서 정렬 (sortContents)
  ↓
콘텐츠 필터/정제 (contentSanitizer)
  ↓
출력 생성 (JSON/Markdown/HTML/Text/Annotated PDF)
```

**Java 프로세서 목록 (20+ 프로세서)**:
- `ContentFilterProcessor` — 텍스트 필터링 (CID 폰트 감지 포함)
- `TextProcessor` / `TextLineProcessor` — 텍스트 전처리/라인 구성
- `ParagraphProcessor` / `HeadingProcessor` — 단락/제목 감지
- `TableBorderProcessor` / `ClusterTableProcessor` / `SpecialTableProcessor` — 테이블 감지 (3가지 방식)
- `TableStructureNormalizer` — 테이블 구조 정규화
- `ListProcessor` / `CaptionProcessor` — 목록/캡션 처리
- `HeaderFooterProcessor` / `HiddenTextProcessor` / `StrikethroughProcessor` — 특수 요소
- `XYCutPlusPlusSorter` — XY-Cut++ 읽기 순서 알고리즘
- `TriageProcessor` — 하이브리드 트리아지 (6단계 신호)

### 1.3 하이브리드 모드 아키텍처

```
PDF Input → ContentFilterProcessor
  ↓
TriageProcessor.triageAllPages()
  ↓
┌─────────────────┐      ┌─────────────────┐
│ JAVA Path       │      │ BACKEND Path    │
│ (ExecutorService│      │ (단일 배치 API) │
│  병렬 처리)     │      │ BackendClient   │
│ TableBorder     │      │ → docling-fast  │
│ TextLine        │      │   FastAPI서버   │
│ Paragraph       │      │ SchemaTransformer│
└────────┬────────┘      └────────┬────────┘
         └──────────┬─────────────┘
                    ↓ (동시 실행)
            Result Merger (페이지 순서 보존)
                    ↓
         Post-processing & Output
```

**하이브리드 서버 (`hybrid_server.py`)**:
- FastAPI + uvicorn 기반
- 기본 포트: 5002
- Docling `DocumentConverter` 싱글턴 (모델 로딩 1회)
- `asyncio.to_thread()` + `threading.Lock()`으로 비블로킹 처리
- 엔드포인트: `POST /v1/convert/file` → DoclingDocument JSON 반환
- 100MB 파일 크기 제한
- 유니코드 정화: lone surrogate(U+D800~U+DFFF) + null char → U+FFFD

### 1.4 트리아지 로직 상세

6단계 신호 우선순위:

- **Signal 0**: CID 폰트 추출 실패 (replacementRatio ≥ 0.3) → confidence 1.0
- **Signal 1**: TableBorder 존재 → confidence 1.0
- **Signal 2**: hasVectorTableSignal (그리드 라인) → confidence 0.95
- **Signal 3**: hasTextTablePattern (연속 패턴) → confidence 0.9
- **Signal 4**: hasSuspiciousPattern → confidence 0.85 (**비활성화됨**)
- **Signal 5**: lineToTextRatio > 0.3 → confidence 0.8
- **Signal 6**: alignedLineGroups ≥ 5 → confidence 0.7 (**비활성화됨**)

5차 실험(200개 PDF, 42개 테이블 포함)을 통해 최적화:
- 최초: Precision 27.15%, Recall 97.62%, F1 42.49%
- 최종: Precision 43.30%, **Recall 100%**, F1 60.43%
- 전략: "FP는 허용하되 FN은 0" (보수적 접근)

### 1.5 XY-Cut++ 읽기 순서 알고리즘

4단계 프로세스 (`XYCutPlusPlusSorter.java`):

1. **Cross-Layout 감지**: 다중 컬럼에 걸치는 요소(전체 너비 제목/헤더) 분리
2. **밀도 분석**: 콘텐츠 밀도 > 0.9이면 수평 절단 우선, 아니면 수직 절단 우선
3. **재귀적 분할**: X/Y 축 투영 → 최대 Gap 찾기 → 절단 → 단일 컬럼까지 반복
4. **Cross-Layout 재삽입**: Y 좌표 기준으로 올바른 위치에 재삽입

핵심 파라미터: Beta=2.0, Density=0.9, MinGap=5.0pt
논문: arXiv:2504.10258

### 1.6 벤치마크 상세

**Overall Score = (NID + TEDS + MHS) / 3 (단순 평균)**

200개 실제 PDF 기반 공개 재현 가능 벤치마크:

**읽기 순서 (NID — Normalized Indel Distance, 1.0=완벽)**:
- ODL [hybrid]: **0.94** (#1)
- ODL [local]: 0.91
- docling: 0.90
- pymupdf4llm: 0.89
- markitdown: 0.88

**테이블 (TEDS — Tree Edit Distance Similarity)**:
- ODL [hybrid]: **0.93** (#1)
- docling: 0.89
- ODL [local]: 0.49
- pymupdf4llm: 0.40
- markitdown: 0.00

**핵심 통찰**: 로컬 모드 0.49 → hybrid 0.93 = **+90% 개선**. 테이블 추출은 AI 백엔드가 결정적 차이.

**제목 (MHS — Markdown Heading Similarity)**:
- ODL [hybrid]: **0.83** (#1)
- docling: 0.80
- ODL [local]: 0.76

**처리 속도 (s/page)**:
- markitdown: 0.04 (테이블/헤딩 미추출)
- **ODL [local]: 0.05** (정확도 대비 최고 속도)
- pymupdf4llm: 0.09
- ODL [hybrid]: 0.43
- docling: 0.73
- marker: 53.93 (GPU 기반, 극단적)

내부 실험: docling-serve HTTP 2.28s → FastAPI 싱글턴 0.69s (**3.3배 가속**)

### 1.7 API/SDK 분석

**Python convert() 전체 파라미터**:
```python
convert(
    input_path,                    # 필수: PDF 경로 또는 경로 리스트
    output_dir=None,               # 출력 디렉토리
    password=None,                 # 암호화 PDF 비밀번호
    format=None,                   # json,text,html,pdf,markdown 등
    quiet=False,                   # 로그 억제
    content_safety_off=None,       # 안전 필터 비활성화
    sanitize=False,                # 민감정보 익명화
    keep_line_breaks=False,        # 줄바꿈 보존
    replace_invalid_chars=None,    # 잘못된 문자 치환
    use_struct_tree=False,         # PDF 구조 트리 사용
    table_method=None,             # 테이블 감지 방법 (default|cluster)
    reading_order=None,            # 읽기 순서 (off|xycut)
    markdown_page_separator=None,  # Markdown 페이지 구분자
    text_page_separator=None,      # 텍스트 페이지 구분자
    html_page_separator=None,      # HTML 페이지 구분자
    image_output=None,             # 이미지 출력 (off|embedded|external)
    image_format=None,             # 이미지 포맷 (png|jpeg)
    image_dir=None,                # 이미지 저장 디렉토리
    pages=None,                    # 페이지 범위 ("1,3,5-7")
    include_header_footer=False,   # 헤더/푸터 포함
    detect_strikethrough=False,    # 취소선 감지 (실험적)
    hybrid=None,                   # AI 백엔드 (off|docling-fast)
    hybrid_mode=None,              # 트리아지 모드 (auto|full)
    hybrid_url=None,               # 하이브리드 서버 URL
    hybrid_timeout=None,           # 타임아웃 (ms)
    hybrid_fallback=False,         # 에러 시 Java 폴백
) → None                          # 결과는 파일로 출력 (메모리 반환 없음)
```

**중요**: `convert()` 반환값이 `None`이다. 결과는 파일 시스템에 직접 기록되며, Python 메모리로 반환되지 않는다.

**출력 형식 7가지**:
- `json` — 바운딩 박스, 의미 타입 포함 구조화 데이터 (기본값)
- `text` — 순수 텍스트
- `html` — 스타일 포함 HTML
- `pdf` — 감지된 구조를 시각화한 주석 PDF
- `markdown` — 제목/테이블/목록 보존 마크다운
- `markdown-with-html` — HTML 요소 포함 마크다운
- `markdown-with-images` — Base64 이미지 포함 마크다운

### 1.8 JSON 출력 스키마

```json
{
  "file name": "document.pdf",
  "number of pages": 10,
  "author": "...",
  "title": "...",
  "creation date": "D:YYYYMMDDHHMMSS+HH'MM'",
  "modification date": "...",
  "kids": [
    {
      "type": "heading|paragraph|table|list|image|caption|header|footer|text block",
      "id": 42,
      "level": "Doctitle|1|2|...",
      "page number": 1,
      "bounding box": [left, bottom, right, top],  // PDF 포인트, 좌하단 원점
      "font": "Pretendard-Regular",
      "font size": 32.005,
      "text color": "[0.0]",
      "content": "텍스트 내용",
      "heading level": 1
    }
  ]
}
```

테이블은 `rows → cells → kids` 중첩 구조. 페이지 걸침 시 `previous table id` / `next table id`로 링크드 리스트 연결.

### 1.9 AI 안전 기능

**레이어 1: 렌더링 불일치 필터 (기본 활성화)**:
- `hidden-text` — 투명/저대비 텍스트 차단
- `off-page` — 페이지 외부 텍스트 제거
- `tiny` — 극소 폰트 (≤1pt) 필터링
- `hidden-ocg` — Optional Content Group 숨김 콘텐츠 제거

**레이어 2: `--sanitize` (기본 비활성화)**:
- 이메일 → `email@example.com`
- 전화번호 → `+00-0000-0000`
- 신용카드 → `0000-0000-0000-0000`
- IP → `0.0.0.0` / URL → `https://example.com`

### 1.10 OCR & 다국어

OCR은 **하이브리드 모드에서만** 작동 (로컬 Java는 디지털 PDF만 처리):
- EasyOCR 기반 80+ 언어 지원
- `--force-ocr`: 전체 페이지 강제 OCR
- `--ocr-lang "ko,en"`: 한국어+영어
- RTL 스크립트(아랍어 등) 제한: 문자 인식은 가능하나 읽기 순서 재정렬 미지원

### 1.11 추가 기능

- **수식 추출**: hybrid + `--enrich-formula` → LaTeX 출력
- **이미지 설명**: hybrid + `--enrich-picture-description` → SmolVLM-256M 모델
- **Tagged PDF**: `--use-struct-tree`로 PDF 구조 태그 직접 활용
- **PDF/UA 접근성**: Audit(무료), Auto-Tag(Q2 2026 예정), PDF/UA Export(Enterprise)
- **LangChain 통합**: `langchain-opendataloader-pdf` 패키지

### 1.12 라이선스 및 제약

- **Apache License 2.0** (v2.0부터, 이전 MPL 2.0)
- Copyright: **Hancom Inc.** (한컴)
- 상업적 사용: **제한 없음** (LICENSE, NOTICE 파일 유지 의무)
- veraPDF 의존성: MPL-2.0 (수정 파일 소스 공개 의무, ODL 자체 코드에는 영향 없음)
- Enterprise 전용: PDF/UA Export, Accessibility Studio
- 하이브리드 `docling-fast`: **로컬 실행, API 비용 없음**
- 향후 유료 백엔드 예정: hancom, azure, google

---

## Phase 2: 기존 PDF 스킬 심층 분석

### 2.1 구조 개요

```
/home/jay/.claude/skills/pdf/
├── SKILL.md          (314줄) — 메인 가이드, 라이브러리별 레시피
├── reference.md      (611줄) — 고급 기능, JS 라이브러리
├── forms.md          (294줄) — 폼 처리 워크플로우
└── scripts/          (8개 스크립트)
    ├── check_bounding_boxes.py     — 바운딩 박스 교차 검증 (QA)
    ├── check_fillable_fields.py    — AcroForm 필드 유무 판별
    ├── convert_pdf_to_images.py    — PDF → PNG 변환 (200 DPI, max 1000px)
    ├── create_validation_image.py  — 좌표 시각화 디버깅
    ├── extract_form_field_info.py  — AcroForm 필드 ID/타입/좌표 추출
    ├── extract_form_structure.py   — non-fillable PDF 텍스트/선/체크박스 추출
    ├── fill_fillable_fields.py     — AcroForm 필드에 값 기입
    └── fill_pdf_form_with_annotations.py — FreeText 어노테이션으로 텍스트 삽입
```

### 2.2 스크립트별 핵심 분석

**check_bounding_boxes.py**: O(n²) 교차 검사. 표준 라이브러리만 사용. 페이지 경계/out-of-bounds 미검사.

**check_fillable_fields.py**: pypdf `get_fields()` 반환값의 truthy 여부만 확인. XFA 폼 오탐 가능.

**convert_pdf_to_images.py**: pdf2image(poppler pdftoppm) 사용. **200 DPI + max 1000px 축소** — OCR 권장값(300-400 DPI) 미달.

**extract_form_field_info.py**: AcroForm 딕셔너리 파싱. `/FT` 키로 타입 분류(text/checkbox/choice/radio). XFA 미지원.

**extract_form_structure.py**: pdfplumber로 단어/수평선/사각형 추출. **원형 체크박스 미감지**, 세로선 미추출, 병합 셀 미지원.

**fill_fillable_fields.py**: pypdf로 AcroForm 필드 기입. pypdf `get_inherited` 버그 monkeypatch. **CJK 폰트 미임베딩 → 한글 깨짐**.

**fill_pdf_form_with_annotations.py**: FreeText 어노테이션 방식. 이미지→PDF 좌표 변환 포함. **기본 폰트 Arial → CJK 미지원**.

### 2.3 의존성 현황

실제 스크립트에서 사용하는 라이브러리:
- `pypdf` — PDF 읽기/쓰기, AcroForm
- `pdfplumber` — 텍스트/좌표 추출
- `pdf2image` (poppler) — PDF → 이미지
- `Pillow` — 이미지 처리

SKILL.md 레시피에만 언급 (전용 스크립트 없음):
- `pytesseract` — OCR
- `reportlab` — PDF 생성
- `pypdfium2` — 고속 렌더링
- `pandas` — 테이블 DataFrame

### 2.4 능력 종합 평가

- **텍스트 추출**: 중 — pypdf/pdfplumber 기반, 다단 레이아웃에서 순서 뒤섞임
- **테이블 추출**: 하~중 — pdfplumber extract_tables() 레시피만 존재, 병합 셀/보더리스 테이블 미지원
- **OCR**: 하 — pytesseract 레시피만 존재, 전용 스크립트 없음, 전처리 파이프라인 없음
- **폼 처리 (Fillable)**: 중~상 — AcroForm 완전 지원 (XFA 미지원)
- **폼 처리 (Non-fillable)**: 중 — 어노테이션 방식, 좌표 정확도 의존
- **이미지 추출**: 하 — CLI 레시피만 존재
- **읽기 순서 보존**: 하 — 알고리즘 없음
- **수식 추출**: 없음
- **AI 통합**: 없음
- **한국어 지원**: 하 — CJK 폰트 미처리, 한글 OCR 설정 없음
- **출력 형식**: JSON만 (Markdown/HTML 변환 없음)

### 2.5 아키텍처적 한계

1. **폼 작성 전용 설계**: 8개 스크립트 전체가 PDF 폼 작성 워크플로우에 특화
2. **단방향 파이프라인**: 중간 결과 피드백/재처리 루프 없음
3. **오류 복구 없음**: exit(1) 또는 메시지 출력 후 종료
4. **보험 약관 PDF 처리 한계**: 다단 레이아웃 뒤섞임, 복잡한 표 구조 파악 불가, 각주/주석 순서 보장 안됨, CID 폰트 문제

---

## Phase 3: 기능 비교 분석

### 3.1 기능별 1:1 비교

**텍스트 추출 정확도**
- 기존: pypdf/pdfplumber 기반, 레이아웃 미보존, 다단에서 뒤섞임
- ODL: Java 코어 + XY-Cut++ 읽기 순서, NID 0.94 (hybrid)
- **ODL 압도적 우세** — 읽기 순서 알고리즘 자체가 없는 기존 스킬 vs 학술 논문 기반 알고리즘

**테이블 추출 (복잡한 표)**
- 기존: pdfplumber extract_tables() 레시피만 존재. 병합 셀 미지원, 보더리스 테이블 불가
- ODL: 3가지 테이블 프로세서(TableBorder/Cluster/Special) + hybrid AI 테이블 감지. TEDS 0.93
- **ODL 압도적 우세** — 전용 프로세서 3개 + AI vs 레시피 코드 1줄

**OCR (스캔 PDF)**
- 기존: pytesseract 레시피만 존재, 전처리 없음, 200DPI 이미지
- ODL: EasyOCR 80+ 언어, hybrid 모드 자동 OCR, CID 폰트 감지 → 자동 OCR 라우팅
- **ODL 우세** — 통합된 OCR 파이프라인 vs 레시피 수준

**읽기 순서 보존**
- 기존: 없음 (PDF 내부 객체 순서 그대로)
- ODL: XY-Cut++ 4단계 알고리즘, NID 0.94
- **ODL 완전 우세** — 기존은 기능 자체가 없음

**수식 추출**
- 기존: 없음
- ODL: hybrid + `--enrich-formula` → LaTeX 출력
- **ODL 완전 우세**

**이미지/차트 처리**
- 기존: pdfimages CLI 레시피만
- ODL: 이미지 추출(embedded/external) + SmolVLM AI 설명 생성 + 바운딩 박스
- **ODL 압도적 우세**

**폼 처리**
- 기존: AcroForm 필드 기입/추출 8개 전용 스크립트, 비주얼 검증 도구
- ODL: 폼 처리 기능 없음 (추출 전용)
- **기존 스킬 우세** — ODL은 폼 작성 기능 없음

**출력 형식 다양성**
- 기존: JSON (폼 데이터만)
- ODL: JSON, Markdown, HTML, Text, Annotated PDF, Markdown+HTML, Markdown+Images (7가지)
- **ODL 압도적 우세**

**AI 통합**
- 기존: 없음
- ODL: 하이브리드 트리아지, Docling AI, EasyOCR, SmolVLM, LangChain 통합
- **ODL 완전 우세**

**한국어 지원**
- 기존: CJK 폰트 미처리, pytesseract `lang='kor'` 레시피만
- ODL: EasyOCR `--ocr-lang ko`, CID 폰트 감지(한국 문서 특화), Hancom(한컴) 개발
- **ODL 우세** — 한컴 기반 프로젝트로 한국어 특화

**처리 속도**
- 기존: pdfplumber/pypdf 직접 호출, 빠르나 기능 제한적
- ODL: 로컬 0.05s/page (Java JVM 기동 오버헤드 있음), hybrid 0.43s/page
- **기존 약간 우세 (단순 작업)** — 직접 라이브러리 호출 vs JVM subprocess

**의존성/설치 복잡도**
- 기존: pip install pypdf pdfplumber pdf2image → 간단
- ODL: pip install opendataloader-pdf + Java 11+ 필수, hybrid 시 docling + CUDA 선택
- **기존 우세** — Java 런타임 불필요

**프롬프트 인젝션 방어**
- 기존: 없음
- ODL: 4가지 렌더링 불일치 필터 + --sanitize 민감정보 익명화
- **ODL 완전 우세** — LLM 보안 특화 기능

### 3.2 종합 비교 요약

- 기존이 우세: **폼 처리**, 설치 간편성, 단순 작업 속도
- ODL 압도적 우세: 텍스트 추출, 테이블 추출, OCR, 읽기 순서, 수식, 이미지, AI 통합, 출력 형식, 한국어, AI 안전
- **결론**: 기존 스킬은 "폼 작성" 특화 도구, ODL은 "문서 이해(Document Understanding)" 종합 엔진. 두 도구의 목적이 다름.

---

## Phase 4: InsuWiki + InsuRo 적용 방안

### 4.1 InsuWiki 활용 시나리오

**보험 약관 PDF 파싱 (복잡한 표, 주석)**
- ODL hybrid 모드로 처리 시:
  - TEDS 0.93 수준의 테이블 추출 (병합 셀, 보더리스 포함)
  - XY-Cut++로 다단 레이아웃 읽기 순서 보존
  - CID 폰트 감지로 한국어 약관 자동 OCR 라우팅
  - 바운딩 박스로 원본 위치 추적 가능
- 현재 스킬로는 불가능한 수준의 구조화 추출

**보험 상품 설명서 PDF → 구조화된 데이터**
- JSON 출력의 `kids` 배열에서 heading/paragraph/table 구조화
- RAG 파이프라인 연동: basic_chunking.py 패턴 (요소별/섹션별/최소크기 3전략)
- LangChain 통합으로 벡터 DB 직접 연동

**고객 제출 서류 OCR 처리**
- `--force-ocr --ocr-lang "ko,en"`으로 스캔 문서 처리
- `--sanitize`로 개인정보 자동 마스킹 (이메일, 전화, 카드번호)

### 4.2 InsuRo 활용 시나리오

**보험 비교 자료 PDF 처리**
- 경쟁사 상품 비교표 자동 추출 → 구조화 JSON
- Markdown 출력으로 직접 콘텐츠 활용

**공개 보험 데이터 PDF 대량 처리**
- batch_processing.py 패턴 활용
- 단일 JVM으로 수백 PDF 일괄 처리 (JVM 기동 오버헤드 1회)
- 디렉토리 입력으로 재귀 처리 가능

### 4.3 업그레이드 전략

**A안: OpenDataLoader 전면 교체** (기존 스킬을 ODL 기반으로 재작성)
- 장점: 모든 기능 일괄 업그레이드, 유지보수 단일화
- 단점: 폼 작성 기능 소실 (ODL에 없음), Java 런타임 의존성 추가
- 구현 난이도: 높음 (스킬 전체 재작성)
- 소요 시간: 2-3주
- **비권장**: 폼 작성 기능 소실이 치명적

**B안: 하이브리드 도입 — 기존 스킬 + ODL 강점 추가 (★ 권장)**
- 장점: 폼 작성 유지 + 문서 이해 능력 대폭 강화
- 단점: 두 시스템 병행 유지 필요
- 구현 난이도: 중간 (스킬에 ODL 섹션 추가)
- 소요 시간: 1-2주
- **구체적 구현**:
  1. SKILL.md에 "문서 이해/추출" 섹션 추가 (ODL convert() 래핑 스크립트)
  2. 기존 폼 처리 스크립트 유지
  3. 작업 유형별 라우팅: 폼 작성 → 기존 스크립트, 문서 추출 → ODL
  4. `opendataloader-pdf` + Java 11 설치 가이드 추가

**C안: 핵심 알고리즘만 차용** (XY-Cut++, 테이블 추출 로직)
- 장점: Java 의존성 없음
- 단점: Java 소스를 Python으로 포팅 필요 (수천 줄), 유지보수 불가능
- 구현 난이도: 매우 높음
- **비권장**: ROI 대비 비용이 과도

### 4.4 권장안: B안 (하이브리드 도입) 상세

**즉시 도입 가능한 것** (pip install로 바로):
1. `pip install opendataloader-pdf` → 기본 텍스트/테이블/구조 추출 (Java 11 필요)
2. `--format json,markdown` → 구조화 JSON + Markdown 출력
3. `--reading-order xycut` → 읽기 순서 보존
4. `--sanitize` → 개인정보 마스킹
5. 배치 처리 패턴 (batch_processing.py 참조)

**커스터마이징 필요한 것** (1-2주):
1. hybrid 서버 설정 + docling 설치 (GPU 선택)
2. `--hybrid docling-fast --ocr-lang "ko,en"` 한국어 OCR 파이프라인
3. RAG 청킹 스크립트 (basic_chunking.py 기반 보험 특화)
4. 보험 약관 전용 후처리 (표 병합, 주석 연결 등)
5. SKILL.md 업데이트 (ODL 사용 가이드 추가)

**장기 검토 필요한 것** (1개월+):
1. LangChain 통합 파이프라인 구축
2. 수식 추출 활용 방안 (보험 계리 문서)
3. PDF/UA 접근성 파이프라인 (Enterprise 라이선스 검토)
4. Hancom 백엔드 평가 (한국어 특화 AI)

### 4.5 구체적 업그레이드 우선순위

| 우선순위 | 항목 | 효과 | 노력 |
|---------|------|------|------|
| P0 | ODL 설치 + 기본 추출 | 즉시 텍스트/테이블 추출 능력 확보 | 1일 |
| P1 | hybrid 서버 + 한국어 OCR | 스캔 문서 + 한글 약관 처리 | 3일 |
| P2 | RAG 청킹 스크립트 | 보험 문서 벡터 DB 연동 | 1주 |
| P3 | SKILL.md 통합 업데이트 | 단일 스킬에서 모든 PDF 작업 가능 | 2일 |
| P4 | LangChain 파이프라인 | 질의응답 시스템 | 2주 |
| P5 | 수식 추출 + PDF/UA | 계리 문서 + 접근성 | 장기 |

---

## 발견 이슈 및 해결

본 작업은 연구/분석 작업이므로 코드 변경 이슈 없음.

### 분석 중 발견된 핵심 주의사항

1. **Java 런타임 필수**: ODL 사용 시 Java 11+ 설치 필요. 현재 시스템에 Java 존재 여부 확인 필요.
2. **반환값 None**: `convert()` 함수가 결과를 파일로만 출력하므로, 프로그래매틱 사용 시 JSON 파일을 별도로 읽어야 함.
3. **hybrid 모드 주의**: `--enrich-formula`, `--enrich-picture-description` 사용 시 반드시 `--hybrid-mode full` 필요 (auto에서는 조용히 스킵).
4. **veraPDF MPL-2.0**: ODL 코드 자체는 Apache 2.0이나, veraPDF 파일을 수정하면 해당 파일 소스 공개 의무 발생. 단순 사용 시에는 문제 없음.

---

## 생성/수정 파일 목록

- `/home/jay/workspace/memory/reports/task-937.1.md` (본 보고서)

## 머지 판단

- **머지 필요**: No (분석/보고서 작업, 코드 변경 없음)
