6.9.3 과도한 중첩 구조(Deep Nesting) 피하기: Flat Structure 지향 설계

6.9.3 과도한 중첩 구조(Deep Nesting) 피하기: Flat Structure 지향 설계

소프트웨어 아키텍트나 숙련된 시니어 백엔드 엔지니어들이 거대 언어 모델(LLM) 기반의 파이프라인 데이터 모델을 처음 설계할 때 관성적으로 범하기 쉬운 가장 치명적인 인지적 설계 오류(Design Anti-pattern)는, 기존 레거시 백엔드의 복잡하고 우아한 도메인 주도 설계(DDD, Domain-Driven Design) 개념 객체나 관계형 데이터베이스(RDBMS)의 정규화된(Normalized) 깊은 테이블 계층 구조를, LLM의 Pydantic 런타임 강제 스키마(Schema)로 **단 1의 가공 없이 ‘그대로’ 1:1 일대일 거울 매핑(Mirror Mapping)**해 버리려는 강박적인 시도이다.

전통적인 객체 지향 프로그래밍(OOP) 패러다임에서는 모듈의 응집도(Cohesion)를 높이고 결합도(Coupling)를 낮추기 위해, 클래스(Class) 안에 세부 클래스를 겹겹이 양파껍질처럼 쌓아 올리는 깊은 중첩(Deep Nesting)과 추상화가 훌륭한 엔지니어링의 미덕일 수 있다.
그러나 출력 토큰(Output Token) 글자 하나하나가 기업의 막대한 API 과금(Cost) 결제와 직결되고, 밀리초(ms) 단위의 응답 지연 시간(Latency)이 고객 경험 코어 퀄리티를 좌우하는 생성형 AI 인퍼런스 환경에서, 이러한 과거의 무비판적인 과도한 데이터 중첩 스키마 구조 채택은 실시간 프롬프트 시스템의 목을 서서히 조르는 끔찍하고 최악의 아키텍처 안티 패턴(Anti-pattern)으로 전락한다.

1. 중첩(Nesting) 레이어가 유발하는 잉여 토큰의 구문적 폭증(Syntactic Explosion)

가장 직관적인 예시를 들어보자. 수만 건의 고객 피드백 텍스트 덩어리에서 단축된 ’사용자의 거주 도시 단어 하나’를 정보 추출(Information Extraction)하는 파이프라인 작업을 생각해 보자. 기존 백엔드의 거대한 계층형(Hierarchical) 도메인 사용자 모델 인터페이스를 그대로 차용하여 Pydantic 스키마를 강제하면 다음과 같은 우스꽝스럽고 무거운 JSON 페이로드 출력이 LLM에게 강요된다.

/* [안티 패턴] 과도하게 깊고(Deep) 중첩된 레거시 거울 모델 구조 */
{
  "user_profile_context": {
    "demographics_data": {
      "location_metadata": {
        "residential_address": {
          "city_name": "Seoul"
        }
      }
    }
  }
}

백엔드 파이프라인에서 다음 로직으로 넘기기 위해 실질적으로 필요했던 데이터는 오직 "Seoul" 이라는 단 5글자 알파벳의 단 하나의 핵심 데이터 밸류(Core Value)일 뿐이다. 그러나 이 단어 하나를 얻어내기 위해, 무거운 LLM 엔진은 여닫는 중괄호 {, } 기호들과 눈에 보이지 않는 수십 개의 띄어쓰기 탭 인덴트(Indentation), 그리고 본질적 질문과 아무런 상관없는 쓸데없이 길고 무거운 시멘틱 껍데기 문자열 키(Key) 토큰("user_profile_context", "demographics_data", "residential_address")들을 무수하고 처절하게 허공에 불태우며 생성해 내어야 한다.

이러한 불필요하게 뎁스(Depth)가 깊은 트리 구조(Deep Tree Structure) 강제는, LLM의 소중하고 비싼 아웃풋 토큰 생성 비용을 최소 5배에서 10배 이상 허공에 낭비(Token Bleeding)할 뿐만 아니라 더 무서운 런타임 부작용을 낳는다.
생성 토큰의 길이가 길어지고 JSON 중첩 레벨이 3단계 이상 깊은 심연으로 진입할수록, 확률에 기반한 로컬 오픈소스 LLM의 문맥 어텐션 추론 능력(Context Window Focus)은 급격히 교란되고 길을 잃어, 결국 마지막 단계에서 클로징 중괄호를 제대로 닫지 못하는(Unmatched Braces, JSON Parsing Error) 치명적이고 허무한 런타임 파싱 에러(Fail)를 무더기로 유발하는 1순위 원인이 된다.

