
가능한 곳에서는 결정론적으로, 필수적인 곳에서는 모델로, 취향은 인간에게
요약
AI 코딩 에이전트의 성능을 평가할 때 단일 점수 대신 결정론적 심판, LLM 심판, 인간의 판단을 결합한 다차원적 평가 체계의 필요성을 강조합니다. 리더보드의 한계를 지적하며 실제 도구와 컨텍스트 내에서의 실행 능력을 측정하는 것이 중요함을 설명합니다.
핵심 포인트
- 단일 수치 기반의 리더보드는 실제 에이전트의 복잡한 성능을 반영하지 못함
- 결정론적 측정, LLM 평가, 인간의 취향을 결합한 3단계 계층 구조 제안
- 사양 준수, 실행 가능성, 코드 품질, 시각적 외관 등 다각도 평가 필요
- 실제 프로덕션 환경과 유사한 에이전트 엔진 기반의 반복 가능한 평가 강조
지난번에 제 벤치마크를 점수 매기는 심판에 대해 썼을 때, 한 가지를 빠뜨렸습니다. 그 포스트는 점수 산정에 모델을 추가하는 것에 관한 것이었습니다. 모델이 이 시스템에서 제가 가장 마지막에 찾는 수단이라는 사실에 대해서는 다루지 않았습니다.
AI 코딩 모델을 평가하는 것은 단 하나의 숫자로 결정되지 않습니다. 그것은 여러 가지 서로 다른 질문들입니다: 사양(spec)을 충족했는가, 실제로 실행되는가, 보기 좋은가, 코드가 깔끔한가, 그리고 에이전트(agent)가 합리적으로 행동했는가와 같은 질문들입니다. 각 질문에는 서로 다른 자연스러운 심판이 있습니다. 그래서 Refio에서는 점수 산정을 세 가지 계층으로 나누었습니다: 결정론적 심판 (deterministic judge) (기계가 측정할 수 있는 것을 측정), 강력한 LLM 심판 (strong LLM judges) (코드를 읽고 기계가 가늠할 수 없는 것을 점수 매김), 그리고 인간 (human) (시각적 취향과 최종 결정). 이 모든 과정은 프로덕션 플러그인이 사용하는 것과 동일한 에이전트 엔진 위에서 헤드리스(headless) 방식으로 실행됩니다. 그 결과: 모델 비교를 실제로 신뢰할 수 있게 되었습니다. 왜냐하면 이 비교는 다차원적이고, 반복 가능하며, 도구가 실제로 어떻게 작동하는지를 반영하기 때문입니다.
"내 컴퓨터에서는 되는데" 방식은 480번의 실행에 적용될 수 없습니다
자신의 에이전트에 새로운 모델을 연결해 본 사람이라면 누구나 그 순간을 압니다. 프롬프트를 날리면 모델이 앱을 뱉어내고, 브라우저에서 열어본 뒤 "허, 나쁘지 않네" 또는 "아니, 쓰레기네"라고 말하게 됩니다. 다시 시도하면 다른 결과가 나옵니다. 다음 모델을 연결하고 한 시간 뒤에 남는 것은 "아마 첫 번째 것이 더 나았던 것 같아"라는 모호한 느낌뿐입니다. 그것은 평가가 아닙니다. 그것은 선의에 기반한 추측일 뿐입니다.
리더보드(Leaderboards)는 당신을 구원해주지 못합니다. 왜냐하면 그것들은 다른 것, 즉 모델이 닫혀 있고 자기 완결적인 퍼즐(closed, self-contained puzzles)을 어떻게 처리하는지를 측정하기 때문입니다. 리더보드는 당신의 에이전트가, 당신의 도구와 당신의 컨텍스트 예산(context budget)을 가지고, 오류로 콘솔을 가득 채우지 않으면서 무언가를 제대로 해낼 수 있을지 알려주지 않습니다. 저는 플러그인을 만들면서 이 문제를 아주 날카로운 형태로 겪고 있습니다. 왜냐하면 Refio는 제가 다음과 같이 솔직하게 말할 수 있을 때에만 의미가 있기 때문입니다: '이 로컬 모델은, 무료이며, 당신의 GPU에서 돌아가는데, 이런 종류의 작업에는 충분히 훌륭하지만, 저런 작업에는 그렇지 않다'라고 말입니다.
하나의 숫자가 거짓말을 하는 이유
제 카탈로그에서 실제 작업 하나를 가져와 보겠습니다: 브라우저 기반의 간단한 3D 에디터, 단일 HTML 파일 — 장면 보기(scene view), 객체 추가 및 이동, 속성 패널(properties panel), 콘솔 오류 제로. 이것을 단 하나의 숫자로 어떻게 점수화할 수 있을까요? 불가능합니다. 왜냐하면 그 안에는 여러 개의 독립적인 질문들이 존재하기 때문입니다:
- 사양 준수 (spec compliance) - 실제로 객체를 추가할 수 있는가, 속성 패널이 있는가, 파일 이름이 일치하는가,
- 즉시 실행 가능 여부 (works out of the box) - 수동 수정 없이 열리는가, 오류를 발생시키는가,
- 외관 (look) - 이것은 측정이 아니라 취향(taste)의 영역입니다,
- 코드 품질 및 구조 (code quality and structure) - 깔끔한가, 아니면 죽은 함수들이 엉켜 있는 상태인가,
- 로직의 정확성 (logic correctness) - 코드를 직접 읽었을 때 논리가 유지되는가. 화면은 아름답게 거짓말을 할 수 있습니다,
- 에이전트 로직 (agent logic) - 에이전트가 파일을 확인하고, 생성하고, 검증하고, 요약했는가. 아니면 방황했는가.
모델은 한 차원에서는 압도적인 성능을 보이다가도 다른 차원에서는 완전히 실패할 수 있습니다. 망가진 로직 위에 훌륭한 외관을 얹어 놓는 일은 이곳에서 매일 일어나는 일입니다. 여기에 더해 비결정론 (non-determinism) 문제도 있습니다. 동일한 프롬프트를 두 번 입력하면 두 개의 서로 다른 파일이 생성됩니다.
이 현상이 기반하고 있는 원칙
모든 것을 하나의 도구로 판단하지 마십시오. 단순한 함수로 충분한 곳에 모델을 호출하지 말고, 정규 표현식(regex)이 취향을 가늠할 수 있는 척도인 양 가장하지 마십시오.
극단적인 사례들을 살펴보십시오. "이 페이지가 렌더링되는가?"라는 질문은 이진적(binary)이며 기계가 확인할 수 있는 답변을 가집니다. 여기에 모델에게 "렌더링될 것 같나요?"라고 묻는 것은 확실성을 가질 수 있는 곳에 노이즈를 주입하는 것입니다. 그냥 렌더링하십시오. 반대 방향으로 가보자면, "이것이 보기 좋은가?"는 정의상 미적 판단입니다. 정규 표현식(regex)은 이를 측정할 수 없으며, 강력한 모델이라 할지라도 취향을 가진 인간보다 이를 더 못하게 수행합니다.
따라서 세 개의 계층(layer)이 존재합니다.
계층 1: 의견이 없는 판사
첫 번째 계층은 AI와 아무런 관련이 없으며, 사전에 중요한 주의 사항을 말씀드려야 합니다: 이것은 힌트이지 결과가 아닙. 해당 점수들은 제가 항목을 살펴보는 동안 옆에 표시될 뿐이며, 그 지점에서 역할이 끝납니다. 점수는 결코 최종 결과에 포함되지 않습니다. 이 계층은 엔드 투 엔드(e2e) 실행으로부터 객관적으로 계산할 수 있는 세 가지 요소를 측정합니다.
니들(needles)을 통한 준수 여부. 모든 작업에 대해 저는 일련의 니들(needles)을 정의합니다. 이는 전달된 파일에 반드시 나타나야 하는 콘텐츠 마커(content markers)입니다. 모두 충족하면 1, 일부는 0.5, 하나도 없으면 0입니다. 니들은 일반 텍스트이거나 정규 표현식(regex)이므로 규칙이 엄격하고 반복 가능합니다. 여기서 사람들은 보통 "하지만 여기에는 유닛 테스트(unit tests)가 없는데, 어떻게 무엇인가를 측정하나요?"라고 묻곤 합니다. 바로 이 방식입니다. 결과물이 시그니처(signature)가 있는 함수가 아니라 HTML 파일인 경우, 고전적인 테스트를 작성할 수는 없지만 그 안에 무엇이 반드시 있어야 하는지는 말할 수 있습니다.
실제 렌더링을 통한 즉각적인 작동 여부. 파일은 헤드리스 브라우저(headless browser)로 들어갑니다. 깨끗하게 렌더링되면 1, 콘솔 에러와 함께 렌더링되면 0.5, 전혀 렌더링되지 않으면 0입니다. 해석은 배제됩니다. 이 계층은 제가 브라우저를 죽이는 코드(the code that kills the browser)에 대해 쓴 내용에서 직접 파생되었습니다. 무한 드로우 루프(draw loop)가 탭을 잠가버리는 것을 한 번이라도 보고 나면, 무언가가 "작동한다"는 증거로서 스크린샷을 신뢰하지 않게 됩니다.
상태 및 도구 순서에 따른 에이전트 로직 검증. 실행은 반드시 SUCCESS 상태로 끝나야 하며, 특정 도구 순서를 요구하는 작업의 경우, 실제 호출 기록에서 그것이 **부분 수열(subsequence)**인지 확인합니다. 인접할 필요는 없지만 순서는 유지되어야 합니다. 올바른 순서로 성공하면 1점, 잘못된 순서면 0.5점, 실패하면 0점입니다.
이 모든 과정은 무료이고 즉각적이며 백 퍼센트 재현 가능합니다. 제가 어떤 것을 보기 전에 이미 페이지가 나타났는지, 그리고 에이전트가 올바른 경로를 거쳤는지를 알고 있습니다. 그리고 중요한 점은: 이는 외관이나 코드 품질을 의도적으로 측정하지 않는다는 것입니다. 왜냐하면 그것들은 기계적으로 측정할 수 없기 때문입니다.
레이어 2: 모델 활용, 하지만 지금만
두 번째 레이어는 기계가 가늠할 수 없는 것을, 신중한 코드 읽기를 통해 파악하는 것, 즉 코드 구조와 로직의 정확성을 다룹니다. 여기에서 판단력은 지능을 필요로 하므로, 제가 마침내 모델(Claude Code 및 Codex 에이전트)을 호출합니다. 저는 이전 게시물에서 구성 방식을 설명했습니다. '1점부터 10점까지 평가해 달라'는 방식 대신 증거 폴더, 세 시점에서의 스크린샷, 컨트롤 클릭 경로 추적, 블라인드 스코어링을 사용합니다. 이러한 레이어링 방식으로부터 두 가지가 직접적으로 파생됩니다.
저는 평균이 아닌 중앙값(median)으로 집계합니다. 중앙값은 궤도를 이탈한 심사위원 한 명의 영향을 무시하지만, 평균은 그 편차를 결과에 정중하게 포함시켜 버립니다. 모델 심사위원들이 가진 알려진 문제점들(장황함 편향(verbosity bias), 위치 민감성(position sensitivity), 실행 간 비일관성(inconsistency across runs))이 사라지지는 않지만, 두 명의 심사위원을 두고 중앙값을 취함으로써 결정적인 영향을 미치지 못하게 합니다. 이것이 바로 여기서의 심사위원이 최종 권위자가 아니라 조언자라는 이유입니다. 이들은 제가 어디를 봐야 할지 알려줄 뿐이며, 순위는 여전히 저의 서명을 받습니다.
LLM 심사위원은 에이전트 로직을 점수 매기지 않습니다. 그것들을 할 수 없어서가 아닙니다. 에이전트가 실제로 어떻게 작동했는지에 대한 과정(process)은 죽은 파일(dead file)만으로는 재구성할 수 없기 때문입니다. 이것은 제품(product)의 문제가 아니라 과정에 관한 질문입니다. 훌륭한 평가 시스템은 자신의 심사위원들이 손대지 말아야 할 것을 알고 있습니다.
Layer 3: 최소한으로 다듬어진 인간
마지막 단계(last mile)는 제 몫이며, 저는 그 과정에서 자동화할 수 없는 단 한 가지 일을 수행합니다. 바로 **외관 (look)**을 더하는 것입니다 (이는 0-2점 척도에서 유일한 기준인데, 왜냐하면 "기대보다 나음"이라는 판단은 바로 이 영역에 속하기 때문입니다) 그리고 최종 결정을 내립니다.
자동화된 단계는 리뷰 큐(review queue)에 제출될 준비가 된 항목을 구성합니다. 즉, 결과물(artifact), 스크린샷, 지속 시간, 토큰(tokens), 비용, 결정론적 힌트(deterministic hints), 심사위원의 판결(judge verdicts), 그리고 잠정적인 합격/불합격(pass/fail) 여부 등이 포함됩니다. 저는 그곳에 들어가서 살펴보고, 제 몫을 더한 뒤, 해당 항목을 결과로 승격시키거나 거절합니다. 계산될 수 있는 그 어떤 것도 수동으로 다시 타이핑하지 않습니다. 여기에 더해 발산 마커(divergence marker)가 있습니다. 이는 제 점수와 심사위원들의 합계 점수 사이의 가장 큰 격차를 보여줍니다. 이는 양방향으로 작동합니다. 심사위원이 틀렸거나, 혹은 제가 코드를 읽는 동안 모델이 포착한 무언가를 놓쳤을 수도 있습니다.
반복 가능성, 그리고 작업의 출처
모델은 비결정론적(non-deterministic)이기 때문에, 하나의 좋은 결과는 운일 수 있습니다. 그래서 저는 **안정성 (stability)**을 별도로 측정합니다. 저의 경우 모델당 작업당 6번의 실행을 수행합니다. 3번 미만이면 운과 실력을 구분할 수 없고, 6번을 초과하면 12개 이상의 모델을 대상으로 할 때 효율이 떨어지기 때문입니다. 최소 2번 이상의 실행이 있는 모든 그룹(작업, 모델, 환경)에 대해 저는 점수의 분산(variance)과 생성된 코드의 유사성(similarity)을 계산합니다. 덧붙이자면, 이 두 번째 측정 지표는 그 자체로 하나의 포스트가 되었습니다. 결과적으로 모든 LLM은 똑같은 Todo App을 작성한다는 사실이 밝혀졌는데, 이는 문자 그대로의 의미였습니다.
태스크 자체는 단일 진실 공급원 (Single source of truth)을 가집니다. 즉, 하나의 설명과 하나의 프롬프트가 존재하며, 생성기 (Generator)는 이를 통해 자동화된 e2e 시나리오와 관리자 패널의 리뷰 태스크 둘 다를 방출합니다. 저는 이를 고통스러운 경험을 통해 배웠습니다. 태스크 설명을 두 곳에 두면, 한 달 뒤에 하나의 이름 아래 서로 다른 두 개의 태스크가 존재하게 됩니다. 난이도는 의도적으로 분산되어 있습니다. Snake와 Todo부터 3D 에디터를 거쳐, 모듈형 Web Audio 신디사이저, 논리 회로 시뮬레이터, 또는 절차적 복셀 월드 (Procedural voxel world)와 같은 단일 파일 괴물들에 이르기까지 말입니다. 바로 이 지점에서 성능이 낮은 모델들은 단순히 무너지게 되며, 이것이 바로 이 테스트의 핵심입니다.
창(Windows)만 없는 동일한 엔진
가장 중요한 부분이 마지막에 있습니다. 이 벤치마크는 실험실 조건 하에서 깨끗한 API를 통해 모델을 호출하는 것이 아닙니다. 대신, 실제 프로덕션 IntelliJ 플러그인이 사용하는 것과 정확히 동일한 에이전트 엔진, 동일한 도구, 동일한 컨텍스트 파이프라인 (Context pipeline), 그리고 동일한 가드레일 (Guardrails)을 통해 모델을 구동합니다. 단지 헤드리스 (Headless) 상태일 뿐입니다.
따라서 저는 여러분이 Refio에서 실제로 경험하게 될 방식 그대로 모델을 측정합니다. 즉, 도구 사용 (Tool-use) 규율과 에이전트 루프 (Agent loop) 내부에서의 동작을 측정합니다. 이 덕분에 벤치마크는 두 가지 측면에서 유용합니다. 모델의 점수를 매길 뿐만 아니라, 저 자신의 시험장이 되기도 합니다. 가드레일이 합리적인 실행을 차단하거나 모델이 루프에 빠질 때, 저는 다른 누구보다 먼저 여기서 이를 확인합니다.
이것을 통해 얻는 것
- 정직함. 모델은 예쁜 표면 뒤에 망가진 로직을 숨길 수 없습니다. 왜냐하면 이 두 가지는 서로 다른 두 명의 심사원에 의해 판단되는 기준이기 때문입니다.
- 재현 가능성. 제가 모든 항목의 시작 부분에 넣는 힌트들은 결정론적 (Deterministic)이며, 안정성은 명시적으로 측정됩니다.
- 현실성. 여러분이 사용하는 것과 동일한 엔진에서 모델을 측정합니다.
- 저렴한 의사결정. 새로운 로컬 모델을 투입해 보고, 오후가 끝나기 전에 그것을 배포할 가치가 있는지 알 수 있습니다.
전체 철학은 한 문장으로 요약됩니다: 가능한 곳에서는 결정론적으로, 필수적인 곳에서는 모델로, 그리고 취향은 인간에게. 지루할 정도로 단순하지만, 이 방식은 "처음 것이 아마 더 나았을 거야"라는 말을 제가 신뢰할 수 있는 숫자로 바꿔줍니다.
결과를 여기서 확인할 수 있습니다: benchmark.refio.dev. 만약 여러분만의 평가 하네스 (evaluation harness)를 구축하고 있다면, "이것은 내가 직접 계산하겠다"와 "모델이 점수를 매기게 하겠다" 사이의 경계선을 어디에 두었는지 궁금합니다. 제 직감으로는 대부분의 사람들이 곧바로 2단계로 건너뛰며, 그로 인해 발생하는 노이즈 (noise)에 대한 대가를 치르게 될 것 같습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
