
Fable5로 심해 포트폴리오를 만들고, 그 로그를 Opus 4.8로 감사(Audit)한 이야기
요약
Claude Code(Fable5)를 사용하여 Three.js 기반의 심해 포트폴리오를 제작하고, 작업 과정의 객관성을 검증하기 위해 세션 로그를 Opus 4.8로 감사(Audit)한 경험을 다룹니다.
핵심 포인트
- Claude Code 세션 로그(.jsonl)를 통해 작업 시간, 토큰 사용량, 도구 호출 횟수를 정밀하게 측정 가능
- 지시사항의 추상도가 높을수록 모델의 출력 토큰 소모량이 급격히 증가함
- AI 모델의 작업 결과에 대한 인간의 기억 왜곡을 방지하기 위해 로그 기반의 객관적 검증 시도
Fable5로, 심해로 잠수하는 포트폴리오를 만들었다
Claude의 신모델 Fable5에게, 자신의 포트폴리오용 페이지를 한 페이지 만들게 했다.
스크롤을 통해 해수면에서 수심 6000m까지 잠항해 가는 Three.js 체험 페이지다.
잠수할수록 빛이 줄어들고, 수온·수압 계기가 움직이며, 심해 생물이 나타난다. 커서는 탐사 라이트가 되어, 빛을 비춘 곳만 읽을 수 있다.

