13.6.4 Chain-of-Thought(CoT)를 활용한 자체 검증 유도 프롬프트 설계
앞서 13.4절에서 우리는 2단계 오라클(Semantic Consistency Oracle)을 통해 수학적 ’산술 검증(단가 × 수량 = 합계)’과 시계열적 ’날짜 검증(발주일 ≤ 청구일 ≤ 마감일)’을 파이썬 코드로 깐깐하고 차갑게 수행했다.
하지만 이 오라클은 결국 LLM이 대답 세션을 모두 마친 후(Post-generation)에 채점표를 들이대어 에러를 던지는 수동적인 방어망 구조다.
만약, 오라클에게 욕을 먹고 데이터가 반려되어 API를 비싼 돈 주고 처음부터 다시 호출(Retry) 해야 하는 최악의 상황 자체를 막고, 1차 추출 통과율(Pass Rate)을 극적으로 99%까지 높이고 싶다면 어떻게 해야 할까?
해답은 바로 프롬프팅 최전선에서, LLM 스스로가 대답을 JSON으로 최종 확정 짓기 직전에 먼저 연습장에 자신이 추출할 숫자들을 꺼내놓고 스스로 교차 수학 문제를 한 번 풀어보게 강제하는 ‘Chain-of-Thought (CoT, 생각의 사슬)’ 프롬프팅 기술을 구조적 스키마 안에 융합 도입하는 것이다.
1. 사슬 추론(CoT)을 통한 오라클 선제 조율 및 메타인지 활성화
단순히 “이 문서에서 영수증 필드를 JSON으로 추출해라” 라고 1차원적으로 명령하면, LLM은 이미지에 시각적 어텐션(Attention)을 그저 한 번 훑고 스친 뒤 곧바로 최종 값을 오토레그레시브하게 뱉어내 버린다. 이때 모델의 단일 추론 샷에는 심각한 확률적 환각이나 산술 연산 오류가 섞여 들어갈 확률이 매우 높다.
하지만 우리가 주입하는 Pydantic 스키마 최상단에 reasoning_steps 나 inner_monologue 같은 ‘사고 과정 스크래치 패드(Scratchpad)’ 텍스트 필드를 의도적으로 만들어두고, 숫자 도출 과정을 자연어로 먼저 길게 서술하게 강제하면 상황은 180도 달라진다.
트랜스포머 모델의 특성상 다음 토큰을 예측하기 위해 앞서 본인이 적어둔 문맥을 다시 참조하는 과정에서 모델 논리의 메타인지(Meta-cognition) 능력이 극대화되어, 최종 산술/맥락 정확도가 말 그대로 폭발적으로 상승하게 된다. (이는 “Chain-of-Thought Prompting Elicits Reasoning in Large Language Models”, Wei et al., 2022 등의 논문에서 증명된 가장 확실한 엔지니어링 기법이다.)
[SYSTEM PROMPT - CoT 유도 및 2단계 오라클 방어용 전처리]
당신은 단순히 눈에 보이는 문자를 옮겨 적는 타이핑 기계가 아니라,
거대 엔터프라이즈의 무결성을 수호하는 극도로 정밀한 회계 감사관(Auditor)이다.
최종 JSON 필드를 작성하기 전에, 반드시 맨 위에 위치한 `reasoning_steps` 배열 필드에
당신이 이 숫자와 맥락을 도출하기까지의 사고 과정(Chain of Thought)을 순차적으로 낱낱이 기록하라.
[필수 사고 검증 과정 (Must Include in reasoning_steps)]
Step 1. [증거 수집] 각 품목의 단가(Unit Price)와 수량(Qty) 필드가 이미지의 어느 좌표 근처에 위치하는지 텍스트로 주변 문맥을 명시해라.
Step 2. [자체 산술 연산] (단가 * 수량)의 곱셈 연산을 당신의 언어 모델 내부적으로 스스로 수행해 보고 그 값을 적어라.
Step 3. [교차 모순 검증] 당신이 연산한 Step 2의 결괏값과, 실제 문서 이미지상에 적혀있는 합계(Line Total) 숫자를 나란히 놓고 일대일로 비교해라.
Step 4. [최종 결재] 두 값이 완벽히 일치할 경우에만 최종 정형 필드에 값을 기재하고, 모순될 경우 'null'을 선언하며 추출을 포기해라.
2. Pydantic 구조 레이아웃을 활용한 CoT-Integrated 추출 구현
이러한 CoT는 단순히 프롬프트 자연어 영역을 넘어, 우리가 1단계 오라클을 위해 정의한 JSON 스키마(Pydantic)의 필드 순서 설계에 직접적으로 의도 반영되어야 한다.
from pydantic import BaseModel, Field
from typing import List
class LineItemWithCoTOracle(BaseModel):
# 아키텍트는 반드시 이 reasoning 필드를 JSON 스키마의 '최상단'에 배치해야 한다.
# LLM이 최종 값을 적기 전, 자신의 생각을 강제로 먼저 정리하도록 유도하는 자유 연습장 필드
reasoning_steps_for_audit: List[str] = Field(
...,
description="이 품목의 단가와 수량을 찾고, (단가*수량=합계) 부등식을 스스로 검증한 사고 절차를 순서대로 나열하시오."
)
# CoT 정화 과정을 거친 뒤에야 비로소 도출되는 최종 정제 데이터
# (이 데이터들이 최종적으로 2단계 산술 오라클에 의해 채점받을 타겟이 된다)
item_description: str
unit_price: float
quantity: int
line_total: float
3. CoT가 후방 오라클 파이프라인 아키텍처에 내리는 공학적 축복
이 교묘한 CoT 강제 프롬프트 아키텍처의 가장 눈부신 마법은, LLM이 reasoning_steps 배열 필드를 자연어 텍스트로 중얼중얼 적어 내려가는 그 순간의 토큰 생성(Token Generation) 과정 자체에서 발생한다. 이 과정에서 모델 내부의 수많은 어텐션 층에서 역전파된 숨겨진 상태(Hidden States)가 거대하게 활성화되며, 뒤이어 뱉어낼 unit_price, quantity, line_total 간의 후속 수학적 연산과 스칼라 맵핑 정확도를 무지막지하게 비약적으로 끌어올리는 효과를 낳는다.
이는 마치 초등학생에게 암산으로 두 자릿수 곱셈을 시켰을 때는 빈번하게 틀리지만, 이면지 연습장에 수식 전개 과정을 차근차근 직접 손으로 쓰게 만들면 자기 검산(Self-verification)이 이루어져 오답률이 기하급수적으로 0에 수렴하는 것과 완벽히 동일한 인지 공학적 메커니즘이다.
이렇게 파이프라인 최전선에서 전방위적 CoT 프롬프트를 통해 스스로 결점을 한 번 걸러내고 정화된 퓨어(Pure) 한 텐서들만이 마침내 파이프라인 후방의 ’2단계 산술 오라클(13.4절)’로 넘어가게 되며, 그 결과 오라클이 화가 나서 ValidationError를 격발시키고 파이프라인을 롤백(Rollback) 시키는 사고 발생률은 놀라울 만큼 드라마틱하게 줄어들게 된다.