TRENDSHIFT #6 딥다이브 · 2026-03-28 분석

Chandra OCR 딥다이브
— ~5B VLM으로 90개 언어와 복잡한 레이아웃을 인식하는 OCR 엔진

단순 텍스트 추출을 넘어 표·수식·손글씨·좌표까지 HTML로 구조화하는 Vision Language Model 기반 OCR. olmOCR 벤치마크 1위(85.9%), Gemini 2.5 Flash를 전 카테고리에서 압도. datalab-to/chandra · ⭐11.1k · Python · Apache 2.0 / OpenRAIL-M
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

Chandra가 정확히 무엇을 하는 물건인가

Chandra는 이미지·PDF를 HTML·Markdown·JSON으로 변환하는 VLM 기반 OCR 엔진으로, 복잡한 표·수식·손글씨·90개 이상의 언어를 레이아웃까지 보존하며 인식합니다.

Chandra 2(2026년 3월 출시)는 9B 파라미터를 ~5B(Qwen3.5)로 줄이면서 olmOCR 정확도는 83.1% → 85.9%로 오히려 높아졌습니다. 처리량도 2배 개선. HuggingFace 월간 165K+ 다운로드. GitHub 스타: 11.1k(2026-06-04 기준).

한 컷 비유

"종이 문서를 찍으면 진짜 HTML 표로 돌아오는 스캐너"

Tesseract 같은 전통 OCR은 "이미지에서 글자를 뽑아내는" 도구입니다. 표의 셀 구분, 수식의 분수 구조, 손글씨의 맥락은 신경 쓰지 않죠. Chandra는 VLM(Vision Language Model)이 이미지를 이해하고 구조화합니다.

결과물은 단순 텍스트가 아니라 <table>, <math>, <div data-bbox="..."> 같은 의미 있는 HTML입니다. 이 HTML이 중간 표현(IR)이 되어 Markdown·JSON으로 변환됩니다.

2왜 주목받는가

트렌딩 이유와 경쟁 제품 대비 장점
기존 OCR의 한계
Tesseract는 "텍스트 덩어리"를 뽑지, "의미"를 이해하지 못한다

전통 OCR은 표의 셀 경계를 오해하고, 수식의 분수 구조를 한 줄 텍스트로 뭉개며, 동남아시아 저자원 언어에서 정확도가 크게 떨어집니다. 결과물을 다시 파싱해야 하는 후처리 공수가 막대합니다.

Chandra의 해법
VLM이 이미지를 이해해 구조화된 HTML을 직접 생성

Qwen3.5 기반 ~5B 모델이 이미지를 보고 36개 허용 태그·14개 허용 속성 범위 안에서 HTML을 직접 생성합니다. data-bbox로 좌표 정보까지 포함. 90개 언어 평균 72.7% vs Gemini 60.8%.

경쟁 제품 비교

비교 항목Chandra 2Gemini 2.5 FlashTesseractolmOCR
파라미터~5B비공개(거대)전통 ML7B+
olmOCR 정확도85.9%~63.8%~60%기준 모델
90개 언어 평균72.7%60.8%제한적-
레이아웃 보존HTML + bbox텍스트 위주텍스트만텍스트 위주
로컬 실행vLLM/HFAPI만로컬로컬

3기술 스택 전체 지도

모델 / 백엔드 / 인프라

모델 (AI/ML)

구성 요소기술역할
기반 아키텍처Qwen3.5이미지+텍스트 멀티모달 추론
모델 크기v1: 9B, v2: ~5B (Qwen3.5)파라미터 수
텐서 타입BF16 (bfloat16)메모리 효율적 추론
프레임워크HuggingFace Transformers 5.2+모델 로딩/추론
서빙 엔진vLLM고성능 LLM 서빙 (OpenAI 호환 API)
가속Flash Attention어텐션 연산 최적화

백엔드 (Python)

기술역할
Python 3.10+ / uv코어 언어 / 빠른 의존성 관리
Pydantic Settings환경변수 → Python 객체 자동 매핑
pypdfium2Chrome PDF 렌더링 엔진 — PDF → 이미지 변환
Pillow이미지 리사이즈 / 크롭 / LANCZOS 리샘플링
BeautifulSoup4생성된 HTML 파싱 및 구조 분석
markdownifyHTML → Markdown 변환 (커스터마이징)
openaivLLM OpenAI 호환 API 호출
Streamlit인터랙티브 데모 UI

4아키텍처 심화 분석

