space ocr
가이드아티클요금문서

왜 space-ocr는 다른 LLM OCR과 다른가: 검증 가능한 구조화 추출

LLM에 직접 OCR을 시키는 방식과 space-ocr의 차이. 추출된 모든 값에 페이지에서 검증한 박스와 match_ratio가 붙고, 그대로 조회 가능한 행으로 저장된다.

9 분 분량· 2026-07-05

영수증이나 청구서 한 장을 GPT-4o, Gemini, Claude에 던지면서 합계와 거래처, 품목 내역을 뽑아 달라고 할 수 있다. 대부분은 그럴듯한 JSON이 돌아온다. 문제는 이걸 대량으로 신뢰하려 할 때 시작된다. 모델이 돌려주는 건 문자열이고, 문자열에는 위치가 없다. 합계가 48,200으로 나왔다면 페이지의 어느 픽셀을 읽은 것일까? 그 숫자가 실제로 문서에 인쇄되어 있었을까, 아니면 모델이 그럴듯한 값을 채워 넣은 걸까? LLM 호출만으로는 페이지를 직접 다시 읽어 보기 전까지 이 질문에 답할 수 없다.

바로 이 간극이 범용 LLM을 OCR 도구로 쓰는 것과 space-ocr를 쓰는 것의 차이 전부다. space-ocr는 LLM에 반대하는 물건이 아니다. 내부적으로는 OCR 엔진(Google Cloud Vision)과 구조화를 담당하는 Gemini를 함께 쓴다. space-ocr가 더하는 것은 모델을 둘러싼 층이다. 반환하는 모든 값을 OCR 엔진이 페이지에서 실제로 본 것과 대조하고, 점수를 매기고, 조회 가능한 행으로 저장한다. 이 두 가지, 곧 검증할 수 있는 값별 출처와 별도 데이터베이스 없이 조회할 수 있는 구조화된 출력이야말로 LLM 호출이 사용자에게 떠넘기는 부분이다.

LLM 직접 OCR vs space-ocr

LLM 직접 호출 (GPT-4o / Gemini / Claude)space-ocr
값별 위치없음, 텍스트만 반환모든 값에 박스(0–1000 격자 위의 xmin, ymin, xmax, ymax)와 네 점짜리 방향 사각형
값별 검증없음, 문자열을 그대로 믿어야 함match_ratio: 값의 문자 중 몇 개가 페이지에서 감지된 심볼에 실제로 있었는지, bbox_source 라벨과 함께
값을 맥락에서 확인문서를 직접 다시 읽어야 함앱에서 셀을 클릭하면 원본 이미지의 해당 영역이 그대로 표시됨
출력 형태프롬프트에 좌우되어 실행마다 달라지는 JSON고정 스키마: fields를 한 번 정의(또는 templateId 전달)하면 업로드마다 한 행으로 저장
저장과 조회직접 구축해야 함결과는 시트의 행이며 GET /view(where, sort, select, limit, offset)로 조회, OCR 재실행 없음, 과금 없음
문자 체계모델과 프롬프트에 따라 다름일본어, 한국어, 중국어, 영어 등을 자동 감지, 언어 파라미터 없음
설정직접 만든 프롬프트, 재시도, 파싱, 검증 파이프라인Bearer 키로 HTTPS 호출 한 번
✓ Verified

'검증됨'이 실제로 무슨 뜻인지 짚어 둔다. 과장하기 쉬운 대목이라서다. 언어 모델은 좌표를 만들어 내지 않는다. 각 값의 텍스트와 단어 토큰 힌트를 반환할 뿐이고, 그다음 엔진이 그 텍스트를 Google Cloud Vision이 페이지에서 감지한 심볼과 한 글자씩 대조한다. 박스는 그 실제 심볼 위에 놓이고, 값에는 match_ratio가 매겨진다. match_ratio는 값의 문자 중 페이지의 심볼에서 찾아낸 비율이다. match_ratio가 높으면 심볼에 매칭된 신뢰할 만한 값이고, 낮으면 bbox_source를 통해 표시되어 사람에게 넘길 수 있다. 이는 모델이 절대 틀리지 않는다는 약속이 아니다. 토큰 힌트는 여전히 어긋날 수 있다. 각 값을 그냥 믿는 대신 페이지와 대조해 점수를 매긴다는 뜻이다.

POST /ocr/fields — 응답 속 필드 하나
1
2
3
4
5
6
7
8
9
10
11
12
{
  "vendor": {
    "value": "ACME Trading Co.",
    "bbox": { "xmin": 120, "ymin": 84, "xmax": 512, "ymax": 118 },
    "vertices": [
      { "x": 120, "y": 84 }, { "x": 512, "y": 84 },
      { "x": 512, "y": 118 }, { "x": 120, "y": 118 }
    ],
    "match_ratio": 1.0,
    "bbox_source": "vision_symbol_match"
  }
}

