OCR + Rule + LLM

AI & HCI
영수증 사진을 올리면 OCR이 읽고, Rule이 좁히고, LLM이 뽑아낸다 — 근거 없는 값은 절대 반환하지 않는다
Posted on June 26, 2026, 10:57 a.m. by SANGJIN
random_image

Built a local-first receipt understanding pipeline that separates concerns across three explicit stages: OCR extracts text, Rules narrow candidates, and LLM performs semantic extraction — each doing only its own job.

The key principle: no hallucinated evidence. The LLM returns a value only when it explicitly provides supporting evidence from the OCR text. When evidence is missing, the field stays empty. Rule-based fallback values are clearly labeled in the UI — never mixed with LLM outputs.

Every stage is visible in the Streamlit UI: raw OCR text, rule candidates, raw LLM output, and final extracted fields. Nothing is hidden.

Key decisions:

Decision Rationale
OCR → Rule → LLM pipeline LLMs infer, not read. Narrowing input with Rules reduces hallucination surface
No hallucinated evidence LLM output is only accepted when evidence is explicitly provided
Fully local (Ollama + PaddleOCR) Receipts contain personal data — no external API calls
SQLite (no ORM) Simple, inspectable storage with direct SQL access
Raw LLM output stored Parse failures are surfaced in the UI, not silently swallowed

Tech Stack:

Layer Tool
Language Python 3.10+
UI Streamlit
OCR PaddleOCR (local, singleton)
LLM Ollama (local inference)
Rules regex + heuristics
Storage SQLite

OCR · Rule · LLM 세 단계가 역할을 분리해 영수증을 처리하는 로컬 파이프라인을 만들었다. OCR은 텍스트만 추출하고, Rule은 후보만 좁히고, LLM은 의미만 뽑는다. 각자 자기 일만 한다.

핵심 원칙: 근거 없는 값은 반환하지 않는다. LLM이 OCR 텍스트에서 명시적인 근거를 제공할 때만 필드를 채운다. 근거가 없으면 비워둔다. Rule 기반 fallback 값은 UI에서 별도 표시 — LLM 추출값과 절대 섞지 않는다.

Streamlit UI에서 모든 단계의 출력을 확인할 수 있다: OCR 원문, Rule 후보, LLM 원본 출력, 최종 추출값. 블랙박스가 없다.

핵심 결정:

결정 이유
OCR → Rule → LLM 순서 LLM은 읽는 게 아니라 추론한다. Rule로 입력을 좁혀야 할루시네이션이 줄어든다
근거 없는 값 반환 금지 "그럴듯한 값"과 "근거 있는 값"을 구분해야 파이프라인을 신뢰할 수 있다
완전 로컬 실행 영수증에는 개인정보가 있다. Ollama + PaddleOCR로 외부 API 호출 없음
SQLite (ORM 없음) 단순하고 검사하기 쉬운 저장소. SQL로 직접 접근 가능
LLM 원본 출력 저장 파싱 실패도 UI에서 보인다. 조용히 삼키지 않는다

사용 기술:

레이어 도구
Language Python 3.10+
UI Streamlit
OCR PaddleOCR (로컬, 싱글턴)
LLM Ollama (로컬 추론)
Rules regex + 휴리스틱
Storage SQLite

Github: https://github.com/SangjinKO/ocr-rule-llm-receipt

Velog: https://velog.io/@kosang234/%EC%98%81%EC%88%98%EC%A6%9D-%EC%82%AC%EC%A7%84%EC%9D%84-%EC%98%AC%EB%A6%AC%EB%A9%B4-OCR%EC%9D%B4-%EC%9D%BD%EA%B3%A0-Rule%EC%9D%B4-%EC%A2%81%ED%9E%88%EA%B3%A0-LLM%EC%9D%B4-%EB%BD%91%EC%95%84%EB%82%B8%EB%8B%A4-%EC%84%B8-%EB%8B%A8%EA%B3%84-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8%EC%9D%84-%EC%A7%81%EC%A0%91-%EB%A7%8C%EB%93%A4%EB%A9%B4%EC%84%9C-%EA%B9%A8%EB%8B%AC%EC%9D%80-%EA%B2%83%EB%93%A4

AI

Leave a Comment: