에이전트 평가 하네스(Agent Eval Harness)를 구축했습니다: 실제 에이전트들이 깔끔했던 이야기의 버전을 망가뜨렸습니다
요약
에이전트의 실행 경로와 도구 사용, 안전 경계를 검증하기 위한 평가 프레임워크인 AgentEval Forge를 소개합니다. 단순 답변 평가를 넘어 시나리오, 스코어링 레이어, 적대적 사례 생성 등을 포함한 통합 검증 환경을 제공합니다.
핵심 포인트
- 에이전트의 실행 과정(run)과 도구 사용을 평가하는 데 집중
- LangGraph, PydanticAI 등 다양한 인터페이스를 위한 어댑터 지원
- 정답 누출 방지를 위한 엄격한 페이로드 및 보안 모델 구축
- LLM-as-judge와 결정론적 체크를 결합한 다각도 스코어링
- CI/CD 통합 및 샌드박스 모드를 통한 안전한 테스트 환경 제공
2주 전, 저는 "모델 평가보다 에이전트 평가가 더 어려운 이유"를 게시했습니다. 핵심 논지는 다음과 같습니다. 에이전트의 경우, 단순히 답변만을 판단하는 것이 아닙니다. 실행 과정(run)을 판단하는 것입니다. 경로가 중요합니다. 도구(tools)가 중요합니다. 안전 경계(safety boundaries)가 중요합니다. 저는 준비가 되면 저장소(repo)를 공유하겠다는 말로 글을 마쳤습니다.
이제 준비가 되었습니다. AgentEval Forge가 공개되었으며, PyPI에도 등록되었습니다. 이번 출시는 에이전트를 검증할 수 있는 신뢰할 수 있는 방법을 구축하려 노력하는 동안 제가 배운 것에 대한 보고서이기도 합니다.
저는 제가 주로 점수 산정 시스템(scoring system)을 구축하고 있다고 생각했습니다. 하지만 실제 에이전트들은 제가 준비하지 못한 쓰나미로 변했고, 이 프로젝트는 예상보다 훨씬 빠르게 통합 현실 점검(integration reality check) 과정이 되었습니다.
제가 실제로 구축한 것
저는 기존의 평가 프레임워크(eval framework)를 얇게 감싼 래퍼(wrapper)를 만들고 그것을 출시라고 부르고 싶지 않았습니다. 그래서 깊게 파고들었습니다.
PRD(제품 요구 사항 문서)는 출시 시나리오, 회귀 워크플로(regression workflows), 적대적 사례 생성(adversarial case generation), 그리고 CI 게이팅(CI gating)에 걸쳐 20개의 핵심 사용자 여정(Critical User Journeys)을 정의합니다. 사양(spec)에는 다섯 가지 핵심 구성 요소로 이루어진 아키텍처가 상세히 기술되어 있습니다: 시나리오 팩 엔진(scenario pack engine), 러너(runner), 17개의 결정론적 체크(deterministic checks)와 11개의 LLM-as-judge 메트릭(metrics)을 갖춘 스코어링 레이어(scoring layer), 회귀 엔진(regression engine), 그리고 적대적 생성기(adversarial generator)입니다. WBS(작업 분할 구조)는 M0 스캐폴드(scaffold)부터 M12 출시까지 12개의 마일스톤에 걸쳐 118개의 작업으로 나뉩니다.
저는 다섯 가지 에이전트 인터페이스(agent surfaces)를 위한 어댑터(adapters)를 구축했습니다: subprocess, Python import, HTTP, LangGraph, 그리고 PydanticAI입니다. 각 어댑터는 얇은 계약(contract)을 구현합니다: 에이전트는 제한된 호출 페이로드(invocation payload) — 즉, 시나리오 입력, 허용된 도구, 허용되지 않은 도구, 그리고 예산(budget) — 를 받습니다. 에이전트는 기대되는 정답이나 점수 임계값(scoring thresholds)을 절대 볼 수 없습니다. 정답 누출(ground-truth leakage)은 없습니다.
저는 보안 모델을 구축했습니다: 샌드박스 모드 (sandbox mode), 신뢰 정책 (trust policies), 감사 추적 (audit trail), API 키 살균 (API key sanitization). CI 통합을 구축했습니다: GitHub Actions, GitLab CI, Docker 샌드박스 (Docker sandbox). 문서를 구축했습니다: 사용자 가이드, 채점 가이드 (scoring guide), 시나리오 작성 가이드 (scenario authoring guide), 그리고 원시 데이터 (raw data)가 포함된 전체 필드 테스트 보고서입니다.
전체 기능 목록은 repo README에 있습니다. 더 심도 있는 제품/설계 문서를 원하신다면 PRD, spec, scoring guide, 그리고 scenario guide를 참조하십시오. 하지만 핵심 요약은 다음과 같습니다: 10개 제품군에 걸친 20개의 출시 시나리오, 8개의 보안 시나리오, 17개의 결정론적 채점기 (deterministic scorers), 11개의 LLM-as-judge 지표, 5개의 프레임워크 어댑터 (framework adapters), 그리고 안전 실패 (safety failures)가 다른 모든 것보다 우선하는 제품 계층 구조입니다.
필드 테스트가 프로젝트를 바꾸어 놓았습니다
저는 제가 직접 작성한 예시들에 대해서만 작동하는 테스트 하네스 (test harness)를 출시하고 싶지 않았습니다. 하지만 필드 테스트는 원래 계획의 일부가 아니었습니다. 유닛 테스트 (unit tests)와 모의 에이전트 (mock agents)가 실제 통합 문제 (integration problems)를 숨기고 있다는 불안감이 들기 시작하면서, 구축 후반부에 임시방편(ad hoc)으로 추가되었습니다. 실제로 그랬습니다.
GitHub에서 실제 에이전트를 소싱하는 것은 간단해 보였습니다.
결과가 의미를 갖도록 필드 테스트 버킷(field-test buckets)도 만들어야 했습니다. 별(star) 개수가 많은 에이전트들은 신뢰성 버킷(reliability bucket)이었습니다. 이들은 널리 사용되는 저장소(repos)로, 제가 그들을 테스트하기보다 제 도구를 그들에게 테스트하게 만드는 경우가 더 많아야 했습니다. 만약 EvalForge가 이들과 통합조차 할 수 없다면, 그것은 우선 제 문제입니다. 중간 정도의 별 개수를 가진 에이전트들은 상호 마찰 버킷(mutual-friction bucket)이었습니다. 실제 상황일 만큼 충분히 성숙하면서도, 테스트가 양방향으로 작용할 만큼 충분히 무질서한 것들이었습니다. 때로는 그들의 패키징(packaging)이나 부트스트랩(bootstrap)에서 약점을 발견하기도 했고, 때로는 제 하네스(harness)의 잘못된 가정을 발견하기도 했습니다. 별 개수가 적은 에이전트들은 확장 버킷(stretch bucket)이었습니다. 더 많은 혼란이 예상되는 실험적인 저장소(repos)들이지만, 동시에 EvalForge가 거친 에이전트를 더 쉽게 평가, 비교 및 개선함으로써 명확한 가치를 보여줄 수 있는 곳이기도 했습니다.
각 에이전트는 자신만의 설정 파일(configuration file), 시나리오 팩(scenario pack), 가상 환경(virtual environment)을 가졌습니다. 저는 로컬(local), 저렴함(cheap), 그리고 더 좋음(better)의 세 가지 티어(tier)에 걸쳐 테스트했습니다. 처음부터 토큰 비용(token costs)이 걱정되었기 때문에, 로컬 티어를 단순히 가짜 데모 모드처럼 취급하는 대신 실제 노력을 기울였습니다. 제 기기에서 이는 MLX를 통해 Qwen3.5-9B-MLX-4bit를 서빙하는 것을 의미했으며, 이는 제 Apple Silicon 설정에 여유롭게 들어맞았고 엔드포인트(endpoint)가 정상일 때 로컬 스윕(local sweeps)을 수행할 가치가 있을 만큼 충분히 성능이 좋았습니다. 클라우드 티어는 저렴한 용도로 gpt-4o-mini를, 더 좋은 용도로 gpt-4o를 사용했습니다.
그 순간이 바로 이야기의 깔끔한 버전이 깨진 지점이었습니다. 저는 제가 주로 점수 산정 시스템(scoring system)을 구축하고 있다고 생각했습니다. 하지만 실제 에이전트들은 이 프로젝트를 통합에 대한 현실 점검(integration reality check)으로 강제 전환시켰습니다.
내가 집중한 것 — 그리고 PRD로부터 배운 것
PRD(제품 요구 사항 문서)는 사후에 덧붙여진 것이 아니었습니다. 그것은 제가 정직함을 유지할 수 있게 해준 핵심이었습니다.
Product DNA(제품 DNA) 섹션은 제가 코드 한 줄을 쓰기 전에 불편한 질문들에 답하도록 강제했습니다. 이것은 누구를 위한 것인가? 순서대로라면, 첫째는 개인 오픈 소스(OSS) 빌더, 둘째는 소규모 팀, 셋째는 플랫폼 팀입니다. 가장 작으면서도 의미 있는 채택 결과(adoption outcome)는 무엇인가? 머지(merge) 전 단 하나의 회귀(regression)라도 잡아내는 것입니다. 평가 계층(evaluation hierarchy)은 무엇인가? 안전성(Safety) > 정확성(Correctness) > 효율성(Efficiency)입니다.
마지막 항목은 강제 기제(forcing function)로 작용했습니다. 이는 과정 중에 정책 위반(policy violation)이 발생했더라도 마지막에 깔끔한 답변이 나왔다고 해서 이를 상쇄하는 점수 시스템을 설계할 수 없음을 의미했습니다. 안전성 실패는 항상 해당 실행(run)을 실패로 처리합니다. 정확성 회귀는 기본적으로 경고를 보내지만, 사용자가 설정하지 않는 한 차단(block)하지는 않습니다. 효율성 회귀는 정보 제공용입니다. 이 계층 구조는 이제 시스템이 생성하는 모든 스코어카드(scorecard)에 내장되어 있습니다.
20개의 CUJ(핵심 사용자 여정, Critical User Journeys)는 또 다른 강제 기제였습니다. CUJ는 기능(feature)이 아닙니다. 그것은 제품이 제 역할을 다하거나 혹은 그러지 못하는 구체적인 순간입니다. "개인 개발자가 베이스라인(baseline)에 대해 후보 에이전트 버전을 평가하고 싶어 한다." "팀 리더가 도메인 특화 도구를 위한 새로운 시나리오 팩을 추가하고 싶어 한다." "CI 파이프라인이 안전성 점수가 임계값 아래로 떨어질 때 PR(Pull Request)을 차단해야 한다." 모든 마일스톤은 최소 하나 이상의 CUJ를 통해 그 정당성을 입증해야 했습니다.
이러한 규율은 지금 생각하면 감사할 정도로 저의 속도를 늦추어 주었습니다. 덕분에 모든 것을 적당히 해내지만 제대로 하는 것은 아무것도 없는 범용 평가 라이브러리를 만드는 일을 방지할 수 있었습니다.
그것이 이 프로젝트에서 얻은 가장 초기 단계의 실제 교훈 중 하나였습니다. 만약 제품이 머지 전 누군가가 의미 있는 회귀를 하나라도 잡아내는 데 도움을 줄 수 없다면, 나머지 아키텍처는 대부분 장식에 불과합니다.
현장 테스트가 내게 가르쳐 준 것
다음은 제가 예상했던 것, 예상하지 못했던 것, 그리고 저를 가장 놀라게 했던 것들입니다.
예상했던 것
저는 일부 에이전트들이 특정 시나리오 군(families)에서 어려움을 겪을 것이라고 예상했습니다. 더 높은 등급의 판사(judge)가 저렴한 등급의 판사보다 더 변별력이 있을 것이라고 예상했습니다. 대부분의 에이전트가 대부분의 시나리오를 통과할 것이며, 흥미로운 신호는 어떤 시나리오가 왜 실패했는지에 있을 것이라고 예상했습니다.
하지만 이 중 어느 것도 사실로 드러나지 않았습니다.
예상하지 못했던 것들
통과율(pass rate)은 9%였습니다. 19개의 에이전트와 95개의 시나리오 전체를 통틀어 단 9번만 통과했습니다. 이것이 해당 목록이 약한 에이전트들로 가득 차 있다는 뜻은 아닙니다. 이는 현재 필드 테스트가 에이전트의 품질보다 어댑터(adapter)의 현실성을 측정하고 있음을 의미합니다. 래퍼(wrapper)가 하네스(harness)를 계속 작동시키기는 하지만 빈 결과물(completions)을 반환할 경우, 판정관(judge)은 이를 0점으로 처리합니다. 이는 품질의 실패가 아니라 호환성의 실패입니다. 하지만 이 수치가 여전히 헤드라인 숫자를 지배하고 있습니다.
가장 비싼 모델을 추가해도 아무런 변화가 없었습니다. 19개 에이전트 모두에 대해 두 가지 클라우드 티어(cloud tiers)를 실행해 보았습니다. 저렴한 티어와 더 나은 티어는 동일한 결과(둘 다 9/95 통과)를 냈습니다. 더 나은 티어는 저렴한 티어가 놓친 단 하나의 퇴보(regression)나 개선 사항도 드러내지 못했습니다. 병목 현상(bottleneck)은 판정관 모델이 아닙니다. 병목 현상은 하네스가 실제 에이전트 로직을 얼마나 충실하게 실행하느냐에 있습니다. 어댑터 품질이 낮으면, 판정관 뒤에 어떤 모델이 있느냐에 관계없이 판정관은 약한 출력을 보고 낮은 점수를 부여합니다.
설정(config)의 혼란이 진짜 장애물이었습니다. 한 에이전트는 모듈 범위(module scope)에서 제 로컬 MLX 엔드포인트가 제공하지 않는 모델 이름으로 ChatOpenAI()를 하드코딩해 두었습니다. 이를 수정하려면 임포트(import) 전에 실행되는 __init__에 대한 몽키패치(monkeypatch)가 필요했습니다. 다른 에이전트는 임포트 시점에 /root에 쓰기 작업을 수행했습니다. 세 개의 에이전트는 C 확장 ABI(C extension ABI)가 제 Python 런타임과 일치하지 않는 ormsgpack을 가져왔고, 이들은 격리되었습니다. 한 리포지토리(repo)는 하위 디렉토리에 pyproject.toml이 있었는데, 루트에서 실행한 uv sync는 아무런 작업도 하지 않고 조용히 종료되었습니다. 결국 저는 8개의 호환성 래퍼(wrapper) 모듈을 작성했고, 패키징이 깨진 리포지토리들을 위해 3개의 pyproject.toml 파일을 생성했으며, 구버전 PydanticAI API 버전에 머물러 있는 에이전트 하나를 완전히 제거했습니다.
이것이 바로 직접 작성하지 않은 소프트웨어를 직접 설정하지 않은 머신에서 실행할 때 발생하는 일입니다. 또한 대부분의 에이전트 평가가 왜 작성자의 환경 내에서, 작성자의 예제를 대상으로, 작성자의 모델을 사용하여 머무르는지에 대한 이유이기도 합니다. 그것은 편안합니다. 하지만 에이전트가 실제로 작동하는지 평가하는 가장 최악의 방법입니다.
성공한 사례
lg-mcp-agents는 이전에는 원래의 Streamlit 앱 외부에서 실행할 수 없었던 LangGraph 멀티 에이전트 (multi-agent) 저장소였으나, 타겟 어댑터 (adapter) 작업을 거친 후 클라우드 티어(cloud tiers) 양쪽 모두에서 5/5 통과를 달성했습니다.
이 결과가 중요한 이유는 어댑터가 실제 에이전트 동작을 실행하고 있음을 알려주기 때문입니다. 불과 이틀 전에는 임포트 (import)조차 할 수 없었던 에이전트가 5/5를 기록하는 것을 볼 때, 그 통합 (integration)은 실재하는 것입니다.
현장 테스트 (field testing)가 뒤늦게 발견된 이유 — 그리고 발견되지 말았어야 했던 이유
현장 하네스 (field harness)는 작업 분할 구조 (WBS)에 포함되어 있지 않았습니다. 제가 이를 추가한 이유는 단위 테스트 (unit tests)와 모의 에이전트 (mock agents)가 너무 깔끔하게 통과하고 있었고, 그것이 잘못되었다고 느껴졌기 때문입니다. 모의 에이전트들은 너무나 모범적이었습니다. 그들은 어댑터 계약 (adapter contract)이 명시한 대로만 정확히 동작했습니다. 실제 에이전트는 그렇지 않습니다.
실제 에이전트는 ffmpeg를 간접적으로 임포트 (transitively import)합니다. 여러분의 환경과는 다른 Python 버전을 사용하는 가상 환경 (venvs)을 생성합니다. 절대 경로 (absolute paths)에 파일을 씁니다. 모듈 범위 (module scope)에 API 키를 하드코딩합니다. 프로젝트 파일들을 하위 디렉토리에 중첩시킵니다. 모의 커버리지 (mock coverage)는 이 중 어느 것도 잡아내지 못했는데, 모의 커버리지는 실제 코드를 실행하지 않기 때문입니다.
교훈은 단순히 "현장 테스트를 추가하라"가 아닙니다. 교훈은 단위 테스트 및 모의 커버리지가 평가 하네스 (evaluation harness)를 위해 필요하긴 하지만 충분하지는 않다는 것입니다. 처음부터 실제 에이전트 현장 레이어 (real-agent field layer)를 계획하십시오. 그것이 통합의 실체를 잡아낼 수 있는 유일한 테스트 레이어가 될 것입니다.
이것이 아마도 출시 과정에서 얻은 가장 큰 배움일 것입니다. 에이전트 평가는 마치 점수 산정 (scoring) 문제처럼 논의되지만, 실제로는 대부분의 팀이 예상하는 것보다 훨씬 빠르게 환경 (environment), 어댑터 (adapter), 그리고 현실성 (realism)의 문제로 변합니다.
아직 끝나지 않았습니다
이것은 v0.1.0입니다. 그 점을 분명히 하고 싶습니다.
현장 테스트(field test)를 통해 AgentEval Forge가 GitHub의 실제 제3자 에이전트들을 대규모로 가져오고(import), 설정하고(configure), 호출하며(invoke), 점수를 매길(score) 수 있음을 입증했습니다. 하지만 이것이 스코어러(scorer)가 크고 이질적인 명단(heterogeneous roster) 전체에서 에이전트들의 순위를 의미 있게 매길 수 있다는 것을 아직 증명하는 것은 아닙니다. 일부 PydanticAI 래퍼(wrappers)들은 모든 시나리오에서 빈 완성(blank completions)을 보여주었습니다. 즉, 하네스(harness)는 실행되었지만 에이전트가 실제 출력을 생성하지 못한 것입니다. 이것은 호환성(compatibility) 측면의 성과이지, 평가(evaluation) 측면의 성과는 아닙니다. 저는 이 점을 솔직하게 밝히고자 합니다. 왜냐하면 이런 문제들이 출시 발표 시에는 대충 얼버무려졌다가, 나중에 사용자들이 고통스럽게 발견하게 되는 종류의 것이라고 생각하기 때문입니다.
일부 PydanticAI 래퍼(wrappers)에서 나타나는 빈 완성(blank-completion) 동작은 조사가 필요합니다. ormsgpack C 확장(C extension) 불일치 문제로 인해, 다른 조건에서는 실행 가능했던 세 개의 에이전트가 격리되었으며, 컨테이너화된 해결책(containerized workaround)이 필요합니다. 현장 테스트 명단은 더 확장되어야 합니다: 더 많은 에이전트, 더 높은 다양성, 더 많은 예외 케이스(corner cases)가 필요합니다. 어댑터(adapter)의 품질은 현장 수준의 호환성이 평가 수준의 유용성으로 넘어갈 때까지 개선되어야 합니다. SWE-bench 및 WebArena 커넥터(connectors)는 구축되어 엔드 투 엔드(end-to-end)로 검증되었으나, 아직 기본 CI 경로에 통합되지는 않았습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기