언어 모델에게 “strawberry”라는 단어에 철자가 몇 개 들어있는지 물어보세요. 틀릴 확률이 높습니다. 10개라고 할 수도 있고, 11개라고 추측할 수도 있습니다. 아주 확신에 찬 말투로 말하겠지만, 여전히 틀린 답일 것입니다. 같은 모델에게 대출의 복리 계산을 요청하거나, 큰 두 숫자를 더하거나, 두 날짜 사이의 영업일을 계산해 달라고 하면, 숫자가 약간, 그리고 위험할 정도로 틀린 그럴듯해 보이는 답변을 받게 되는 경우가 많습니다.

이는 대규모 언어 모델이 인간과 같은 방식으로 숫자에 대해 추론하지 않기 때문에 발생합니다. 모델은 토큰을 예측합니다. 토큰은 단어 전체일 수도, 단어의 일부일 수도, 혹은 단일 숫자일 수도 있습니다. 모델이 “strawberry”를 볼 때, 일렬로 늘어선 8개의 개별 철자를 보는 것이 아닙니다. 몇 개의 덩어리(chunk)를 보는 것입니다. 모델은 문자를 세는 법을 배운 적이 없으며, 오직 다음에 올 텍스트 덩어리가 무엇인지 예측하도록 학습되었을 뿐입니다. 산술 연산에도 동일한 한계가 적용됩니다. 모델에게는 내부 계산기가 없습니다. 올림(carry) 로직이 부족하며, 자릿값(place value)에 대한 진정한 이해도 없습니다. 148에 279를 곱할 때, 모델은 곱셈을 수행하는 것이 아닙니다. 훈련 과정에서 보았던 유사한 표현들과 패턴을 매칭하여, 어떤 숫자 시퀀스가 뒤따라야 할지 추측하는 것입니다. 아주 작은 합계의 경우 패턴이 충분히 강력하여 작동할 수 있습니다. 하지만 정밀함이 요구되는 작업에서는 결국 추측이 어긋나게 됩니다.

두 가지 작업, 하나의 봇

표준적인 프롬프팅 방식은 단일 시스템에 두 가지 매우 다른 작업을 동시에 수행하도록 요청합니다. 첫째, 문제의 논리를 이해하는 것. 둘째, 정확한 수학 계산을 실행하는 것입니다. 모델은 첫 번째 작업에는 진정으로 인상적인 능력을 보여줍니다. 문장제 문제를 읽고, 변수를 추출하며, 관계를 매핑하고, 해결 경로를 계획할 수 있습니다. 하지만 그다음에는 스스로 계산기 역할까지 수행해야 합니다. 바로 이 지점에서 연결 고리가 끊어집니다. 3단계에서 숫자 하나만 잘못되어도 그 이후의 모든 단계가 오염됩니다. 논리 자체는 완벽할지 몰라도, 모델이 계산을 틀렸기 때문에 최종 답은 엉터리가 됩니다.

Program-Aided Language Models, 즉 PAL은 작업을 분리함으로써 이 문제를 해결합니다. 모델에게 정답을 묻는 대신, 프로그램을 작성해 달라고 요청하는 것입니다.

실제 흐름은 다음과 같습니다. 문제를 제시합니다. 모델은 논리를 파악하고, 변수를 정의하며, 알고리즘을 구조화합니다. 그런 다음 결과를 직접 계산하는 대신, 보통 Python으로 된 짧은 스크립트를 작성합니다. 이 스크립트는 실제 코드 인터프리터로 전달됩니다. 인터프리터는 논리를 실행하고 정확하며 결정론적인(deterministic) 결과를 반환합니다. 모델은 수학적 원리를 설명하고, Python이 수학을 수행합니다.

실전에서의 실행 가능한 추론

PAL을 '실행 가능한 추론(executable reasoning)'이라고 생각하십시오. 스크립트가 문제를 해결할 수 있다면, 모델에게 스크립트를 쓰게 하십시오.

구체적인 예를 들어보겠습니다. 연이율 8.5%로 분기별 복리가 적용되는 ₹50,000의 정기 예금을 7년 동안 유지했을 때의 만기 금액을 계산해야 합니다. 언어 모델에게 직접 물어보면, 모델은 공식을 쓰고 값을 대입하여 사고의 흐름(chain of thought) 과정에서 결과를 계산할 수도 있습니다. 하지만 자세히 살펴보면, 이율을 잘못 나누어 분기별 복리 계산을 잘못 처리했거나, 중간 단계를 반올림하여 오류를 다음 단계로 넘겼을 수도 있습니다. 답은 그럴싸해 보이지만 실제로는 수백 루피의 오차가 발생합니다.

