/prewalk는 저비용 모델에 계획이 아니라 작업 궤적(trajectory)을 넘겨줍니다. 그 결과 SWE-Bench Pro에서 프런티어 모델 통과율의 92~97%를 유지하면서 비용은 절반 수준으로 줄었습니다.
따라 하는 건 원숭이가 제일 잘하죠! 🍌

비용 대비 통과율, 7개 구성 · SWE-Bench Pro · 모델 단독 = oneshot · 태스크당 비용에는 프런티어 모델이 진행한 초반 턴이 포함 · † Flash 3.5로 실행 · ‡ 5.6 Luna로 실행
이런 제안은 들어 보셨을 겁니다. 직접 적용해 본 분도 있겠죠. 비싼 모델이 설계를 더 잘하는 건 분명하지만, 파이프라인 전체에 쓰기에는 아깝습니다. 그렇다면 "어려운 부분"만 맡기면 어떨까요?
코드를 읽고, 깊이 생각하고, 정확한 계획을 세웁니다. 그다음 가격이 10분의 1인 모델이 그 계획을 실행합니다. 시니어 아키텍트와 주니어 엔지니어의 분업이죠.
꽤 그럴듯하죠?
위 차트에서 Opus 4.8 + /plan† 라벨이 붙은 빨간 점을 찾아보세요. Opus가 읽기 전용으로 계획을 세우고 Gemini Flash가 구현한 결과는 태스크당 $3.18, 12.7분, 통과율 84.6%입니다.
반면 Opus가 주니어 없이 처음부터 끝까지 혼자 처리하면 $2.78, 10.1분, 통과율 84.6%입니다.
"비용 절감" 방식이 아끼지 않은 쪽보다 14% 더 듭니다. 어라?

문제는 아키텍처 다이어그램보다 더 앞단에 있습니다. 사람들은 에이전트의 비용을 사람 인건비 계산하듯 매깁니다. 시니어의 시간은 비싸니 시니어 투입을 최소화하자는 식이죠.
하지만 에이전트가 일하는 동안 비용이 많이 나가는 부분은 수정이나 구현, 심지어 사고도 아닙니다. Opus가 코드를 고치는 데는 돈이 들지 않습니다. Opus가 코드를 읽는 데 돈이 듭니다.
토큰이 어디에 쓰였는지 보여 주는 분포를 한번 보세요. 표본이 일화적인 건 인정하지만, 완전 자동화된 에이전트도 크게 다르지 않습니다.

도구 호출 약 200만 회에 걸친 토큰 18.1억 개 · "작업 수행"(모든 수정과 쓰기)은 9%; 비용을 키우는 건 읽기이고, 두 모델 모두 읽기에 정가를 냅니다
토큰의 9%만이 수정에 쓰입니다. 나머지는 전부 읽기입니다. 이 비율은 특정 하니스의 특이한 성향도 아니고, "고칠" 수 있는 문제도 아닙니다. 저희도 해 봐서 압니다. snapcompact가 나온 것도 그래서입니다.
어떤 에이전트, 어떤 모델, 어떤 스캐폴드든 청구서의 본질은 결국 O(reads)입니다.
이 점을 염두에 두고 /plan을 쓰려는 이유를 하나씩 짚어 보겠습니다.
실제로 어떤 모습인지, 지나치게 공들여 만든 다이어그램으로 살펴보겠습니다.

맨 위 리본을 보세요. Opus가 base.py, signing.py, 테스트 파일(회색 카드 스무 장)을 읽고 계획을 쓴 뒤 퇴장합니다. 그러면 Flash는 그 멋진 문서를 받고 제일 먼저 무엇을 할까요? base.py와 테스트 파일을 다시 읽습니다. 계획은 파일이 아니고, 산문은 편집할 수 없기 때문입니다. 회색 읽기 블록은 계속 쌓이고, 처음에는 Opus 가격으로, 그다음에는 Flash 가격으로 또 쌓입니다. 두 번째 독자를 두는 것이 비용 최적화가 될 방법은 없습니다.
계획 문서는 말 그대로 엽서입니다. 가 본 적 없는 모델에게 여정을 설명하는 글이죠.
실제로 가치 있는 것을 넘길 수 있는 수단은 컨텍스트 윈도우 자체입니다.
/prewalk는 다음과 같이 동작합니다.
핵심은 다음과 같습니다.

