Post

PDF/OCR 문서 처리 실습 정리: Layout, Table, Parser

PDF/OCR 문서 처리 실습 정리: Layout, Table, Parser

처음에는 PDF 처리를 단순하게 봤다. 파일을 넣고, parser로 텍스트를 뽑고, 그 텍스트를 RAG에 넣으면 된다고 생각했다.

여러 구현 자료를 비교하면서 생각이 바뀌었다. PDF/OCR에서 어려운 지점은 “읽는 것”보다 “읽은 결과를 어떤 구조로 남길 것인가”에 있었다. 본문, 표, 그림, 수식, 페이지 번호, caption, section 정보가 섞이면 검색 품질은 OCR 모델 하나로 해결되지 않는다.

PDF/OCR 문서 처리 흐름

내가 헷갈렸던 부분

PDF에서 텍스트를 추출하면 문서 처리가 끝난다고 생각하기 쉽다. 하지만 실제로는 텍스트가 뽑힌 뒤가 더 중요했다.

헷갈린 지점다시 정리한 기준
OCR 정확도가 높으면 충분한가정확한 글자보다 문서 구조 보존이 중요하다
표는 텍스트처럼 chunking하면 되는가표는 행/열 관계가 깨지면 의미가 사라진다
그림은 설명을 생략해도 되는가Figure/Table caption이 답변 근거가 될 수 있다
페이지 단위로 저장하면 되는가질문 단위에 따라 section, figure, table metadata가 필요하다

PDF 처리의 목표는 “텍스트 파일 만들기”가 아니다. 나중에 검색, 요약, QA, 번역, 오디오 변환 같은 downstream 작업이 사용할 수 있는 구조를 만드는 것이다.

처리 흐름

내가 정리한 기본 흐름은 다음과 같다.

단계역할체크포인트
Layout Analysis본문, 제목, 표, 그림, 수식 영역 분리OCR 전에 영역을 나눴는가
OCR / Parser영역별 텍스트 추출스캔본과 디지털 PDF를 분리했는가
Table 처리행, 열, 헤더, 셀 관계 보존행 단위로 의미가 깨지지 않는가
Figure 처리그림 설명과 caption 연결그림만 남고 설명이 사라지지 않는가
Metadata 저장page, section, source, element type 저장검색 결과가 원문 위치로 돌아갈 수 있는가
RAG 입력화chunk와 구조화 데이터를 검색 단위로 변환chunk가 너무 작거나 크지 않은가

여기서 핵심은 element type을 남기는 것이다. 같은 텍스트라도 본문인지, 표의 셀인지, 그림 caption인지에 따라 답변에서 쓰이는 방식이 달라진다.

표 데이터는 따로 본다

표는 일반 문장과 다르다. 예를 들어 재무 리포트의 표에서 “매출”, “영업이익”, “전년 대비” 같은 값은 행과 열 관계 속에서 의미가 생긴다.

그래서 표를 RAG에 넣을 때는 다음 질문을 먼저 해야 한다.

질문이유
헤더가 보존됐는가셀 값만 있으면 값의 의미를 알 수 없다
행 단위와 표 단위 중 무엇을 검색할 것인가너무 잘게 쪼개면 근거가 깨진다
표 주변 문단을 같이 저장할 것인가표가 왜 등장했는지 설명이 필요하다
숫자 단위와 기간이 보존됐는가금융/논문 문서에서는 단위 손실이 치명적이다

실습 관점에서는 표를 Markdown이나 HTML로 변환한 뒤, 표 전체와 핵심 행을 함께 저장하는 방식이 안정적이었다. 표 전체는 맥락을 보존하고, 핵심 행은 검색 recall을 보완한다.

Parser 선택 기준

문서 parser를 고를 때 단순히 “텍스트가 잘 나오나”만 보면 부족하다.

기준확인할 것
Layout 보존제목, 문단, 표, 그림 영역을 구분하는가
표 처리표를 plain text로 뭉개지 않는가
이미지 처리OCR이 필요한 이미지 영역을 분리하는가
Metadatapage, bbox, section 정보를 남기는가
후처리 난이도결과를 DB나 vector store에 넣기 쉬운가

PDF가 길고 복잡할수록 parser 결과를 그대로 믿기보다, 저장 전에 한 번 더 정규화하는 단계가 필요하다.

실습 체크리스트

내가 다음에 PDF/OCR 파이프라인을 만들면 이 순서로 확인할 것이다.

체크질문
문서 유형 분리스캔 PDF와 디지털 PDF를 구분했는가
구조 보존본문, 표, 그림, 수식을 분리했는가
단위 설계page, section, element 중 검색 단위를 정했는가
표 보존헤더와 셀 관계를 잃지 않았는가
그림 설명caption과 주변 문단을 연결했는가
근거 추적답변에서 원문 위치로 돌아갈 수 있는가

코드 조각으로 다시 보기

PDF OCR layout label code note

이 코드 조각에서 가장 중요하게 본 부분은 OCR 호출이 아니라 CLASS_LABELS였다. 문서를 읽기 전에 title, plain text, figure, table, formula처럼 block type을 먼저 고정한다. 그래야 뒤에서 표는 표대로, 그림은 caption과 함께, 본문은 문단 단위로 다룰 수 있다.

내가 압축해서 가져간 설계 형태는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from dataclasses import dataclass


@dataclass
class DocumentBlock:
    page: int
    block_type: str
    text: str
    bbox: tuple[int, int, int, int] | None
    metadata: dict


def normalize_layout_blocks(raw_blocks: list[dict]) -> list[DocumentBlock]:
    blocks = []
    for item in raw_blocks:
        blocks.append(
            DocumentBlock(
                page=item["page"],
                block_type=item["label"],
                text=item.get("text", ""),
                bbox=item.get("bbox"),
                metadata={"source": item.get("source")},
            )
        )
    return blocks

핵심은 parser 결과를 바로 chunk로 만들지 않는 것이다. 먼저 문서 요소를 DocumentBlock으로 정규화한 뒤, RAG나 요약 단계가 필요한 단위로 다시 변환하는 편이 안전하다.

정리

PDF/OCR 처리는 RAG 앞단의 전처리 정도가 아니다. 문서를 어떻게 읽고, 어떤 단위로 저장하고, 어떤 metadata를 남기느냐가 뒤의 검색 품질을 결정한다.

내가 가져간 결론은 간단하다. 복잡한 PDF를 다룰수록 OCR 정확도보다 구조화 설계가 먼저다.

This post is licensed under CC BY 4.0 by the author.