# AI 에이전트

haiku로 바꾸면 Claude Code 비용이 열 배 싸진다는데, 과연 진짜일까?

@Hong2026-10-26

이 글에 담긴 코드와 결과는 직접 실행해 측정한 값을 바탕으로 작성했습니다. 실측은 Hong과 팀원들이 진행했고, 그 결과를 바탕으로 AI가 글을 쓰고 Hong이 검토합니다.

실습 코드 내려받기

질문
Claude Code에서 haiku로 바꾸면 opus보다 비용이 정말 열 배 싸질까?
답
상태 전이 규칙 정리에서는 haiku 비용 추정치 중앙값이 $0.0039로 opus($0.1232)의 약 31분의 1이었다. 버그 수정 과제의 성공당 비용도 opus의 약 22분의 1이었다. MAX_THINKING_TOKENS=0은 sonnet의 사고를 끄지 못했다.
조건
2026-10-26, Claude Code 2.1.309 claude -p, effort medium(홈 설정 제외), 세 모델 과제 2개 각 5회, sonnet 사고 설정 2조건 각 5회

환경

측정일
2026-10-26
Claude Code
2.1.309, claude -p --safe-mode --setting-sources project --output-format json
모델
--model haiku, sonnet, opus(결과 JSON modelUsage의 모델 ID는 claude-haiku-5-5, claude-sonnet-5-5, claude-opus-5-5, 세션 로그에 기록된 effort는 세 모델 모두 medium)
대상
티켓 앱 app/ 다섯 파일 239줄, 기준 테스트 6개
반복
실습 1·2는 모델별 5회, 실습 3은 조건별 5회, 모든 실습을 섞은 순서로 모두 40회
비용
구독 로그인으로 호출, 금액은 Claude Code가 API 목록 단가로 환산한 추정치(실제 청구액 아님)
목차
  1. 소 잡는 칼로 닭을 잡고 있지 않았나요
  2. 실습 준비
  3. 실습 1: 쉬운 조사 과제를 세 모델에 시키기
  4. 실습 2: 버그를 찾아 고치는 과제를 세 모델에 시키기
  5. "그럼 작은 모델로 재시도하면 되겠네"가 아닙니다
  6. 실습 3: 같은 모델에서 사고를 꺼 보기
  7. 모델과 사고 깊이는 시작할 때 정합니다
  8. 정리

이번 시간에는 같은 과제를 haiku, sonnet, opus 세 모델에 시키고, 같은 모델에서 사고(thinking)를 끄는 설정까지 바꿔 보면서 비용과 결과를 claude -p로 측정하며 배워가는 시간입니다. claude -p는 대화 화면 없이 프롬프트 하나를 보내고 결과를 JSON으로 받는 실행 방식이에요.

다시 돌리면 숫자가 조금씩 달라질 수 있고, --model opus가 가리키는 모델도 시간이 지나면 달라질 수 있어요.

소 잡는 칼로 닭을 잡고 있지 않았나요

프롬프트를 아무리 잘 써도 출력을 만드는 건 모델이에요. 그런데 우리는 보통 늘 같은 모델을 써요. 간단한 파일을 찾는 일과 복잡한 설계를 다루는 일에 같은 모델을 쓸 이유가 있을까요?

소 잡는 칼로 닭을 잡는다는 말처럼, 작은 일에는 작은 모델을 골라 토큰 비용을 줄일 수 있다는 생각이에요. 이 생각이 실측에서도 맞는지 볼게요.

실습 준비

