추론 모델은 무엇이 다른가: 사고 토큰과 그 청구서

추론 모델이 일반 LLM과 구조적으로 어떻게 다른지, 사고 토큰이 정확도와 비용에 어떤 영향을 주는지, 그리고 어떤 작업에서만 그 대가가 회수되는지 실무 기준으로 정리합니다.

· 14 min read · PALDYN Team

지난 글에서 LLM 비용을 줄이는 방법을 다뤘는데, 실무에서 그 계산을 가장 크게 흔드는 변수가 하나 있다. 추론 모델(reasoning model)을 쓸 것이냐다. 같은 프롬프트를 넣어도 응답 시간이 20배 늘고 출력 토큰이 15배 나오는데, 정작 정확도는 거의 안 오르는 경우가 절반쯤 된다. 반대로 일반 모델로는 아무리 프롬프트를 다듬어도 못 풀던 문제가 추론 모델에서는 한 번에 풀리기도 한다. 이 차이가 어디서 오는지 알면 어떤 요청에 어떤 모델을 붙일지가 훨씬 명확해진다.

구조적으로 무엇이 다른가

일반 LLM은 첫 출력 토큰부터 곧바로 정답을 쓰기 시작한다. “42입니다”라고 답할 때, 모델은 42라는 토큰을 뱉는 그 순간에 이미 결론을 낸 상태다. 중간에 “아 잠깐, 이 조건을 빼먹었네” 하고 되돌아갈 구조적 여지가 없다. 자기회귀 생성은 앞으로만 간다.

추론 모델은 답변을 쓰기 전에 별도의 사고 구간을 먼저 생성한다. 문제를 분해하고, 후보 풀이를 세우고, 스스로 검산하고, 틀렸다 싶으면 다른 경로로 다시 시작한다. 이 구간은 보통 사용자에게 노출되지 않거나 요약된 형태로만 보이지만, 모델 입장에서는 똑같은 출력 토큰이다. 즉 되돌아가기를 생성 과정 안으로 집어넣은 것이 추론 모델의 본질이다.

일반 LLM과 추론 모델의 토큰 소비 위치 비교

여기서 실무자가 가장 자주 놓치는 지점이 과금이다. 사고 토큰은 화면에 안 보여도 출력 토큰으로 계산된다. 답변 300자를 받았는데 출력 토큰이 4,000개 찍히는 상황이 정상이다. 비용 대시보드에서 “출력 토큰이 왜 이렇게 많지?”라는 의문이 생긴다면 십중팔구 추론 모델을 켜 둔 경로다.

정확도는 왜 오르는가

추론 모델의 이득은 마법이 아니라 확률 계산이다. 한 번에 정답을 맞힐 확률이 $p$인 문제를, 서로 다른 접근으로 $k$번 시도해서 그중 맞은 것을 골라낼 수 있다면 성공 확률은 이렇게 된다.

Psuccess=1(1p)kP_{\text{success}} = 1 - (1-p)^k

$p = 0.4$인 문제에서 $k = 5$면 성공률이 92%까지 올라간다. 문제는 “맞은 것을 골라낼 수 있다면”이라는 전제다. 모델이 자기 답이 맞는지 판별하지 못하면 이 식은 성립하지 않는다. 5개의 후보 중에 정답이 하나 있어도 엉뚱한 것을 고르면 아무 의미가 없다.

그래서 추론 모델의 이득은 자기 검증이 가능한 문제에 집중된다. 수학 문제는 답을 원식에 대입해 보면 되고, 코드는 실행해 보면 되고, 논리 퍼즐은 제약 조건을 하나씩 다시 확인하면 된다. 반면 “이 문단의 톤을 부드럽게 바꿔줘” 같은 작업은 아무리 오래 생각해도 검증할 기준 자체가 없다. 사고 토큰 3,000개를 태워도 첫 시도 결과와 사실상 같은 것이 나온다.

추론 모델이 값을 하는 작업 영역 사분면

실제로 얼마나 차이 나는가

