Edit 툴 4종, 880회 실측 성공률 — replace가 이긴 이유와 patch의 토큰 블랙홀
코딩 에이전트를 만들 때 “모델이 코드를 어떻게 수정하게 할까?”는 보통 구현 디테일로 취급된다. Git 스타일 unified diff(apply_patch)나 퍼지 매칭(patch)이 사람 개발자에게 익숙하다는 이유로 기본값이 되기 쉽다. 하지만 LLM은 코드를 토큰 스트림으로 본다. 줄 번호 오프셋 계산, 컨텍스트 매칭, hunk 헤더의 산수 실수가 쌓이면 단순한 “실패”가 아니라 비싼 재시도 루프로 이어진다.
이 글은 Oh My Pi 하네스가 제공하는 4가지 코드 편집 툴 — replace, hashline, apply_patch, patch — 의 성공률과 토큰·비용 효율을 11개 LLM × 20개 TypeScript 태스크, 총 880회 실행으로 실측한 결과다.
결론부터: replace가 평균 성공률 85.0%로 압도적이다. patch는 평균 성공률 68.2%로 오히려 2위인데도 입력 토큰이 replace의 3.05배, 성공 1건당 비용은 2.8배로 최악이다. 성공률만 보면 안 되는 이유가 여기 있다.
TL;DR
| 툴 | 평균 성공률 | 11개 모델 중 최고 툴로 선택 | 비용/성공 |
|---|---|---|---|
replace | 85.0% | 8/11 | $0.0094 |
hashline | 74.5% | 2/11 | $0.0118 |
apply_patch | 59.1% | 1/11 | $0.0228 |
patch | 68.2% | 0/11 | $0.0260 |
replace는 “실패의 하한선”이 가장 높다. 11개 모델 최저 성공률이 60% — 어떤 모델이든 어느 정도는 고쳐낸다.patch는 어떤 모델에서도 최고 툴이 되지 못했고, 실패할 때마다 파일 전체 재독 → 더 큰 패치 재시도 루프로 토큰을 태운다.hashline은 구조적 정밀도가 필요한 모델(kimi-k3, qwen3.7-plus)에서 강점을 보였다.apply_patch는 mimo-v2.5 한 모델만 85%로 최고 툴로 선택 — 모델별 편향이 뚜렷하다.
1. 하네스의 4가지 edit 툴
| 툴 | 동작 방식 | 장점 | 실패 모드 |
|---|---|---|---|
replace | path, startLine, endLine, newText — 줄 범위를 통째로 교체 | 컨텍스트 드리프트 없음, 지역 수정에 출력 토큰 최소 | 줄 번호가 밀리면 off-by-one |
hashline | [파일#태그] 콘텐츠 해시 헤더 + SWAP/DEL/INS 연산 | 스냅샷 검증이 결정적, 낡은 줄 번호에 면역 | 해시 문법을 엄격히 따라야 함 |
apply_patch | 표준 unified diff (@@ -N,M +N,M @@) | Git 형식, 학습 데이터에 익숙 | hunk 헤더 줄 수를 모델이 자주 잘못 계산 |
patch | oldContext 문자열을 찾아 newContext로 교체 | 줄 번호 불필요, 프롬프트가 직관적 | 공백/들여쓰기 민감, 다중 턴 재시도 루프 유발 |
2. 측정 설계
- 스케일: 11개 모델 × 4개 툴 × 20개 태스크 = 880회 시도 (arm당 20회, best-of-1)
- 태스크: 100% TypeScript — Core TS(45%), Express/Node(25%), React+TSX(20%), DOM+jsdom(10%). 난이도는 Easy 25% ~ Nightmare(10+ 파일 아키텍처 리팩터링) 10%
- 검증: Docker verifier 컨테이너(
--network=none)에서tsc --noEmit+ 숨은 동작 테스트. 모델이 자기 환경을 속일 수 없게 격리 - 설정: 모든 실행은
--thinking off— 추론 토큰 노이즈를 제거하고 순수한 툴 콜·편집 정밀도만 측정 - 비용: 공식 리스트 가격 기준. 429 쿼터 실패(인프라 원인)는 0토큰으로 제외, 에이전트 유발 재시도는 100% 부과
3. 툴별 성공률
11개 모델 각각에서 해당 툴로 20개 태스크를 돌린 성공률의 평균·중앙값·하한·상한:
| 툴 | 평균 | 중앙값 | 최저 | 최고 | 총 성공 / 220 |
|---|---|---|---|---|---|
replace | 85.0% | 85% | 60% (mimo-v2.5) | 100% (deepseek-v4-flash) | 187 |
hashline | 74.5% | 80% | 25% (qwen3.8-max) | 95% (deepseek-v4-flash) | 164 |
apply_patch | 59.1% | 65% | 0% (qwen3.8-max)¹ | 90% (deepseek-v4-flash) | 130 |
patch | 68.2% | 70% | 35% (minimax-m3) | 85% (kimi-k3·qwen3.8-max·deepseek-v4-flash·deepseek-v4-pro) | 150 |
¹ qwen3.8-max × apply_patch arm은 토큰 0·비용 $0 — 쿼터/인프라 실패로 보이며 실측치가 아니다. 제외 시 apply_patch 평균은 65.0%.
여기서 가장 중요한 지표는 하한선(floor) 이다. replace는 가장 못하는 모델(mimo-v2.5)도 60%를 기록했다. 반면 hashline의 바닥은 25%, apply_patch는 사실상 측정 불가(0%)였다. 좋은 툴은 모델의 천장을 높이는 게 아니라 바닥을 끌어올린다 — 그리고 replace가 유일하게 그 역할을 했다.
흥미로운 반전: 모든 툴에서 가장 높은 성공률은 deepseek-v4-flash가 가져갔다 (replace 100%, hashline 95%, apply_patch 90%, patch 85% 공동 1위). 모델 역량이 받쳐주면 어떤 툴이든 잘 쓰지만, 툴은 모델의 바닥을 결정한다.
4. 토큰 & 비용: 성공률 너머
성공률만 보면 patch는 2위다. 그런데 실제 지출을 보면 이야기가 완전히 달라진다 (44개 arm 합산):
| 툴 | 총 입력 토큰 | 총 출력 토큰 | 캐시 읽기 | 총 비용 | 태스크당 입력 | 평균 $/성공 |
|---|---|---|---|---|---|---|
replace | 4.26M | 197k | 6.89M | $1.78 | 19.4k | $0.0094 |
hashline | 6.51M | 260k | 8.59M | $2.07 | 29.6k | $0.0118 |
apply_patch | 8.82M | 243k | 12.07M | $2.26 | 40.1k | $0.0228 |
patch | 13.01M | 376k | 16.79M | $3.28 | 59.1k | $0.0260 |
patch는 태스크당 평균 59.1k 입력 토큰 — replace(19.4k)의 3.05배다. 성공률 격차(68% vs 85%)보다 토큰 격차가 훨씬 크다. 성공 1건당 비용으로 환산하면 patch는 replace의 2.8배였고, 880회 전체 총지출($9.38)에서도 replace는 4개 툴 중 가장 적게 썼다.
전체로는 631회 성공(71.7%) 이었다.
5. 모델 × 툴 상호작용 매트릭스
성공률(%) — 굵은 값은 해당 모델의 최고 툴:
| 모델 | apply_patch | hashline | patch | replace |
|---|---|---|---|---|
| deepseek-v4-flash | 90 | 95 | 85 | 100 |
| qwen3.8-max | 0¹ | 25 | 85 | 95 |
| glm-5.2 | 45 | 80 | 45 | 95 |
| kimi-k2.7-code | 65 | 80 | 70 | 90 |
| hy3 | 75 | 80 | 55 | 90 |
| kimi-k3 | 25 | 90 | 85 | 85 |
| mimo-v2.5 | 85 | 60 | 60 | 60 |
| mimo-v2.5-pro | 50 | 80 | 65 | 85 |
| deepseek-v4-pro | 80 | 80 | 85 | 85 |
| qwen3.7-plus | 75 | 85 | 80 | 70 |
| minimax-m3 | 60 | 65 | 35 | 80 |
툴별 우승 횟수: replace 8, hashline 2, apply_patch 1, patch 0.
replace가 11개 중 8개 모델에서 최고 — 현대 LLM은 번호가 매겨진 read 출력만 있으면 절대 줄 번호 이해에 강하다. 오프셋 산수를 아예 제거해 버리는 게 핵심이다.hashline은 kimi-k3(90%)와 qwen3.7-plus(85%)처럼 구조적 정밀도를 잘 따르는 모델에서 빛났다. 콘텐츠 해시 태그가 낡은 앵커 덮어쓰기를 원천 차단한다.apply_patch는 mimo-v2.5 한 모델만 85%로 선호. 나머지 모델에선 hunk 헤더 산수 실패가 잦았다.patch는 단 한 모델의 최고 툴도 되지 못했다.
6. 사례 연구: glm-5.2, 툴 하나로 50%p가 갈렸다
같은 모델, 같은 20개 태스크에서 툴만 바꿨을 뿐인데:
replace : 95% (19/20) | 298,956 입력 토큰 | $0.3433patch : 45% ( 9/20) | 1,481,206 입력 토큰 | $1.0886 (토큰 4.95배, 비용 3.2배)apply_patch : 45% ( 9/20) | 1,482,332 입력 토큰 | $1.0882replace로 바꾸자 성공률이 45% → 95%로 두 배가 되면서 토큰은 79.8% 감소했다. 툴 설계가 모델의 실제 코딩 능력보다 더 큰 변수인 경우가 있다는, 가장 극적인 증거다.
7. 왜 patch는 실패 루프에 빠지는가
원본 이벤트 스트림(sample-failed-patch-loop-glm52.jsonl)을 보면 패턴이 반복적이다:
graph TD A[patch 컨텍스트 매칭 실패] --> B[read로 파일 전체 재독] B --> C[컨텍스트를 더 크게 붙인 patch 재시도] C -->|여전히 공백/들여쓰기 미스매치| B C -->|턴 한도 초과| D[실패 · 토큰 폭증]- 미세한 공백 차이(탭 vs 스페이스, 줄바꿈, 들여쓰기)로 첫 매칭이 실패한다.
- 모델은 거의 예외 없이 파일 전체를 다시 읽어 재정렬한다.
- 더 큰 컨텍스트로 재시도하지만, 근본 원인(컨텍스트 오해)이 해결되지 않아 또 실패한다.
- 2~4턴 반복 후 턴 한도에 걸려 실패 — 태스크 하나에 75,000+ 토큰을 태운 사례도 있다.
반면 replace·hashline은 실패 시 “정확한 앵커 오류”라는 결정적 피드백을 주므로 모델이 즉시 재조준한다. 실패가 비싸지 않은 구조가 핵심이다. 퍼지 매칭은 컨텍스트 오해를 숨기고, 그 대가를 토큰으로 지불하게 만든다.
8. 하네스에 주는 교훈
- 기본값은
replace로. 최신 프론티어·중간 모델에서 가장 높은 신뢰성, 가장 낮은 지연, 가장 적은 토큰 낭비. - 대형 파일·동시 편집 환경에서는
hashline. 1,000줄 이상 파일에서 전체 블록 교체가 동시 편집을 덮어쓸 위험이 있다면, 콘텐츠 해시 태그가 낡은 앵커 문제를 제거한다. - 순수 컨텍스트 diff
patch는 피할 것. 컨텍스트 블록 형식에 특화 파인튜닝된 모델이 아니라면, 실패 루프가 컨텍스트 윈도우와 API 예산을 빠르게 소진한다. - 성공률 단일 지표로 툴을 평가하지 말 것. 이 벤치마크처럼 성공률 2위인 툴이 비용은 최악일 수 있다. 성공 1건당 비용($/success)과 토큰 분포를 함께 봐야 한다.
9. 데이터 & 재현
이 글의 모든 수치는 공개된 원본 데이터에서 직접 재계산했다. 벤치마크 데이터, 원본 이벤트 스트림, 재현 스크립트는 omp-bench-review 저장소에 포함돼 있다 (누구나 같은 인프라로 재현 가능):
data/summary-leaderboard.json— 44개 arm 전체 메트릭 (토큰 버킷, 가격, wall time)data/model-rankings.csv— 스프레드시트용 테이블data/raw-samples/— 실제 JSONL 이벤트 스트림 3종 (완벽한 1턴 replace / patch 실패 루프 / 429 쿼터 오류)scripts/analyze-results.ts·scripts/export-charts.ts— 리더보드·차트 재현 스크립트
bun run analyze # 리더보드 출력bun run charts # ASCII 차트 출력검증은 Docker 격리 verifier에서 tsc --noEmit + 숨은 동작 테스트로 수행했고, 실행 인프라는 Azure Spot(시간당 약 0.02달러 수준)의 일회성 VM으로 전체 캠페인 비용을 10달러 미만으로 유지했다.