
Claude Fable가 Opus로 폴백(Fallback)된 부분만 Codex를 감독으로 하여 다시 수행하기
요약
Claude Fable 사용 중 모델이 Opus로 자동 폴백되어 작업 내용이 혼재되는 문제를 해결하기 위한 워크플로우를 다룹니다. Codex를 감독 모델로 활용하여 Claude Code CLI의 실행 결과를 검증하고, 의도한 모델의 결과물만 채택하는 구조적 재발 방지책을 제안합니다.
핵심 포인트
- Claude Fable 작업 중 Opus로의 자동 폴백 발생 시 데이터 혼재 문제 확인
- 로컬 로그를 활용하여 폴백 전 Fable의 마지막 상태 복원 방법 제시
- Codex를 감독(Supervisor)으로 설정하여 모델 실행 결과의 합격 여부 검증
- CLI 환경에서 모델 전환을 포착하고 의도한 모델의 결과만 채택하는 자동화 흐름 구축
Claude Fable 5에게 글을 쓰게 하고 있었더니, 생성 도중에 Claude Opus 4.8로 폴백(Fallback)되어 하나의 파일 안에 두 모델의 편집 내용이 혼재되었습니다. 작성 중이었던 것은 일련번호로 28개 파일로 나뉜 긴 문장이었습니다.
'어라?' 하고 느낀 것은 파일 12를 작성하던 도중이었습니다. 전환 알림은 뜹니다. 응답 모델 표시도 있습니다. 그럼에도 불구하고 여러 파일을 연속으로 편집한 뒤에는, 완성된 문장만 보고는 "여기까지가 Fable, 여기서부터가 Opus"라고 선을 그을 수 없었습니다.
수행한 작업은 두 가지입니다. 우선, 로컬 로그에서 "Fable이 마지막으로 작성한 상태"를 복원합니다. 다음으로, Codex의 GPT-5.6 Sol을 감독 역할로 세워, Claude Code CLI의 Fable에게 파일 단위로 의뢰하고, 실제 모델을 검사하여 합격한 실행 결과만 채택하는 흐름으로 바꿉니다. 이 기사는 그 구조 작업과 재발 방지에 대한 기록입니다.
이 기사에서 다루는 내용
다루는 내용은 다음 4가지입니다.
- 로컬 로그를 통해 Fable과 Opus의 경계를 조사
- Opus의 편집을 제외하고, 직전의 Fable 상태를 복원
- Codex에서 Claude Code CLI의 Fable로 재실행을 의뢰
- 실제 모델과 폴백(Fallback) 이벤트를 검사하여 합격한 후보만 채택
미리 말씀드리면, 혼재 사고 자체는 Claude 앱 측에서 발생했습니다. 그 이후에 구축한 CLI 운용에서는 자동 전환을 중단했으며, 실제로 포착한 이상은 주로 API 이용 한도입니다. 즉, 이 글은 "CLI 상의 Opus 폴백을 포착한 실록"이 아니라, 사고 이후에 폴백된 실행을 채택하지 않을 수 있는 흐름을 만든 기록입니다.
검증 환경은 macOS, Codex Desktop 내의 세션(cli_version: 0.144.0-alpha.4), GPT-5.6 Sol, Claude Code 2.1.205 ~ 2.1.207, macOS 표준 Ruby 2.6.10입니다. 완전한 러너(Runner) 구현은 싣지 않고, 구성과 검사의 요점만 게재합니다. Codex의 모델 구성은 변경될 가능성이 있으므로, 최신 정보는 공식 모델 안내를 확인해 주세요.
또한, 이것은 Fable의 세이프가드(Safeguard)를 회피하는 방법이 아닙니다. 전환이나 정지를 성공으로 오인하지 않기 위한, 그리고 허가된 작업을 적절한 문맥에서 다시 수행하기 위한 운용입니다. 내용 자체에 문제가 있다면 사람이 검토합니다.
Fable로 완수하고 싶었던 이유
Claude Fable 5는 Anthropic이 장시간·복잡·자율적인 작업에 적합하다고 안내하는 모델입니다. 다단계 계획, 위임, 자기 검증을 포함하는 에이전트 작업도 주요 용도로 꼽힙니다.
제 용도에서는 긴 자료를 가로질러 전제를 파악하고, 파일별 역할을 유지하며, 전후 연결성을 해치지 않고 문장을 수정하는 부분이 잘 작동했습니다. 단발적인 한 문장을 부탁했을 때보다, 긴 작업을 한 덩어리로 맡겼을 때 그 특징이 잘 나타납니다.
그래서 Fable에게 부탁한 일은 Fable로 완수하고 싶었습니다. 어느 모델이 더 뛰어난가 하는 문제가 아니라, 모델별 차이점을 포함하여 Fable을 선택했기 때문입니다.
폴백(Fallback)은 생성 도중에도 발생한다
Fable 5에는 요청마다 세이프티 체크(Safety Check)가 있습니다. 대상은 직전 메시지만이 아니라 대화 이력, 메모리, 파일 등 모델이 읽는 문맥 전체입니다. 차단되었을 때 자동 전환이 활성화되어 있다면, 많은 요청은 동일한 대화 상태 그대로 Opus 4.8로 재실행됩니다.
주의해야 할 점은, 전환이 입력 시점뿐만 아니라 생성 도중에도 일어날 수 있다는 것입니다. Anthropic의 공식 도움말에도 Fable이 중간까지 생성한 뒤 차단되어, 나머지를 Opus가 생성하는 경우가 명시되어 있습니다.
알림과 응답 모델 라벨은 표시됩니다. 따라서 "전환된 것을 모르는" 것은 아닙니다. 곤란한 점은 도구 실행을 포함한 긴 작업이 끝난 뒤입니다.
| 확인하고 싶은 것 | 화면만으로 알 수 있는가 |
|---|---|
| Opus로 전환되었는가 | 알림과 모델 표시로 알 수 있음 |
| ... |
2026년 6월 9일의 첫 발표에서는 세이프가드 발화는 전체 세션 평균 5% 미만이라고 설명되었습니다. 반면, 제 작업에서는 여러 번 발생했습니다. "Fable은 빈번하게 전환된다"는 일반론이 아니라, 긴 이력과 다수의 파일을 읽는 이번 작업에서는 무시할 수 없었다는 것이 정확한 표현입니다.
로그를 읽어보니, 하나의 파일 안에서 혼재되어 있었다
당초의 예상은 단순했습니다. 전환된 시점에는 알림이 뜨므로, 로그와 대조하면 경계를 즉시 구분할 수 있을 것이라고 생각했습니다.
Claude 앱 측에 남은 ~/.claude/projects/**/*.jsonl에는 각 assistant 메시지의 실제 모델명과 Write 또는 Edit의 대상이 기록되어 있습니다. 이를 28개 파일의 최종 상태와 대조해 본 결과, 우선 다음과 같은 사실을 알 수 있었습니다.
| 범위 | 최종 파일 상태 |
|---|---|
| 파일 1~10 | Fable만 존재 |
| ... |
여기까지는 예상대로였습니다. 빗나간 것은 그곳에 도달하기까지의 이력(history)이었습니다. 첫 번째 폴백(Fallback) 이후 Opus가 파일 828을 작성했고, 그 후 다시 Fable로 돌아와 파일 812를 덮어쓴 뒤, 파일 12를 마무리하던 도중에 다시 한번 Opus로 전환되었습니다. 경계는 하나의 선이 아니라, 동일한 범위를 두 모델이 오간 흔적이었습니다.
결정적으로, Opus의 응답 중에는 "Fable로 다시 작성했다"라고 스스로 신고한 사례까지 있었습니다. 작성한 것은 당신입니다. 문체, 파일의 업데이트 시간, AI의 자기 신고——그 어느 것도 판정 재료가 될 수 없습니다. 남는 것은 어떤 모델이 어떤 순서로 어떤 도구(tool) 조작을 성공시켰는가에 대한 기록뿐입니다.
폴백 행을 일부 가리고 추출하면 다음과 같은 형태였습니다.
{
"type": "system",
"subtype": "model_refusal_fallback",
...
일반적인 assistant 행에는 message.model이 있습니다. 다만, 이 JSONL은 Claude Code의 내부 형식이며 안정적인 공개 API가 아닙니다. 버전 업데이트 후에는 반드시 형식을 재확인해야 합니다.
Fable의 최종 상태까지 되돌리기
파일 11과 파일 12에는 남기고 싶은 Fable의 본문과, 제외하고 싶은 Opus의 편집 내용이 공존하고 있었습니다. 이 부분은 Codex에게 로그를 개별 분석하게 하여 다음 단계로 복원했습니다.
tool_use와 대응하는tool_result를 대조하여, 성공한Write와Edit만을 시계열로 나열한다.- 폴백 직전까지의
message.model == "claude-fable-5"조작만을 선택한다. - 첫 번째 Fable
Write로 가상 파일을 만들고, 이어지는Edit의old_string을new_string으로 순차적으로 치환한다. - 실제 파일에 들어간 Opus의 편집은 성공 순서의 역순으로 되돌린다.
- 복원 파일과 가상 파일의 글자 수, 내용, SHA-256을 비교한다.
대상 로그에서는 각 파일의 첫 성공 조작이 Write였기 때문에 빈 상태에서 재생할 수 있었습니다. 만약 처음이 Edit였다면 그 이전의 기준 파일이 필요합니다. 실패한 도구 호출을 재생해서도 안 됩니다. 이 부분은 범용 스크립트가 아니라, 이번 로그에 맞춘 일회성 포렌식(forensics)입니다.
결과는 파일 11과 파일 12 모두에서 복원 파일과 가상 파일이 해시(hash)까지 일치했습니다. "Fable다운 문장"으로 수동으로 맞춘 것이 아니라, 로그에 남은 Fable의 조작만을 재생한 상태로 되돌릴 수 있었다는 뜻입니다.
프롬프트 단위로 통째로 되돌릴 수 있는 상황이라면, Claude Code 공식 체크포인트 기능에서 /rewind를 하는 편이 더 간단합니다. 이번에는 하나의 실행 중간 단계까지 남기고 싶었기 때문에 로그를 사용했습니다.
Codex를 감독 역할로 하여 후보만 작성하게 하기
동일한 긴 세션에 동일한 지시를 다시 내리는 것만으로는 또다시 같은 문맥에서 멈출 수도 있습니다. 그래서 역할을 나누었습니다.
- Fable: 본문을 읽고, 생각하고, 작성한다.
- Codex: 입력을 구성하고, Claude Code CLI를 실행하며, 로그를 감사하고, 채택 여부를 결정한다.
실제 작업에서는 입력용, 개정 중, 승인 완료 파일을 구분하였고, 실행 전후의 해시도 저장했습니다. 재현한다면 더욱 안전하게 일회용 git worktree나 임시 복사본을 사용하여 Claude Code의 작업 공간 자체를 격리하는 것이 좋습니다.
프롬프트에 "원본 파일은 읽기 전용"이라고 적더라도 파일 권한을 보장해주지는 않습니다. --permission-mode acceptEdits로 동작시키는 이상, 지정되지 않은 변경을 감지하면 작업 환경 전체를 불채택할 수 있는 구성으로 만들어 둡니다.
Claude Code CLI를 Fable로 실행하기
Claude Code를 설치 및 인증한 상태에서, Codex로부터 다음과 같은 형태로 실행했습니다. --resume은 사용하지 않고, 파일 하나당 새로운 세션을 생성합니다.
set -euo pipefail
WORKDIR="$(pwd)/fable-worktree"
PROMPT_FILE="$WORKDIR/input/request.txt"
...
-p는 비대화형 (non-interactive) 실행입니다. --model로 Fable을 명시하고, 도구(tool)도 Read, Write, Edit로 제한합니다. --output-format json은 나중에 종료 상태와 session_id를 기계적으로 판정하기 위해 사용합니다.
지시서는 공통 규칙과 대상 파일의 짧은 브리프(brief)로 나누었습니다.
다음 순서로 자료를 끝까지 읽어주세요.
1. 공통 규칙
2. 대상 파일의 브리프
...
긴 대화 이력을 이어받지 않고, Fable이 필요한 자료만 읽는 방식입니다. 채택되지 않은 중간 출력물도 다음 세션의 입력으로는 사용하지 않습니다.
표준 출력과 생성 로그를 이중으로 검사하기
--model claude-fable-5를 붙이는 것만으로는 채택 조건으로 부족합니다. 해당 Fable이 도중에 Opus로 전환될 수 있기 때문입니다.
먼저 표준 출력의 JSON이 정상 종료되었는지 확인하고, session_id로부터 대응하는 로그를 찾습니다.
SESSION_ID="$(ruby -rjson -e '
row = JSON.parse(File.read(ARGV.fetch(0)))
ok = row["type"] == "result" &&
...
verify_fable_only.rb는 적어도 assistant의 실제 모델과 폴백 (fallback) 이벤트를 확인합니다. 핵심은 fail-closed (실패 시 차단) 방식으로 만드는 것입니다. 해석할 수 없는 행을 건너뛰도록 만들면, 깨진 로그가 "문제 없음"으로 통과될 수 있기 때문에 깨진 JSON도 채택하지 않습니다.
require "json"
models = []
fallback = false
...
modelUsage에는 세션 이름 생성 등 본문 이외의 모델이 섞일 수 있습니다. 이번에는 본문과 관련된 assistant.message.model과 system.subtype의 폴백 이벤트를 판정 근거로 삼았습니다.
모델 검사만으로 결과물을 승인해서도 안 됩니다. 실제 러너 (runner)에서는 다음 사항도 모두 실패로 취급합니다.
- API 이용 한도
- 권한 거부, 도구 에러
- 지정 외 파일의 변경
- 빈 출력, 또는 중간까지만 출력된 경우
- 지시한 요구사항을 충족하지 못하는 문장
하나라도 해당하면 승인 대상에 반영하지 않고, 부분 출력을 격리합니다. 첫 번째 구조 작업에서는 로그로부터 정밀하게 되돌렸지만, 이 구성으로 바꾼 이후에는 "불합격된 worktree를 버리는" 것만으로 충분합니다.
총 28개 파일을 처리 완료
처음에 Codex가 파일 11과 파일 12를 Fable 시점으로 되돌렸고, 이후에는 파일별로 실행·감사·승인을 반복했습니다. 최종적으로 총 28개 파일을 처리하여 수락된 Claude Code 실행 결과, 본문의 assistant 모델은 모두 claude-fable-5였습니다. claude-opus-4-8과 model_refusal_fallback은 0건이었습니다.
한편, CLI 운용 중에 실제로 발생한 이상은 Opus로의 폴백이 아니라 API 이용 한도였습니다. 중간 출력을 격리하고, 이용이 가능해진 후 새로운 세션에서 재실행했습니다. 이때의 재개는 사람이 지시했으므로, 이번 실행을 "완전 무인"이라고 부르지는 않습니다.
다만, 대기와 재개까지 Codex 측의 감시에 포함시킨다면, 모델 표시 확인도, 경계 판정도, 수동으로 되돌리는 작업도 중간에 개입하지 않고 진행할 수 있습니다. Fable과는 다른 모델이 외곽에 존재함으로써, Fable의 출력을 검사하고 실패를 실패로서 처리할 수 있게 되었습니다.
나중에 알게 된 사실: 자동 모델 전환은 끌 수 있다
Fable의 세이프가드 (safeguard)에 의해 메시지가 플래그(flag)되었을 때의 자동 전환은 설정에서 무효화할 수 있습니다. 미리 알았더라면 좋았을 것입니다. 2026년 7월 14일 기준 위치는 다음과 같습니다.
Claude 앱:
설정 > 기능 > 메시지가 플래그되었을 때 모델을 전환하기
Claude Code:
/config > 모델과 출력 > 메시지가 플래그되었을 때 모델을 전환하기
영어 표시는 Switch models when a message is flagged입니다.
이를 끄면, 차단(block) 시 Opus로 전환되지 않고 대화가 일시 중지됩니다. 이것만으로 Fable의 완수를 보장할 수 있는 것은 아닙니다.
그럼에도 불구하고, 혼재된 후보(candidate)가 생성되는 대신 '중지'로 처리할 수 있다는 점은 매우 큽니다. 중지되거나 불완전한 출력은 Codex가 감지할 수 있습니다. 원본 파일을 유지한 채 후보를 채택하지 않고, 필요한 문맥을 정리하여 새로운 Fable 세션으로 넘길 수 있습니다. 허용된 편집 작업을 재구성할 수 있는 경우에는 모니터링부터 재실행, 승인까지 Codex에 맡겨, 사람의 개입 없이 완수할 수 있는 설계가 됩니다.
내용 자체가 차단 대상이라면 이야기가 달라집니다. 재시도를 반복하지 않고 사람이 직접 검토합니다.
요약
이번에 효과를 본 것은 다음 3가지입니다.
- 문체가 아니라, 실제 모델명과 성공한 도구 조작(tool operation)을 통해 혼재된 부분을 특정한다
- 원본 파일에 직접 쓰게 하지 않고, 격리된 후보를 검사한 후 승인한다
- Codex를 감독 역할로 하여, 중지·혼재·불완전한 실행을 채택하지 않는다
어디까지가 어느 모델인지 선을 긋는 작업은 더 이상 하고 싶지 않습니다. 다음에 Fable에 긴 문장을 요청할 때는, 우선 자동 모델 전환을 끕니다. 그 상태에서 후보 파일의 생성과 감사는 Codex에 맡기고, 처음부터 이 구성으로 실행합니다.
참고
Discussion

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