2. 평면화(Flattening)된 인퍼런스 전용 LLM DTO 설계 아키텍처

이 비효율의 늪을 빠져나오기 위한 아키텍처 백엔드 공학의 근본적인 해법 혁신은, 아주 무겁고 논리적인 백엔드 본진의 ’비즈니스 도메인 영속성 객체(Persistence Domain Object)’와, 오직 가벼운 용병인 LLM과 텍스트로 통신하기 위해 일회성으로 존재하는 API 레이어의 ’데이터 전송 파싱 객체(DTO, Data Transfer Object)’를 소프트웨어 공학적으로 매우 철저하게 분리(Decoupling)해 내는 결단이다.
결정론적 오라클 시스템 파이프라인의 심판을 돕기 위해 LLM 엔진에 주입되는 **응답 강제 DTO 스키마는 뎁스 레벨이 무조건 1을 초과하지 않는, 극도로 1차원적이고 납작한 평면 구조(Flat Structure)**를 강박적으로 지향해야만 한다.

from pydantic import BaseModel, Field

# [베스트 프랙티스] 극한으로 구조 다이어트를 마친 LLM 추출 전용의 평면화(Flat) DTO 스키마
class UserCoreExtractionDTO(BaseModel):
    user_city_name: str = Field(description="사용자의 거주 도시 영문명 (예: Seoul, Tokyo)")
    user_physical_age: int = Field(description="사용자의 만 나이 정수형")

위의 평면화(Flattening)된 1단 구조 프롬프트를 주입하면, LLM의 런타임 출력 결과 토큰은 그토록 우리가 원했던 미니멀리즘(Minimalism)의 궁극적 형태에 도달하게 된다.

{"user_city_name": "Seoul", "user_physical_age": 20}

3. 백엔드 서비스 레이어에서의 객체 매핑(Object Node Mapping) 최종 복원 로직

API를 맞이하는 인퍼런스 엔진인 LLM은 아키텍처의 맨 앞에서 최대한 구조적으로 납작하고 빈틈없이 가벼운 1차원 DTO 형태로, 비즈니스의 핵심 에센스 데이터(Core Essence Data)만을 빛의 속도로 파싱하여 뱉어내고 파이프라인을 쿨하게 빠져나오면 그것으로 제 역할을 100% 다한 것이다.
그렇게 JSON으로 투박하게 추출되어 메모리에 올라온 납작한 UserCoreExtractionDTO 텍스트 객체를 들고 와서, 다시 기존 레거시 사내 백엔드의 무겁고 복잡한 깊은 트리 구조인 역설계 정규화 엔티티(Entity Class) 트리로 끼워 맞추어 재조립(Re-assembly)하고 DB에 하이드레이션(Hydration)해 넣는 무거운 연산 작업은, 온전히 그 데이터를 소비하는 백엔드 서버(Spring Boot / Django / Node.js)의 물리적 CPU와 엔지니어가 짠 맵핑(Mapping) 코드 컴포넌트의 몫으로 남겨두어야 한다.

말귀를 가장 똑똑하게 알아듣지만 타이핑이 영락없이 느리고 토큰 생성 비용이 극도로 비싼 천재 LLM 엔진에게, 불필요한 괄호 치기와 ’객체 지향적 깊은 데이터 구조화(Deep Structuring)’라는 멍청한 타건 노가다 짐을 절대 지우지 마라.
똑똑한 모델일수록 그 본연의 능력을 가장 직관적이고 날렵한 ’핵심 텍스트 추출 마이크로서비스(Extraction Microservice)’로만 독립적으로 대우하라. JSON 스키마 구조의 극단적인 평면화(Flattening) 기법은, 구조화 출력(Structured Outputs)을 코어로 활용하는 복잡한 수백 단계 오라클 시스템 파이프라인에서, 전체 인퍼런스 구간 지연 시간(API Latency) 낭비를 절반 이상 무자비하게 깎아내고 모델 파서의 문법 구조 달성 정확도를 99.9%로 극대화시키는 통제 가능한 생성 AI 아키텍처의 가장 강력하고 위대한 소프트웨어 설계 기초 원칙(Design Principles)이다.