Skip to content

OCR Worker

donghoong2 edited this page Oct 28, 2026 · 1 revision

OCR 워커 구성

dev a9974a0 (2026-10-12) 기준

OCR 워커는 사용자가 올린 보험·의료 문서(진단서·보험증권·지급결과안내문·청구서·입퇴원확인서·진료비영수증)를 SQS로 받아, GPU OCR → 분류·추출 → PII 마스킹 → 저장 → 리포트 워커 발행까지 처리하는 단일 책임 워커다. 개인정보 보호를 위해 외부 OCR API를 쓰지 않고 모든 처리를 로컬 GPU에서 한다.

이 페이지는 코드의 현재 동작이 아니라 각 단계를 왜 이렇게 만들었는가를 모은 것이다. 동작 상세는 src/ocr_worker/README.md와 docs/architecture/ocr.md가 기준이다.

OCR 워커 13단계: SQS 소비, S3 GetObject, 페이지 렌더, surya-ocr 추론, 문서 분류·엔티티 추출, 텍스트 마스킹·잔류 검사, 하이브리드 VLM 보완, 품질 판정, 이미지 마스킹 트랙, ocr_results 저장, 원본 삭제 트리거, ReportJob 발행, DeleteMessage

전체 흐름. 색은 실행 자원(SQS·외부 I/O·GPU·CPU)과 안전 게이트를 구분한다. 6(텍스트 마스킹)과 8(품질 판정)이 저장 전에 막는 게이트다

단계별 설계 근거

단계 결정 이유 관련 기록
소비 메시지 큐 워커로 분리, at-least-once + 애플리케이션 멱등 OCR·VLM은 GPU를 오래 점유한다. 업로드와 같은 경로에 두면 API 지연과 GPU 경합이 함께 생긴다. SQS 표준 큐의 중복 전달은 브로커가 아니라 진입부 멱등 조회·결정적 ID·업서트로 흡수한다 결정 로그 D-009~D-011
재시도 인프로세스 재시도 없음, 브로커 재전달에 맡김. 결정적 실패(NonRetryableError)는 즉시 종결 재시도 규약을 한 곳에 둔다. 다시 해도 같은 결과인 실패는 재전달할 이유가 없다 청구 fan-in 기록
OCR 엔진 surya-ocr 0.17.x in-process, 결과를 라인 구조(텍스트·bbox·신뢰도)로 보존 분류·추출은 텍스트, 텍스트 마스킹은 문자열, 이미지 마스킹은 좌표가 필요하다. OCR은 한 번만 돌리고 세 트랙이 같은 결과를 쓴다. 0.18부터는 별도 추론 서버가 필요해 0.17에 고정 —
렌더 PDF 200dpi, 큰 판형은 페이지별로 DPI 자동 하향 A3 이상 스캔본이 PIL 압축폭탄 한도를 넘었다. 한도를 해제하지 않고 입력을 줄였다 (PR #40) —
분류·추출 가중 키워드 점수, 비-PII 도메인 값만 정규식 추출. 후보에 PII가 섞이면 부분 편집 없이 통째로 버림 추출이 마스킹보다 먼저 실행된다. OCR이 인접 셀을 한 줄로 합치면 "병명: … 성명: 홍길동"처럼 PII가 같이 잡힌다 초록불 기록
텍스트 마스킹 정규식 ∪ NER 스팬, 잔류 검사 실패 시 저장하지 않음(fail-closed) 확신이 없으면 저장하지 않는다. PII에서는 가용성보다 안전이 우선 NER 기록
VLM 보완 표 문서 또는 신뢰도 < 0.90 페이지만, groundedness·재마스킹·잔류 검사 통과 시 채택 필요한 페이지에만 쓰고, VLM 환각을 원문 대조로 거른다 VLM 하이브리드 기록
품질 판정 신뢰도 < 0.90 그리고 (이름 없음 또는 도메인 정보 없음) → needs_reupload 문서 전체 임계값은 재업로드를 너무 자주 만들고, 유형별 필수 필드는 유지 비용이 크다 같은 기록
이미지 마스킹 PII 줄 검은 블록 사본, 검증 통과 시에만 원본 삭제 손해사정사가 원본과 비슷한 형태로 열람해야 한다. 삭제는 되돌릴 수 없다 원본 삭제 게이트 기록
fan-in 청구의 모든 문서가 종결된 뒤 청구당 ReportJob 1건 문서마다 리포트가 생기거나 미완성 청구가 조기 발행되지 않게 한다 청구 fan-in 기록

하이브리드 VLM

하이브리드 5단계: 문서 업로드, OCR 읽기, 신뢰도 판단(< 0.90), VLM 전사(필요한 페이지만), 대조 검증 및 병합

VLM은 고른 페이지에만 쓰고, surya 원문과 대조해 지어낸 내용이 없을 때만 병합한다

용도 모델 고른 이유
표 전사 qwen3.6:35b-a3b 같은 문서에서 qwen3-vl:8b보다 정확하고 빠름(약 11초 vs 약 15초)
PII 좌표(grounding) qwen3-vl:8b-instruct 0~1000 정규화 좌표로 이름 칸을 정확히 짚음. 35b-a3b는 박스가 헤더 영역으로 벗어남
(제외) glm-ocr 0.9B — 표 정렬은 좋았지만 "급성 심근경색증"을 "급성 심근경쟁증"으로 읽는 의료 용어 오독, 무한 반복 출력

시험용 가상 보험금 지급 심사 결과서 사진

표 전사 대상의 예(시험용 가상 문서 촬영본). 지급 결정 표의 행마다 청구·지급 금액과 결과가 있어 surya의 라인 순서만으로는 행·열이 복원되지 않는다

마스킹 두 트랙

A. 텍스트 마스킹 (필수) B. 이미지 검은블록
입출력 str → str image → image
OCR 좌표 불필요 필수 (surya bbox + 저신뢰도 문서는 VLM grounding 추가)
결과 masked_text (LLM 입력), masked_lines masked/ 사본 (SSE-KMS)
보안 함정 모델 입력 상한 뒤 무음 누락 PDF에 박스만 덧그리면 밑 텍스트가 복사됨 → 래스터화
일치 보장 페이지 스팬을 라인 로컬 오프셋으로 잘라 두 트랙이 같은 검출 결과를 씀 같음

시험용 가상 진단서 마스킹 전후

이름·주민번호·주소·연락처·면허번호는 가리고, 진단명·KCD 코드·날짜·치료 기간은 남긴다. 판단에 필요한 값까지 지우면 리포트를 만들 수 없다

원본 삭제 게이트와 Outbox 재시도

이미지 트랙과 원본 삭제. 검증 실패는 예외가 아니라 "원본 보존 + 경고"로 끝난다

알려진 한계

  • 진단서·청구서처럼 엔티티 필드가 1~2개인 유형은 그 필드가 원래 없는 양식이어도 재업로드로 오탐할 수 있다.
  • groundedness 0.3, 저신뢰 0.90은 표본 3건 기준 시작값이다.
  • 서명·인감·손글씨 PII는 OCR 라인이 없어 마스킹·검증 모두 못 잡는다.
  • 검증 실패 페이지의 사본도 정상 서빙된다. 원본 삭제만 막는다.

참고

  • 팀 설계 문서 "OCR Worker 파이프라인 설계 문서", "마스킹 전략", "OCR 표 문서 — surya 한계와 VLM 검증"
  • src/ocr_worker/, docs/architecture/ocr.md

Clone this wiki locally