시스템 구조도 + 핵심 설계 패턴 4가지
사용자 입력 (PDF / 이미지 / 문서 스캔) │ ▼ ┌────────────────────────────────────────┐ │ input.py (전처리) │ │ load_file() → PDF 감지 → pypdfium2 │ │ 이미지: RGB 변환, 최소 1536px, LANCZOS │ └────────────────────────┬───────────────┘ │ ▼ ┌────────────────────────────────────────┐ │ prompts.py (프롬프트 엔진) │ │ OCR_LAYOUT_PROMPT: │ │ "OCR this image to HTML, │ │ arranged as layout blocks" │ │ + data-bbox (0~1000 스케일) │ │ + 시맨틱 라벨 (Caption, Table, ...) │ │ 허용 태그 36개 / 허용 속성 14개 제한 │ └────────────────────────┬───────────────┘ │ ▼ ┌────────────────────────────────────────┐ │ model/ (추론 엔진 — Strategy 패턴) │ │ ┌──────────────┐ ┌────────────────┐ │ │ │ vllm.py │ │ hf.py │ │ │ │ OpenAI 호환 │ │ HuggingFace │ │ │ │ ThreadPool │ │ AutoModel │ │ │ │ 지수 백오프 │ │ Flash Attn │ │ │ │ 온도 0→0.8 │ │ GPU 직접 추론 │ │ │ └──────────────┘ └────────────────┘ │ └────────────────────────┬───────────────┘ │ (생성된 HTML) ▼ ┌────────────────────────────────────────┐ │ output.py (후처리) │ │ parse_html() → 빈 페이지·헤더 필터 │ │ parse_layout() → bbox 추출, 시맨틱 분류│ │ extract_images() → WebP 저장, MD5 해시│ │ parse_markdown() → markdownify 커스텀 │ └────────────────────────┬───────────────┘ │ ▼ 최종 출력: output.md / output.html / output_meta.json / images/

핵심 설계 패턴

① Strategy 패턴 — 추론 백엔드 교체

# 사용자는 method만 바꾸면 됨
manager = InferenceManager(method="vllm")  # 또는 "hf"
result = manager.generate(batch)

vLLM(서버 모드, 높은 처리량)과 HuggingFace(서버 없이 단일 스크립트)가 동일한 generate(batch) 인터페이스를 구현합니다. 같은 모델을 다른 환경에 맞게 서빙하는 실전적 패턴입니다.

② HTML as Intermediate Representation

OCR 결과를 바로 텍스트로 뽑지 않고 HTML을 중간 표현(IR)으로 사용합니다. HTML이 이미 table·div·math 구조를 갖고 있으므로 Markdown이나 JSON으로 변환이 훨씬 쉽습니다. 허용 태그/속성을 제한해 모델 출력의 일관성을 확보합니다.

용어 설명
data-bbox
Chandra가 HTML 요소에 부여하는 바운딩박스 좌표. 0~1000 스케일로 정규화된 (x0, y0, x1, y1) 값. 이 좌표로 문서에서 각 블록의 위치를 정확히 알 수 있습니다.

③ Retry with Escalation — 점진적 온도 상승

vLLM 추론 실패 시 온도를 0.0 → 0.8까지 점진적으로 올립니다. 반복 토큰 패턴(degenerate output)을 감지하면 자동 재시도합니다. LLM 서빙에서 흔한 품질 저하 문제를 우아하게 해결하는 패턴입니다.

④ Pipeline 패턴 — 단계별 독립 모듈

입력(input.py) → 프롬프팅(prompts.py) → 추론(model/) → 후처리(output.py) 각 단계가 독립 모듈로 분리되어 한 단계만 교체하거나 테스트할 수 있습니다.

5디렉토리 구조 해부