내부 작업 로그를 기준으로 대략적인 감을 정리하면 이렇다. 절대값은 모델과 시점에 따라 달라지므로 비율만 보면 된다.

작업 유형일반 모델 정확도추론 모델 정확도출력 토큰 배수지연 배수
경쟁 수학 문제34%81%12×15×
테스트 있는 버그 수정52%74%
다중 제약 스케줄링41%69%10×11×
코드 리뷰 코멘트 생성71%76%
문서 요약88%88%
의도 분류94%94%

아래 세 줄을 보면 답이 나온다. 요약과 분류에서 추론 모델은 정확도를 1%포인트도 못 올리면서 비용을 4~5배 쓴다. 이런 경로에 추론 모델을 켜 두는 것은 순수한 손실이다. 그런데 실무에서는 “일단 제일 좋은 모델로 다 돌리자”는 판단 때문에 이 손실이 아주 흔하게 발생한다.

요청 단위로 나누는 법

가장 실용적인 접근은 모델을 하나로 통일하지 않고, 요청의 성격에 따라 경로를 나누는 것이다. 판별 기준은 앞서 본 두 축, 즉 단계 깊이와 검증 가능성이다.

from dataclasses import dataclass
from enum import Enum


class Tier(Enum):
    FAST = "fast"          # 일반 모델, thinking 끔
    REASONING = "reasoning"  # 추론 모델


@dataclass
class RoutingRule:
    task_type: str
    multi_step: bool       # 중간 단계가 3개 이상 필요한가
    verifiable: bool       # 결과를 기계적으로 검증할 수 있는가
    latency_budget_ms: int


def choose_tier(rule: RoutingRule) -> Tier:
    # 지연 예산이 빡빡하면 추론 모델은 애초에 후보가 아니다
    if rule.latency_budget_ms < 3000:
        return Tier.FAST

    # 깊이와 검증 가능성이 모두 충족될 때만 값을 한다
    if rule.multi_step and rule.verifiable:
        return Tier.REASONING

    return Tier.FAST


RULES = [
    RoutingRule("intent_classification", False, True, 500),
    RoutingRule("doc_summary", False, False, 8000),
    RoutingRule("sql_generation", True, True, 15000),
    RoutingRule("bug_fix_with_tests", True, True, 60000),
    RoutingRule("tone_rewrite", False, False, 4000),
]

for r in RULES:
    print(f"{r.task_type:28s} -> {choose_tier(r).value}")

실행하면 sql_generationbug_fix_with_tests만 추론 경로로 빠지고 나머지는 전부 빠른 경로로 간다. 이 단순한 규칙만 적용해도 전체 트래픽의 70~80%가 일반 모델로 처리되는 경우가 많다.

호출할 때 실제로 신경 쓸 것

API 레벨에서는 사고 예산을 명시적으로 지정하는 형태가 일반적이다. 예산을 주지 않으면 모델이 알아서 정하는데, 그 “알아서”가 예상보다 훨씬 큰 값일 때가 있다.

import anthropic

client = anthropic.Anthropic()

resp = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=8000,
    thinking={
        "type": "enabled",
        "budget_tokens": 4000,  # 사고에 쓸 상한
    },
    messages=[{
        "role": "user",
        "content": "재고 30개, 주문 4건의 우선순위 제약을 만족하는 배분안을 구하라.",
    }],
)

usage = resp.usage
print(f"입력 토큰: {usage.input_tokens}")
print(f"출력 토큰: {usage.output_tokens}")  # 사고 + 답변 합계

for block in resp.content:
    if block.type == "thinking":
        print(f"[사고 구간 {len(block.thinking)}자]")
    elif block.type == "text":
        print(block.text)

주의할 점이 두 가지다. 첫째, max_tokens는 사고 토큰까지 포함한 총량이므로 budget_tokens보다 넉넉히 잡아야 한다. 사고에 예산을 다 쓰고 답변을 쓸 자리가 없으면 응답이 잘린 채 끝난다. 둘째, 사고 예산은 상한일 뿐 목표치가 아니다. 쉬운 문제에는 모델이 알아서 적게 쓰므로, 상한을 넉넉히 준다고 매 요청이 그만큼 비싸지는 것은 아니다.

