실제 Pull Request를 통한 AI 코딩 에이전트 벤치마킹
요약
실제 오픈소스 프로젝트의 최신 Pull Request를 활용하여 AI 코딩 에이전트의 성능을 평가하는 새로운 벤치마크 'octobench'를 소개합니다. 기존 벤치마크의 데이터 오염과 주관적 평가 문제를 해결하기 위해 2026년 머지된 실제 태스크를 기반으로 설계되었습니다.
핵심 포인트
- 데이터 오염 방지를 위해 모델 학습 데이터 이후의 최신 PR 활용
- 단순 모방이 아닌 실제 프로젝트 테스트 통과 여부로 성능 측정
- 5개 언어와 다양한 난이도의 시나리오를 포함한 범용성 확보
- 실험 결과 오픈 모델 기반 octomind가 Claude Code보다 높은 성능 기록
합성된 퍼즐도, 오염된 테스트 세트도 없습니다. 5개 언어에 걸쳐 2026년에 머지(merged)된 PR에서 수집한 25개의 태스크를 각 프로젝트 자체의 홀드아웃 테스트(held-out tests)로 평가했습니다. 기본 설정 상태의 4개 에이전트를 비교했습니다. 오픈 모델을 사용한 octomind는 25개 중 24개를 해결하며 Opus를 탑재한 Claude Code보다 앞섰으며, 동일한 모델을 다른 하네스(harness)에서 사용했을 때는 비용이 두 배로 들면서 19개만 해결했습니다. 우리가 이 벤치마크를 어떻게 구축했는지, 그리고 이를 통해 무엇을 배웠는지 소개합니다.
우리는 실제로 신뢰할 수 있는 단 하나의 수치를 원했습니다. 코딩 에이전트에게 관리자가 평범한 화요일에 마주하는 종류의 작업—실제 버그, 실제 기능 요청, 실제 코드베이스—을 맡겼을 때, 프로젝트 자체 테스트 스위트(test suite)가 통과시키는 수정 사항을 얼마나 자주 제공하는가 하는 점입니다.
기존의 공개 벤치마크 중 그 수치를 제공할 수 있는 것은 없었기에, 우리는 octobench를 구축했습니다. 이 포스트는 우리가 어떻게 구축했는지, 그 과정에서 무엇이 문제였는지, 그리고 스코어보드가 무엇을 말해주는지에 대한 이야기입니다.
기존 벤치마크를 사용하지 않은 이유
대중적인 테스트 세트들을 사용할 때 두 가지 문제가 계속 발목을 잡았습니다.
오염 (Contamination). 잘 알려진 벤치마크들은 너무 오래되어, 최첨단 모델(frontier models)들이 훈련 데이터 내에서 해당 수정 사항들을—때로는 커밋 단위로 문자 그대로—이미 본 상태입니다. 한 번은 어떤 모델이 알 권리가 없는 커밋 해시(commit hash)에 대해 git show를 실행하는 것을 포착하기도 했습니다. 그것이 무엇을 측정하든, 그것은 문제 해결 능력이 아닙니다.
취향 기반 평가 (Taste-grading). 많은 벤치마크 태스크들은 구현자의 임의적인 선택—내부 변수 이름, 에러 메시지의 정확한 문구 등—을 단언하는 테스트에 의해 평가됩니다. 에이전트가 관리자 수준의 수정안을 작성하고도, 원래 작성자와 에러 메시지 표현 방식이 다르다는 이유로 실패할 수 있습니다. 이는 엔지니어링이 아니라 모방 능력을 측정하는 것입니다.
따라서 설계 목표는 다음과 같았습니다: 실제 태스크, 신선한 태스크, 공정한 평가.
25개 태스크, 5개 언어, 대부분 모델보다 최신임
우리는 존경받는 오픈 소스 프로젝트들로부터 최근 머지된 실제 Pull Request에서 모든 태스크를 수집했습니다: werkzeug, click, anyio, pydantic, twig, carbon, symfony, guzzle, commonmark, uuid, rayon, chrono, bytes, serde-json, fmt, yaml-cpp, catch2, spdlog, eslint, fastify, undici, pino, pino-pretty.
이 목록은 두 가지 축을 기준으로 의도적으로 구성되었습니다. 언어 (Languages): python, php, rust, c++, js 등 5가지 언어를 포함했습니다. 이는 python에는 능숙하지만 CMake 빌드에서 길을 잃는 에이전트는 범용 코딩 에이전트 (general coding agent)가 아니기 때문입니다. 최신성 (Freshness): 모든 수정 사항은 2026년에 병합되었으며, 대부분 현재 모델의 학습 데이터 차단 시점 (training cutoffs) 이후의 것입니다. 일부는 데이터 수집 후 불과 며칠 이내의 것입니다. 한 사례인 chrono의 역방향 날짜 반복자 (reversed date iterators)는 우리가 이를 선택한 당일 아침에 병합되었습니다. 학습 데이터 차단 시점이 진행됨에 따라 다시 수집할 수 있는 벤치마크는 노후화될 수 없는 벤치마크입니다.
시나리오 구성은 한 줄짜리 충돌 수정 (crash fixes)부터 여러 파일에 걸친 기능 구현까지 다양하며, 각 사례는 수정 사항이 존재하기 직전의 순간을 재구성합니다:
- setup.sh는 수정 전 커밋 시점의 저장소를 체크아웃합니다. 이는 단일 커밋 얕은 복제 (shallow clone) 방식으로 이루어지므로, 정답이 git 오브젝트 저장소 (git object store)에 숨겨져 있지 않습니다. 또한 툴체인 (toolchain)을 준비하고, 에이전트가 단순히 업스트림 (upstream) 수정 사항을 가져올 수 없도록 git 원격 저장소 (git remote)를 제거합니다.
- 에이전트는 작업 프롬프트 (task prompt)를 받고 고용된 계약자처럼 저장소 내에서 작업합니다.
- 에이전트가 작업을 마치면 validate.sh가 실행됩니다. 이는 에이전트가 한 번도 본 적 없는, 병합된 수정 사항의 테스트 파일들을 가져와서 에이전트가 테스트 스위트 (test suite)에 수행했을지 모르는 모든 작업을 덮어쓰고, 정확히 해당 테스트들을 실행합니다. 프로젝트 자체 유지 관리자 (maintainers)가 작성한 프로젝트 고유의 테스트가 통과 여부를 결정합니다.
- LLM 판사 (LLM judge)가 diff와 로그를 바탕으로 작업 품질을 별도로 평가합니다.
모든 사례가 벤치마크에 포함되기 전, '실패 후 통과 (fail-to-pass)'를 입증해야 했습니다. 즉, 홀드아웃 테스트 (held-out tests)가 수정 전 코드에서는 실패해야 하며, 실제 병합된 수정 사항이 적용되었을 때는 통과해야 합니다. 증명이 없으면 사례로 인정되지 않습니다.
양방향 모두에서 부정행위를 하지 않는 프롬프트 작성하기
20개의 태스크에 대해서는, 각 병합된 커밋(merged commit)을 대상으로 전용 에이전트(octomind의 developer:reverse-spec)를 실행하여 해당 커밋을 생성했을 법한 요청을 재구성했습니다. 그 후 '도출 가능성 규칙(derivability rule)'이라는 단 하나의 규칙을 적용하여 수동으로 큐레이션했습니다. 즉, 숨겨진 테스트(hidden tests)가 단언하는 모든 사항은 프롬프트로부터 도출 가능해야 합니다. 버그 수정(Bug fixes)에는 짧고 비공식적인 프롬프트를 제공했는데, 이는 올바른 수정이라면 무엇이든 통과하기 때문입니다. 테스트가 공개 API 이름이나 정확한 출력 형식을 고정하는 기능(Features)의 경우에는 스펙이 엄격한(spec-tight) 버전을 제공했습니다. 실제 요청자는 와이어 포맷(wire format)을 명시할 것이기 때문입니다.
나머지 5개(언어당 하나씩)에 대해서는 실제 GitHub 이슈(issue) 텍스트를 그대로 사용하되, 수정 사항이 유출될 수 있는 부분(예: 한 작성자가 친절하게 "X를 수행하는 PR이 준비되었습니다"라고 작성한 경우)만 제거했습니다. 이는 다른 측면을 테스트합니다. 즉, 때로는 예상 출력 대신 스크린샷이 포함된 사용자 형태의 버그 보고서를 유지보수자 수준의 수정 사항으로 전환하는 능력을 테스트하는 것입니다.
분리해낸 기술적 역량에 따른 몇 가지 주요 사례는 다음과 같습니다:
- anyio의 cancel-scope 스핀 - asyncio 이벤트 루프가 왜 CPU 코어를 고정(pins)하는지 이해해야 하는 4줄짜리 수정 사항입니다. 차이(diff)는 미미하지만, 깊은 비동기 추론(async reasoning)이 필요합니다.
- guzzle의 쿠키 접두사(cookie prefixes) - 세 개의 독립적인 함정이 포함된 27줄의 코드입니다. 단순한
startsWith("__Secure-") && !secure방식의 수정은 테스트의 절반을 통과하지 못합니다. - commonmark의 fenced-code 탭 - 한 사용자가 스크린샷과 함께 "코드 블록이 때때로 첫 번째 문자를 잃어버립니다"라고 보고했습니다. 별도로 보관된 피스처(fixtures)에는 이슈에서 언급되지 않은 케이스들이 포함되어 있습니다. 오직 진정한 근본 원인(root-cause) 수정만이 통과하며, 증상에 대한 패치(symptom-patch)는 실패합니다.
- pino-pretty의 제어 문자(control characters) - 너무 광범위한 정화(sanitizing)를 방지하기 위해 존재하는 두 개의 숨겨진 테스트가 있습니다. 이 테스트들은 고장 난 코드에서는 통과하지만, 신뢰 경계(trust boundary)를 존중하지 않는 모든 수정 사항은 실패하게 만듭니다.
자체 서비스 이용 (Eating our own dogfood)
최종 실행 전, 세 명의 검토자가 모든 홀드아웃 단언(held-out assertion)을 모든 프롬프트에 대해 대조하며 읽었습니다. 이 감사(audit) 과정에서 실제 문제들이 발견되었습니다. 이는 에이전트의 문제가 아니라, 우리의 벤치마크 자체의 문제였습니다. 한 사례의 경우, 테스트가 이슈(issue)에서 한 번도 인용되지 않은 에러 메시지의 정확한 문구를 단언하고 있었습니다. 두 개의 프론티어 에이전트(frontier agents)는 완벽한 수정안을 생성했으며(그중 하나는 유지 관리자와 동일한 에러 코드 번호를 선택하기까지 했습니다), 두 에이전트 모두 문구(wording) 문제로 실패했습니다. 우리는 해당 사례를 교체했습니다. 또 다른 사례의 숨겨진 테스트는 해당 이슈 텍스트와 모순되었습니다. 세 번째 사례는 홀드아웃 테스트가 소스 파일 내부에 포함되어 있어, 골드 테스트(gold tests)를 통째로 복구할 경우 올바른 수정 사항이 조용히 되돌아가는(revert) 문제가 있었습니다.
메타 레슨(meta-lesson): 벤치마크 인프라는 모델의 실패와 똑같이 보이는 방식으로 실패합니다. 우리가 추적했던 모든 이상 징후들 — 통과한 실행에 대해 심판(judge)이 0점을 부여하거나, 빈 디프(empty diff)를 가진 "해결된" 사례 등 — 은 실제 근본 원인(root-cause)을 규명할 가치가 있었으며, 그중 약 절반은 우리의 문제였습니다.
스코어보드 (The scoreboard)
각각 기본 상태(stock)로, 별도의 튜닝이나 커스텀 프롬프트 없이 단일 에이전트 호출(single-agent invocation) 방식으로 진행된 네 개의 에이전트입니다.
| 에이전트 (Agent) | 해결됨 (Solved) | 심판 Σ / 2500 (Judge Σ / 2500) | 비용 (Cost) | 실제 소요 시간 (Wall Time) |
|---|---|---|---|---|
| octomind + glm-5.2 | 24/25 | 2264 | $63.43 | 3.6h |
| ... |
표가 보여주는 네 가지 사실:
-
하네스 (Harness)는 모델만큼이나 중요합니다. octomind와 opencode는 동일한 모델을 동일한 엔드포인트에서 동일한 가격으로 실행했습니다. 즉, 순수한 하네스 A/B 테스트였습니다. octomind는 24개를 해결했고, opencode는 절반의 비용으로 19개를 해결했습니다. 차이점은 컨텍스트 규율 (Context discipline, opencode는 하나의 작업에 30M의 입력 토큰을 밀어 넣은 반면 octomind는 8M이 필요했습니다)과 감독 (Supervision)에 있습니다. opencode가 놓친 사례들은 정확히 근본 원인이 깊고 여러 함정이 있는 사례들이었으며, 이러한 경우 감독되지 않은 에이전트는 너무 일찍 승리를 선언해 버립니다.
-
오픈 모델이 모든 토큰에 대해 정가를 지불하면서도 Opus를 이겼습니다. glm-5.2는 프롬프트 캐싱 (Prompt caching) 기능이 없는 Ollama cloud를 통해 실행되었습니다. 즉, 에이전트의 매 턴마다 전체 컨텍스트를 정가로 다시 구매했습니다. 반면 Opus는 컨텍스트 재읽기 비용의 약 97%를 1/10 수준의 캐시 요율로 청구했습니다. glm의 달러 수치는 최악의 경우를 가정한 것이지만, 그럼에도 불구하고 해결 수, 비용, 시간 면에서 앞섰습니다. 캐싱이 활성화된 엔드포인트라면 비용 격차는 거대한 심연이 될 것입니다.
-
속도에는 철저함에 대한 세금이 붙습니다. Codex는 놀랍습니다. 사례당 2~4분, 중앙값 $0.59를 기록했지만, 네 가지 실패 사례 모두 호출자 하나, 표면 하나, 함정 하나를 더 확인하지 않아 발생하는 사례들이었습니다.
-
불가능한 작업은 없었습니다. 모든 사례가 최소 하나 이상의 에이전트에 의해 해결되었으며, 실패 유형은 명확했습니다. 신뢰 경계 (Trust-boundary) 사례는 opus, codex, opencode를 잡아냈고, 깊은 근본 원인 파서 (Deep root-cause parser) 사례는 octomind를 제외한 모두를 잡아냈습니다. 그리고 두 glm 하네스가 동일하게 실패한 한 가지 사례는 하네스의 산물이 아닌, 진정한 모델의 사각지대 (Blind spot)였습니다.
하네스의 우위가 어디에서 오는가
"컨텍스트 규율 (context discipline)"의 큰 비중은 단순히 에이전트가 코드를 찾는 방식에 달려 있습니다. Claude Code, Codex, Opencode와 같은 기존 모델들은 grep, 파일 읽기, 다시 grep, 더 많이 읽기 등 동일한 방식으로 저장소(repository)를 탐색합니다. 그리고 다시 읽을 때마다 모델은 이후의 모든 턴(turn)에서 그 컨텍스트에 대한 비용을 지불해야 합니다. Octomind의 개발자 General이 탑재한 Octocode는 기본적으로 구조적 검색 (structural search) 기능을 제공합니다. 이는 정확한 심볼(symbol), 시그니처(signature), 또는 코드 패턴을 직접 찾아내므로, 에이전트가 관련 없는 파일들을 페이지 넘기듯 훑는 대신 중요한 세 개의 함수로 즉시 점프할 수 있게 합니다. 시맨틱 인덱싱 (semantic indexing)을 활성화하면 의미에 따라 코드베이스를 검색할 수도 있습니다. 즉,
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기