패키지 구조와 모듈별 역할
chandra/ ├── .github/ # GitHub Actions CI/CD 워크플로 ├── assets/ # README용 이미지, 벤치마크 차트 ├── chandra/ # 메인 패키지 │ ├── input.py # 입력 처리: PDF→이미지, 리사이즈, 파일타입 감지 │ ├── output.py # 출력 처리: HTML 파싱, 이미지 추출, MD 변환 │ ├── prompts.py # 프롬프트 템플릿: OCR/레이아웃, 허용 태그 정의 │ ├── settings.py # Pydantic Settings: 모든 설정값 (모델·DPI·API 등) │ ├── util.py # 유틸리티 함수 │ └── model/ # 추론 엔진 │ ├── __init__.py # InferenceManager (Strategy 패턴 진입점) │ ├── hf.py # HuggingFace Transformers 백엔드 │ ├── vllm.py # vLLM OpenAI API 백엔드 │ └── schema.py # BatchInputItem 등 Pydantic 스키마 ├── tests/ # pytest 테스트 모음 ├── FULL_BENCHMARKS.md # 90개 언어 전체 벤치마크 데이터 ├── MODEL_LICENSE # 모델 가중치 라이선스 (OpenRAIL-M 수정) ├── pyproject.toml # 의존성 + 빌드 설정 (uv/pip) └── .pre-commit-config.yaml # pre-commit 훅 설정
모듈핵심 역할배울 것
input.pyPDF→이미지 변환, 해상도 보장pypdfium2 사용법, 파일타입 감지 패턴
output.pyHTML 파싱→MD/이미지 추출BeautifulSoup + markdownify 파이프라인
prompts.pyVLM 프롬프트 설계Structured Output 유도 기법
settings.py환경변수 기반 설정Pydantic Settings 실전 패턴
model/vllm.pyvLLM API 호출 + 재시도OpenAI 호환 API, ThreadPool 병렬화
model/hf.py로컬 HF 추론Transformers AutoModel 사용법

6학습 포인트 (기술별)

이 레포에서 무엇을 배울 수 있는가

Vision Language Model (VLM)

VLM이 이미지를 "보고" 텍스트를 생성하는 원리(Vision Encoder → Language Model), 4B 파라미터로 9B를 능가하는 모델 경량화 기법, BF16 추론의 의미와 메모리 절약 효과를 배웁니다.

vLLM 서빙

vLLM이 HuggingFace 대비 빠른 이유(PagedAttention, Continuous Batching), OpenAI 호환 API로 LLM 서빙하는 표준 패턴, ThreadPoolExecutor로 동시 요청 처리를 익힙니다.

# vLLM 클라이언트 OpenAI 호환 호출 패턴
from openai import OpenAI

client = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1")
response = client.chat.completions.create(
    model="chandra",
    messages=[{
        "role": "user",
        "content": [
            {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}},
            {"type": "text", "text": "OCR this image to HTML"}
        ]
    }],
    temperature=0.0,
    max_tokens=12384
)

Pydantic Settings — 설정 관리 모범 사례

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    MODEL_CHECKPOINT: str = "datalab-to/chandra-ocr-2"
    MAX_OUTPUT_TOKENS: int = 12384
    VLLM_API_BASE: str = "http://localhost:8000/v1"
    IMAGE_DPI: int = 192
    MIN_IMAGE_DIM: int = 1536

    class Config:
        env_file = "local.env"
        extra = "ignore"  # 알 수 없는 env 변수 무시

settings = Settings()  # 모듈 레벨 싱글톤

구조화된 프롬프트 설계

허용 태그/속성을 제한하여 모델 출력 품질을 제어하는 기법, data-bbox로 좌표 정보를 HTML에 내장하는 아이디어, 시맨틱 라벨(Caption·Table·Code-Block) 분류 프롬프트를 배웁니다.

7하드웨어 / 시스템 요구사항

HuggingFace 백엔드 vs vLLM 프로덕션

최소 사양 (HuggingFace 백엔드)

항목요구사항
GPU VRAM8GB+ (4B 모델 BF16 기준)
RAM16GB+
디스크~10GB (모델 가중치)
Python3.10+
CUDA12.0+ (권장)

권장 사양 (vLLM 프로덕션)

항목요구사항
GPUNVIDIA H100 80GB (벤치마크 기준)
GPU VRAM24GB+ (동시 처리 96 시퀀스 기준)
RAM32GB+
처리량~1.44 pages/sec (H100 80GB 기준)

GPU 없이 사용하는 방법: Hosted API(datalab.to), 웹 Playground, HuggingFace에 11개 양자화 버전(GGUF·AWQ) 제공.

8직접 해볼 수 있는 실습 과제

난이도별 4개 실습
과제 1 · 초급

CLI로 PDF OCR 체험 ★☆☆☆☆

설치 후 아무 PDF로 OCR을 실행하고 결과물(Markdown·HTML·JSON·이미지)을 직접 확인합니다. 일반 OCR과의 차이를 체감하는 것이 목표입니다.

pip install chandra-ocr
chandra my_document.pdf ./output --method vllm
cat ./output/my_document.md
과제 2 · 초급

Streamlit 데모 앱 실행 ★★☆☆☆

드래그앤드롭으로 다양한 문서(손글씨·표·수식)를 넣어보고 인식 결과를 비교합니다. Streamlit 앱 구조도 함께 분석합니다.

pip install "chandra-ocr[all]"
chandra_app  # 브라우저에서 http://localhost:8501
과제 3 · 중급

