5.1.2 유닛 테스트 대상의 분리: 프롬프트 로직, 모델 파이프라인, 후처리 코드
AI 기능을 포함한 단일 함수나 클래스를 테스트할 때, 개발자들이 흔히 겪는 두 번째 오류는 **테스트 대상의 통합(Integration)**이다. 사용자의 입력을 받아 프롬프트를 조립하고, LLM API를 호출한 뒤, 그 결과를 파싱하여 데이터베이스에 저장하는 일련의 과정을 하나의 유닛 테스트로 뭉뚱그려 검증하려 든다.
이러한 모놀리식(Monolithic) 접근법은 심각한 ’테스트 취성(Test Brittleness)’을 유발한다. API 네트워크의 일시적 장애, 프롬프트 템플릿의 사소한 띄어쓰기 변경, 예기치 않은 모델의 출력 포맷 변화 등 어떤 이유로든 테스트가 실패할 수 있으며, 개발자는 도대체 파이프라인의 어느 계층(Layer)에서 에러가 발생했는지 추적하는 데 막대한 시간을 허비하게 된다.
견고한 결정론적 오라클을 구축하기 위해서는 AI 파이프라인을 최소 세 개의 논리적 계층으로 날카롭게 분리(Decoupling)하고, 각 계층에 맞는 독립적인 유닛 테스트를 작성해야 한다.
1. 프롬프트 로직(Prompt Logic) 계층의 테스트
이 계층은 어플리케이션의 상태(사용자 입력, 컨텍스트 데이터)를 LLM이 이해할 수 있는 텍스트 문자열(또는 메시지 배열)로 조립하는 ‘문자열 포매팅’ 엔진이다.
- 비결정성 유무: 0% (완전한 결정론적 코드)
- 테스트 목표: 변수 주입(Variable Injection), 누락된 인자(Missing Arguments), 조건부 템플릿(Conditional Templates)의 렌더링 무결성 확인.
- 검증 오라클: 입력 변수 세트(Context)를 제공했을 때, 출력되는 최종 프롬프트 문자열이 기대하는 형태와 정확히(Exact Match) 일치하는지 단언(
assertEquals)한다. 이 단계에서는 네트워크 호출이나 LLM 개입이 절대 있어서는 안 된다.
2. 모델 파이프라인(Model Pipeline) 계층의 테스트
조립된 프롬프트를 입력받아 실제 LLM API(예: OpenAI, Anthropic) 또는 로컬 모델러버를 호출하고 응답을 받아오는 통신 계층이다. AI 소프트웨어의 핵심이자 비결정성의 진원지다.
- 비결정성 유무: 매우 높음
- 테스트 목표: 네트워크 오류 처리(Retry, Timeout), 보안 가드레일 작동, 그리고 프롬프트 변경이 모델의 ’의도된 응답’을 훼손하지 않는지 확인.
- 검증 오라클: 이 계층의 단위 테스트는 비용과 속도를 고려하여 평상시에는 목(Mock) 객체를 사용하여 네트워크를 격리한다. 실제 LLM을 호출하는 테스트(동적 테스트)의 경우, 정답의 완전한 일치가 아닌, 핵심 키워드 포함 규칙(Inclusion Rule), 부정적 제약 위반(Negative Constraints), JSON 스키마 검증 등 유연한 스펙트럼 기반의 오라클을 적용해야 한다.
3. 후처리 및 파싱(Post-processing) 계층의 테스트
LLM이 반환한 원시 텍스트(Raw Text)를 비즈니스 로직에 맞는 정형화된 데이터 구조(Object, DB Record 등)로 변환하는 계층이다.
- 비결정성 유무: 0% (완전한 결정론적 코드)
- 테스트 목표: 불완전한 JSON 문법(예: Trailing Comma), 마크다운 코드 블록(
```json)이 섞인 텍스트, 예상치 못한 필드가 포함된 응답 등을 파서(Parser)가 깨지지 않고 안전하게 추출/복구(Fallback)할 수 있는지 확인. - 검증 오라클: 모델의 환각(Hallucination)이나 포맷 이탈 사례를 모방한 다양한 ’깨진 문자열(Dummy Error Responses)’을 강제로 주입한 후, 후처리 코드가 예외를 발생시키는지, 혹은 정상적으로 방어하고 기본값(Default Value)을 반환하는지 전통적인 결정론적 테스트로 검증한다.
이처럼 ’결정론적 로직(프롬프트 조립, 파싱)’과 ’확률적 로직(모델 추론)’경계를 명확하게 분리하는 아키텍처만이, 유지보수 가능한 확정적 단위 테스트 오라클을 구현하는 유일한 길이다. 파이프라인이 섞여 있는 한, 당신의 테스트 코드는 영원히 통제 불가능한 텍스트의 파도에 흔들릴 수밖에 없다.