13.3.6 중첩된 JSON 구조(List, Dict)의 깊이 및 개수 제한 검증

13.3.6 중첩된 JSON 구조(List, Dict)의 깊이 및 개수 제한 검증

비정형 재무 문서 추출 파이프라인에서 가장 가변성이 크고 통제하기 지독하게 어려운 영역은, 바로 ‘세부 구매 품목(Line Items)’ 배열처럼 리스트(List)와 딕셔너리(Dict)가 N차원으로 지속적으로 중첩되어 뻗어나가는 재귀적(Recursive) 공간이다.

거대 언어 모델(LLM)은 어텐션 윈도우(Attention Window) 내에서 이 중첩된 루프(Loop) 구조를 파싱(Parsing)해 나갈 때, 종종 심각한 ’반복 환각(Repetitive Hallucination)’에 빠지곤 한다. 그 결과 원본 문서에 존재하지도 않는 가상의 유령 품목 수백 개를 JSON 배열 안에 무한동력처럼 계속해서 써 내려가거나, 반대로 수십 개의 품목이 있음에도 불구하고 중간에 생성이 귀찮다는 듯이 단 하나의 텅 빈 배열 껍데기([])만 뱉고 응답을 조기 종료(Early Convergence)해 버리기도 한다.

이러한 생성 모델 특유의 제어 상실을 시스템 레벨에서 멱살 잡아 막아내기 위해, 1단계 오라클 아키텍처는 반드시 컬렉션(Collection) 데이터 타입의 크기와 깊이(Depth)에 대한 강제적인 물리적 리밋(Limit Barrier) 검증 규칙을 Pydantic 메모리 상에 하드코딩해야만 한다.

1. Pydantic의 min_lengthmax_length를 이용한 배열(Array) 팽창 통제

가장 기초적이면서도 서버 다운을 막아내는 압도적으로 강력한 오라클 통제 기법은, JSON 배열(List) 객체가 가질 수 있는 최소 및 최대 길이의 임계값(Threshold)을 스키마 레벨에 봉인해 버리는 것이다.

from pydantic import BaseModel, Field
from typing import List

class LineItem(BaseModel):
    description: str
    price: float

class InvoiceExtractOracle(BaseModel):
    # 추출된 품목 리스트는 반드시 최소 1개(비어있음 불가) 이상이어야 작동하며,
    # 어떠한 경우에도 100개를 초과하면 LLM 환각(OOM 공격)으로 간주하고 방어망을 가동한다.
    items: List[LineItem] = Field(
        ..., 
        min_length=1, 
        max_length=100, 
        description="추출된 구매 품목 데이터 배열 (1개~최대 100개 제한)"
    )

이 무자비한 O(1) 단위의 크기 검증을 통해, 시스템은 구매 내역이 전혀 없는 [] 텅 빈 인보이스 깡통 데이터가 무단으로 데이터베이스 트랜잭션에 INSERT 되는 것을 100% 결벽증적으로 차단한다. 나아가 LLM의 망상으로 인해 수천 개의 쓰레기 텍스트 아이템이 쏟아져 들어와 MLOps 백엔드 서버의 메모리를 가득 채우고 뻗게 만드는 OOM(Out of Memory) 환각 공격을 1단계에서 매우 저렴하고 빠르게 사전에 튕겨낼 수 있다.

2. 재귀 구조와 깊이(Depth) 제한을 통한 스택 오버플로우 방어

조직도나 다단계 카테고리 등 더욱 복잡한 트리(Tree) 형태의 문서를 추출할 때, 스키마 내부에 자기 자신을 계속해서 참조하는 재귀(Recursive) 필드를 설계할 수가 있다 (예: 상위 카테고리 노드 안에 하위 카테고리 리스트가 무한히 포함되는 구조).
문제는 통제력이 없는 LLM이 이 자유로운 재귀적 스키마 인터페이스를 부여받으면, 종종 모델 스스로도 빠져나올 수 없는 깊이의 JSON 노드를 재귀 생성(Deep Nesting Hallucination)하여, 결국 파이썬 런타임의 콜스택 리밋(Recursion Limit)을 박살 내고 서버를 덤프시켜 버린다는 점이다.

따라서 딕셔너리(dict)가 다른 딕셔너리를 포함하는 중첩(Nested) 객체를 설계할 때는, 오라클 레이어에서 @field_validator를 이용해 JSON 트리의 깊이(Tree Depth)를 재귀적으로 탐색하는 로직을 심어야 한다. 트리의 깊이가 특정 하드 임계치(예: Depth 3)를 초과하여 내려가려는 시도가 감지되면, 즉각 모든 런타임 연산을 멈추고 ValueError를 발생시켜 백엔드 인프라를 사이버 위협(환각)으로부터 방어해야만 한다.

“LLM의 무한한 텍스트 생성 능력은, 닫힌 백엔드 생태계에서는 곧 무한한 시스템 파괴 능력을 의미한다.”
이 무한함과 불확실성의 확장을, 우리 인프라가 안전하게 감당하고 계산할 수 있는 유한한 단위의 ListDict 사이즈 감옥 안으로 강제로 찌그러뜨리고 욱여넣는 잔인한 통제 장치. 그것이 바로 이 1단계 오라클의 컬렉션 검증(Collection Validation)이 존재하는 지엄한 철학이다.