오픈소스 하니스로 작업하면 좋은 점은 다른 사람들과 일하는 방식을 이야기할 수 있다는 것입니다. 그러다 보면 거의 모두가 전혀 다른 환경을 쓰고 있다는 걸 알게 됩니다.
저는 쉬운 태스크나 중간 난이도 태스크를 가끔 프런티어 모델로 시작했다가, 몇 턴 뒤 Kimi K27로 바꾸곤 했습니다. Kimi K27이 평소처럼 생각의 루프에 빠지지 않게 하려는 것이었죠. 이 방식이 합리적인지는 굳이 측정해 보지 않았습니다. 다른 누군가도 같은 방법을 쓴다고 말하기 전까지는요.
당연히 벤치마크를 돌려 봐야 했습니다. 우리가 바보짓을 한 걸까, 아니면 실제로 효과가 있을까? 있다면 언제 그럴까?
첫 번째 시도: 정해진 턴(예를 들어 4번째)에서 교체합니다. 돌이켜 보면 분명히 좋지 않았습니다. 프런티어 모델이 4턴째에도 길을 잃은 경우가 있고, 이미 수정을 모두 끝낸 경우도 있었으니까요. 두 번째 시도: 첫 번째 수정 직후에 교체합니다. 모델이 패턴을 한 번, 그 자리에서, 같은 스타일로 보여 준 셈이라 꽤 괜찮았습니다. 다만 여전히 까다로웠습니다. 작은 모델이 갑자기 태스크가 끝났다고 선언하는 일이 잦았거든요.

해결책은 본의 아니게 양치기 역할을 맡게 된 에이전트에게 계획을 단계별로 풀어 쓰게 하고, 실행에 들어갈 준비가 되면 항목마다 검증 단계가 붙은 TODO 목록을 만들게 하는 것이었습니다. 그 뒤 코드를 한 군데 수정하면, 그때 교체를 발동합니다.
수정 여부만으로 교체 시점을 정하면 좋지 않습니다. 여기서는 할 일 목록이 여전히 아주 중요한 역할을 합니다. 작은 모델은 계획이나 검증 단계, 심지어 자기가 무엇을 하고 있는지도 잊을 수 있지만, 끈질기게 따라붙는 할 일 알림만큼은 잊지 못합니다. 덕분에 공짜로 방향을 잡아 줄 수 있죠.
또 하나 재미있는 실패 사례가 있습니다. 안내 역할을 맡은 GPT 5.6은 60개짜리 TODO 목록을 만들어 놓고 한꺼번에 완료 처리하기를 유난히 좋아합니다(뭘 해도 보상을 주는 걸까요?). 그래서 프롬프트에 항목 수 제한을 꼭 넣어야 합니다.
GPT-5.6 Sol:
| 구성 | 통과율 | 비용 | 소요 시간 |
|---|---|---|---|
| 실행 모델: oneshot (GPT 5.6 Luna) | 77% | $0.60 | 570초 |
| /prewalk | 85%(+10%) | $1.04(−39%) | 300초(−47%) |
| GPT 5.6 Sol: oneshot | 88% | $1.71 | 372초 |
Sol 통과율의 97%를 비용 61%로 달성했고, 세 구성 중 가장 빠릅니다. Sol이 초반 이후에는 느린 프런티어 토큰을 더 쓰지 않고, Luna는 숲속에서 길을 잃고 턴을 낭비하지 않기 때문입니다.
Opus 4.8:
| 구성 | 통과율 | 비용 | 소요 시간 |
|---|---|---|---|
| 실행 모델: oneshot (Gemini Flash 3.5) | 60% | $1.16 | 360초 |
| /prewalk | 78%(+30%) | $1.46(−47%) | 402초(−34%) |
| Opus 4.8: oneshot | 85% | $2.78 | 606초 |
Opus 통과율의 92%를 비용 53%, 1.5배 빠른 속도로 달성했고, oneshot Flash보다 18포인트 높습니다.
넘어가기 전에 한 가지만 더 짚겠습니다. 위로 돌아가 django-13279 테스트 실행의 리본을 보고, 거기에 없는 것을 찾아보세요. 바로 꼼수입니다!
SWE-bench의 모든 태스크는 몇 년 전에 공개적으로 실제 수정된 버그입니다. 시험의 정답이 GitHub에 있는 셈이죠.
아래는 정답을 찾으려고 웹을 뒤진 실행의 비율입니다. 이런 얌체들!

