Chapter 6. JSON Schema 및 강제 구조화 출력(Structured Outputs)을 이용한 데이터 정합성 보장

Chapter 6. JSON Schema 및 강제 구조화 출력(Structured Outputs)을 이용한 데이터 정합성 보장

자연어는 인간 간의 소통을 위한 최고의 인터페이스지만, 기계와 기계(Machine-to-Machine)가 데이터를 교환하는 환경에서는 최악의 프로토콜이다. AI를 웹 애플리케이션의 백엔드나 데이터 파이프라인의 일부로 편입시키기 위해서는, “안녕하세요, 요청하신 결과를 드리겠습니다.“와 같은 장황한 서술어를 제거하고 시스템 코드가 즉각적으로 파싱(Parsing)할 수 있는 확정적인 자료구조가 필요하다.

이 장에서는 대형 언어 모델(LLM)의 예측 불가능한 텍스트 생성을 강력한 제약 조건 아래 묶어두고 프로그래밍 언어의 인터페이스 사양을 엄격히 준수하도록 강제하는 ‘구조화 출력(Structured Outputs)’ 기술과 이를 활용한 데이터 정합성 오라클 구축 방안을 다룬다.

1. 프롬프트 기반 포맷팅의 취약성과 한계

과거에는 프롬프트 하단에 “출력은 반드시 JSON 포맷으로 할 것” 또는 “```json 태그 안에 감싸서 응답하라“는 식의 자연어 지시(Natural Language Instruction)를 통해 구조화를 시도했다. 그러나 이는 다음과 같은 치명적인 한계로 인해 프로덕션(Production) 레벨의 시스템 오라클로 사용하기에 부적합하다.

  • 포맷 파손(Formatting Breakage): 모델이 쉼표(,)를 누락하거나 이스케이프 구문(\n, \") 처리에 실패하여 파서(Parser)에서 JSONDecodeError를 유발하는 경우가 빈번하다.
  • 구조적 환각(Structure Hallucination): 시스템이 요구하지 않은 임의의 Key를 새로 만들어내거나(예: user_name 대신 name을 리턴), 정수형(Integer) 배열을 담아야 할 필드에 문자열(String)을 반환하는 등 데이터 타입 정합성을 파괴한다.
  • 사족 덧붙이기(Chattiness): JSON 코드 블록 앞뒤로 “네, 알겠습니다. 분석된 JSON은 다음과 같습니다.“라는 불필요한 인삿말을 덧붙임으로써 정규식 우회 및 추출 로직의 복잡성을 가중시킨다.

자연어 지시문만으로는 멱등성(Idempotency)을 지닌 신뢰 구간을 확보할 수 없다. 오라클 시스템을 성립시키기 위해서는 텍스트 생성 파이프라인 자체의 아키텍처적 개입이 요구된다.

2. JSON Schema 강제(Enforcement) 메커니즘

최근의 모델과 API 환경에서는 모델의 추론(Inference) 단계에서 토큰 생성 확률 분포를 조작하여 유효하지 않은 포맷의 텍스트가 물리적으로 생성되지 못하도록 원천 차단하는 기술(예: OpenAI의 response_format, Strict Structured Outputs)을 제공한다. 이것이 확정적 오라클의 뼈대다.

2.1 엄격한 스키마 정의 (Strict Schema Definition)

결정론적 애플리케이션 개발자는 모델에 요청을 보내기 전, 예상되는 출력의 형태를 JSON Schema 사양(또는 Pydantic, Zod 같은 라이브러리의 클래스 정의)으로 견고하게 선언해야 한다.

  • 타입 명시: 필드 속성이 string, integer, boolean, array 중 무엇인지 지정하라.
  • 필수 속성(Required Fields) 강제: 해당 작업에서 반드시 추출되어야 하는 키(Key) 값들을 명시하여 누락을 방지하라.
  • 열거형(Enum)에 의한 값의 제한: 특정 상태 값의 경우, 열린 문자열 추론을 허용하지 말고 사전에 정의된 상태 값(예: ["POSITIVE", "NEGATIVE", "NEUTRAL"]) 내에서만 토큰을 선택하도록 강제(Constrain)하라.

2.2 디코딩 단계의 결정론적 제어(Deterministic Decoding)

JSON Schema가 체결되면, 백엔트 추론 엔진은 디코딩 루프(Decoding Loop) 매 단계마다 생성 가능한 토큰 목록(Vocab)을 스키마 규칙에 따라 필터링(Logit Bias 적용 등)한다.
예를 들어 {"age": 까지 텍스트가 생성된 시점에서, 오직 숫자로 된 토큰의 생성 확률만 남기고 텍스트 기반 토큰의 확률은 0으로 만들어버린다. 이를 통해 애플리케이션 계층에서는 문법 검사(Syntax Check)를 생략하고 즉시 비즈니스 로직(예: .age > 19)으로 데이터를 직렬화(Deserialize)할 수 있는 수학적 보증을 얻게 된다.

3. 구조화 출력을 활용한 계층적(Hierarchical) 오라클 파이프라인

강제 구조화 출력이 결합되면, 기존의 모호했던 LLM 평가 방식이 전통적인 소프트웨어 테스트의 논리 흐름으로 편입된다.

  1. Level 1 오라클 (문법 및 구조 검증): 수신된 JSON 데이터가 미리 정의된 Pydantic 모델에 역직렬화(Deserialize)되는가? 이 과정에서 발생하는 ValidationError는 컴파일 에러와 동일하게 취급되어 즉각적인 치명적 실패(Fatal Failure)로 로깅된다.
  2. Level 2 오라클 (도메인 룰 검증): 구조적 파싱이 보장되었다면, 내부의 Value들에 대해 결정론적 소프트웨어 어서션(Assertion)을 수행한다. “추출된 시작 날짜(Start Date)가 종료 날짜(End Date)보다 선행하는가?”, “추출된 상품 ID가 사내 데이터베이스(RDB)에 실제로 존재하는 외래키(Foreign Key)인가?” 와 같은 하드 코딩된 비즈니스 룰을 통해 환각(Hallucination) 사실을 필터링한다.

강제화된 JSON Schema는 LLM의 창의성을 철창 안에 가둬두고, 그 결과물을 결정론적 시스템의 부품(Component)으로 완벽히 호환되도록 만드는 강력한 소프트웨어 인터페이스(API Contract)다.