6.10 사례 연구: 구조화 출력을 통한 결정론적 시스템 구현

6.10 사례 연구: 구조화 출력을 통한 결정론적 시스템 구현

거대 언어 모델(LLM)이 생성하는 비정형(Unstructured) 텍스트를 엔터프라이즈 시스템 마이크로서비스(MSA) 아키텍처나 관계형 데이터베이스(RDB)에 직접 연동하기 위해서는, 그 모호한 자연어를 컴퓨터가 즉각적으로 파싱(Parsing)할 수 있는 엄격한 규격의 ’형태(Shape)’로 주조해 내야 한다.

본 단원에서는 6장에서 논의된 JSON Schema, Pydantic, Zod와 같은 강제 구조화 출력(Structured Outputs) 기법들이 실제 프로덕션(Production) 환경에서 어떻게 불확실성을 통제하고 기계적인 오라클(Oracle) 파이프라인과 결합되었는지 입증하는 성공적인 사례 연구(Case Study)를 분석한다.

1. 사례 1: 금융권 EMR 비정형 문서의 정형 데이터 파이프라인

A 금융사는 매일 쏟아지는 수만 건의 고객 의료 기록(EMR)과 보험 청구 서류 판독을 자동화하기 위해 LLM을 도입했다. 초기에는 “주치의 소견과 진단 코드를 추출해 줘“라는 개방형 프롬프트를 사용했으나, 모델은 빈번하게 “네, 추출해 드리겠습니다: 진단 코드는 M545입니다“와 같은 불필요한 대화형 서술어를 혼합하여 반환했다. 이로 인해 백엔드 시스템의 정규표현식(Regex) 파서가 모조리 실패하며(CRASH) 심각한 장애를 유발했다.

해결책 및 결정론적 오라클 도입:
개발팀은 OpenAI의 response_format API 설정에 엄격한 JSON Schema를 주입하는 방향으로 아키텍처를 전면 개편했다.

{
  "name": "Extract_Medical_Claims",
  "schema": {
    "type": "object",
    "properties": {
      "patient_id": { "type": "string" },
      "icd_10_code": { "type": "string", "pattern": "^[A-Z][0-9]{2}(\\.[0-9]{1,4})?$" },
      "confidence_score": { "type": "number", "minimum": 0, "maximum": 1 }
    },
    "required": ["patient_id", "icd_10_code", "confidence_score"],
    "additionalProperties": false
  }
}
  • 정합성 1차 오라클: additionalProperties: false 모범 사례를 적용함으로써 LLM이 JSON 객체 내에 불필요한 서술형 Key를 환각(Hallucination)으로 임의 생성하는 변수를 원천 차단했다.
  • Validation 결합: 응답이 도착하자마자 Pydantic 모델에 역직렬화(Deserialize)시켜, icd_10_code 필드가 국제 질병 분류 정규식을 만족하는지 O(1)의 속도로 확정 검증하는 1차 파이프라인을 완성할 수 있었다.

2. 사례 2: 자율형 에이전트(Autonomous Agent)의 함수 호출(Function Calling) 체인

사내 업무 프로세스를 돕는 B사의 에이전트 시스템은 자연어를 입력받아 사내 Jira 플랫폼에 Create Issue API를 트리거(Trigger)하는 과업을 수행한다. 이 태스크의 본질은 인간 사용자의 장황한 요구사항을 API 페이로드(Payload) 양식으로 정확히 ‘번역’하는 것이다.

초기 모델 체인에서는 Jira의 필수 파라미터인 board_idpriority_level이 종종 누락되거나, High 대신 Urgent와 같은 잘못된 열거형(Enum) 문자열이 반환되어 HTTP 400 Bad Request가 빗발쳤다.

해결책 및 복구(Fallback) 전략:
개발팀은 함수 호출 구조체(Function Calling Schema) 안에 특정 필드에 들어갈 수 있는 열거형 제약을 명시적으로 선언했다.

// Zod를 활용한 TypeScript 환경의 스키마 정의 사례
const JiraIssueSchema = z.object({
  title: z.string().max(100),
  priority: z.enum(["Lowest", "Low", "Medium", "High", "Highest"]),
  estimated_story_points: z.number().int().optional()
});
  • 이 데이터 계약(Data Contract)을 LLM에게 프롬프트로 주입함과 동시에, 만약 AI가 실수로 Critical이라는 Enum 외의 값을 뱉어냈을 때, 이를 그대로 API로 쏘아 에러를 발생시키는 대신 시스템 내부의 재조정 루프(Self-Correction Loop) 오라클을 가동했다.
  • 오라클은 ZodError의 파싱 실패 메시지를 포착하여 “너의 이전 텍스트 생성은 priority 필드의 Enum 제약(Medium, High 등)을 위반했다. 교정된 JSON만 다시 반환하라“며 기계적 피드백을 주입했고, 그 결과 최종 API 전송 성공률을 99.8%까지 끌어올렸다.

강제 구조화 출력을 활용한다는 것은 AI가 발산(Divergence)하려는 무형의 사고 과정 위로, 엔지니어가 거푸집(Mold)을 찍어 내어 한 치의 오차도 없는 쇳덩이를 만들어내는 과정(Convergence)과 같다. 이 강력한 ’데이터 스키마’야말로 생성형 AI와 견고한 백엔드 시스템(Backend System)을 안전하게 이어주는 가장 공학적이고 결정론적인 접착제이다.