같은 모델, 같은 스캐폴드, 거의 같은 아이디어인데도 행동은 크게 다릅니다. /plan는 왜 여전히 꼼수를 쓰고 /prewalk는 쓰지 않을까요?
저희가 내놓을 수 있는 가장 그럴듯한 설명은 prewalk이 양쪽 끝에서 꼼수의 싹을 잘라 버린다는 것입니다. 꼼수는 유능한 모델이 절박해졌을 때 하는 행동입니다. 단독 실행 기록을 보면 GitHub 조회는 탐색이 막힌 실행 중반에 시작됩니다. Sol은 14턴 즈음, Opus는 12턴 즈음에 무너집니다. prewalk은 프런티어 모델을 작업 예산의 초반, 중앙값 기준 약 7턴에서 끝냅니다. 접근법을 도출하고 첫 수정을 반영하는 확신에 찬 단계에서 빠져나오므로, 구글링을 시작하는 단계는 한참 멀었을 때입니다. /plan는 어느 쪽 자비도 받지 못합니다. 턴 제한이 없고, 결과물이 코드에 수정을 한 번도 시험해 보지 않은 채 수정이 어떻게 동작해야 하는지 설명하는 포괄적인 문서이기 때문입니다. 이런 과제야말로 절박함을 키우기 딱 좋습니다.
반대로 실행 모델이 물려받는 것은 절박함과 정반대의 컨텍스트입니다. 접근법이 이미 코드와 부딪혀 검증을 통과한 상태죠. 재현 코드가 작성되어 있고, 첫 수정이 반영되었으며, 체크리스트가 하나씩 지워지고 있습니다. 이 컨텍스트에는 검색하는 것처럼 보이는 요소가 전혀 없으니, 흉내 내기 기계는 검색하지 않습니다.
새로운 아이디어는 아닙니다. 가장 오래된 기법인 prefill입니다. 어시스턴트가 원하는 대로 동작하지 않나요? 어시스턴트의 턴을 직접 시작해 주면, 모델은 그 말을 자기가 한 것처럼 이어 갑니다.
prefill은 문법 제약 디코딩이 나오기 전에 출력 일관성을 맞추려는 꼼수로 시작되었습니다. omp를 비롯한 많은 도구가 지금도 씁니다. 세션 제목은 아주 작은 로컬 모델이 만드는데, 이 모델은 턴을 <title>로 시작해 주면 더 잘 해내거든요.
그렇게 작은 모델은 형식을 지키라고 설득할 수는 없지만, 속여서 지키게 할 수는 있습니다.
그러다 레드팀이 반대쪽 끝을 발견했습니다. "물론이죠, 방법은 이렇습니다…"를 prefill하면 훨씬 큰 모델도 자신의 거부 응답을 가볍게 넘어갑니다. 모델에게는 자기가 한 말과 입에 넣어 준 말을 구분할 통로가 없고, "이미 수락했다"는 일관성이 시스템 프롬프트를 이기기 때문입니다. prefill은 대표적인 탈옥 유형이 되었고, 지금은 추론 계층에서 거의 모든 곳이 막아 둘 만큼 강력합니다. 제 기억이 맞다면 Anthropic은 Sonnet 4.5부터 막았습니다. JSON 모드와 구조화된 출력이 정당한 용도를 대체하면서 prefill은 자취를 감췄습니다.
그래도 이 원리는 작동을 멈출 수 없습니다. 재미있는 특이 동작이 아니라 자기회귀가 바로 그런 것이기 때문입니다. 이제 프런티어 모델에 prefill 토큰을 열 개 넘겨줄 수는 없습니다. 일부 모델은 thinking을 끄지도 못하게 합니다. 악의적으로 prefill한 턴을 넣지 못하게 하려는 것이죠(모델이 사고 과정에서 어시스턴트의 thinking 블록이 없다는 점을 알아차리길 바라면서요). 하지만 악의 없이 prefill한 턴 열 개를 넘겨주는 것까지 막을 수는 없습니다. 이미 일어난 탐색과, 체크 표시가 절반쯤 된 할 일 목록 같은 것들이죠.
이 기능은 omp에 업스트림했고, 오늘부로 --prewalk, --prewalk-into <model>, 또는 간단히 /prewalk으로 사용할 수 있습니다.
거의 어디에나 쉽게 구현할 수 있으니, 기회가 된다면 한번 써 보시고 결과를 알려 주세요!