
개발자 도구를 위한 LLM 평가(Evals): 유용성, 정확성, 안전성
요약
개발자 도구용 LLM 기능을 구축할 때 데모의 성공을 넘어 실제 성능을 증명하기 위한 평가(Evals) 방법론을 다룹니다. 챗봇과 달리 개발자 도구는 결과물의 이진적 특성이 강하므로 유용성, 정확성, 안전성이라는 세 가지 축을 중심으로 평가해야 합니다.
핵심 포인트
- 개발자 도구는 챗봇과 달리 결과물이 이진적(성공/실패)인 특성을 가짐
- 평가의 세 가지 핵심 축은 유용성, 정확성, 안전성임
- 잘못된 코드 생성은 챗봇보다 훨씬 더 큰 영향 범위와 위험을 초래함
- 단순 텍스트 일치보다 빌드, 테스트, 린터 통과 여부가 중요함
팀원 중 누군가가 LLM 기능을 만들었습니다. 아마 인라인 코드 제안(inline code-suggest)일 수도 있고, "이 PR 코멘트를 수정해줘" 버튼일 수도 있습니다. 혹은 스스로 Pull Request를 여는 완전한 에이전트(agent)일 수도 있습니다. 데모는 성공적이었습니다. 스크린샷도 훌륭했습니다. 당신은 그것을 출시했습니다.
이제 실제 사용자가 실제 코드베이스(codebase)를 입력했을 때, 당신은 이것이 매주 나아지고 있는지 아니면 나빠지고 있는지 전혀 알 수 없습니다.
"데모에서는 작동했다"와 "이것이 개선되고 있음을 증명할 수 있다" 사이의 그 간극을 메우는 것이 바로 평가(evals)입니다. 그리고 2026년인 지금도 우리는 놀라울 정도로 이 부분에 서툽니다. 우리는 SWE-bench Verified 점수가 "우리 리포지토리(repo)에서 작동하는가"와 같은 의미인 것처럼 가리키고, 문헌에서 권장하는 것보다 LLM-as-judge 점수를 더 신뢰하며, 낮은 지연 시간(low-latency)의 토큰 스트리밍(token streaming)을 유용성으로 착각합니다. 이 글은 개발자 도구에서 중요한 세 가지 요소, 즉 유용성(useful), 정확성(correct), 그리고 **안전성(safe)**을 측정하는 방법에 대한 실질적인 지도입니다.
개발자 도구 평가(Dev-Tool Evals)가 다른 점
많은 일반적인 LLM 평가(eval) 조언들은 출력이 사람이 읽는 문단 형태인 챗봇(chatbot)을 위해 작성되었습니다. 개발자 도구는 그 스펙트럼의 반대편에 위치합니다. 출력은 대개 diff, 파일, 검색 결과, 구조화된 JSON 조각, 또는 부수 효과(side effect)인 닫힌 이슈(issue), 성공적인 빌드(green build), 게시된 아티팩트(artifact) 등입니다. 이는 평가 방식의 거의 모든 것을 변화시킵니다.
챗봇의 답변은 그저 "충분히 괜찮기"만 하면 됩니다. 하지만 diff는 깔끔하게 적용되거나 그렇지 않거나 둘 중 하나입니다. 단위 테스트(unit test)는 통과하거나 통과하지 못하거나 둘 중 하나입니다. Pull Request는 머지(merged)되거나 영원히 그 자리에 머물러 있거나 둘 중 하나입니다. 당신은 챗봇 팀보다 훨씬 더 자주 정답(ground truth), 실제 테스트에 대한 실제 실행을 사용할 수 있습니다. 그것이 좋은 소식입니다.
나쁜 소식은 실패 모드(failure modes)가 훨씬 더 날카롭다는 점입니다. 약간 틀린 사실을 환각(hallucinate)하는 챗봇은 '싫어요' 표시와 사과를 받는 것으로 끝납니다. 하지만 클래스에 없는 메서드를 환각하는 코딩 어시스턴트(coding assistant)는 (언어가 동적이라면) 컴파일은 될지언정, 그렇지 않다면 빌드를 깨뜨립니다. CLI 플래그를 지어내는 에이전트(agent)는 잘못된 명령을 실행할 것입니다. 영향 범위(blast radius)는 더 크고, 침묵하는 실패(silent failures)는 더 미묘하며, 사용자는 이를 전혀 좋아하지 않습니다.
따라서 개발자 도구(dev tool)를 위한 평가(eval) 질문은 결코 단순히 "모델이 올바른 단어를 말했는가"가 아닙니다. 그것은 다음과 같은 형태의 질문입니다: 이 실제 입력이 주어졌을 때, 생성된 결과물(artifact)이 빌드, 테스트, 린터(linter), 리뷰어, 그리고 사용자의 의도와 접촉했을 때 살아남았는가?
세 가지 축: 유용성, 정확성, 안전성
저는 평가를 세 가지 독립적인 축을 따라 나누는 것이 유용하다고 생각합니다. 왜냐하면 각 축에 사용하는 기술이 진정으로 다르며, 서로 다른 이해관계자(stakeholders)를 움직이기 때문입니다.
**정확성 (Correctness)**은 정의하기 가장 쉽고 측정하기 가장 쉽습니다. 이는 이진(binary) 또는 이진에 가깝습니다. 패치(patch)가 컴파일됩니다. 테스트를 통과합니다. SQL이 올바른 행을 반환합니다. 리팩터링(refactor)이 동작을 보존합니다. API 호출이 2xx를 반환합니다. 정확성은 SWE-bench, HumanEval 및 자체 단위 테스트(unit tests)와 같은 벤치마크(benchmarks)가 측정하는 것입니다. 정답(ground truth)이 있다면 반드시 이를 사용해야 합니다.
**유용성 (Usefulness)**은 더 모호합니다. 잘못된 질문에 대한 올바른 답변은 유용하지 않습니다. 개발자가 막 버리려던 코드를 완벽하게 다시 작성하는 것도 유용하지 않습니다. 사용자가 한 줄짜리 해결책을 원할 때 14단계의 계획을 제시하는 것도 유용하지 않습니다. 유용성이란 "이 결과물이 실제로 사용자가 하려는 일에 더 가까워지도록 만들었는가"입니다. "평가는 훌륭해 보이는데"와 "사용자는 싫어해" 사이의 대부분의 의견 불일치는 바로 이 지점에서 발생합니다.
**안전성 (Safety)**은 사람들이 문제가 터지기 전까지는 과소평가하는 축입니다. 에이전트가 환경으로부터 비밀을 유출했나요? 묻지도 않고 파괴적인 명령을 실행했나요? 스크래핑한 README로부터 프롬프트 인젝션 (Prompt Injection)을 허용했나요? 데이터를 유출하는 PR (Pull Request)을 열었나요? 챗봇에게 안전성이란 주로 "당황스러운 말을 했는가"를 의미합니다. 하지만 당신의 머신에 셸 (Shell) 접근 권한이 있는 에이전트에게 안전성이란 "머신을 복구 가능한 상태로 남겨두었는가"를 의미합니다.
개발자 도구를 위한 모든 정직한 평가 세트 (Eval suite)는 이 세 가지를 모두 측정합니다. 만약 당신의 평가가 하나만 측정하고 있다면, 나머지 두 가지는 여전히 일어나고 있는 것입니다. 단지 당신의 눈에 보이지 않을 뿐입니다.
정확성 (Correctness): 벤치마크가 도움이 되는 지점과 당신을 속이는 지점
코드 생성의 정확성을 측정하는 가장 깔끔한 방법은 _고정된 작업 세트에 대한 유닛 테스트 (Unit-test) 통과율_입니다. 이것이 2021년 7월 공개된 OpenAI의 HumanEval이 수행한 방식입니다. 164개의 수기로 작성된 Python 문제들로 구성되었으며, 각 문제당 평균 7.7개의 테스트가 포함되었고, pass@k 지표로 점수를 매겼습니다. pass@1은 모델이 첫 번째 시도에서 정답을 맞힐 확률을 추정하며, pass@10은 10개의 샘플 중 최소 하나가 통과하는지를 묻습니다. 초기 GitHub Copilot의 기반이 된 모델인 Codex는 pass@1에서 28.8%를 기록했으며, 문제당 100번의 시도가 허용되었을 때는 70.2%까지 올라갔습니다. HumanEval은 규모가 작고 범위가 좁으며, 현재는 최첨단 모델(Frontier models)들이 90% 이상의 점수를 기록하며 완전히 포화 상태입니다. 하지만 그 밑바탕에 깔린 pass@k 개념은 이후 모든 진지한 코드 평가 (Code eval)가 구축되는 기반이 되었습니다.
자연스럽게 이어지는 다음 질문은 "좋습니다, 하지만 실제 소프트웨어 엔지니어링은 164개의 짧은 함수가 아니라, 여러 파일로 구성된 리포지토리(repo) 내부의 버그 수정입니다"였습니다. 바로 이 지점에서 2023년 말, Princeton이 주도한 벤치마크인 SWE-bench가 등장했습니다. 이 벤치마크는 모델에게 실제 GitHub 이슈와 주변 리포지토리(repo)를 제공하고, 프로젝트의 기존 테스트를 통과하는 패치(patch)를 생성하도록 요구합니다. SWE-bench는 진정으로 실제 업무에 더 가깝습니다. 하지만 이 또한 노이즈가 있는 것으로 드러났습니다. 이슈 설명이 때때로 모호했고, 테스트가 때때로 유효한 솔루션을 오답으로 처리했으며, 일부 작업들은 테스트 환경(harness)의 시간 제한 내에 실제로 해결할 수 없는 것들이었습니다.
OpenAI의 Preparedness 팀과 원본 SWE-bench 저자들은 2024년 8월, SWE-bench Verified를 통해 이에 대응했습니다. 이는 93명의 개발자가 문제 설명이 모호하지 않은지, 그리고 테스트가 올바른 패치를 공정하게 채점하는지 수동으로 검토한 500개의 작업으로 구성된 하위 집합입니다. 약 1년 반 동안 이것은 프론티어(frontier) 코딩 모델들이 보고하는 지배적인 수치였습니다. 그것은 결정적인 헤드라인 지표가 되었습니다.
그러다 2026년 2월, OpenAI는 이 지표의 보고를 중단했습니다. 그것도 완만하게 중단한 것이 아니었습니다. 그들은 가장 어려운 138개의 작업을 감사(audit)했고, 그 결과 59.4%가 기능적으로 올바른 패치를 잘못된 이유로 거부하는 유형의 실질적으로 결함이 있는 테스트를 가지고 있음을 발견했습니다. 또한 일부 작업에서는 프론티어 모델들이 솔루션을 도출하는 것이 아니라, 원래의 골드 패치(gold-patch) 솔루션이나 그 특정 세부 사항을 기억으로부터 재현할 수 있다는 것을 발견했습니다. 해결한 것이 아니라, 회상(Recall)한 것입니다. "검증된(verified)"이라는 태그도, 기반이 되는 리포지토리(repo)들이 사전 학습(pretraining) 데이터셋에 너무 철저하게 스크래핑되어 있어서, 점수가 높아지는 것이 모델의 엔지니어링 능력이 아니라 모델이 해당 벤치마크를 얼마나 많이 보았는지를 점점 더 측정하게 된다는 사실을 앞지를 수 없었습니다.
여기서 얻을 수 있는 교훈은 "벤치마크는 쓸모없다"가 아닙니다. 교훈은 _벤더(vendor)가 인용하는 벤치마크가 당신의 코드베이스(codebase)를 위한 벤치마크는 아니라는 점_입니다. 두 가지 실질적인 결과는 다음과 같습니다:
리더보드(leaderboard) 점수는 해당 모델이 그럴듯한 능력을 갖추고 있음을 알려줍니다.
당신의 사내 평가(in-house eval)는 그것이 당신에게 실제로 작동하는지를 알려줍니다.
당신은 둘 다 필요합니다. 어느 것도 다른 하나를 대체할 수 없습니다.
당신만의 정확성 평가(correctness eval)를 구축하세요. 거대할 필요는 없습니다. 당신의 저장소(repo)에서 발생한 실제 이슈 12개 정도를 가져와, 각 이슈에 대해 버그를 처음 발견했던 실패하는 테스트(failing tests)와 사람이 실제로 배포한 실제 패치(actual patch)를 준비한다면, 이는 그 어떤 리더보드보다 더 많은 것을 알려줄 것입니다. 후보 모델을 실패 상태(failing state)에 대해 실행하고, 모델의 패치를 적용한 뒤, 테스트 스위트(test suite)를 실행하여 통과/실패(pass/fail)를 계산하세요. 그 숫자는 _당신의 것_입니다. 리더보드에 있는 것이 아닙니다. 어떤 벤더(vendor)도 이에 맞춰 최적화할 수 없습니다. 그것이 당신이 마주한 현실의 바닥입니다.
최소한의 하네스(harness)는 TypeScript로 다음과 같이 구성됩니다:
evals/correctness/run-patch.ts
import { execSync } from "node:child_process";
import { writeFileSync, mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
...
이것이 실제 정확성 하네스의 형태입니다. 화려하지는 않습니다. 중요한 요소는 다음과 같습니다: 처음부터 다시 구축할 수 있는 고정된 베이스라인(baseline), 시작하기 전에 실패하는 테스트가 실제로 실패하는지 확인하는 절차(이것이 버그인 경우가 생각보다 많아 놀라실 겁니다), 작업당 격리된 워크스페이스(workspace), 그리고 마지막의 결정론적인(deterministic) 통과/실패 여부입니다. 패치의 "우아함(elegance)"을 판단하거나, 부분 점수를 매기거나, 모델에게 설명을 요구하는 등의 나머지 모든 것들은 선택적인 부가 기능(sugar)일 뿐입니다.
하네스는 TypeScript이지만 pytest를 셸(shell)로 호출한다는 점에 주목하세요. 이는 의도된 것입니다. 당신의 평가 러너(eval runner)와 테스트 대상인 저장소(repo)가 반드시 같은 언어를 사용할 필요는 없습니다. 두 언어가 같다고 가정하는 것이 바로 사람들이 도구(tooling)를 만족시키기 위해 멀쩡한 테스트 스위트를 다시 작성하게 만드는 원인이 됩니다.
매번 싸워야 할 몇 가지 사항들입니다:
첫 번째는 _오염 (contamination)_입니다. 만약 작업 세트(task set)에 포함된 버그들이 공개된 적이 있다면, 모든 최신 모델은 이미 그것들을 학습했습니다. 공개한 적이 없는 작업들과 공개된 작업들을 분리하여 점수를 매기세요. 두 그룹 사이의 격차는 겉으로 보이는 정확도가 얼마나 회상 (recall)에 의존하고 있는지를 알려줍니다. SWE-bench Verified에서 일어난 일이 바로 생생한 교훈입니다. 사람이 직접 큐레이션하고 검토한 벤치마크조차 결국 학습 데이터에 의해 잠식됩니다.
두 번째는 _거짓 성공 (false success)_입니다. 모델은 관련 없는 테스트를 삭제하거나, 예상 출력값을 하드코딩하거나, 단언문 (assertion)을 약화시킴으로써 목표 테스트를 통과할 수 있습니다. 패치를 적용한 후에는 항상 전체 테스트 스위트 (suite)를 다시 실행해야 하며, 다른 부분에서 발생하는 회귀 (regression)를 실패로 간주해야 합니다. 위의 하네스 (harness)는 "fixed_target_broke_others"라는 판정을 통해 이 작업을 수행합니다. 대부분의 팀은 이를 한 번 경험하고 경악하며, 이후 이를 영구적인 가드레일 (guardrails)로 추가합니다.
세 번째는 _플래키 테스트 (flaky tests)_입니다. 일부 테스트는 확률적 (stochastic)입니다. 만약 베이스라인 (baseline)이 플래키하다면, 모델과는 아무런 상관이 없는 노이즈 섞인 평가 신호를 받게 됩니다. 작업을 스위트에 추가하기 전에 각 작업을 여러 번 실행하세요. 만약 베이스라인이 안정적으로 실패하거나 안정적으로 통과하지 않는다면, 해당 작업을 제외하거나 테스트를 수정해야 합니다.
유용성 (Usefulness): 정직한 부분은 그것이 주관적임을 인정하는 것이다
유용성은 대부분의 팀이 어려움을 겪는 지점입니다. 그들은 _"이 기능은 훌륭해"_라는 직관에서 시작하여, 이를 정당화할 수 있는 숫자를 찾아 나섭니다. 그렇게 하면 허영심을 채우기 위한 대시보드 (vanity dashboard)만 얻게 됩니다.
더 나은 시작점은 유용성을 결과물(artifact)이 루프 내의 인간 (human in the loop)의 업무량을 줄여주는지 여부로 정의하는 것입니다. 코드 완성 도구의 경우, 업무 감소 신호는 구체적입니다. 제안된 코드가 수락되었는지, 그리고 최종 커밋 (commit)에 유지되었는지 여부입니다. "PR 생성" 에이전트의 경우, 신호는 다음과 같습니다. PR이 머지 (merge)되었는지, 후속 커밋이 몇 개나 발생했는지, 그리고 리뷰에 시간이 얼마나 걸렸는지입니다.
이 두 가지 종류의 측정값 사이의 격차는 대부분의 팀이 예상하는 것보다 더 크며, 이는 깊이 고민해 볼 가치가 있습니다. GitHub 자체의 설문 조사 연구에 따르면, Copilot 사용자의 6075%가 코딩할 때 업무에 대한 만족감이 높아지고 좌절감이 줄어들었다고 보고했습니다. 이는 좋은 소식이며 주목할 만한 가치가 있습니다. 하지만 Microsoft와 Accenture의 개발자 1,974명을 대상으로 한 현장 실험은 대신 행동적 (behavioral) 결과, 즉 실제로 완료된 풀 리퀘스트 (Pull Request, PR)를 추적했으며, 그 결과는 더 복잡했습니다. Microsoft에서는 약 1322% 더 많은 PR이, Accenture에서는 8~9% 더 많은 PR이 발생했으나, 저자들은 이 추정치가 부정확할 수 있다고 공개적으로 경고했습니다.
이 격차를 잠시 생각해 보십시오. 이것이 바로 핵심 교훈입니다. 동일한 도구, 동일한 지표, 두 회사, 그리고 측정하는 위치에 따라 효과가 대략 두 배로 달라집니다. AI 코딩 도구가 생산성에 미치는 영향에 대해 단 하나의 확신에 찬 수치를 인용하는 사람은 무언가를 팔려고 하는 것입니다. 정직한 버전은 이렇습니다. 이득은 실재하지만, 체감하는 느낌보다는 작으며, 타인의 대시보드에서는 읽어낼 수 없는 맥락에 따라 크게 달라진다는 것입니다. 이것이 바로 타인의 코드베이스가 아닌, 당신의 코드베이스에서 측정해야 한다는 논거입니다.
개발 도구의 유용성과 실제로 상관관계가 있는 몇 가지 측정 지표는 다음과 같습니다:
조작하기 어려운 순서대로 나열한 유용한 지표
- 제안 수락률 (Suggestion acceptance rate) 및 N일 후 유지율 (retention-at-N-days) (유지율이 없는 수락률은 허영 지표 (vanity metric)입니다)
- AI가 생성한 PR에 대한 평균 후속 커밋 수 (낮을수록 좋음; 4개 초과 시 리뷰어가 에이전트의 역할을 대신하고 있음을 의미함)
- 유사한 PR에 대한 인간 기준점 대비 머지 소요 시간 (Time-to-merge vs human baseline)
...
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기