iPhone 앱을 혼자 개발하고 있는 Atsushi입니다. 저는 Claude Code의 세션을 앱별, 역할별로 나누어 10개 이상 사용하고 있습니다 (세션을 '부서'로 분리하는 방식).
이렇게 많이 구동하다 보면 금방 사용량 상한선이 신경 쓰이기 시작합니다. 한때는 상한선에 근접하여 모든 세션에 '절약해 달라'고 지시를 내린 적도 있었습니다.
본문에서는 각 세션에서 얻은, 실제로 효과가 있었던 토큰 절약 노하우들을 소개합니다.
왜 토큰이 줄어드는가
トークンが減るのは、この4か所
Claude Code는 주고받을 때마다 지금까지의 대화 전체를 다시 전송합니다. 즉, 한 번 대화에 들어간 내용은 나중에 여러 번 계산됩니다.
따라서 절약해야 할 생각은 간단합니다.
- 대화에
넣는 양을 줄인다 (긴 출력물, 큰 이미지, 파일 전체 복사)
- 왕복 횟수를 줄인다 (한 단계씩 호출하지 않고 한 번에 모아서 처리)
아래에서 이 두 가지 측면으로 나누어 구체적인 방법을 작성하겠습니다.
1. 출력을 짧게 만들기
빌드 및 테스트는 결과 라인만 읽기
가장 효과적이었던 방법입니다. xcodebuild의 로그는 수천 줄에 달합니다. 이대로 대화에 넣으면 그 자체로 엄청난 양이 됩니다.
그래서 저는 오류와 결과 라인만 추출하도록 합니다.
xcodebuild test -scheme MyApp -destination "id=$SIM_ID" 2>&1 \
| grep -E "error:|Executed [0-9]+ tests|TEST (SUCCEEDED|FAILED)"
테스트를 400건 이상, 수십 번 돌려도 대화에 들어가는 것은 몇 줄에 불과합니다. 실패했을 때만 그 이유를 읽습니다.
명령어 출력물을 짧게 해주는 도구 사용하기
모든 세션에서 공통적으로 RTK라는 도구를 Claude Code의 후크(hook)에 넣었습니다. 이 도구는 명령어 출력을 핵심 내용만 남기고 줄여줍니다. 긴 출력물은 요점만 반환되며, 나머지는 필요한 경우에만 추출할 수 있습니다.
CLAUDE.md에는 다음과 같이 작성되어 있습니다.
# 명령어의 출력
명령어의 출력은 짧게 모아서 반환된다. 모아진 결과를 그대로 결과로 취급한다.
원래 출력이 필요할 때만, 원래 출력을 추출한다.
...
긴 출력물은 파일에 기록하고 필요한 부분만 읽기
테스트 전체를 돌릴 때처럼 출력이 길어질 것이 확실하다면, 먼저 파일로 저장합니다. 그 후 실패한 부분과 결과 라인만 읽습니다.
xcodebuild test ... > /tmp/test.log 2>&1
grep -E "error:|✘|TEST (SUCCEEDED|FAILED)" /tmp/test.log
2. 테스트는 '수정한 부분만' 돌리기
테스트 전체를 돌리면 앱에 따라 30분 이상 걸립니다. 시간뿐 아니라 출력물도 엄청나게 늘어납니다.
그래서 수정한 부분 근처의 테스트만을 돌리도록 합니다. 모든 것을 돌리는 것은 버전 업그레이드 전이나 실제 기기에 넣기 직전에만 합니다.
# 수정한 것과 관련된 테스트만
xcodebuild test -scheme MyApp -destination "id=$SIM_ID" \
-only-testing:MyAppTests/CalendarTests
어떤 앱의 경우, 전체를 돌리면 30분 이상 걸리던 것이 수정할 때마다 5~8분으로 단축되었습니다.
3. 이미지는 압축하여 한 장에 모아서 보기
AI에게 화면 사진을 보여주면, 한 장이라도 상당한 양이 됩니다. iPhone의 화면 사진을 여러 장 연속으로 보여주면 대화가 금방 무거워집니다.
画面写真は、縮めて1枚に並べてから見る
그래서 압축하여 가로로 나열된 단일 이미지 (연락처 시트와 같은 방식)로 만든 후 확인합니다.
# 이미지를 압축하여 가로로 나열하는 한 장으로 만들기
import sys
from PIL import Image
...
소개 사이트의 이미지 20장 이상을 2~3회의 확인만으로 끝낼 수 있었습니다. 궁금한 부분이 있다면, 그 단일 이미지 중 해당 부분만 확대해서 봅니다.
같은 방식으로 다른 것도 처리합니다.
브라우저 화면 사진은 절반 크기로 찍는다.
- 영상은 몇 초 간격의 프레임을 나열한 한 장으로 본다 (ffmpeg로 프레임 추출).
- 화면 사진 대신 텍스트로 확인한다. 브라우저 확인 시 페이지의 텍스트나 '깨진 이미지 개수'를 JavaScript로 한 줄에 반환하게 한다. 게시 화면에 입력된 글도, 입력 필드의 텍스트를 추출하여 확인합니다.
화면을 눈으로 봐야 하는 경우는 외관 자체를 확인할 때뿐입니다. '포함되었는지 여부'는 문자나 숫자로 확인하는 것이 훨씬 가볍고 확실합니다.
4. 큰 파일을 통째로 읽지 않기
소개 사이트의 데이터 파일은 2,000줄이 넘습니다. 앱 번역 파일은 9,000줄을 넘는 경우도 있습니다. 이런 파일을 통째로 읽으면 그 자체만으로도 엄청난 양이 됩니다.
그래서 저는 grep으로 줄 번호를 찾아 필요한 범위만 읽도록 합니다.
grep -n "photo-widget" assets/apps-data.js # 줄 번호 찾기
sed -n '820,860p' assets/apps-data.js # 그 주변만 읽기
수정할 때는 Python으로 '해당 문장이 단 한 번 존재하는지'를 확인한 후에 대체합니다. 같은 문장이 2군데에 있으면 예상치 못한 곳까지 변경될 수 있기 때문입니다.
import pathlib, sys
path, old, new = sys.argv[1:4]
p = pathlib.Path(path)
...
조사할 때도 마찬가지입니다. '전부 읽기'보다는 '개수를 세고 요약하기'를 우선합니다. 검색 결과나 기록은 짧은 스크립트를 이용해 '건수 및 상위 3건'만 추출한 후에 읽습니다.
5. 왕복(Round-trip) 횟수 줄이기
한 번에 모아서 호출하기
브라우저 조작을 하나씩 호출하면, 그 때마다 전체 대화를 다시 보내야 합니다. 클릭, 입력, 확인 과정은 한 번의 호출로 모읍니다.
명령어도 마찬가지입니다. 관련된 확인(git 상태, 빌드, 실기 도입, 실행)은 한 번에 연결하여 흘려보냅니다.
긴 처리는 백그라운드에서 돌리고 알림을 기다리기
테스트를 전부 돌릴 때처럼 긴 처리 과정은 백그라운드에서 돌리고 완료되었다는 알림을 기다립니다. 도중에 '끝났어?'라고 여러 번 확인하면, 그때마다 주고받는 내용이 늘어납니다.
긴 문장은 대화에 붙이지 않기
App Store의 9개 언어 설명문 같은 긴 문장은 대화창에 붙여넣지 않습니다. 파일에 두고 JavaScript를 이용해 브라우저 입력란에 한 번에 넣습니다. 글자 하나하나 타이핑하게 하면 양도 시간도 많이 걸립니다.
6. 요약에 대비하여 대화 밖에 남기기
대화가 길어지면 Claude Code는 자동으로 요약합니다. 요약 후 세부 규칙이 빠지게 되면, 다시 조사해야 하는 상황이 생겨 오히려 양이 늘어나게 됩니다.
決まったことは、会話の外に残す
각 세션은 정해진 내용을 대화 밖에 남깁니다.
| 보관 장소 | 내용물 |
|---|
| 메모리 | 지켜야 할 규칙, 작업 방식의 선호도 (1건 1파일) |
| ... | |
| 긴 문장은 파일에 두고 수정하고, 대화에는 차이점이나 요점만 제시합니다. 다른 세션과도 파일 위치를 전달하는 것만으로 공유할 수 있습니다. | |
임시 폴더에 둔 것은 사라진다
실패한 적도 있습니다. 작업용 임시 폴더에 두었던 유용한 스크립트가 세션 전환 과정에서 두 번이나 사라졌습니다. 대화 기록에서 만드는 방법을 다시 찾아야 했고, 오히려 수고가 들었습니다. 남기고 싶은 것은 리포지토리나 메모리에 보관하는 것이 원칙이 되었습니다.
7. 모델과 서브 에이전트
절약하고 싶을 때는 다음을 했습니다.
모델을 Opus에서 Sonnet으로 전환했습니다.
서브 에이전트를 사용하지 않았습니다. 서브 에이전트는 각각 자료를 다시 읽기 때문에 양이 늘어나기 쉽습니다. 조사할 때도 세션 자신이 직접 grep으로 찾는 방식으로 바꿨습니다.
다만 예외도 있습니다. 수백 건의 데이터 출처를 한 건씩 확인할 때는 하나의 세션으로는 처리하기 어려운 양이었기 때문에, 서브 에이전트로 나누어 맡겼습니다. 대화에 담을 수 없는 작업만은 분리하는 것이 좋다는 판단입니다.
참고로 지금은 Opus로 되돌렸습니다. 새로운 버전의 Opus가 된 후부터는 같은 작업을 해도 사용량이 가벼워진 느낌이었기 때문입니다 (이는 어디까지나 제 감각일 뿐입니다).
잘 되지 않았던 점
출력을 너무 제한하여 실패 사례를 발견하지 못했다. 테스트와 커밋을 &&
연속하여 사용하며 테스트 출력을 grep으로 필터링하다가 실패를 눈에 띄지 않게 하여 망가진 버전을 커밋한 적이 있었습니다. 테스트는 단독으로 실행하고, 결과를 읽은 후에 커밋하도록 했습니다.
명령어를 수정하는 훅(hook)과 자동 승인 기능의 조합이 좋지 않았습니다. 출력을 짧게 하는 훅이 명령어를 수정하면, Claude Code의 자동 승인이 명령어 내용을 판단하지 못하고 단순 개수 세기 명령어까지 멈추는 경우가 있었습니다.
요약 후, 답변을 영어로 하게 되었습니다. 긴 세션 도중에 답변 언어가 영어로 바뀌는 일이 있었습니다. CLAUDE.md 맨 위에 '예외 없이 일본어'라고 적고, 중간의 한마디까지 포함하여 명시했습니다.
요약
- Claude Code는 대화 전체를 매번 다시 전송합니다. 그러므로 넣는 양과 왕복 횟수를 줄입니다.
- 빌드와 테스트는 오류와 결과 라인만 읽습니다.
- 테스트는 수정한 부분만. 모든 것을 버전 업 전에 합니다.
- 이미지는 축소하여 한 장에 배치합니다. '넣었는지'는 문자나 숫자로 확인합니다.
- 큰 파일은 grep으로 검색해서 필요한 부분만 가져옵니다.
- 결정된 사항은 대화 외부(conversation outside)에 남깁니다. 임시 폴더에는 두지 않습니다.
이 모든 것이 작은 노하우들이지만, 십여 세션에 걸쳐 사용하면 그 누적 효과가 매우 큽니다.
AI를 '부서'로 나누어 개인 개발을 진행하는 전체 메커니즘은 note의 유료 기사 시리즈(총 3회)에 정리되어 있습니다.
토론 (Discussion)