약 970줄의 Python 코드로 코딩 에이전트를 구축하고 정직하게 벤치마크했습니다
요약
약 970줄의 Python 코드로 구성된 경량 코딩 에이전트 'nano-harness' 구축 사례를 소개합니다. 복잡한 오케스트레이션 없이 bash, read_file, edit_file 도구만을 활용하여 Terminal-Bench 2.0에서 59.6%의 성능을 기록했습니다.
핵심 포인트
- 코드 라인당 점수(score-per-line-of-code)를 핵심 가치로 지향
- 임베딩이나 플래너 없이 최소한의 도구로 에이전트 구현
- Terminal-Bench 2.0 스위트에서 59.6%의 벤치마크 점수 달성
- 읽기 쉽고 재현 가능한 작은 규모의 하네스 구축의 중요성 강조
요약 (TL;DR): 저는 약 970줄의 Python 비공백 코드(5개 파일, 3개 도구, 2개 제공자, MIT 라이선스)로 코딩 에이전트인 nano-harness를 구축했습니다. Claude Opus 4.8을 사용하여 Terminal-Bench 2.0 전체 스위트에서 59.6% (53/89)의 점수를 기록했습니다. 그 과정에서 독립적인 프런티어 모델(GPT Sol 5.6)이 코드를 검토하고 4/10점을 주었는데, 이것이 프로젝트에서 일어난 일 중 가장 유용한 일이 되었습니다. 점수, 버그, 그리고 잘못된 부분들까지의 전체 과정을 담았습니다.
왜 하필 하네스(harness)를 구축했는가?
지난 2월, 저는 다름 아닌... Andrej Karpathy의 글을 통해 하네스(harness)에 대해 읽기 시작했습니다. 당시 llm-wiki가 막 바이럴이 되었을 때 이 저장소를 보게 되었습니다. 그래서 이를 읽고 하네스와 루프(loops)에 대해 더 공부하기 시작했습니다. 모든 사람이 루프와 하네스에 대해 이야기하고 모든 YouTube 영상이 프롬프트(prompts)에 관한 것이기 전의 일이었습니다. 저는 새로운 것을 배우고 싶었고, 당시에는 Azure Machine Learning을 사용하여 저만의 모델을 학습시키고 있었습니다(학습 비용이 매우 비쌌습니다). 그 후에는 PyTorch를 사용하여 저의 AI 운영 체제(AI Operating System) 내의 패턴을 학습하고 있었습니다. 어쨌든, 제가 팔로우하던 대부분의 에이전트 프로젝트들은 플러그인, 오케스트레이션 그래프(orchestration graphs), UI 대시보드, 메모리 시스템(그들의 obsidian "제2의 뇌")과 같은 기능 위주로 나아갔습니다. 저는 재현 가능한 전체 스위트 벤치마크 점수와 결합된 작고 읽기 쉬운 하네스를 찾는 데 더 큰 어려움을 겪었습니다(그리고 하네스를 벤치마크하고 싶다면 그것이 결코 저렴하지 않다는 것을 알고 계실 겁니다!). 이 점이 저에게 깊이 각인되었고, 왜 더 많은 사람이 이에 대해 이야기하지 않는지 이해할 수 없었습니다. 저에게 이것은 모든 것이 향하고 있는 방향이었으며, 하네스는 에이전트에서 실제로 엔지니어링할 수 있는 부분입니다. 따라서 코드를 작성하고 측정할 수 있어야 하는 부분입니다.
따라서 nano-harness의 핵심 논지는 **코드 라인당 점수 (score-per-line-of-code)**입니다. 즉, 실제 벤치마크에서 유의미한 수치를 내면서도 읽을 수 있는 가장 작은 규모의 하네스(harness)를 만드는 것입니다. Karpathy의 nanochat을 에이전트 하네스 버전으로 생각하면 됩니다. 한 번에 끝까지 읽을 수 있을 만큼 작으면서도, 그 수치가 의미를 가질 만큼 정직해야 합니다.
저의 원래 목표는 약 500줄의 코드로 실제 코딩 벤치마크 점수를 45% 이상으로 올리고 계속해서 발전시켜 나가는 것이었습니다. 이는 적어도 저에게는 도전적인 과제였습니다.
약 970줄의 코드로 얻을 수 있는 것
전체 하네스는 하나의 루프와 세 가지 도구로 구성됩니다:
bash- 지속적인 셸 (호출 간에 현재 작업 디렉토리(cwd), 환경 변수(env), 상태가 유지됨)read_file- 슬라이싱(slicing) 기능이 포함된 행 번호 기반 읽기edit_file- 정확한 고유 일치 문자열 치환 (exact unique-match string replacement)
그게 전부입니다. 임베딩 (embeddings), 플래너 (planner), 서브 에이전트 (sub-agents)는 없습니다. bash가 ls, grep, 빌드(build), 테스트(test), 설치(install)를 모두 포괄합니다. 모델은 코딩을 수행하며, 하네스의 역할은 단 하나입니다: 실행을 유지(keep the run alive)하고 정직함을 유지(keep it honest)하는 것.
"유지(Alive)"한다는 것은 다음을 의미합니다: 일시적인 API 오류 재시도, 컨텍스트 윈도우 (context window)가 가득 차기 전 히스토리 축소, 도구 호출 (tool-call) 도중 출력이 끊길 때 연속성 유도, 셸이 멈췄을 때 종료 후 재시작, 그리고 모든 예외(exception)를 충돌(crash) 대신 구조화된 결과로 변환하는 것입니다.
"정직함(Honest)"을 유지한다는 것은: 실패한 명령은 반드시 실패로 읽혀야 하며, "완료(done)"는 자격을 갖추어야 함을 의미합니다. 핵심적인 부분은 **검증 게이트 (verify gate)**입니다. 실행 과정에서 도구를 사용했다면, 첫 번째 "완료" 신호는 검증 과정을 거칩니다: 작업을 다시 읽고, 관련 체크를 실행하여 이를 증명하십시오. 이후의 완료는 해당 검증 이후에 성공적인 도구 사용 증거가 나타났을 때만 수락됩니다. 만약 증거 없이 반박이나 반복 예산(iteration budget)이 소진되면, 결과는 unverified로 반환되며 따라서 성공으로 간주되지 않습니다. 도구가 필요 없는 작업(순수 질문)은 정상적으로 종료될 수 있으며, 검증할 대상이 없습니다.
벤치마크 곡선: 20% → 80% → 53.9% → 59.6%
저는 Harbor를 통해 Terminal-Bench 2.0에서 벤치마크를 수행했습니다. 총 89개의 작업(task)이 각각 독립된 Docker 컨테이너 내에서 실행되었으며, 각 컨테이너에는 정확한 배포용 하네스(shipping harness)가 설치되었습니다. 진행 순서는 다음과 같습니다:
| 실행 (Run) | 설정 (Config) | 점수 (Score) |
|---|---|---|
| 10개 작업 슬라이스 | Haiku 4.5, 50회 반복 | 20% |
| ... | ... | ... |
마지막 실행: 16.5시간 소요, 두 개의 작업을 병렬로 처리, 오류가 발생한 시도는 실패로 간주되었습니다 (가장 무거운 작업에서 발생한 10번의 wall-clock 타임아웃과 한 번의 컨테이너 OOM(Out of Memory) 모두 저의 점수에 불리하게 작용했습니다).
공개된 Terminal-Bench 결과는 에이전트-모델 _쌍(pairs)_이므로, 모든 수치에는 모델의 품질과 하네스(harness)의 품질이 뒤섞여 있습니다. 공식 2.0 리더보드는 Codex CLI + GPT-5.5 (82.2%) 및 WOZCODE + Opus 4.7 (80.2%)과 같은 조합이 상위권을 차지하고 있습니다. 해당 표에서 제가 사용한 정확한 모델에 대한 검증된 항목을 찾을 수 없었기에, 59.6%라는 수치를 "하네스 격차(harness gap)"에 대한 깔끔한 측정값인 것처럼 꾸미지는 않겠습니다. 이는 여기에 공개된 조건 하에서 제가 직접 실행한 결과이며, 튜닝된 훨씬 더 큰 규모의 하네스들이 80% 초반대의 점수를 기록하고 있는 스위트(suite)에 맞서 약 970줄 규모의 하네스로 수행한 결과입니다. 코드와 작업 수준의 기록은 확인을 원하는 누구든 볼 수 있도록 리포지토리(repo)에 남겨두었습니다.
솔직히 말해서, 시니어 엔지니어 (SR Engineer)로서 풀타임 직업을 유지하면서, 매일 업데이트되는 유료 사용자가 있는 API를 호스팅하고, 몇 개의 레딧 (Reddit) 게시물 외에는 마케팅 없이 100명의 활성 사용자가 있는 무료 웹 앱을 운영하면서, 3.5개월 동안 쏟아부은 모든 노력에 대해 스스로가 자랑스러웠습니다. 매일 밤 새벽 2~3시까지 깨어 있다가 새벽 5시에 일어나는 생활을 반복했습니다. 이는 건강에 좋지 않으며, 매일 운동을 했음에도 불구하고 수면 부족과 계속 앉아 있는 습관 때문에 실제로 건강에 위협을 느낀 적도 있었습니다. 하지만 요즘은 배우는 것이 더 쉽고 훨씬 더 재미있을 뿐만 아니라, AI 시대에는 하루만 쉬어도 한 달 동안 자리를 비운 것 같은 기분이 들 수 있다는 점을 우리 모두 인정할 수 있을 것입니다. 지난 몇 주 동안 모델이 연달아 나오고 벤치마크 (benchmark)가 쏟아지는 상황에서는 압도될 수도 있습니다. 게다가 저는 제가 가진 것들로 작업하고 있습니다. 저는 Mac mini나 NVIDIA SPARK를 가지고 있지 않습니다. 제 가격대에서 구할 수 있는 유일한 64GB 모델이었기에 Beelink SER 10 MAX OpenClaw 에디션 64GB를 구매했습니다. 아, 정말 로컬 모델 (local models)을 실행하고 원하는 것을 테스트할 수 있는 좋은 미니 PC가 있었으면 좋겠다고 간절히 바랍니다. 다시 하네스 (Harness) 이야기로 돌아가겠습니다.
GPT Sol이 내 코드에 4/10점을 준 부분
여기가 제가 실제로 여러분께 말씀드리고 싶은 부분입니다. 그리고 저는 모든 사람이 이 점을 이해해주길 바랍니다. 이 프런티어 모델 (frontier models)들이 점수를 받는 벤치마크들은, 그들이 사용하는 하네스 (harnesses)가 수천 줄, 심지어 수만 줄의 코드로 이루어져 있다는 사실을 말입니다.
첫 번째 전체 벤치마크 실행을 마친 후, 저는 다섯 개의 핵심 파일을 GPT Sol에 붙여넣었습니다. 왜냐하면 첫 번째 실행을 시작한 지 13시간이 지났을 때 GPT Sol이 막 출시되었기 때문입니다. 저는 제 하네스 (harness)를 Opus 4.8로 감싸서
제 bash 도구는 출력값은 캡처했지만 종료 상태(exit status)는 캡처하지 못했습니다. false, 실패한 테스트 스위트(test suite), 일치하는 결과가 없는 grep까지 모두 정상인 것처럼 반환되었고, 저는 바보가 된 기분이었습니다 (...키크론(Keychron) 키보드 사이에 머리를 박고 깨어났던 밤들이 떠올랐습니다... 그것도 별로 유쾌한 기억은 아니네요). 이는 제 검증 게이트(verify gate), 즉 "정직함 유지"의 핵심 요소가 테스트 실행이 실패했을 때조차 충족될 수 있음을 의미했습니다. 하네스(harness)의 존재 이유 자체에 커다란 구멍이 뚫려 있었던 것입니다.
그래서 저는 테스트 우선(test-first) 방식으로 발견된 문제들을 해결해 나갔으며, 모든 수정 사항은 수정 전 실패하는 회귀 테스트(regression test)를 동반했습니다. (정직함에 관한 글이므로 덧붙이자면: nano-harness는 강력한 AI 보조 코딩(AI-assisted coding)을 통해 구축되었습니다. 이미 눈치채셨겠지만, 대부분의 경우와 달리 저는 모든 단계를 확실히 학습했습니다. 제가 작업을 지시하고, 결정을 내리고, 모든 벤치마크와 리뷰를 실행했지만, 967줄 전체를 직접 타이핑하지는 않았습니다. 다시 한번 솔직히 말씀드리자면, 제가 직접 타이핑한 것은 약 50줄 정도입니다. 아래의 리뷰 가틀릿(review gauntlet)은 공유된 대화 문맥이 없는 세 번의 독립적인 리뷰 패스를 사용했으며, 이는 서로 다른 유형의 실패 사례들을 드러내는 데 도움이 되었습니다.) 그 후 결과물에 대해 두 번째 독립적인 리뷰 패스를 진행했습니다. 그 결과 6/10점을 받았으며, 제가 수행한 수정 사항 중 두 가지가 절반의 수정(half-fixes)에 불과하다는 것을 잡아냈습니다.
- 도구 호출(tool calls)을 두 곳에 저장했는데, 제 컨텍스트 절단(context-truncation) 패스가 그중 한 곳만 축소했습니다. 그래서 OpenAI 직렬화(serialization) 경로가 제가 축소했다고 생각했던 거대한 도구 인자(tool arguments)들을 조용히 다시 부풀렸습니다. 분명히 축소했다고 알고 있었지만, 아마 커밋(commit)을 누락하여 실수로 넘어갔던 것 같습니다.
- 제 CRLF 수정 사항은 균일한 파일의 줄 바꿈(line endings)은 보존했지만, 혼합된 줄 바꿈을 가진 파일들을 하나로 균질화(homogenized)해 버렸습니다.
이 문제들도 수정했습니다. 그다음 세 번째 패스로 멀티 에이전트 클라우드 리뷰 플릿(multi-agent cloud review fleet)을 가동하여 정확히 **두 개의 사소한 결함(nits)**을 찾아냈습니다 (클라이언트 측 API 타임아웃에 대한 재시도 케이스 누락, 그리고 기본값을 우회하는 명시적인 JSON null 인자). 두 가지 모두 수정했습니다.
가틀릿을 거치며 발생한 총 피해: 약 20개의 실제 버그, 테스트 스위트가 52개에서 87개로 증가. 수정 사항 중에는 다음과 같은 것들이 있습니다:
- 0이 아닌 셸 상태(Nonzero shell status)가 이제 도구 오류(tool error)를 발생시키므로, 단순히 실패한 테스트 명령이 더 이상 성공적인 검증 증거로 간주되지 않습니다.
- 셸의 센티넬 프로토콜(sentinel protocol)이
set -x상황에서도 유지됩니다 (trace 라인에 달라붙어 이후의 모든 명령을 잘못 프레임화하는 데 사용되는 부분 일치 방식). edit_file은 파일 권한을 보존하며 (이전에는 Linux 벤치마크 컨테이너에서 편집된 모든 스크립트의 실행 비트(executable bit)를 조용히 제거하여 작업을 중단시키곤 했습니다), 심볼릭 링크(symlinks)를 교체하는 대신 링크를 통해 편집하며, 혼합된 CRLF/LF 파일에서 수정되지 않은 줄의 끝부분을 바이트 단위로 동일하게 유지합니다.- 프로세스 트리(Process-tree) 종료가 검증되고 회수(reaped)되어, 타임아웃 발생 시 좀비 셸(zombie shells)이 축적되지 않습니다.
- 검증 게이트(verify gate)는 '실패 시 차단(fails closed)' 방식으로 작동합니다: 푸시백(pushbacks)이 발생하면 '가짜 성공'이 아닌 '미검증(unverified)' 상태가 됩니다.
그리고 이것이 벤치마크가 저에게 안겨준 **결정적인 결과(punchline)**입니다: 강화(hardening) 전의 하네스(harness) 점수는 53.9%였습니다. 강화 후 동일한 모델, 동일한 스위트로 실행한 결과, 5개의 작업을 더 통과하여 **59.6%**를 기록했습니다. 5.7포인트의 상승이지만, 동시에 약 180줄의 코드가 추가되었습니다. 이는 확률적인 단일 실행 결과이므로, 모든 상승분이 특정 수정 사항 때문이라고 증명할 수는 없습니다. 제가 말할 수 있는 것은 다음과 같습니다: 중간에 이루어진 변경 사항들은 작업 특화된 벤치마크 패치가 아니라 정확성(correctness)과 안전성(safety)을 위한 수정이었으며, 다음 전체 실행에서 더 높은 점수를 기록했다는 점입니다. 가장 큰 단일 수정 사항은 실패를 모델에게 '실패처럼 보이게' 만든 것이었으며, 결과적으로 모델은 하네스가 거짓말을 멈출 때 더 멀리 나아간다는 사실이 밝혀졌습니다... 누가 생각이나 했을까요...
이로 인한 비용
정확한 달러 금액을 인용하기에는 그 이상이며, 솔직한 이유는 제 어댑터(adapter)의 결함 때문입니다. nano는 토큰 사용량을 Harbor의 결과 스키마(result schema)로 보고하는 대신 에이전트의 표준 출력(stdout)에 기록하기 때문에, 실행 요약 JSON에는 토큰 필드가 null로 표시됩니다. 살아남은 작업별 에이전트 로그를 모두 합산하면 약 3.0M 토큰 (입력 약 1.54M, 출력 약 1.43M)입니다. 이후의 재시도(retry) 과정에서 일부 로그가 덮어씌워졌으므로, 이는 영수증이 아닌 추정치로 간주하십시오. Opus 4.8의 2026년 7월 리스트 요금(입력 1M당 $5, 출력 1M당 $25)을 기준으로 하면, 89개 작업 전체 실행에 약 $45가 소요되었습니다. 10개 작업 단위의 반복(iteration) 슬라이스는 12시간 정도 소요되며, 비용은 $4$6 수준입니다. 예산이 아닌 실제 소요 시간(wall-clock)이 병목 현상이 될 정도로 충분히 저렴합니다. 제게는 아직 수백 달러가 남아 있으며, 누군가 이 과정을 검토하고 저에게 벤치마크 실행을 요청한다면 기꺼이 도와드리겠습니다. 다만, 이는 먼저 요청하는 몇 분에게만 해당됩니다.
저장소 복제 (Clone the repo)
저장소는 github.com/TroyJLorents-GH/nano-harness이며 MIT 라이선스입니다. agent.py, tools.py, providers.py, prompts.py, cli.py에 걸쳐 공백을 제외한 약 970줄의 코드로 구성되어 있습니다. 트리 구조에는 87개의 테스트 스위트(test suite), Terminal-Bench 어댑터, 전체 벤치마크 세부 내역, 그리고 재검토 프롬프트(re-review prompt)와 그 결과로 나타난 수정 이력이 포함되어 있습니다.
이 글에서 한 가지만 얻어가신다면 이것입니다: 하네스(harness)의 역할은 똑똑해지는 것이 아니라, 모델이 똑똑해지는 것입니다. 하네스의 역할은 실행을 유지하고, 모델을 포함하여 당신을 포함한 그 누구도 거짓말을 하지 못하게 거부하는 것입니다. 4/10점의 리뷰가 나왔던 순간이 바로 그 논지가 현실이 된 시점이었습니다. 낮은 점수, 부분적인 수정, 변동성 등 전체 과정을 공개하는 것이 핵심입니다.
코드를 검토하다가 버그 #21을 발견한다면, 이슈(issue)를 생성해 주세요. 그것이 이 게임의 규칙입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기