GitHub Actions 머지 큐에서 보낸 8개월은 기능 비교 매트릭스가 결코 가르쳐 줄 수 없는 것을 깨닫게 해줍니다. 어떤 프레임워크는 50개의 지표, 화려한 대시보드, 그리고 저명한 연구소의 인용구를 제공할 수도 있습니다. 하지만 동일한 코드에 대해 "바이브 체크(vibe check)" 점수가 0.72에서 0.68로 미세하게 변했다는 이유로 배포를 막는다면, 그 프레임워크는 무용지물을 넘어 해롭기까지 합니다. 그것은 배포 속도에 대한 실질적인 위협이 됩니다.

이것이 대부분의 LLM 평가 요약본들이 놓치는 필터입니다. 그들은 기능(capabilities)을 세는 데 집중합니다. 하지만 머지 큐에서 가장 중요한 유일한 질문, 즉 "이 체크가 실행될 때마다 매번 정확히 똑같은 방식으로 통과하거나 실패하는가?"라는 질문은 거의 던지지 않습니다.

저는 불편한 작업을 직접 수행하며 이를 배웠습니다. 6개의 오픈 소스 LLM 평가 프레임워크를 실제 CI 파이프라인에 연결했습니다. 이들은 8개월 동안 실제 운영 환경의 풀 리퀘스트(PR)를 대상으로 실행되었습니다. 그중 두 가지만이 게이트키퍼(gatekeeper)로서 남을 자격을 얻었습니다. 나머지는 권고용 대시보드로 강등되거나, 야간 작업(nightly jobs)으로 옮겨지거나, 아예 제거되었습니다. 교훈은 뼈아프고 값비쌌습니다. 메인 브랜치를 지키고 있을 때는 확률론적 품질보다 결정론적 구조가 승리한다는 것입니다.

머지 게이트의 진짜 역할

CI 게이트는 연구 환경이 아닙니다. 그것은 보안 요원(bouncer)입니다. 게이트의 유일한 목적은 특정 변경 사항을 보고 예 또는 아니오로 답하는 것입니다. "예, 이 PR은 메인 브랜치에 합류할 수 있습니다." 또는 "아니오, 안 됩니다." 이 답변은 몇 초 내에 도착해야 하며, 비용이 거의 들지 않아야 하고, 소급하여 결과가 바뀌어서는 안 됩니다. 조용한 화요일과 정신없는 금요일에 동일한 커밋에 대해 동일한 파이프라인을 다시 실행하더라도 결과는 반드시 동일해야 합니다.

바로 이 지점에서 대부분의 LLM 평가 프레임워크가 비틀거립니다. 이들은 데이터 과학자가 데이터 과학자를 위해 만든 도구들입니다. 이들은 통찰력, 탐색, 그리고 미묘한 점수 산출에 최적화되어 있습니다. 반면 머지 큐는 이진 결정(binary decisions), 속도, 그리고 제로 플래키함(zero flakiness)에 최적화되어 있습니다. 이 두 목표는 부분적으로만 겹칩니다.

LLM-as-Judge가 머지 큐를 망가뜨리는 이유

제 테스트에서 실패한 도구들은 한 가지 설계상의 죄를 공유하고 있었습니다. 바로 주요 게이트 메커니즘으로서 LLM-as-Judge 호출에 너무 과도하게 의존했다는 점입니다.

LLM-as-judge 프롬프트는 모델에게 출력값에 1점에서 10점 사이의 점수를 매기거나, 두 응답 중 더 나은 것을 선택하거나, 사실 관계의 정확성을 평가하도록 요청합니다. 이 방식은 품질 트렌드를 이해하는 데는 강력합니다. 하지만 차단형(blocking) CI 체크에는 독약입니다. 온도(temperature), 모델 버전, 프롬프트 포맷팅 등이 모두 노이즈를 유발하기 때문에, 동일한 입력이라도 날짜에 따라 다른 점수가 나올 수 있습니다. 그 점수가 엄격한 임계값 및 종료 코드(exit code)와 연결되어 있다면, 여러분의 머지 큐는 유령 때문에 멈추게 됩니다.

실패는 빠르게 연쇄 반응을 일으킵니다. 비결정론적인 체크는 큐의 정체를 유발합니다. 엔지니어들은 결과가 유리하게 나올 때까지 재시도하는 법을 배우게 되고, 이는 팀이 실패한 빌드(red builds)를 무시하도록 훈련시키는 결과를 초래합니다. 모든 재시도마다 API 크레딧이 소모되므로 토큰 비용도 쌓여갑니다. 무엇보다 최악인 것은 신호 자체가 무의미해진다는 것입니다. '레드 빌드'는 "버그를 도입했다"는 의미여야 합니다. 만약 그것이 "판단 모델이 오늘따라 까다롭게 굴고 있다"는 의미라면, 신뢰는 무너집니다.

살아남은 도구들의 차이점

Promptfoo와 DeepEval이 살아남은 이유는 결정론적 체크를 일급 시민(first-class citizens)으로 취급하고, LLM judge 점수를 보조적인 비차단형(non-blocking) 신호로 취급했기 때문입니다. 이들은 게이트에 필요한 것이 의견이 담긴 부동 소수점이 아니라 종료 코드라는 점을 이해하고 있습니다.