이 글의 명령은 모두 실습 코드의 claude-model-thinking-choice/ 디렉터리에서 실행합니다.

  • app/: 티켓을 만들고 담당자를 정하고 상태를 옮기는 작은 티켓 앱
  • tests/baseline/test_app.py: 앱이 제대로 도는지 보는 기준 테스트 6개
  • tests/tasks/: 버그 과제의 새 테스트를 둘 빈 디렉터리
  • tasks/patches/TASK-003.patch, tasks/prompts/TASK-003.md: 버그를 심는 패치와 버그 신고 원문
  • pyproject.toml: pytest 설정
  • prompt-models.txt, prompt-think.txt: 실습 1과 실습 3의 프롬프트 원문
  • schedule.txt, run.sh: 섞은 실행 순서와, 그대로 claude -p를 부르는 스크립트
  • summarize.py: 결과 JSON과 세션 로그를 모아 조건별 중앙값과 범위를 내고, 실습 2만 자동 판정하는 스크립트
  • .gitignore: git 제외 목록

Claude Code와 jq, Python 3.11 이상이 필요해요. 실행마다 깨끗한 사본을 만들 첫 커밋을 하고, 가상 환경에 pytest를 설치해 기준 테스트를 돌려 볼게요.

git init -q
git add .
git commit -q -m "start"
python3 -m venv .venv
.venv/bin/python -m pip install pytest==8.3.4
.venv/bin/python -m pytest -q tests/baseline

설치 마지막 줄과 테스트 결과는 이렇게 나와요(발췌).

Successfully installed iniconfig-2.3.1 packaging-26.3 pluggy-1.7.0 pytest-8.3.4
......                                                                   [100%]
6 passed in 0.14s

실습 1: 쉬운 조사 과제를 세 모델에 시키기

먼저 티켓 앱의 상태 전이 규칙을 정리하는 간단한 조사 과제를 haiku, sonnet, opus에 시켜 볼게요. 모델을 빠르게 바꿔 가며 돌려야 하니 headless(대화 화면 없이 실행하는 방식)로 갑니다.

mkdir -p artifacts/raw/models

Q="app 폴더 티켓 앱의 상태 전이 규칙을 표로 정리해 줘. 근거 파일과 줄도 같이."

for m in haiku sonnet opus; do
  claude --safe-mode --model "$m" -p "$Q" --output-format json --max-turns 10 2>/dev/null | jq . > "artifacts/raw/models/$m.json"
done

질문을 Q 변수에 담고, 세 모델로 같은 질문을 돌려 결과 JSON을 모델 이름의 파일에 저장해요. --max-turns 10은 한 실행에서 에이전트가 돌 수 있는 횟수의 상한이에요. 상한에 걸려 끊긴 실행은 싸게 끝난 게 아니라 실패한 거라서, 결과를 볼 때 끊겼는지도 같이 봐야 해요.

한 번씩으로는 흔들림을 알 수 없어서, 이 글의 숫자는 같은 프롬프트를 run.sh로 모델마다 5번씩 돌려 얻었어요. run.sh는 schedule.txt에 섞어 둔 순서대로, 회차마다 첫 커밋을 복제한 새 사본에서 claude -p를 부릅니다(발췌).

  case "$task" in
    p1)
      prompt="$(cat "$HERE/prompt-models.txt")"
      turns=10
      ;;
    p2)
      prompt="$(cat "$HERE/tasks/prompts/TASK-003.md")"
      turns=15
      extra=(--permission-mode acceptEdits --allowedTools "Bash(pytest:*)" "Bash(python -m pytest:*)" "Bash(python3 -m pytest:*)" "Bash(.venv/bin/pytest:*)" "Bash(.venv/bin/python -m pytest:*)")
      ;;
    p3)
      prompt="$(cat "$HERE/prompt-think.txt")"
      turns=12
      [ "$cond" = tof ] && thinking=(MAX_THINKING_TOKENS=0)
      ;;
  esac
  (cd "$dir" && env ${thinking[@]+"${thinking[@]}"} SHELL=/bin/bash PATH="$PWD/.venv/bin:$PATH" \
    claude --safe-mode --setting-sources project --session-id "$sid" \
    --model "$(model_of "$cond")" -p "$prompt" --output-format json --max-turns "$turns" \
    ${extra[@]+"${extra[@]}"} < /dev/null) > "$OUT/$name.json" 2> "$OUT/$name.err"