PAL을 사용하면 상호작용 방식이 바뀝니다. 모델에게 principal = 50000, rate = 0.085, time = 7, n = 4를 정의한 다음 amount = principal * (1 + rate/n) ** (n * time)을 계산하는 Python 코드를 생성하도록 지시합니다. 모델이 코드를 출력하면, Python 런타임이 이를 실행합니다. 그러면 매번 마지막 소수점 자리까지 정확한 수치를 얻을 수 있습니다. 곱셈 과정에서의 추측도, 환각(hallucination)으로 인한 나머지 값도, 자신만만한 반올림 오류도 없습니다.

이와 동일한 패턴이 날짜 계산에도 적용됩니다. 주말을 제외하고 오늘로부터 정확히 120 영업일 뒤가 언제인지 모델에게 물어보십시오. 텍스트 전용 모델은 날짜를 세다가 토요일에서 실수할 수 있습니다. PAL 방식은 모델이 datetimecalendar 로직을 사용하는 스크립트를 작성하게 한 다음, 인터프리터가 정확하게 반복 계산하도록 합니다. 데이터 조작도 마찬가지입니다. 지저분한 CSV를 파싱하거나, 중첩된 JSON을 필터링하거나, 빠른 통계 변환을 실행해야 하는 경우, 모델은 논리를 초안하고 인터프리터가 반복 작업을 처리해야 합니다.

이것이 실제로 중요한 이유

산문 형태의 답변에서 실행 가능한 코드로의 전환은 세 가지 실질적인 이점을 제공합니다.

결정론. 언어 모델에 같은 질문을 두 번 던지면 표현이 달라지거나 숫자가 바뀔 수 있습니다. 인터프리터는 동일한 입력에 대해 매번 동일한 출력을 반환합니다. 이러한 안정성은 회계, 물류, 일정 관리, 그리고 일관성이 선택이 아닌 필수인 모든 공학적 계산에서 매우 중요합니다.

검증 가능성. 모델이 세 단락의 추론 과정을 내놓으면, 단 하나의 잘못된 숫자를 찾아내기 위해 모든 문장을 읽어야 합니다. 하지만 10줄짜리 스크립트를 내놓으면 코드를 검토할 수 있습니다. 인터프리터가 실행되기도 전에 복리 계산 공식이 맞는지 확인할 수 있습니다. 변수 이름을 검사하고, 오프바이원(off-by-one) 오류를 찾아내며, 심지어 솔루션의 버전 관리까지 할 수 있습니다. 숨겨진 실수가 발생할 수 있는 영역이 극적으로 줄어듭니다.

신뢰성. 모델은 자신의 역할에 충실합니다. 모델은 구조, 의미론, 문제 분해에 대해 추론하는 등 설계된 목적대로 동작합니다. 기계는 정확하게 계산하는 등 설계된 목적대로 동작합니다. 이러한 관심사의 분리(separation of concerns)가 바로 신뢰할 수 있는 소프트웨어를 설계하는 방식입니다. 구성(Composition)이 모놀리식(monolithic) 설계보다 우수합니다.

신뢰할 수 없는 코드처럼 실행하십시오

주의가 필요합니다. 생성된 코드는 신뢰할 수 없는 입력으로 취급해야 합니다. 모델은 무한 루프, 불필요한 네트워크 요청, 또는 요청하지 않은 파일 시스템 작업을 포함하는 스크립트를 작성할 수도 있습니다. 항상 이러한 프로그램은 격리된 샌드박스 내부에서 실행하십시오. 권한이 제한된 컨테이너, 네트워크 액세스가 없는 서버리스 함수, 또는 CPU 시간이 제한되고 영구 저장소가 없는 엄격하게 제어된 환경을 사용하십시오. 여기서 보안은 부차적인 문제가 아닙니다. 시스템 설계의 일부입니다.

PAL이 빛을 발하는 지점과 한계점

PAL은 수학, 날짜, 구조화된 데이터 조작에서 탁월한 성능을 발휘합니다. 텍스트 기반 추론에서 빈번하게 발생하는 기계적 오류를 제거해 줍니다.

하지만 잘못된 논리까지 해결해주지는 않습니다. 만약 모델이 잘못된 공식을 선택한다면,