MIT 라이선스로 출시된 Promptfoo는 커맨드 라인(CLI)을 위해 구축되었습니다. 정규식 매칭, JSON 스키마 검증, 포함 여부 확인(contains checks), 정확한 문자열 비교와 같은 어설션(assertions)을 실행합니다. 이것들은 화려하지 않습니다. 그저 세련된 grep이나 jq 명령에 불과합니다. 하지만 바로 그 점 때문에 CI에서 잘 작동하는 것입니다. 정규식은 매칭되거나 되지 않거나 둘 중 하나입니다. JSON 스키마는 검증되거나 오류를 던지거나 둘 중 하나입니다. Promptfoo는 표준 Unix 종료 코드를 반환하므로, GitHub Actions가 머지를 중단해야 할 시점을 자연스럽게 이해할 수 있습니다. 또한 CLI 도구로 작동하기 때문에 언어에 구애받지 않습니다. 출력값을 검증하기 위해 Node.js 서비스 저장소 안에 굳이 Python 생태계를 설치할 필요가 없습니다.

Apache 2.0 라이선스의 DeepEval은 Python 팀을 위한 선택입니다. pytest처럼 통합됩니다. 익숙한 문법으로 테스트를 작성하면, 실패 시 자연스럽게 테스트 스위트가 차단됩니다. DeepEval은 방대한 지표 카탈로그를 제공하지만, 중요한 점은 이를 주의해서 사용해야 한다는 것입니다. 게이트에는 결정론적 또는 휴리스틱(heuristic) 지표에 의존하십시오. 만약 G-Eval이나 다른 judge 기반 스코어를 사용한다면, 이를 엄격한 어설션(hard asserts) 대신 비차단형 리포트 생성기로 감싸서 사용하십시오. 이런 방식으로 사용하면 DeepEval은 연구용 노트북의 불안정성 없이 테스트 프레임워크의 편리한 사용성(ergonomics)을 제공합니다.

나머지 네 가지 도구의 위치

게이트로서 살아남지 못한 네 가지 프레임워크도 여전히 가치가 있습니다. 단지 여러분의 툴체인 내 다른 곳에 적합할 뿐입니다.

Future AGI (Apache 2.0) ships over fifty metrics and targets teams building custom SDKs. The metrics are thorough. The problem is that the tool expects you to write your own harness to drive it in a CI queue. In a research context, that is a reasonable trade. In a merge queue, every layer of custom wiring is a new source of instability. It is a capable evaluation engine, but not a ready gatekeeper.

RAGAS (Apache 2.0) excels at measuring retrieval-augmented generation quality. Its faithfulness and answer relevance metrics are genuinely useful for understanding how a knowledge base performs over time. Unfortunately, those metrics lean heavily on LLM judges. They are excellent for a nightly quality job that posts trends to Slack. They are poor bouncers for a pull request. Move RAGAS to your scheduled analysis pipeline, not your merge blockers.

Arize Phoenix carries the Elastic License 2.0 and sits at a different intersection entirely. It connects distributed tracing with evaluation, giving you observability into why a model behaved a certain way. You want this when you are debugging a production incident or tracing a hallucination back to a bad retrieval chunk. You do not want a tracing tool deciding whether a junior developer’s feature branch can ship. Its architecture is built for insight, not binary gates.

MLflow Evaluate (Apache 2.0) inherits its pedigree from experiment tracking. It is heavy. Pulling it into a lean CI image adds startup time and dependencies that slow down every single job. If you absolutely must use it inside a pipeline, stick to its heuristic metrics for structural checks. Even then, you are fighting the framework’s fundamental design. MLflow wants to log runs and compare experiments across weeks. A merge queue wants a verdict in under a minute.

Practical Rules for Gating

If you take nothing else from this experiment, take these three rules.

First, gate structure, not vibe. You can enforce that an output is valid JSON. You can enforce that it contains required keys. You can enforce that a classification label belongs to an allowed enum. These checks are fast, cheap, and deterministic. You cannot reliably enforce that a summary is "friendly" or that a rewrite is "creative." Those qualities belong in human review or periodic batch evaluation, not in automated gates.

Second, if a score moves on unchanged input, demote it immediately. Run your evaluation suite twice against the exact same artifact. If any metric flips from pass to fail, it has lost its right to block a merge. Promote it to an advisory dashboard where variance is expected and tolerable.

Third, respect the exit code. A pretty HTML report with a red banner does not stop a merge. A nonzero exit code does. Your evaluation tool must speak the native language of your CI platform. Standard out is for humans. Exit codes are for machines.

The Takeaway

We are still early in figuring out how to test LLM-powered applications. The temptation is to treat evaluation like a human grading rubric: nuanced, contextual, and slightly subjective. That works in a research paper. It collapses in a merge queue.

After eight months of production traffic, my pipeline now runs Promptfoo for structural and schema assertions across services, and DeepEval for Python-side behavioral checks that map cleanly to pass-fail conditions. Everything else reports to nightly dashboards. The queue is stable. The signal is clean. The team trusts a red build again.

You do not need more metrics at your gate. You need fewer metrics that tell the truth every single time.

Based on original testing and write-up shared on Dev.to. For more discussions on building reliable AI systems, join the GyaanSetu community on Telegram.