Python API로 배치 처리 파이프라인 구축 ★★★☆☆

폴더 내 모든 PDF를 일괄 처리하여 결과를 JSON으로 저장하는 파이프라인을 직접 구현합니다. 실제 업무 자동화 패턴을 익힙니다.

목표: InferenceManager + load_file()을 조합해 100개 PDF를 자동 처리하는 스크립트
과제 4 · 고급

output.py 커스터마이징 — 커스텀 출력 포맷 ★★★★☆

Markdownify 클래스를 상속하여 테이블을 CSV로 자동 추출하고, 수식을 LaTeX 파일로 별도 저장하며, 이미지 캡션을 JSON으로 구조화하는 기능을 추가합니다.

9관련 기술 심화 학습 로드맵

6주 커리큘럼

1주차: OCR 기초와 Chandra 체험

OCR 역사(규칙 기반 → CNN → Transformer → VLM), Tesseract vs EasyOCR vs Chandra 비교 실습, Chandra CLI로 다양한 문서 10개 처리, settings.py 환경변수 커스터마이징

2주차: Vision Language Model 이해

Qwen-VL 논문 읽기(Vision Encoder + LLM 연결 구조), HuggingFace Transformers로 VLM 추론 실습, model/hf.py 코드 라인별 분석, Flash Attention 원리

3주차: vLLM 서빙 마스터

vLLM 공식 문서 정독(PagedAttention·Continuous Batching), model/vllm.py 재시도 로직·온도 에스컬레이션 분석, vLLM 서버 직접 띄우고 벤치마크, 멀티 GPU 설정 실습

4주차: 문서 처리 파이프라인

input.py — pypdfium2 PDF 렌더링 심화, output.py — HTML 파싱·Markdownify 커스터마이징, 자체 문서 처리 파이프라인 설계 및 구현

5주차: 프롬프트 엔지니어링 for OCR

prompts.py 분석(허용 태그/속성 제한 전략), 프롬프트 변형 실험, 자체 도메인 특화 프롬프트 설계(영수증·의료문서 등)

6주차: 프로덕션 배포와 최적화

양자화(GGUF·AWQ) 적용 실습(VRAM 50% 절약), Docker로 Chandra 서비스 컨테이너화, FastAPI + vLLM API 서버 구축, 처리량·에러율·지연시간 모니터링

10핵심 키워드 사전

이 레포를 이해하는 데 필수적인 용어 18개
키워드설명
VLMVision Language Model. 이미지와 텍스트를 동시에 이해하는 멀티모달 AI 모델
OCROptical Character Recognition. 이미지에서 텍스트를 추출하는 기술
vLLMLLM 빠른 서빙 엔진. PagedAttention으로 메모리 효율 극대화
PagedAttentionvLLM의 핵심 기술. OS 가상 메모리처럼 KV 캐시를 페이지 단위로 관리
Continuous Batching요청 완료 즉시 새 요청을 배치에 추가하는 동적 배칭 기법
BF16bfloat16. 16비트 부동소수점. FP32 대비 메모리 절반, FP16보다 넓은 범위
Flash Attention어텐션 연산 메모리를 O(N²)→O(N)으로 줄이는 알고리즘
pypdfium2Chrome PDF 엔진(PDFium)을 Python에서 사용하는 바인딩. 렌더링 품질 브라우저 수준
data-bboxChandra가 HTML 요소에 부여하는 바운딩박스 좌표 (0~1000 스케일)
시맨틱 라벨문서 요소의 의미적 분류: Caption·Table·Section-Header·Code-Block 등
Form FlatteningPDF 폼 필드를 정적 이미지로 변환. 체크박스·입력란 등이 렌더링에 포함됨
MarkdownifyHTML을 Markdown으로 변환하는 Python 라이브러리. Chandra가 커스터마이징
OpenRAIL-M모델 가중치용 오픈 라이선스. 특정 제한 조건 부과 (코드는 Apache 2.0)
olmOCROCR 모델 성능 표준 벤치마크. 수학·표·오래된 스캔 등 카테고리별 평가
Pydantic Settings환경변수를 Python 객체로 자동 매핑하는 설정 관리 프레임워크
ThreadPoolExecutorPython 내장 스레드 풀. vLLM 요청을 병렬 처리하는 데 사용
LANCZOS 리샘플링이미지 업스케일링 시 고품질을 보장하는 보간 알고리즘
KaTeX빠른 수학 수식 렌더링 라이브러리. Chandra는 수식을 KaTeX 호환 LaTeX로 출력

11참고 링크

공식 문서 및 학습 자료