본문 바로가기
생각

문서 추출 JSON의 null은 무슨 뜻일까: 누락된 키·false와 구분하기

Dharma의 문서 추출 예시로 null·키 누락·false의 차이를 설명한다. 가상 청구서를 따라 필드 계약, 원문 대조, 누락률과 오기입률을 나누는 평가 방법을 살핀다.

문서 추출 JSON의 null은 무슨 뜻일까: 누락된 키·false와 구분하기 관련 이미지

영수증에서 금액을 읽어 JSON으로 받았는데 담당자 칸이 null이다. 값이 원래 없었던 걸까, 모델이 읽지 못한 걸까. 키 자체가 빠진 응답이나 false와 같게 처리해도 될까. 문서 추출을 업무 시스템에 연결할 때는 JSON 문법보다 이 구분이 먼저 문제가 된다.

Dharma Field Extractor의 공개 예시를 출발점으로 삼아, 요청한 필드가 결과에 담기기까지 어떤 계약이 필요한지 따라가 보자. 모델을 직접 실행한 성능 평가는 아니다. 이어지는 청구서와 건수 계산은 처리 규칙을 설명하기 위한 가상 예시다.

요청한 키를 고정하면 누락을 발견할 수 있다

Dharma의 발표 (새 창)는 문서 이미지에서 필드를 추출하는 두 방식을 소개한다. Open은 발견한 필드를 반환하고, schema-directed는 요청한 이름과 자료형에 맞춰 반환한다. 문서에 없는 요청 필드는 null로 표현한다고 설명한다.

가상의 청구서에 공급자 ACME, 청구번호 A-17, 합계 68.90이 있고 납기일은 없다고 하자. 저장할 필드를 supplier, invoice_id, total, due_date로 정했다면 첫 세 값과 due_date: null이 기대 결과다. 반면 due_date 키가 아예 없다면, 요청한 네 필드가 모두 반환됐는지부터 확인해야 한다. null을 허용하는 것과 키 생략을 허용하는 것은 별개의 선택이다.

Open 결과는 처음 보는 서식에서 필드를 탐색할 때 유용하다. 하지만 어떤 페이지에서는 total이 나오고 다른 페이지에서는 amount_due가 나오면, 저장 단계에서 이름을 다시 맞춰야 한다. 고정 스키마는 이 매핑을 추출 요청에 포함한다. 대신 계약에 넣지 않은 새 필드는 결과에서 놓칠 수 있으므로, 서식 탐색과 정해진 칸 채우기는 목적을 나눠 쓰는 편이 낫다.

아래 공식 영수증 그림에서는 빈 Salesperson 칸이 salesperson: null로 연결된다. 금액은 따옴표가 있는 문자열로 표시된다. 그림 속 숫자 모양만 보고 number 자료형이라고 판단해서는 안 된다.

영수증의 빈 Salesperson 칸은 JSON의 salesperson: null로 연결되고 합계 68.90은 문자열로 표시된다.
Dharma 공개 영수증 예시. 왼쪽 빈 담당자 칸과 오른쪽 salesperson: null을 비교한다. 금액은 따옴표가 있는 문자열이다. 직접 실행 결과가 아니며 작은 원문 글자는 확대해 확인한다. 출처: Dharma-AI.

null은 값의 부재를 나타내지만 원인을 설명하지 않는다

JSON 표준 RFC 8259 (새 창)는 문자열, 숫자, 불리언, null을 서로 다른 값의 종류로 정의한다. 다만 null이 “원문에 없음”인지 “판독 실패”인지까지 정해 주지는 않는다. 그 의미는 추출 서비스와 이를 사용하는 측이 합의해야 한다.

앞의 청구서에서 due_date가 null일 때 오늘 날짜를 자동으로 채우지 않는 규칙을 생각해 보자. 날짜가 정말 없다면 보완 요청으로 넘길 수 있다. 그러나 원본이 잘려 날짜 영역이 사라졌거나 글자가 흐려 읽지 못한 경우에도 같은 출력이 나올 수 있다. null 하나만 저장하면 나중에 이 두 상황을 구분할 단서가 없다.

이 글에서 제안하는 처리 방식은 원본 페이지와 요청 스키마 버전을 함께 보존하고, 필수 필드가 null인 결과를 검토 대상으로 보내는 것이다. 추출기가 별도 판독 상태나 근거 위치를 제공한다면 함께 쓰되, Dharma가 그런 진단 필드를 제공한다고 가정하지는 않는다. 반환값만으로 알 수 없는 원인을 마치 모델이 확신한 결과처럼 만들어 넣지 않는 것이 핵심이다.

값이 없는 결과를 임의의 0이나 빈 문자열로 바꾸면 정보가 더 줄어든다. 합계가 0인 무료 청구서와 합계를 읽지 못한 청구서가 같은 레코드로 남기 때문이다. 저장 형식을 단순하게 만들수록, 그 전에 구분해야 할 상태가 무엇인지 먼저 정해야 한다.

