문서 사진 한 장을 구조화된 데이터로 바꾸는 시스템을 만들었다. 영수증, 청구서, 계약서 — 종류를 가리지 않고, 사진을 올리면 AI가 필드를 추출하고 사람이 효율적으로 검수할 수 있는 워크플로우를 제공한다.
핵심 설계: "AI는 읽기만, 코드는 처리만"
가장 중요한 설계 결정은 역할 분리였다. Gemini Vision에게 모든 걸 시키는 대신, 텍스트 인식과 필드 식별만 맡겼다. 정규화, 검증, 좌표 매칭은 모두 결정론적 코드가 처리한다.
왜 이렇게 했는가? 초기에 Gemini에게 값 추출과 좌표를 동시에 요청했더니, 밀집 영수증에서 좌표 계산에 출력 토큰을 소진하면서 뒷부분 품목 3개가 누락됐다. 17개에서 14개로. 그래서 원칙을 세웠다: Gemini는 값만, PaddleOCR은 위치만.
두 AI의 결과를 텍스트 유사도로 매칭하는 bbox 스냅핑이 이 시스템의 핵심 메커니즘이다.
7단계 파이프라인
- 이미지 전처리 — 문제 있을 때만 조건부 적용 (회전, 기울기, 샤프닝)
- 리사이즈 + Auto-crop — 배경 제거, 문서 영역만 추출
- 문서 유형 분류 — Gemini가 영수증/청구서/계약서 등 자동 판별
- Gemini 필드 추출 — 품목명, 가격, 합계 등 구조화된 데이터 반환 (멀티페이지 병렬)
- 후처리 + 정규화 — 바코드 필터링, 날짜→ISO, 금액→숫자, 합계 검증
- PaddleOCR → Bbox 스냅핑 — 텍스트 좌표 감지 → 필드와 1:1 매칭
- 신뢰도 보정 → 저장 — 다중 시그널로 confidence 보정, 3단계 색분류
차별점 다섯 가지
가장 자주 받는 질문이 "일반 OCR과 뭐가 다르냐"다.
첫째, 두 AI의 역할 분리. Gemini의 맥락 이해력과 PaddleOCR의 좌표 정밀도를 각각 살린다. 둘째, 코드가 AI를 검증한다. 합계 산술 대조, 바코드 필터링 같은 규칙이 AI의 실수를 잡는다. 셋째, 다중 시그널 신뢰도. Gemini의 일률적 confidence를 5가지 코드 시그널로 보정하여 실제 정확도에 가깝게 만든다. 넷째, 피드백 루프. 검수자 수정 패턴을 분석해서 다음 추출에 반영한다. 모델 재학습 없이 프롬프트만으로 점진 개선. 다섯째, 동적 자동 승인. 필드별 실제 정확도에 따라 임계값을 조정한다.
솔직한 약점
Gemini API에 의존하므로 네트워크 장애 시 추출이 불가하고, 문서당 ~65초의 처리 시간은 대량 처리에 병목이 된다. 좌표계 관리(전처리→crop→정규화)가 디버깅하기 까다롭고, 파이프라인 단위 테스트 커버리지가 부족하다.
어디서 볼 수 있나
라이트 모드 HTML 문서로 정리했다. 핵심 기능, 설계, 구조, 차별점, 장단점, 향후 개선까지 7개 섹션. 동료에게 시스템을 소개할 때 이 한 장이면 충분하다.