1.4.1.1 동적이고 예측 불가능한 문자열 결과에 대한 단언(Assertion)의 어려움
대규모 언어 모델(LLM)이 비즈니스 로직에 결합되었을 때, 테스트 엔지니어가 가장 먼저 부딪히는 실무적 벽은 생성된 동적 텍스트를 검증하기 위해 기존의 문자열 처리 기법들을 동원하려 할 때 발생한다. 엄격한 동치성(Equality) 비교가 실패함을 깨달은 엔지니어들은 대안으로 하위 문자열 매칭(Substring Matching)이나 정규 표현식(Regular Expression)과 같은 유연한 문자열 검사 기법을 시도한다. 그러나 이러한 시도 역시 예측 불가능한 언어 모델의 본질 앞에서는 손쉽게 무력화된다.
1. 느슨한 문자열 검증(Loose String Matching)의 파국
가장 흔하게 시도되는 우회 방법은 assertTrue(output.contains("성공")) 과 같이 결과 문자열에 특정 핵심 키워드가 포함되어 있는지를 단언(Assertion)하는 것이다. 얼핏 보면 모델이 어조(Tone)나 조사, 어미를 무작위로 바꾸더라도 ’성공’이라는 단어만 포함되면 테스트를 통과시킬 수 있으므로 공학적 타협점으로 보인다.
하지만 자연어망의 광범위한 벡터 공간(Vector Space)에서 생성되는 출력물은 이러한 1차원적인 규칙을 가볍게 벗어난다.
- 유사어 및 동의어 발현(Synonym Generation): 모델이 “요청이 성공했습니다” 대신 “요청이 완수되었습니다”, “처리가 완료되었습니다”, 혹은 “정상적으로 적용되었습니다“라고 답변할 경우, 의미상 완벽히 목적을 달성했음에도 불구하고 하드코딩된 특정 키워드(“성공”)가 부재하므로 컴파일러는 이를 거짓 음성(False Negative)으로 처리하여 테스트를 실패시킨다.
- 부정 결합(Negation Binding)에 의한 오탐: 모델이 환각이나 오류로 인해 “요청 처리에 성공하지 못했습니다“라고 출력했을 때, 문자열 검사기는 “성공“이라는 키워드를 발견하고 이를 참(True)으로 잘못 평가하는 치명적인 거짓 양성(False Positive)을 발생시킨다.
2. 정규 표현식(Regular Expression)의 한계와 유지보수성 붕괴
단순 키워드 검색의 한계를 넘기 위해 엔지니어들은 더욱 정교한 정규 표현식을 작성하여 여러 패턴을 동시에 매칭하려 시도한다. 예를 들어 JSON 형태의 출력을 기대하고 regex = /^\{.*\}$/ 등을 적용하거나, 데이터 포맷의 구조를 규정하려 애쓴다.
하지만 프롬프트 엔지니어링(Prompt Engineering)을 통해 아무리 강력한 페르소나(Persona)와 출력 형식을 강제하더라도, LLM은 종종 다음과 같은 비정형 텍스트를 함께 산출하며 패턴 매칭을 무너뜨린다.
- Markdown 블록 삽입:
json { "key": "value" } - 서론 및 결론부 덧붙임: “네, 요청하신 데이터는 다음과 같습니다. { “key”: “value” } 도움이 더 필요하신가요?“
- 키(Key) 네이밍의 자의적 변형:
user_name을userName이나User_Name으로 무작위 변경
graph TD
subgraph Input_Space [단언문 검증 규칙 파이프라인]
A(정규표현식 및 하위 문자열 조건\nContains / Regex)
end
subgraph LLM_Dynamic_Output [AI의 예측 불가능한 문자열 출력]
B[의미는 맞으나 동의어 사용\n"작업이 완수됨"]
C[부정어가 결합된 오류 문장\n"결코 성공하지 못함"]
D[장황한 서사가 섞인 포맷\n"네, 성공입니다!"]
end
subgraph Assertion_Result [검증 결과]
A -.매칭 실패.-> B
B --> E[False Negative\n정상 로직이나 테스트 실패]
A -.키워드 단독 매칭.-> C
C --> F[False Positive\n오류 객체이나 테스트 패스]
A -.포맷 파싱 실패.-> D
D --> E
end
style E fill:#ffcdd2,stroke:#c62828,stroke-width:2px;
style F fill:#b71c1c,stroke:#fff,stroke-width:2px;
모든 예외 변수를 감당하기 위해 정규 표현식을 기하급수적으로 길고 복잡하게 만들게 되면, 테스트 코드의 작성 비용과 유지보수 오버헤드(Maintenance Overhead)가 메인 비즈니스 로직의 작성 비용을 초과하게 된다. 이는 테스트 자동화의 근본 목적을 심각하게 훼손하는 공학적 모순(Engineering Contradiction)이다.
의미론적 척도(Semantic Metric) 검증의 부재
결국 이 모든 어려움은 전통적인 단언(Assertion) 연산자들이 오로지 컴퓨터 자원의 바이트(Byte) 레벨 비교, 즉 구조론적 공간(Syntactic Space)에만 머무르고 있기 때문이다. 문자의 물리적 배열이 아니라 문장이 내포한 의미의 영역, 즉 의미론적 공간(Semantic Space)의 판단 없이는, 끝없이 요동치는 문자열 파도 속에서 변하지 않는 비즈니스 규격을 확정적으로 건져낼 방법이 없다.
동적 문자열이 뱉어내는 숱한 파편들을 단언(Assertion)하기 위해서는 유연성이 없는 프로그래밍 코드가 아니라, 문장의 함의와 논리적 참거짓을 유연하고도 엄밀하게 평가할 또 다른 형태의 공학적 판단 기준, 즉 **테스트 오라클(Test Oracle)**의 지위 격상이 불가피해진다. LLM의 산출물을 1.0 체제의 컴파일러에 우겨 넣으려는 집착을 버리고, 언어의 본질을 검열할 수 있는 새로운 차원의 검증 망라 체계를 고민해야 할 시점이다.