빈 체크박스와 비어 있는 텍스트 칸은 다르다

같은 발표의 FUNSD 예시 (새 창)에는 체크박스와 빈 텍스트 칸이 함께 나온다. 체크된 poor_quality_original은 true, 체크되지 않은 항목은 false, 비어 있는 page_number_s와 bates_number는 null로 나타난다. 이 사례는 값이 없다는 표현을 모든 필드에 똑같이 적용할 수 없음을 보여 준다.

앞의 가상 청구서에 “선결제 완료” 체크박스를 추가해 보자. 양식 계약상 미체크가 미결제를 뜻하고 박스 영역이 선명하게 보인다면 paid: false로 처리할 수 있다. 반면 체크박스 자체가 잘린 사진이라면 false는 결제 상태를 추측한 값이 된다. “표시가 없다”와 “표시를 볼 수 없다”를 구분하려면 원문 영역까지 확인해야 한다.

결과를 처리하는 코드가 false와 null을 모두 거짓으로 분기하면, 두 결과가 똑같이 미결제 알림으로 이어질 수 있다. false일 때만 미결제로 분류하고, null이나 키 누락은 검토 단계로 보내는 분기가 더 명확하다. 이는 이 글의 처리 설계 예시일 뿐, 공개 모델의 내부 구현 설명이 아니다.

FUNSD 양식의 체크 항목은 true 또는 false이고 비어 있는 page_number_s와 bates_number는 null이다.
Dharma 공개 FUNSD 예시. 체크된 poor_quality_original은 true, 미체크 항목은 false, 빈 텍스트 칸은 null이다. 이 한 사례를 전체 정확도로 일반화하지 않는다. 긴 키와 원문은 확대해 확인한다. 출처: Dharma-AI.

형식 검사 뒤에는 원문과 업무 규칙이 남는다

가상 청구서의 total이 68.90이 아니라 86.90으로 나왔다고 하자. 둘 다 유효한 JSON 숫자이고 total이라는 키도 맞다. 키 집합과 자료형 검사만으로는 자릿수가 바뀐 오류를 잡아낼 수 없다. JSON 파싱, 요청 스키마 대조, 원문 값 대조는 각각 다른 종류의 실패를 잡는다.

합계 검산도 조건을 정해야 한다. 품목 합계가 65.00이고 세금이 3.90인 예시에서는 68.90과 맞아떨어진다. 하지만 실제 서식에 할인·반올림·별도 배송비가 포함된다면, 품목과 세금만 더하는 규칙은 정상적인 문서를 거절할 수 있다. 검산에 실패했다는 이유로 모델이 읽은 값을 계산값으로 몰래 덮어쓰는 대신, 적용한 업무 규칙과 원문을 함께 묶어 검토 대상으로 남길 수 있다.

평가에서도 분모를 나눠 보자. 가상의 100장 중 JSON 파싱 통과가 98장, 요청 키와 자료형까지 맞는 것이 95장, 원문 값과 필요한 업무 규칙까지 맞는 것이 90장이라면, 마지막 단계의 전체 통과율은 90%다. 스키마 통과분만 분모로 삼은 90/95(약 94.7%)와는 답하려는 질문이 다르다. 이 수치는 Dharma의 평가 결과가 아니다.

null도 별도로 센다. 날짜가 있는 80장 중 8장을 null로 반환했다면 값이 있는 문서의 누락률은 10%다. 날짜가 없는 20장 중 3장에 날짜를 만들어 넣었다면 값이 없는 문서의 오기입률은 15%다. 전체 null 비율만 보면 두 실패가 섞여 버린다. 필드를 많이 채우는 설정이 실제로 누락을 줄였는지, 없는 값을 더 만든 것인지는 이 두 분모로 나눠 확인할 수 있다.

자동 저장 여부는 필드별로 결정한다

문서 추출기를 도입할 때는 “JSON이 나오는가”보다 “어떤 값일 때 다음 단계로 보내는가”를 먼저 정하는 편이 유용하다. 앞의 예시에서 납기일이 선택 항목이라면 null을 그대로 둔 채 저장할 수 있지만, 납기 알림을 자동으로 예약하려면 날짜가 확인되기 전까지 그 동작을 보류한다. 같은 추출 결과라도 뒤이어 실행할 작업에 따라 허용 조건이 달라진다.

고정 스키마는 필드 이름과 자료형을 맞추는 수고를 줄여 준다. 하지만 원문에 없는 값과 읽지 못한 값의 구분, false의 업무상 의미, 숫자 자체의 정확성까지 대신 결정해 주지는 않는다. 요청한 키, 반환된 값, 원문 근거를 함께 비교할 수 있어야 추출 오류를 찾아내고 다음 동작을 결정할 수 있다.

채용 제안 보내기

생각

함께 해결할 LLM 과제와 기대하는 역할을 알려 주세요.

연락하기