운영에서 반드시 계측할 지표

추론 모델을 도입하면 기존 모니터링이 거의 무력해진다. 최소한 다음 네 가지는 별도로 봐야 한다.

사고 토큰 비율. 전체 출력 토큰 중 사고가 차지하는 비중이다. 이 값이 90%를 넘는 요청이 많다면 해당 경로는 추론이 필요 없는 작업일 가능성이 높다. 답변은 두 줄인데 사고가 5,000토큰이면 문제 설정이 잘못된 것이다.

지연 분포의 꼬리. 추론 모델의 응답 시간은 평균이 의미 없다. 같은 엔드포인트에서 p50이 4초인데 p99가 90초인 상황이 흔하다. 난도에 따라 사고 길이가 요동치기 때문이다. 타임아웃과 사용자 대기 UI를 p99 기준으로 설계해야 한다.

예산 도달률. 지정한 budget_tokens에 실제로 도달해서 사고가 잘린 요청의 비율이다. 이 비율이 높으면 예산이 부족해 모델이 결론을 못 낸 채 답변을 쓰고 있다는 뜻이고, 그런 답변의 품질은 일반 모델보다 나쁠 수도 있다.

동일 요청 정확도 델타. 가장 중요한 지표다. 같은 입력 집합을 일반 모델과 추론 모델에 각각 돌려 정확도 차이를 주기적으로 측정한다. 이 델타가 통계적으로 유의하지 않다면 그 경로는 즉시 일반 모델로 되돌려야 한다. 도입 시점에 유의했더라도 일반 모델이 업그레이드되면서 격차가 사라지는 일이 자주 있다.

자주 하는 오해 셋

“추론 모델은 항상 더 똑똑하다.” 틀렸다. 짧은 사실 질의나 지시 준수 작업에서는 오히려 나쁠 때가 있다. 모델이 단순한 요청을 과도하게 해석해서 요청하지 않은 것까지 덧붙이는 과잉 사고가 발생한다. “JSON만 출력하라”는 지시를 주고 추론 모델을 돌렸을 때 설명이 딸려 나오는 사례가 대표적이다.

“사고 과정을 프롬프트로 흉내 내면 된다.” 부분적으로만 맞다. 프롬프트로 단계를 유도하는 방식은 모델이 이미 알고 있는 절차를 꺼내 쓰게 만드는 데는 효과적이지만, 훈련으로 체득한 되돌아가기 능력까지 재현하지는 못한다. 이 둘의 차이는 별도로 다룰 만큼 크다.

“비쌀 뿐 손해는 없다.” 지연이 손해다. 사용자가 응답을 기다리는 인터랙티브 경로에서 90초는 사실상 실패다. 정확도가 20%포인트 올라도 사용자가 그전에 창을 닫으면 아무 의미가 없다. 배치 처리나 백그라운드 작업에서는 이 제약이 사라지므로, 같은 작업이라도 실행 맥락에 따라 판단이 달라진다.

정리

추론 모델은 만능 업그레이드가 아니라 특정 형태의 문제에 특화된 도구다. 판단 기준은 두 개면 충분하다. 중간 단계가 여러 개 필요한가, 그리고 결과를 기계적으로 검증할 수 있는가. 둘 다 예일 때만 추가 비용과 지연이 회수된다. 나머지 경우에는 일반 모델에 프롬프트를 다듬는 쪽이 거의 항상 낫다.

도입할 때는 전체 트래픽을 한 번에 옮기지 말고, 정확도 델타를 측정할 수 있는 경로 하나부터 시작하는 것이 안전하다. 그리고 사고 토큰 비율과 p99 지연을 처음부터 대시보드에 올려 두면, 나중에 비용 청구서를 보고 놀랄 일이 없다.


지난 글: LLM 비용 최적화: 더 저렴하게, 더 빠르게

다음 글: 테스트 타임 컴퓨트: 생각할 시간을 사는 법


읽어주셔서 감사합니다. 😊