5.5.1 Hypothesis 등 프레임워크를 활용한 입력 불변식(Invariant) 검증
파이썬(Python) 생태계에서 속성 기반 테스트(Property-based Testing)를 주도하는 가장 강력한 프레임워크는 Hypothesis다. 이는 Haskell의 퀵체크(QuickCheck)에서 영감을 받아 만들어진 도구로, 개발자가 테스트하고자 하는 데이터의 ’전략(Strategy)’을 정의하면, 프레임워크가 알아서 수백 개의 무작위 변형 데이터를 생성하여 함수에 주입한다.
AI 오라클 시스템을 구축할 때 Hypothesis를 활용하면, 한 줌의 하드코딩된 더미 텍스트에 의존하던 유닛 테스트를 ’무한한 차원의 스트레스 테스트’로 확장할 수 있다. 프롬프트 로직이 어떠한 악의적이고 기괴한 형태의 자연어 입력 앞에서도 붕괴되지 않는 **결정론적 불변식(Invariant)**을 지켜내는지 입증해 보자.
1. Hypothesis를 이용한 생성 규칙(Strategy) 정의
AI 시스템의 입력은 보통 자연어 텍스트이므로, 개발자는 Hypothesis의 text() 또는 dictionaries() 전략을 활용하여 입력 데이터를 무작위로 만들어낸다.
예를 들어, “사용자의 입력을 요약하여 무조건 50자 이하의 평문으로 리턴하는” LLM 래퍼 함수 summarize_text(input_string)가 있다고 가정하자. 이 함수의 불변식(Invariant)은 다음과 같다.
- 예외 불발생: 어떤 텍스트가 들어와도 애플리케이션 프레임워크가 크래시(Crash)되거나
500 Server Error를 내뿜지 않아야 한다. - 길이 제약 준수: 반환된 문자열의 길이는 항상 50자 이하여야 한다.
from hypothesis import given, settings, strategies as st
from my_ai_app import summarize_text
# Strategy: 빈 문자열부터 엄청나게 긴 텍스트, 온갖 유니코드, 이모지가 섞인 텍스트 무작위 생성
@given(st.text(min_size=0, max_size=10000))
@settings(max_examples=100) # 매 테스트마다 100개의 무작위 텍스트 주입
def test_summarize_length_invariant(random_input):
# 테스트 대상 함수 (내부적으로 Mocking된 LLM을 사용할 수 있음)
result = summarize_text(random_input)
# 오라클: 모델이 반환한 결과의 길이가 언제나 50자 이하라는 불변식을 증명
assert len(result) <= 50, f"길이 제약 위반: {len(result)}자 반환됨"
2. 입력 불변식 검증의 진정한 가치: 파싱 방어력(Parsing Resilience)
LLM의 응답을 JSON으로 받아와 데이터베이스에 넣는 애플리케이션의 경우, 백엔드의 후처리 파서(Post-processing Parser) 로직은 가장 취약한 지점이다. Hypothesis를 이용하면, 입력된 무작위 특수문자나 개행문자(\n)가 프롬프트를 관통하여 LLM의 생성 과정에 영향을 주고, 결과적으로 파서에 어떻게 예외를 발생시키는지 시뮬레이션할 수 있다.
@given(st.dictionaries(keys=st.text(), values=st.integers()))
def test_json_parsing_invariant(random_dict):
# 무작위 사전을 문자열화하여 프롬프트에 주입했다고 모사
prompt_input = str(random_dict)
# LLM을 통과하고 나온 응답(Mock 처리됨)을 파싱
llm_response = my_llm_json_generator(prompt_input)
parsed_json = my_strict_json_parser(llm_response)
# 불변식 오라클: 원본 데이터의 구조와 타입이 파싱 결과에서도 유지되어야 함
assert isinstance(parsed_json, dict)
3. 축소(Shrinking) 메커니즘을 통한 버그 원인 추적
Hypothesis의 가장 환상적인 기능 중 하나는 **축소(Shrinking)**다.
100번의 무작위 테스트 중 만약 “안녕하세요\t\n \u0000” 이라는 기괴한 문자열에서 파서의 JSONDecodeError 예외가 떨어지며 불변식이 깨졌다고 치자. Hypothesis는 단순히 무작위 값을 콘솔에 던지고 끝내는 것이 아니다. 곧바로 에러를 발생시키는 ’가장 작고 단순한 입력값(Minimal Falsifying Example)’을 찾을 때까지 문자열을 자르고 줄여본다.
결과적으로 개발자에게는 *“단순한 빈 문자열 ""이 들어왔을 때 당신의 파서가 터집니다”*라는 가장 직관적인 디버깅 포인트를 제시한다.
이처럼 프레임워크를 기반으로 한 입력 불변식 오라클은, 개발자의 안일한 엣지 케이스 선정을 맹렬히 파괴하며 AI 애플리케이션 로직 전체를 강력한 방어구로 빈틈없이 코팅해 내는 1등 공신이다.