5.6.1.1 추론의 중간 산출물(Intermediate Steps)을 변수로 캡처하는 기법
화이트박스(White-box) 관점의 유닛 테스트가 성립하려면, LLM이 뱉어내는 수백 줄의 장황한 자연어 응답 속에서 ’검증해야 할 특정 추론 단계의 결괏값’만을 소프트웨어적인 변수(Variable)로 조각내어 메모리 상에 캡처(Capture)할 수 있어야 한다. 만약 응답 전체를 거대한 하나의 문자열(String)로 뭉뚱그려 둔 채 정규식(Regex)만으로 내용을 탐색하려 한다면, 테스트 코드는 작은 띄어쓰기 변화 하나에도 붕괴되고 말 것이다.
따라서 개발자는 프롬프트 설계 단계부터 중간 산출물을 프로그래밍 언어의 딕셔너리(Dictionary)나 객체(Object) 멤버 변수로 1:1 매핑할 수 있도록 강제된 구문 분석(Parsing) 친화적 템플릿을 도입해야 한다.
1. 캡처를 위한 구조화된 템플릿(Structured Templates) 설계
프롬프트를 다룰 때, 인간이 읽기 편한 산문(Prose) 형태의 답변 생성을 금지하라. 대신 XML 태그나 마크다운(Markdown) 코드 블록, 혹은 JSON을 활용하여 각 추론 단계가 명확한 경계(Boundary)를 갖도록 지시해야 한다. 최근의 오픈 오픈소스 모델이나 상용 API들은 XML 태그 기반의 분리 지시를 매우 강력하게 수용한다.
[프롬프트 예시: XML 태그를 이용한 블록 캡처]
당신은 대출 심사관이다. 다음의 순서대로 생각하고, 각 단계를 반드시 지정된 태그 안에 작성하라.
1. 사용자의 신용 점수를 확인한다: <step_credit_check>여기에 작성</step_credit_check>
2. 연봉 대비 부채 비율(DTI)을 계산한다: <step_dti_calc>여기에 작성</step_dti_calc>
3. 최종 승인 여부를 결정한다: <final_decision>승인 또는 거절</final_decision>
2. 정규 표현식 및 파서를 통한 변수화(Variable Binding)
LLM의 텍스트가 반환되면, 테스트 프레임워크(예: pytest) 내부의 오라클은 파라미터를 파싱하는 전용 함수(Extractor)를 통과시켜 각 태그의 내용을 독립적인 변수에 할당한다.
import re
class LoanDecisionSteps:
def __init__(self, raw_response: str):
self.raw_response = raw_response
self.credit_check = self._extract("step_credit_check")
self.dti_calc = self._extract("step_dti_calc")
self.final_decision = self._extract("final_decision")
def _extract(self, tag_name: str) -> str:
# 특정 XML 태그 안의 텍스트를 비어있지 않게 캡처
pattern = f"<{tag_name}>(.*?)</{tag_name}>"
match = re.search(pattern, self.raw_response, re.DOTALL)
if not match:
raise ValueError(f"오류: {tag_name} 캡처 실패. 모델이 포맷을 위반했습니다.")
return match.group(1).strip()
def test_loan_decision_intermediate_steps(mock_llm_response):
# LLM 응답 텍스트를 객체 인스턴스로 캡처
steps = LoanDecisionSteps(mock_llm_response)
# 이제부터는 장황한 자연어가 아니라, 독립된 변수에 대해서 결정론적 오라클 수행
assert "신용 점수 부족" in steps.credit_check, "신용도 심사 로직에 환각이 발생함"
3. 함수 호출(Function Calling) 기능을 이용한 네이티브 캡처
만약 OpenAI의 gpt-4o나 Anthropic의 claude-3-opus와 같이 도구 사용(Tool Use / Function Calling) 기능을 네이티브하게 지원하는 모델을 사용 중이라면, 복잡한 텍스트 파싱을 할 필요도 없다.
개발자는 중간 추론 과정을 기록하는 record_intermediate_thought(step_name, detail, result) 와 같은 더미 함수(Dummy Function) 스키마를 모델에 제공하고, “생각이 진행될 때마다 이 함수를 호출해 기록하라“고 지시하면 된다. 이 경우, 모델이 보내온 JSON 형태의 함수 매개변수 꾸러미(Arguments) 자체가 파이썬의 깨끗한 딕셔너리로 즉시 자동 캡처되므로, 테스트 환경에서의 변수화가 100%의 무결성을 띠게 된다.
추론의 과정을 변수로 통제(Bind)할 수 있다는 것은, AI라는 블랙박스에 소프트웨어 공학의 강력한 디버깅 도구인 메모리 워치(Memory Watch)를 달아놓는 것과 같다. 변수로 캡처되지 않은 생각은 테스트할 수 없으며, 테스트할 수 없는 생각 시스템은 결코 신뢰할 수 없다.