5.2.1.1. 대소문자, 공백, 구두점 무시를 위한 텍스트 정규화 전처리(Normalization Preprocessing)
정교한 정규 표현식(Regex)을 이용한 판별 오라클을 실제 CI/CD 파이프라인에 적용하기 전에, 가장 먼저 필수적이고 강박적으로 수행해야 할 선제적 방어 로직은 거대 언어 모델(LLM)이 생성한 날것의(Raw) 응답 텍스트 버퍼에 대한 ‘텍스트 정규화 전처리(Text Normalization Preprocessing)’ 파이프라인의 전면 도입이다.
인간 문과(Humanities)의 관대하고 유연한 눈으로 볼 때는 “AI Oracle“과 “ Ai oracle “, 그리고 “AI-ORACLE!“이 모두 완벽하게 동일한 의미를 지닌 똑같은 단어 묶음일지 몰라도, 무자비하고 차가운 컴퓨터 시스템의 메모리 힙(Memory Heap) 상에서는 대문자와 소문자의 아스키(ASCII) 코드값 불일치, 불필요하게 섞여 들어간 스페이스바(Whitespace), 화면에 보이지 않는 유령 같은 개행 문자(Carriage Return \r\n), 겉보기에만 똑같은 전각/반각 구두점(Punctuation)의 미세한 인코딩 차이로 인해 이들은 서로 수학적으로 0% 일치하는 전혀 다른 이질적인 바이트(Byte) 코드 덩어리로 인식된다.
따라서, 이러한 ’문맥적 의미 구조를 결정하는 데 아무런 기여를 하지 않는 쓰레기 표면 노이즈(Surface Noise)’를 집요하게 깎아내고 버리지 않은 채, 텍스트 형태 그대로를 오라클의 Assert 정규식 평가기에 날것으로 통과시키는 짓은 언어 모델의 유창함을 핑계 삼아 매번 야간 회귀 테스트(Regression Test)가 황당한 이유로 실패(FALSE FAIL)할 확률을 극단적으로 높이는, 최악의 시스템 기술 부채를 쌓는 안일한 엔지니어링 행위다.
1. 결정론적 판별을 위한 3단계 정규화 파이프라인(Normalization Pipeline) 설계
결정론적 오라클의 정확도(Precision)를 확보하기 위해, LLM의 런타임 결과 문자열 response_text는 뒷단의 채점 Assertion 로직에 도달하기 직전, 반드시 다음과 같은 엄격한 3단계 텍스트 정규화 샌딩(Sanding) 파이프라인을 의무적으로 컨베이어 벨트처럼 거쳐야만 한다.
1.1 단계: 대소문자 획일적 통일 (Global Case Folding)
글로벌 서비스 환경에서 영어, 불어 등 알파벳 기반의 모델 응답은, 그날그날의 토큰 샘플링 온도(Temperature)의 우연성에 따라 첫 글자의 대소문자 캡슐라이징(Capitalization)이 무작위로 뒤섞이기 일쑤다. (예: “Database”, “database”, “DATABASE”)
따라서 오라클 시스템 내부에서의 모든 문자열 비교 연산은, 반드시 텍스트 진입 시점에 response_text.lower() 메서드를 호출하여 전체 텍스트를 강압적으로 식별 불가능한 완전 소문자 평문으로 100% 치환(Lower-casing)하는 과정을 가장 먼저 거친 후 수행되어야 한다. 이 1단계 조치를 통해 복잡한 Regex 정규식 패턴 내에서 [a-zA-Z] 식의 지저분하고 불필요한 대소문자 분기 경우의 수 탐색(Branching)을 원천적으로 막아내어 정규식 파싱 엔진의 성능을 최적화할 수 있다.
1.2 단계: 공백 무결성 유지 및 제어 문자 붕괴 (Whitespace Collapse & Strip)
강력한 파운데이션 LLM은 종종 시스템 프롬프트 제약을 망각하고, 본인의 유창함을 과시하듯 단어와 단어 사이에 두 개 이상의 스페이스(Double space)를 오타처럼 넣거나, 들여쓰기를 위한 탭(\t), 앞뒤 공백(Leading/Trailing whitespaces), 그리고 눈에 보이지 않는 불필요한 시스템 개행 제어 문자(\n, \r\n)를 무분별하게 뱉어내는 끔찍한 악습이 있다.
해결책은 오직 단호한 정규식 스위퍼(Sweeper)뿐이다. re.sub(r'\s+', ' ', response_text).strip() 처리를 통과시켜, 연속된 모든 종류의 잉여 공백 덩어리들을 단일 스페이스바(Single Space) 딱 하나로 폭파 및 붕괴(Collapse)시키거나 아예 공백 자체를 "" (Empty String)로 진공 압축 제거해 버리는 과정이 필요하다.
1.3 단계: 비즈니스 논리 무관 구두점 스트리핑 (Punctuation Stripping)
비즈니스 로직의 결괏값 검증에 전혀 쓸모없는 문장 부호 마침표(.), 쉼표(,), 감탄사(!), 따옴표(") 등은 모두 무자비한 제거 대상이다. 특히 금융권 AI 개발에서 큰 골칫거리는, 화폐 단위를 표기할 때 LLM이 천 단위 구분 기호를 “1,000” (한국식/미국식)과 “1000” (기계 표기식)을 제멋대로 혼용하는 경향이 매우 강하다는 것이다. 따라서 중요한 수치 데이터 엔티티를 정규식으로 안전하게 추출(Extraction)하기 직전, 쉼표(,)나 달러 기호($) 등은 response_text.replace(",", "").replace("$", "")처럼 전면 삭제(Stripping) 전처리를 먼저 수행해 두는 것이 수학적으로 가장 안전하고 오작동이 없는 방어 기제다.
2. 전처리 파이프라인 통과 후의 이상적인 오라클 검증(Validation) 아키텍처
위의 혹독한 3단계 정규화 샌딩 파이프라인을 모두 거치게 되면, 복잡하고 지저분했던 오라클의 검증 비교 로직은 놀라울 정도로 우아하고 직관적이며 오류 없는 단 한 줄의 코드로 단순해진다.
# [Python 기반 결정론적 오라클 정규화 검증 엔진 예시]
def strict_normalized_oracle_test(expected_ground_truth_keyword, llm_raw_response):
# 1. LLM 원시 응답을 가장 낮은 수준의 바이트 문자열 덩어리로 정규화 분쇄 적용 (1~3단계 통합)
# 소문자 변환(lower) -> 모든 공백 문자 트리밍 -> 불필요한 구두점(콤마, 마침표 등) 제거
normalized_response = re.sub(r'[\s,\.!?"\'-]+', '', llm_raw_response.lower())
# 2. 비교 대상인 기준 정답지(Ground Truth) 역시 혹시 모를 오염에 대비해 동일한 정규화 강제 연산 수행
normalized_expected = re.sub(r'[\s,\.!?"\'-]+', '', expected_ground_truth_keyword.lower())
# 3. 불순물이 모두 날아간 정규화된 순수 텍스트 기반의 포함(IN) 여부 결정론적 검증
assert normalized_expected in normalized_response, \
f"오라클 `FAIL`: 정규화 응답({normalized_response}) 내에 정답 키워드({normalized_expected})가 부재함."
이 과정을 통과하면, 처음 LLM이 의기양양하게 내뱉은 “Error Code: [404], Not Found!!!” 라는 끔찍하게 난해하고 장식적인 인간형 문자열은 시스템 내부의 정규화 파산기를 파쇄기처럼 거치며 즉각 errorcode404notfound 라는 단단하고 무결한 바이트 원석 덩어리로 변환된다. 오라클의 진정한 시스템적 역할은, 이렇게 쓸모없는 언어적 불순물이 모두 제거되고 난 뒤 남겨진 순수한 비즈니스 논리 문자열 블록 위에서, 우리가 그토록 애타게 찾고자 하는 본질적인 핵심 인텐트(Intent) 로직 파편이 여전히 살아 숨 쉬고 있는지 그 단 하나만을 단호하게 True/False로 확인하고 증명하면 되는 것이다.