👇 우선 실물을 봐주셨으면 한다.
걸린 시간은 실질적으로 4번의 지시와 약 2시간. 코드는 거의 작성하지 않았다. 솔직히 "대단하다"고 생각했다.
……그런데, 여기서 끝난다면 "Fable을 써봤는데 대단하다"로 끝날 이야기다.
하지만 한 가지 걸리는 점이 있었다.
이 2시간 동안 "대단했던" 것은, 어디까지가 Fable의 힘이고, 어디서부터가 내가 한 일인가. 그것을 스스로 설명할 수 없다.
만든 본인의 기억은, 소망에 의해 얼마든지 왜곡된다.
그래서 조금 색다른 일을 했다.
이 세션의 로그(Claude Code가 출력하는 .jsonl)를, 다른 모델(Opus 4.8)에게 통째로 읽게 하여, 자신의 가설을 로그상의 사실과 대조시켰다.
이 기사는 그 절차와 결과의 공유다.
애초에 로그는 어디에 있는가
Claude Code의 세션은, 1행 1이벤트의 JSON Lines 형식으로 저장되어 있다 (VS Code 확장 / CLI 공통). 이번 세션은 998행, 약 9.7MB. 1행은 대략 다음과 같은 구조로 되어 있다.
{
"type": "assistant",
"message": {
...
type은 assistant / user / system 등이다. user 측의 content에는 tool_result 블록이 들어가고, assistant 측에는 text / thinking / tool_use가 들어간다. 과금과 양을 확인하려면 message.usage의 4개 필드가 핵심이다.
실측: 4번의 지시 · 약 2시간 · 출력 75만 토큰
먼저, 지시별 비용을 집계한 결과부터.
| 지시 (요약) | 실제 시간 | 출력 토큰 | 도구 호출 |
|---|---|---|---|
| ① 심해 페이지를 만들어줘 (확인 필요하면 물어봐) | 약 45분 | 약 28만 | 94 |
| ... |
전체적으로 실제 작업은 약 2시간, 출력 합계는 약 75만 토큰, 도구 호출은 239회 (Bash 76 · Read 58 · Edit 51 · Write 38). 생성·편집한 파일은 약 30개.
이 수치는 로그를 다음과 같이 집계하는 것만으로 나온다.
import json
from collections import Counter
tok = Counter()
...
한 가지 주의할 점. 집계하면 cache_read가 약 97M라는 단위로 나와서 당황스러울 수 있는데, 이는 매 턴마다 과거의 문맥을 다시 읽어들인 양이며, 신규 생성이나 과금의 주역이 아니다.
실제로 "생성한" 양은 output_tokens의 합계인 약 75만 쪽이다.
표에서 흥미로운 점은, 지시의 추상도가 그대로 비용에 반영된다는 것이다.
②의 "자유롭게 발상해줘"는 약 35만 토큰을 소모했고, ④의 "이 지점에 제목을 달아줘"는 약 1.3만 토큰으로 끝났다.
모호한 지시일수록 모델은 더 길게 생각하고 더 길게 작성한다.
※ 애초에 ②와 ④는 태스크 양 자체가 다르지만...
감사한 가설은 3가지
여기서부터가 본론이다.
로그를 Opus 4.8에 전달하여, 나의 선입견을 사실과 대조했다.
미리 말해두자면, 이것은 "AI가 객관적으로 증명해 주었다"는 이야기가 아니다. 사실은 로그 쪽에 있으며, 이해관계가 없는 모델은 그것과 나의 기억을 맞대어 보았을 뿐이다.
그럼에도 불구하고, 스스로 자신의 성과를 말하는 것보다는 신뢰할 수 있다.
세운 가설은 이 3가지다.
- 느낌 좋게 나온 것은 Fable의 기본 실력일 것이다
- 사이트에 잘 녹아든 것은, 이전에 작성한 문서 덕분일 것이다
- 화려함이 나타난 것은 규칙을 벗어났기 때문이며, 즉 너무 얽매이지 않는 것이 좋다
가설 1: 기본 실력 → 정답 (상상 이상)
"한 번에 그럴싸하게 나온 것은 운이 아니었을까?"라고 의심했었다.
하지만 로그는 그렇게 말하지 않았다.
Fable은 구현할 때마다 로컬 서버를 구축하고, Playwright로 자신의 페이지를 스크린샷 찍어 이를 보며 확인하고 있었다 (PC·모바일 모두). 심지어 어떤 조작에서 WebGL 컨텍스트가 끊기는 버그를, "0.45까지 스크롤 → 클릭 시 끊김"이라는 재현 절차까지 스스로 특정하여 수정했다.
"동작하는 코드를 작성한다"에서 멈추지 않고, "동작한 결과를 관찰하여 결함을 찾아낸다"까지 혼자서 수행하고 있었다.
당연하다기보다, 상상 이상이었다.
가설 2: 문서(Document) → 정답. 단, 끌어올린 것은 "좋음"이 아니라 "조화(馴染み)"
이것은 로그를 읽는 관점으로서 가장 추천하고 싶은 부분이다.
에이전트가 "처음에 무엇을 읽었는가"를 보면, 그 출력이 무엇을 근거로 하고 있는지 알 수 있다.
추출 코드는 이것뿐이다.
import json
reads = []
with open("session.jsonl") as f:
...
결과적으로, 세션에서 가장 먼저 열린 파일이 docs/04_design_guideline.md였다.
코드에 손을 대기 전에, 기존의 디자인 규칙이나 컴포넌트의 작법을 읽고 나서 작성을 시작하고 있었다.
결정적인 것은, 이번 프롬프트에 나는 컬러 규칙(텍스트/UI는 흑백, 색상은 빛의 표현만)을 단 한 마디도 쓰지 않았음에도, Fable은 그것을 지켰고, 심지어 "어디까지 엄격히 준수할까요?"라고 역으로 질문해 왔다는 점이다.
이 제약의 출처는 처음에 읽은 저 문서 외에는 없다.
다만 솔직하게 선을 긋자면.
"문서가 없는 짧은 지시에서도 같은 품질이 나왔는가"는 검증하지 않았다.
따라서 "문서 덕분에 좋아졌다"라고는 말할 수 없다.
말할 수 있는 것은, 프롬프트에 적지 않은 제약이 알아서 지켜졌다는 단 한 점뿐이다.
그리고 그 내용은 "화려함"이 아니라 **"이 프로젝트에 조화롭게 녹아드는 힘"**이었다.
기초 체력이 천장을, 문서가 "그다움"이라는 바닥을 마련해주고 있었다. 역할이 다르다.
가설 3: 규칙을 벗어났기에 화려함 → 오답
이것은 기분 좋게 틀렸다.
나는 "②에서 가이드라인을 벗어났기에 화려해졌다, 그러므로 너무 얽매이지 않는 것이 좋다"라고 기억하고 있었다.
하지만 로그에서 ②의 지시문을 다시 읽어보니, 거기에는 별개의 축을 가진 두 가지 지시가 공존하고 있었다.
- (제약을 벗어남) "폰트 크기나 Works의 카드 등, 가이드라인은 지키지 않아도 된다"
- (야심을 높임) "3단계 퀄리티를 높이기 위해 무엇을 하고 싶은가? 다른 화면에 얽매이지 말고 자유롭게 발상하라"
나온 화려함, 즉 코드로 형태와 움직임을 구축한 고래(절차적 생성, Procedural Generation), 발광 포스트 프로세스(Post-process), 계기 HUD, 환경음은 모두 가이드라인이 구속하던 대상이 아니었다.
색상·폰트·카드의 작법에 고래나 소리는 걸리지 않는다.
즉 화려함의 근원은 "제약을 벗어난 것"이 아니라 "자유롭게 발상하라"에서 올라간 야심 쪽이었다.
그렇다면 제약을 벗어난 만큼 무엇을 만들어냈는가?
답은 다음 지시 ③에 나온다. 내가 처음에 외쳤던 것은 "글자가 읽히지 않는다, 겹친다, 배경의 명암이 혼재되어 있다"로, ②에서 벗어난 가독성 가이드라인의 반작용이었다.
제약을 벗어난 것은 화려함이 아니라 가독성의 붕괴를 낳고 있었다.
돌리고 있던 다이얼은 두 개였다.
| 다이얼 | 돌리면 |
|---|---|
| 야심 ("자유롭게 발상하라") | 화려함·놀라움이 나타남 (=이번 화려함의 정체) |
| 제약 (가이드라인 엄수 ⇄ 무시) | 조임 = 조화/가독성, 늦춤 = 붕괴 |
나는 "야심을 높이고 싶을" 때, 무심코 "제약도 함께 벗겨버리고" 있었다. 그래서 재작업(rework)이 발생했다.
그리고 ③에서 내놓은 답은 "가이드라인으로 돌아가기"가 아니라, "읽히는 구간과 보여주는 구간을 나누어 핀(pin)하기" —— 제약의 ON/OFF가 아니라 구간별로 나누어 사용하기였다. 보여줄 곳은 자유롭게, 읽혀야 할 곳은 조여서.
요약: 로그는 "AI와의 공동 작업"의 의사록이 된다
직접 해보며 얻은 가장 큰 수확은 심해 페이지 그 자체보다, "자신의 AI 세션 로그를 다른 모델에게 감사(Audit)하게 하는" 절차가 실제로 기능했다는 점이었다.
집계 스크립트는 수십 줄에 불과하며, usage와 tool_use를 세는 것뿐이다. 그것만으로 "어떤 지시가 얼마만큼의 비용을 썼는지", "에이전트가 무엇을 근거로 작성했는지", "나의 인과관계에 대한 추측이 어디서 빗나갔는지"를 감상이 아닌 사실로서 볼 수 있다.
내용 측면에서의 결론은 심플하다.
에이전트(Agent)에게 맡기는 업무에서 인간이 쥐고 있는 것은, 프롬프트(Prompt)의 숙련도보다는 사전에 컨텍스트(Context, 규칙·제약·방식)를 얼마나 잘 설정해 두느냐와 실행한 후에 어느 구간을 마무리할지에 대한 판단이었다.
화려함을 원한다면 야망의 다이얼을 돌리고, 무너뜨리고 싶지 않은 부분은 제약의 다이얼을 남겨둔다.
자신의 세션 로그(Session Log)를 한 번 다른 모델에게 읽혀보는 것도 재미있을 것이라 생각한다.
대체로, 기억보다는 사실이 더 많은 시사점을 준다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기