에이전트 eval 함수 해부 글 짚어보기 (4) — 비결정성 처리
에이전트 eval 결과가 매번 다른 이유와 이를 다루는 두 가지 핵심 메트릭 pass@k, pass^k를 원문을 따라 해설한다.
들어가며: 같은 입력, 다른 결과
같은 에이전트, 같은 프롬프트, 같은 태스크. 한 번 돌리면 통과하고, 다시 돌리면 실패한다. 세 번째에는 또 통과한다. 에이전트 eval을 처음 짜본 사람이 가장 먼저 부딪히는 벽이 이것이다. "내 eval이 잘못된 건가, 에이전트가 잘못된 건가?"
둘 다 아니다. 에이전트는 본질적으로 비결정적이다. 모델의 출력은 확률 분포에서 샘플링되고, 도구 호출의 순서는 이전 호출 결과에 따라 분기하고, 외부 환경의 상태는 실행마다 미세하게 달라진다. 전통적인 소프트웨어 테스트에서는 같은 입력에 같은 출력이 나오지 않으면 버그다. 에이전트 eval에서는 그것이 기본 전제다.
문제는, 이 비결정성을 어떻게 측정하고 해석하느냐다. 원문은 이를 위해 두 가지 메트릭을 제시한다: pass@k와 pass^k. 이 둘은 같은 데이터에서 출발하지만 정반대의 질문을 던진다.
왜 결과가 매번 다른가
원문은 이 상황을 한 문장으로 요약한다:
Each task has its own success rate -- maybe 90% on one task, 50% on another -- and a task that passed on one eval run might fail on the next.
핵심은 태스크마다 고유한 성공률이 있다는 점이다. 어떤 태스크는 열 번 중 아홉 번 통과하고, 어떤 태스크는 절반만 통과한다. 그리고 그 성공률은 eval을 한 번 돌려서는 알 수 없다. 한 번의 실행은 동전 던지기 한 번과 같다. 동전이 앞면으로 나왔다고 해서 앞면 확률이 100%라고 결론 내리지 않듯, eval 한 번의 pass/fail만으로 에이전트의 능력을 판단할 수 없다.
비결정성의 원인은 여러 층위에 걸쳐 있다.
- 모델 출력의 확률적 특성: temperature가 0이 아닌 이상, 같은 프롬프트에도 다른 토큰이 샘플링된다. temperature가 0이어도 구현에 따라 완전한 결정론이 보장되지 않는 경우가 있다.
- 도구 호출의 분기: 에이전트가 첫 번째 도구 호출에서 얻은 결과에 따라 두 번째 호출이 달라진다. 한 번은 올바른 파일을 먼저 찾고, 다음 번에는 엉뚱한 파일을 먼저 열어서 잘못된 경로로 빠진다.
- 환경 상태의 차이: 파일 시스템, API 응답 지연, 네트워크 상태 등 외부 요인이 실행마다 미세하게 달라진다.
이 세 가지가 겹치면서, 에이전트의 성공 여부는 확률 변수가 된다. eval의 역할은 그 확률을 추정하는 것이다. 그리고 그 추정을 위한 두 가지 렌즈가 pass@k와 pass^k다.
pass@k: "한 번만 맞으면 된다"
원문의 정의부터 보자:
pass@k measures the likelihood that an agent gets at least one correct solution in k attempts. As k increases, the pass@k score rises -- more "shots on goal" means a higher probability of at least one success.
pass@k는 k번 시도 중 최소 한 번 성공할 확률이다. 직관적으로, 기회를 많이 줄수록 최소 한 번은 성공할 가능성이 올라간다. 동전 던지기와 같다. 앞면이 나올 확률이 50%인 동전을 한 번 던지면 50%지만, 열 번 던지면 적어도 한 번 앞면이 나올 확률은 1 - (0.5)^10 ≈ 99.9%에 달한다.
원문이 특히 강조하는 지점은 pass@1이다:
50% pass@1 means that a model succeeds at half the tasks in the eval on its first try.
pass@1은 첫 시도에서 성공할 확률이다. k=1이면 "한 번만 맞으면 된다"와 "첫 번째 시도에서 맞아야 한다"가 동일하므로, 사실상 단일 실행의 성공률 그 자체다.
원문은 코딩 도메인에서 pass@1에 대한 관심이 높다고 짚는다. 코드 생성 도구를 생각해 보면 이해가 간다. 개발자가 "이 함수 작성해줘"라고 요청했을 때, 첫 번째 결과가 맞아야 한다. 다섯 개 중에 하나 골라쓰라는 건 개발자 경험으로서 좋지 않다. 그래서 코딩 벤치마크에서는 pass@1이 대표 메트릭으로 쓰이는 경우가 많다.
반면, pass@k에서 k가 큰 경우가 유효한 시나리오도 있다. 원문에 따르면, 여러 솔루션을 제안하고 그중 하나만 작동하면 되는 경우다. 예를 들어, 수학 문제 풀이에서 다양한 접근법을 시도해 보고 맞는 것을 채택하는 상황이다. 이때는 pass@5나 pass@10이 더 의미 있는 메트릭이 된다.
pass@k의 핵심 특성을 정리하면:
- k가 커질수록 100%에 수렴한다
- 태스크의 성공률이 0%가 아닌 한, 충분히 많은 시도를 하면 언젠가는 성공한다
- "최선의 경우"를 측정하는 메트릭이다
원문이 인용하는 출처는 NeurIPS 2019 논문이다. 코드 생성 벤치마크에서 처음 공식화된 이 메트릭은 이후 다양한 에이전트 eval에서 표준으로 자리 잡았다.
pass^k: "매번 맞아야 한다"
pass@k의 반대편에 pass^k가 있다. 원문의 정의:
pass^k measures the probability that ALL k trials succeed. As k increases, the pass^k score falls -- demanding consistency across more trials is increasingly hard.
pass^k는 k번 시도에서 전부 성공할 확률이다. 한 번이라도 실패하면 pass^k 기준으로는 실패다. 직관적으로, 요구하는 연속 성공 횟수가 늘어날수록 전부 성공할 확률은 떨어진다.
원문이 드는 예시가 명쾌하다:
Example: 75% per-trial success rate, 3 trials -> (0.75)^3 ≈ 42%
한 번 시도의 성공률이 75%라고 하자. 꽤 괜찮아 보인다. 그런데 세 번 연속 성공해야 한다면? (0.75)^3 ≈ 42%. 성공률이 절반 아래로 뚝 떨어진다. 다섯 번이라면 (0.75)^5 ≈ 24%. 열 번이라면 (0.75)^10 ≈ 5.6%. 75%짜리 성공률이 열 번 연속 기준에서는 사실상 실패나 다름없다.
이 메트릭이 중요한 맥락을 원문은 이렇게 짚는다:
This metric especially matters for customer-facing agents where users expect reliable behavior every time.
고객 대면 에이전트를 생각해 보자. 고객 지원 챗봇이 열 번 중 아홉 번은 올바른 답을 주지만, 열 번 중 한 번은 완전히 엉뚱한 답을 준다면? 90% pass@1은 좋은 숫자처럼 보이지만, 고객은 자신이 만난 그 한 번의 실패를 기억한다. 고객이 세 번 쓰는 동안 한 번이라도 실패하면 신뢰를 잃는다. 이때 pass^3이 실질적인 사용자 경험을 반영하는 메트릭이다.
pass^k의 핵심 특성을 정리하면:
- k가 커질수록 0%에 수렴한다
- 단일 시도의 성공률이 100%가 아닌 한, 충분히 많은 연속 성공을 요구하면 실패 확률이 지배한다
- "최악의 경우를 허용하지 않는" 메트릭이다
원문이 인용하는 출처는 τ-Bench 논문이다. 고객 대면 에이전트의 일관성을 측정하기 위해 제안된 이 메트릭은 pass@k와 상호 보완적으로 사용된다.
발산하는 두 메트릭
pass@k와 pass^k의 관계를 보면, k=1에서 출발해서 k가 커질수록 둘이 완전히 반대 방향으로 움직인다.
원문의 설명:
At k=1, they're identical (both equal per-trial success rate). By k=10, they tell opposite stories: pass@k approaches 100% while pass^k falls to 0%.
k=1일 때 pass@1과 pass^1은 동일하다. 둘 다 "한 번 시도해서 성공할 확률"이므로 태스크의 기본 성공률과 같다.
k가 커지면서 이야기가 갈라진다. 성공률이 75%인 태스크를 예로 들어 보면:
- k=1: pass@1 = 75%, pass^1 = 75% (동일)
- k=3: pass@3 =
1 - (0.25)^3≈ 98%, pass^3 =(0.75)^3≈ 42% - k=5: pass@5 ≈ 99.9%, pass^5 ≈ 24%
- k=10: pass@10 ≈ 99.999%, pass^10 ≈ 5.6%
k=10이 되면, pass@k는 "거의 확실히 한 번은 성공한다"고 말하고, pass^k는 "열 번 연속 성공은 거의 불가능하다"고 말한다. 같은 에이전트, 같은 태스크인데 두 메트릭이 전혀 다른 결론을 내린다.
이 발산이 의미하는 바가 있다. 에이전트의 "능력"과 "신뢰도"는 별개의 축이라는 것이다. pass@k가 높다는 건 에이전트가 그 태스크를 풀 능력이 있다는 뜻이다. pass^k가 낮다는 건 그 능력이 안정적으로 발현되지 않는다는 뜻이다. 능력은 있지만 매번 발휘하지는 못하는 것. 두 메트릭의 간극이 바로 비결정성의 크기다.
어떤 메트릭을 골라야 하는가
두 메트릭 중 무엇을 쓸지는 제품의 성격에 달려 있다. 원문의 결론을 따라 구체적 시나리오로 풀어 보자.
pass@k가 적합한 경우: "한 번만 맞으면 된다"
- 코드 생성 도구: 여러 후보를 제안하고, 개발자가 맞는 것을 골라 쓴다. 다섯 개 후보 중 하나만 맞으면 된다.
- 아이디어 발산 도구: 브레인스토밍에서 여러 안을 내놓고, 하나만 채택하면 된다.
- 탐색형 에이전트: 여러 경로를 시도해서 하나라도 정답에 도달하면 된다.
이 시나리오에서는 에이전트에게 여러 번의 기회를 주는 것이 자연스럽다. 사용자도 그것을 기대한다. pass@k가 높으면 "이 에이전트는 솔루션을 찾을 수 있다"는 신뢰를 줄 수 있다.
pass^k가 적합한 경우: "매번 맞아야 한다"
- 고객 지원 챗봇: 고객이 질문할 때마다 정확한 답을 기대한다. 열 번 중 한 번이라도 틀리면 신뢰를 잃는다.
- 자동화된 배포 에이전트: CI/CD 파이프라인에서 매번 올바른 판단을 내려야 한다. 한 번의 잘못된 배포가 서비스 장애로 이어진다.
- 의료/법률 보조 에이전트: 일관된 정확성이 필수다. "대부분 맞다"로는 부족하다.
이 시나리오에서는 사용자가 매 실행의 결과를 신뢰할 수 있어야 한다. pass^k가 높으면 "이 에이전트는 안정적으로 동작한다"는 신뢰를 줄 수 있다.
결국 선택 기준은 이렇게 귀결된다: 사용자가 에이전트에게 재시도의 여지를 줄 수 있는가? 줄 수 있다면 pass@k, 줄 수 없다면 pass^k다. 대부분의 실전 에이전트는 두 메트릭을 함께 보고, 그 간극에서 개선의 방향을 찾는다.
마무리: 비결정성은 제거 대상이 아니라 측정 대상이다
에이전트 eval에서 비결정성을 만나면, 첫 번째 반응은 보통 "이걸 없애야 한다"다. temperature를 0으로 고정하고, seed를 고정하고, 환경을 동결시키려 한다. 하지만 실제 프로덕션에서 에이전트는 비결정적으로 동작한다. eval에서 비결정성을 인위적으로 제거하면, 프로덕션에서의 실제 행동을 예측하지 못하는 eval이 된다.
올바른 접근은 비결정성을 받아들이고, 그 안에서 의미 있는 신호를 추출하는 것이다. pass@k는 "이 에이전트가 이 태스크를 풀 수 있는가?"를 답하고, pass^k는 "이 에이전트가 이 태스크를 믿을 만하게 푸는가?"를 답한다. 두 질문은 모두 필요하다.
다음 편에서는 원문의 마지막 파트, 에이전트 eval을 0에서 1로 만드는 로드맵을 따라간다.