p1, p2, p3는 실습 1, 2, 3이에요. 붙인 플래그 중 --session-id는 세션 로그 파일 이름을 정하려는 것이고, --setting-sources project는 홈 디렉터리의 Claude Code 설정(기본 effort, 권한 허용 목록)이 섞이지 않게 하려는 거예요. --safe-mode만으로는 이 설정이 꺼지지 않아요.

그래서 이 실측에는 Bash 허용 목록이 없었어요. find, cat 같은 읽기 전용 단순 명령은 실행됐고, 반복문·명령 치환·여러 명령을 이은 명령이나 python 실행은 실습 1에서 9번 거부됐어요. 허용 목록이 있는 환경에서는 숫자가 다를 수 있어요.

effort도 세션 로그에 세 모델 모두 medium으로 기록됐어요. 앞에서 보인 반복문 명령을 그대로 치면 홈 설정의 effort가 적용돼서 사고 토큰과 비용이 달라질 수 있어요.

40회를 전부 돌리고 summarize.py로 실습 1 결과를 모아 볼게요. 이 스크립트는 out/의 결과 JSON과, out/<회차>.sid에 적힌 세션 ID로 찾은 세션 로그(~/.claude/projects/*/<세션 ID>.jsonl)를 읽어요. 출력·사고 토큰, 비용, num_turns의 중앙값과 범위, 세션 로그에 기록된 effort와 요청의 thinking 설정을 찍고, 실습 2는 기준 테스트 종료 코드와 git status의 바뀐 파일로 성공을 판정해요.

./run.sh
.venv/bin/python summarize.py p1
실습 1 상태 전이 표
  sonnet: 5회 중 끊김 0회
    output_tokens 1,664 (1,391~2,002)
    thinking_tokens 55 (28~62)
    total_cost_usd $0.0436 ($0.0407~$0.0600)
    num_turns 3 (3~4)
    thinking 블록 1 (1~1)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-sonnet-5-5
  opus: 5회 중 끊김 0회
    output_tokens 2,270 (2,130~2,583)
    thinking_tokens 144 (115~316)
    total_cost_usd $0.1232 ($0.1220~$0.1429)
    num_turns 8 (8~8)
    thinking 블록 1 (1~1)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-opus-5-5
  haiku: 5회 중 끊김 0회
    output_tokens 2,864 (2,698~4,411)
    thinking_tokens 1,153 (773~1,434)
    total_cost_usd $0.0039 ($0.0035~$0.0051)
    num_turns 6 (4~7)
    thinking 블록 2 (1~3)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-haiku-5-5

볼 값은 num_turns, usage.output_tokens, total_cost_usd, result 네 가지예요. 이 글에서 성공은 기능(판정 명령 통과), 범위(건드리면 안 되는 곳을 안 건드림), 품질 세 가지를 다 볼 때만이에요.

먼저 답의 품질부터 볼까요? 표가 그럴듯하다고 성공은 아니에요. 이 과제에는 돌릴 판정 명령이 없으니 기능은 0점이 아니라 "평가할 수 없음"으로 두고 품질을 봐야 해요.

그래서 프롬프트에 "근거 파일과 줄도 같이"를 넣었어요. 적힌 줄을 열어 규칙이 실제로 거기 있는지 보면 눈대중이 아니라 확인으로 판정할 수 있습니다.

열어 보니 15회 모두 전이 규칙 네 줄(app/domain.py 18~21줄의 ALLOWED)과 담당자 검사(app/service.py 31~32줄)를 맞는 줄로 짚었어요. 흠은 haiku에서만 나왔어요. 한 회차는 표 머리글에 베트남어 낱말(từ)이 섞였고, 다른 한 회차는 부가 설명 한 줄에서 app/api.py:43을 import 줄이라고 잘못 적었어요(실제 import는 6~7줄).

출력은 haiku가 제일 많이 썼어요(중앙값 2,864, opus 2,270, sonnet 1,664). haiku는 사고(thinking) 토큰 중앙값도 1,153으로 가장 컸어요.

num_turns는 40회 모두 "도구 호출 수 + 1"이었고, API 요청 수와 다른 회차가 많았어요. opus는 파일 다섯 개를 나란히 읽어서 num_turns가 8이어도 요청은 4번이었어요. 끊겼는지는 결과 JSON의 subtype이 error_max_turns인지로 보시는 게 정확하고, 실습 1은 15회 모두 success였어요.

이제 total_cost_usd를 보죠. run.sh가 out/<회차>.json에 저장한 결과에서 두 회차를 JSON 형태로 발췌할게요.

jq '{num_turns, usage: {output_tokens: .usage.output_tokens}, total_cost_usd, modelUsage: (.modelUsage | keys)}' out/p1-hai-01.json out/p1-opu-01.json
{
  "num_turns": 4,
  "usage": {
    "output_tokens": 2864
  },
  "total_cost_usd": 0.00407668,
  "modelUsage": [
    "claude-haiku-5-5"
  ]
}
{
  "num_turns": 8,
  "usage": {
    "output_tokens": 2583
  },
  "total_cost_usd": 0.14286780000000002,
  "modelUsage": [
    "claude-opus-5-5"
  ]
}

중앙값끼리 나누면 opus는 haiku의 약 31배, sonnet은 약 11배였고 범위도 겹치지 않아요(haiku 최댓값 $0.0051, sonnet 최솟값 $0.0407). "열 배 싸다"는 sonnet과 비교하면 맞고, opus와 비교하면 오히려 작게 말한 셈이에요.

이 차이는 토큰을 더 써서 생긴 게 아니에요. haiku는 출력을 제일 많이 쓰고도 제일 쌌어요. 모델마다 토큰 하나당 단가가 다르기 때문입니다.

같은 결과물을 얻고도 30배 넘게 더 낸 실행이 있었던 거죠.

modelUsage의 키는 실제로 돌아간 모델 ID예요. haiku, sonnet, opus는 별칭이라 가리키는 모델이 시점에 따라 바뀌니, 나중에 다시 비교하실 거면 이 ID를 같이 기록해 두세요.

실습 2: 버그를 찾아 고치는 과제를 세 모델에 시키기

이번에는 어려운 과제예요. 완료된 티켓이 지연으로 판정되는 버그를 패치로 심고, 버그 신고 문장만 주고 고치게 할 거예요. 패치를 적용하면 기준 테스트 하나가 실패하는지 먼저 볼게요.

patch -p1 < tasks/patches/TASK-003.patch
.venv/bin/python -m pytest -q tests/baseline | tail -2
patching file 'app/domain.py'
FAILED tests/baseline/test_app.py::test_완료된_티켓은_지연이_아니다 - Asserti...
1 failed, 5 passed in 0.38s

확인했으면 되돌려 둡니다. run.sh가 회차마다 사본에 패치를 적용해요.

git restore app/domain.py

Claude에게 주는 과제 문장은 이렇습니다.

완료 처리한 티켓이 지연 목록에 계속 나옵니다.

재현 방법:
1. 티켓을 하나 만들고 마감을 어제 날짜로 잡습니다.
2. 담당자를 지정하고 진행 중으로 옮긴 다음 완료로 옮깁니다.
3. 오늘 날짜로 지연 목록을 조회합니다.

기대: 완료된 티켓은 지연으로 세지 않습니다.
실제: 목록에 그대로 나옵니다.

원인을 찾아서 고쳐 주세요. 같은 문제를 잡는 테스트도 함께 남겨 주세요.

편집하고 테스트를 돌려야 하니 세 모델 모두에 같은 최소 권한을 줬어요. --permission-mode acceptEdits(파일 편집 자동 허용)와 --allowedTools의 pytest 실행 허용이에요. --max-turns는 편집과 테스트 단계가 붙는 만큼 실습 1·3보다 조금 큰 15로 정했고, 끊긴 회차는 실패로 셉니다.

사본에는 app/, tests/, pyproject.toml, .gitignore만 두고 패치를 적용한 상태로 새로 커밋해서, 패치 파일이나 버그를 심은 기록이 보이지 않게 했어요. 가상 환경은 PATH 맨 앞에 넣어 pytest가 바로 돌게 했고, Claude의 Bash가 zsh 설정을 읽어 PATH 앞에 다른 python을 넣지 않도록 SHELL=/bin/bash로 실행했어요.

판정은 기능(pytest -q tests/baseline 통과)과 범위(바뀐 파일이 app/domain.py, app/service.py, tests/tasks/ 안)예요. 성공당 비용은 실패 회차까지 넣은 총비용을 성공 수로 나눈 값이고, 아래 중앙값과 범위는 성공한 회차만으로 냈어요.

.venv/bin/python summarize.py p2
실습 2 TASK-003
  haiku: 5회 중 성공 4회, 총비용 $0.0354, 성공당 비용 $0.0088
    범위를 tests/ 아래 새 파일까지 넓히면 성공 5회, 성공당 비용 $0.0071
    output_tokens 5,053 (3,185~6,785)
    thinking_tokens 928 (744~1,126)
    total_cost_usd $0.0075 ($0.0051~$0.0095)
    num_turns 12 (8~20)
    thinking 블록 7 (5~9)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-haiku-5-5
  opus: 5회 중 성공 5회, 총비용 $0.9770, 성공당 비용 $0.1954
    범위를 tests/ 아래 새 파일까지 넓히면 성공 5회, 성공당 비용 $0.1954
    output_tokens 3,552 (2,474~4,365)
    thinking_tokens 138 (100~180)
    total_cost_usd $0.1951 ($0.1620~$0.2325)
    num_turns 14 (9~18)
    thinking 블록 2 (2~3)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-opus-5-5
  sonnet: 5회 중 성공 4회, 총비용 $0.3774, 성공당 비용 $0.0943
    범위를 tests/ 아래 새 파일까지 넓히면 성공 4회, 성공당 비용 $0.0943
    output_tokens 2,370.5 (2,006~2,462)
    thinking_tokens 61.5 (33~74)
    total_cost_usd $0.0725 ($0.0670~$0.0807)
    num_turns 9.5 (8~11)
    thinking 블록 1.5 (1~2)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-sonnet-5-5

기준 테스트는 15회 모두 통과했고, 고친 곳도 모두 같았어요. app/domain.py의 is_overdue에 빠진 DONE 검사를 되살린 한 줄이에요.

실패 2회는 모두 범위에서 나왔어요. haiku 한 회차는 새 테스트를 tests/regression/에 만들었고, sonnet 한 회차는 기준 테스트 파일(tests/baseline/test_app.py)에 테스트를 덧붙였어요.

과제 문장이 테스트 위치를 말하지 않으니 앞의 경우는 기준이 엄격한 탓도 있어요. 그래서 tests/ 아래 새 파일까지 허용한 숫자도 같이 찍었고, 그러면 haiku는 5회 모두 성공이에요. 판정에 쓰는 기준 테스트 파일을 고친 경우는 그대로 실패로 둡니다.

남긴 테스트가 정말 같은 문제를 잡는지도 봤어요. 새 테스트 파일을 만든 14회는 모두 고치기 전 코드에서 실패했어요.

비용은 성공당 비용으로 봐도 opus가 haiku의 약 22배, sonnet은 약 11배였어요. haiku는 출력이 5,053으로 opus(3,552)의 약 1.4배, sonnet(2,370.5)의 약 2.1배였고 num_turns도 8~20으로 크게 흔들렸지만, 단가가 싸서 가장 쌌어요.

num_turns가 상한 15를 넘긴 회차(opus 18, haiku 20)도 subtype은 success였어요. --max-turns가 정확히 무엇을 세는지는 이번에 확인하지 못했지만, num_turns와 같은 단위는 아니에요. 끊긴 회차는 없었어요.

"그럼 작은 모델로 재시도하면 되겠네"가 아닙니다

어려운 과제라면 작은 모델이 실패해서 큰 모델이 오히려 싸지 않을까 했지만, haiku는 한 번 실패하고도 성공당 비용이 가장 쌌어요.

그러면 "낮은 모델로 여러 번 재시도하면 더 싸겠네"라고 생각하실 수 있어요. 틀린 말은 아니지만, 그렇게 해석하시면 안 됩니다. 이번 과제가 작은 모델이 실패하기 시작하는 지점보다 아래에 있었다는 뜻일 뿐이에요.

현실의 더 큰 작업에서는 어딘가에서 작은 모델이 실패하기 시작하고, 실패 한 번은 시도 전체를 버리는 일이라 성공당 비용이 단숨에 역전될 수 있어요. 그 지점에는 일반론이 없으니, 여러분의 과제로 직접 재서 작은 모델이 안정적으로 성공하는 유형 목록을 만드셔야 합니다.

실습 3: 같은 모델에서 사고를 꺼 보기

모델은 답하기 전에 thinking이라는 생각 과정을 거쳐요. 이것도 화면에 보이지 않을 뿐 돈을 내는 출력 토큰이고, 결과 JSON의 usage.output_tokens_details.thinking_tokens에 따로 나와요.

Claude Code에서는 /effort로 사고의 정도를 고를 수 있고, 사고 상한을 주는 환경 변수 MAX_THINKING_TOKENS도 있어요. 여기서는 sonnet으로 고정하고 이 값을 0으로 줘 볼게요.

과제는 코드를 읽고 판단해야 하는, 경계 조건 버그 가능성 분석이에요. 두 번째 명령 앞에만 환경 변수가 붙어요.

Q="app의 is_overdue 로직과 상태 전이 규칙 사이에 경계 조건 버그 가능성이 있는지 분석해 줘. 코드를 읽고 근거를 들어서."

claude --safe-mode --model sonnet -p "$Q" --output-format json --max-turns 12 2>/dev/null | jq . > artifacts/raw/models/think-on.json

MAX_THINKING_TOKENS=0 claude --safe-mode --model sonnet -p "$Q" --output-format json --max-turns 12 2>/dev/null | jq . > artifacts/raw/models/think-off.json

볼 값은 usage 안의 output_tokens(아래쪽 modelUsage에도 나오지만 볼 건 위쪽 값), 두 답이 같은 지점을 짚는지 볼 result, total_cost_usd, num_turns예요. 생각을 끄면 바로 도구를 부르느라 도구 호출이 늘 수 있거든요.

run.sh로 조건마다 5번씩 돌렸어요. summarize.py는 세션 로그에 기록된 요청의 thinking 설정도 찍어요.

.venv/bin/python summarize.py p3
실습 3 사고 깊이
  사고 기본: 5회 중 끊김 0회
    output_tokens 2,667 (2,417~2,902)
    thinking_tokens 35 (31~45)
    total_cost_usd $0.0660 ($0.0609~$0.0682)
    num_turns 6 (4~7)
    thinking 블록 1 (1~1)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-sonnet-5-5
  MAX_THINKING_TOKENS=0: 5회 중 끊김 0회
    output_tokens 2,475 (2,359~2,693)
    thinking_tokens 36 (30~46)
    total_cost_usd $0.0638 ($0.0624~$0.0660)
    num_turns 6 (6~7)
    thinking 블록 1 (1~1)
    요청의 thinking 설정 adaptive, effort medium, 모델 claude-sonnet-5-5

MAX_THINKING_TOKENS=0을 줘도 사고가 꺼지지 않았어요. 두 조건 모두 요청의 thinking 설정이 adaptive(모델이 필요한 만큼 알아서 생각하는 방식)였고, 회차마다 thinking 블록이 1개씩 있었고, 사고 토큰 중앙값도 35와 36이었어요.

출력도 2,667 대 2,475로 차이(192)가 범위보다 작아서 줄었는지 모르겠다고 해야 하고, 비용과 num_turns도 마찬가지예요. 두 조건은 사실상 같은 설정을 10번 돌린 셈이에요.

그래서 result는 같은 설정에서 결론이 얼마나 흔들리는지를 보여 줘요. 10회 모두 "is_overdue의 날짜 경계(due < today, 마감 당일은 지연이 아님)는 맞다"는 같은 결론을 냈고, BLOCKED(막힘) 상태 티켓도 지연으로 집계된다는 점을 짚었어요. 그런데 move로 진행 중으로 옮길 때 WIP 한도(한 사람이 동시에 들 수 있는 진행 중 티켓 수)를 검사하지 않는다는 점은 8회만 짚었고, 그중 2회는 "실제 결함"이라고 단정했어요.

사고를 줄이는 설정을 줬다면 사고 토큰이 실제로 줄었는지부터 확인하고, 그때 result의 결론이 유지되는지 보세요. effort 단계별로 사고 토큰과 비용이 어떻게 달라지는지는 effort를 낮추면 Claude Code는 무엇을 덜 할까?를 참고하세요.

사고를 끌 수 있다 해도 "끄고 쓰면 되겠네"는 아니에요. 설계를 판단하거나 여러 파일이 얽힌 버그를 찾는 작업에서는 사고를 줄인 만큼 실패로 되갚을 수 있어요. 목표는 결론이 흔들리기 시작하는 지점을 찾고, 그 위에서 제일 낮은 수준을 고르는 거예요.

모델과 사고 깊이는 시작할 때 정합니다

모델과 사고 깊이는 작업을 시작할 때 정하고, 세션 중간에 바꾸지 마세요.

왜 그럴까요? 같은 앞부분을 다시 처리하지 않게 해 주는 프롬프트 캐시가 모델 단위로 쌓이기 때문이에요. 중간에 모델을 바꾸면 쌓인 컨텍스트 전체를 캐시 없이 다시 읽게 돼서, 아끼려고 모델을 내렸는데 오히려 더 낼 수 있어요.

캐시가 어떻게 쌓이고 어떻게 깨지는지는 세션 중간에 모델을 바꾸면 Claude 프롬프트 캐시는 얼마나 깨질까?를 참고하세요.

정리

범위: Claude Code 2.1.309, 파일 다섯 개짜리 티켓 앱, claude -p로 haiku·sonnet·opus 과제 2개 각 5회와 sonnet 사고 설정 2조건 각 5회를 잰 결과입니다.

  • 조사 과제는 세 모델 모두 근거 줄까지 맞혔고 비용 추정치 중앙값은 haiku $0.0039, sonnet $0.0436, opus $0.1232였습니다. 조사·요약은 작은 모델로 먼저 시켜 보세요.
  • haiku는 출력을 제일 많이 쓰고도 제일 쌌습니다. 비용 차이는 토큰 수보다 단가에서 나오니, 출력 토큰만 보고 모델을 고르지 마세요.
  • 버그 수정 과제는 범위까지 보면 haiku 4/5, sonnet 4/5, opus 5/5가 성공했고 성공당 비용은 haiku $0.0088, sonnet $0.0943, opus $0.1954였습니다. 실패 회차 비용까지 넣어 비교하세요.
  • num_turns는 도구 호출 수 + 1이었고 API 요청 수와 다른 회차가 많았습니다. 상한에 걸려 끊겼는지는 subtype이 error_max_turns인지로 확인하세요.
  • MAX_THINKING_TOKENS=0은 sonnet(claude-sonnet-5-5)의 사고를 끄지 못했습니다. 사고를 줄이는 설정을 쓰기 전에 결과 JSON의 thinking_tokens가 실제로 줄었는지부터 확인하세요.
  • 별칭(haiku, sonnet, opus)이 가리키는 모델은 바뀝니다. 비교 기록에는 modelUsage의 모델 ID를 함께 남기고, 모델은 세션을 시작할 때 정하세요.
내 링크 만들기