박스는 이미지 크기와 무관한 0–1000 격자 위에서 반환되므로, 화면에 그릴 때는 픽셀로 환산한다: pixel_x = xmin / 1000 * image_width. 네 점짜리 사각형은 기울거나 회전된 스캔을 따라가며, 좌상단, 우상단, 우하단, 좌하단 순서로 정렬된다. 모델 응답만으로는 이 중 어느 것도 얻지 못하므로, 필요한 감사 추적은 전부 손으로 짜맞춰야 한다.

값에서 조회 가능한 표로

LLM 직접 호출은 JSON에서 끝난다. 그걸 여전히 저장해야 하고, '이번 분기에 40,000을 넘는 청구서는 어느 것인가?'를 묻고 싶어지는 순간 먼저 데이터베이스와 조회 계층부터 구축하게 된다. space-ocr에서는 결과가 이미 고정 스키마를 가진 시트의 한 행이므로, 조회는 API 호출 한 번이다. GET /view에 where=total>=40000, sort=-invoice_date, select=vendor,total, 그리고 페이징용 limit과 offset을 붙이면 된다. 서버 측에서 실행되고, OCR을 다시 돌리지 않으며, 과금되지 않는다. 시트는 CSV로 내보낼 수 있다(BOM이 붙은 UTF-8이라 일본어, 한국어, 중국어 텍스트와 통화가 Excel에서 제대로 열리고, 품목 배열은 각자의 행으로 펼쳐진다).

LLM 직접 호출이 더 나은 경우

범용 LLM은 한 번만 읽으면 되거나, 느슨한 요약이 필요하거나, 문서가 무엇을 뜻하는지 추론해야 할 때 맞는 선택이다. '이 계약서는 무슨 내용인가?'는 모델에게 물을 질문이지, 좌표까지 붙은 OCR에 물을 질문이 아니다. 문서를 대량으로 처리하면서 각 값이 검증 가능하고, 일관되게 구조화되고, 조회 가능해야 한다면 space-ocr를 쓰면 된다. 매입 채무 자동화, 경비 정산, 명함을 CRM에 넣기, 쌓인 영수증 디지털화 같은 일이다. 정직하게 말하면 space-ocr는 검증과 저장 계층을 얹은 LLM 기반 OCR이지, 모델 자체와 경쟁하는 물건이 아니다.

과금은 스캔당 종량제이며, 선택형 월정액 플랜과 매월 제공되는 무료 스캔이 있고, 스캔 결과가 비어 있으면 과금하지 않는다. 현재 요금은 요금 페이지에서 확인할 수 있다.

space-ocr는 OCR용으로 GPT-4o나 Gemini를 대체하나요?
아니요. space-ocr는 내부에서 LLM을 씁니다. OCR은 Google Cloud Vision, 구조화는 Gemini를 함께 사용합니다. 차이는 모델을 둘러싼 층에 있습니다. 각 값을 페이지의 심볼과 다시 매칭해 점수를 매기고, 결과를 조회 가능한 행으로 저장합니다. 모델을 대체하는 게 아니라 LLM을 기반으로 한 OCR입니다.
어떤 값이 지어낸 게 아니라는 걸 어떻게 아나요?
모든 값에는 match_ratio가 붙습니다. 값의 문자 중 페이지에서 감지된 심볼에 실제로 있었던 비율이며, bbox_source 라벨도 함께 옵니다. match_ratio가 낮으면 표시되어 사람에게 넘길 수 있습니다. 실제 페이지와 대조해 검증하고 점수를 매기는 것이지, 모델이 절대 틀리지 않는다는 보장은 아닙니다.
space-ocr는 어떤 좌표 형식을 반환하나요?
정규화된 0–1000 격자 위의 정수 네 개(xmin, ymin, xmax, ymax)로 된 바운딩 박스와, 기울거나 회전된 페이지를 위한 네 점짜리 방향 사각형(vertices)입니다. 픽셀로는 비례 환산합니다. 예를 들어 pixel_x = xmin / 1000 * image_width.
직접 데이터베이스를 두지 않고도 추출된 데이터를 조회할 수 있나요?
네. 결과는 시트의 행이고, GET /view가 where, sort, select, limit, offset으로 서버 측에서 걸러 줍니다(예: where=total>=40000). OCR을 다시 돌리지 않고 과금되지 않으며, 시트는 CSV로 내보낼 수 있습니다.
문서의 언어를 space-ocr에 알려 줘야 하나요?
아니요. 언어는 일본어, 한국어, 중국어, 영어 등에 걸쳐 자동으로 감지됩니다. 설정할 언어 파라미터가 없습니다.
PDF도 읽을 수 있나요?
웹 앱은 PDF의 각 페이지를 이미지로 래스터화한 뒤 OCR합니다. API 자체는 래스터 이미지(JPEG, PNG, GIF, BMP, TIFF, WebP)를 호출당 한 장씩 받으므로, 보내기 전에 PDF 페이지를 이미지로 변환하면 됩니다.
어떻게 호출하나요?
Bearer spocr_ 키로 POST /ocr/fields에 HTTPS 요청 한 번을 보내면서, 이미지와 함께 templateId 또는 fields 스키마 중 하나를 전달합니다. 응답에는 각 값이 박스와 match_ratio와 함께 담겨 옵니다.