MMLU·HumanEval 점수, 이제 그대로 믿으면 안 된다: LLM 벤치마크 해석 실전 가이드
LLM 성능을 “수치로” 비교해야 하는 순간이 있습니다. 모델 교체(비용/지연), fine-tuning 효과 검증, 릴리즈 회귀(regression) 탐지, 고객사 PoC 등.
들어가며
LLM 성능을 “수치로” 비교해야 하는 순간이 있습니다. 모델 교체(비용/지연), fine-tuning 효과 검증, 릴리즈 회귀(regression) 탐지, 고객사 PoC 등. 이때 가장 흔히 보는 게 MMLU(일반 지식/추론), HumanEval(코드 생성) 점수인데, 2026년 시점에 이 둘은 “모델의 진짜 실력”이라기보다 평가 프로토콜을 얼마나 잘 맞췄는지를 반영하는 경우가 많습니다.
- 언제 쓰면 좋나:
1) 내부 모델/프롬프트/디코딩 변경의 회귀 테스트, 2) 같은 조건에서의 상대 비교, 3) “이 모델은 지식형/코드형 중 어디가 강한가” 같은 대략적 성격 파악. - 언제 쓰면 안 되나:
1) 프로덕션 품질(신뢰성, 일관성, 보안)을 단일 점수로 보증하려는 경우, 2) 서로 다른 공개 리더보드 점수들을 그대로 섞어서 의사결정하는 경우(프롬프트/샷 수/추출 규칙/디코딩이 다름), 3) “HumanEval 90%면 우리 레포 이슈도 90% 해결” 같은 과잉 일반화(실제로는 상관이 낮다는 리뷰/분석들이 계속 나옵니다).1
🔧 핵심 개념
1) MMLU의 본질: “지식 + 선택지 게임”
MMLU는 다분야 객관식(MCQA)으로, 모델이 정답 선택지(A/B/C/D…)를 맞히는지를 봅니다. 문제는 (a) 정답 자체 오류, (b) 프롬프트 스타일 민감도, (c) 학습 데이터 contamination 가능성 때문에 점수 해석이 점점 어려워졌다는 것.
MMLU의 신뢰성 이슈(ground truth errors): MMLU-Redux 계열 작업은 MMLU에 오류가 적지 않음을 지적하며, 일부 서브셋은 오류 비율이 매우 높다고 보고합니다.2
→ 즉, “MMLU 1~2점 차이”는 모델 차이보다 데이터/프로토콜 잡음일 수 있습니다.MMLU-Pro로의 이동: MMLU가 포화/오류/쉬운 문제 문제를 드러내면서, TIGER-Lab의 MMLU-Pro가 대안으로 자리잡았습니다. 4지선다를 10지선다로 늘리고, 더 reasoning 중심으로 재구성하며, 프롬프트 변형에 대한 민감도를 낮추려는 설계를 합니다.3
핵심은 “더 어려워서 모델 간 분리가 잘 된다”이지만, 여전히 프롬프트/추출/샷 수가 통제되지 않으면 리더보드 비교가 깨집니다(로컬 커뮤니티에서도 regex/추출로 점수 출렁임을 많이 겪습니다).4
2) HumanEval의 본질: “함수 단위 + 테스트 통과 + pass@k”
HumanEval은 164개 정도의 파이썬 함수 생성 문제에서, 생성한 코드가 제공 테스트를 통과하면 성공으로 봅니다. 여기서 대부분 리더보드는 pass@1, pass@10 같은 형태를 사용합니다.
pass@k가 의미하는 것: “k번 뽑아봤을 때 최소 1개가 맞을 확률”입니다. 따라서 k를 늘리면 점수가 올라가며, 이는 ‘최선의 샘플을 고를 수 있는 능력(=검증기/리랭커가 있는 상황)’을 측정합니다.5
프로덕션에서 중요한 “항상 잘 맞는가(신뢰성)”와는 다릅니다.최근(2026년) 쟁점: pass@k의 오용
2026년 8월 공개된 연구는, 에이전트/코드 생성 평가에서 pass@k 구현이 잘못 적용되는 사례(독립 시도 n과 테스트 개수 혼동 등)를 지적합니다.6
→ 팀 내 벤치마크 코드가 “유명 레포니까 맞겠지”가 아니라, 내가 쓰는 harness가 n/k를 어떻게 정의하는지를 반드시 확인해야 합니다.
3) “점수”를 “의사결정”으로 바꾸는 내부 흐름(추천)
실무에서는 벤치마크를 다음 파이프로 다루는 게 안전합니다.
1) 고정된 평가 프로토콜 정의(프롬프트 템플릿, few-shot, temperature, max_tokens, stop, answer extraction)
2) 모델 후보들을 동일 조건으로 실행
3) 단일 점수 대신 서브스킬별 breakdown + 분산/신뢰구간(seed/샘플링)
4) 마지막에 내 도메인 회귀 세트(내 로그/티켓/레포 기반)로 교차검증
이 흐름을 자동화하는 실전 도구로는 LM Evaluation Harness가 널리 쓰이고, CLI/설정 기반으로 재현성을 확보하기 좋습니다.7
💻 실전 코드
아래는 “우리 팀이 모델 후보 2개를 MMLU(또는 mmlu 변형) + HumanEval로 돌리고, 결과를 저장하고, HumanEval은 pass@1뿐 아니라 반복 실행으로 ‘신뢰성 지표’를 근사”하는 현실적인 파이프라인 예시입니다.
(전제: 사내/온프레 모델은 vLLM, 외부는 OpenAI-compatible endpoint로 붙는 경우가 많아 vLLM 백엔드 예시로 작성)
0) 환경/의존성
1
2
3
4
5
6
# 1) eval harness 설치
pip install "lm-eval[vllm]" # vLLM 백엔드 사용
# 필요시: pip install "lm-eval[hf]" # HF Transformers로도 가능
# 2) 결과 폴더
mkdir -p ./eval_out
1) 단일 실행: MMLU + HumanEval (고정 프로토콜)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 모델 A를 동일 조건으로 평가
lm-eval run \
--model vllm \
--model_args "pretrained=/models/modelA,max_model_len=8192,tensor_parallel_size=2" \
--tasks mmlu,humaneval \
--num_fewshot 5 \
--batch_size auto \
--gen_kwargs "temperature=0.0,top_p=1.0,max_gen_toks=512" \
--output_path ./eval_out/modelA_mmlu_humaneval.json \
--log_samples
# 모델 B
lm-eval run \
--model vllm \
--model_args "pretrained=/models/modelB,max_model_len=8192,tensor_parallel_size=2" \
--tasks mmlu,humaneval \
--num_fewshot 5 \
--batch_size auto \
--gen_kwargs "temperature=0.0,top_p=1.0,max_gen_toks=512" \
--output_path ./eval_out/modelB_mmlu_humaneval.json \
--log_samples
예상 출력(요지):
./eval_out/*.json에 태스크별 metric(예: MMLU accuracy, HumanEval pass@1 등)과 샘플 로그가 저장됩니다. harness는 CLI/설정으로 재현 가능한 실행을 지원합니다.8
2) 확장: HumanEval “신뢰성” 근사(반복 실행 → pass^k 스타일로 보기)
pass@k는 “k개 중 1개라도 성공”이라 프로덕션 신뢰성과 다릅니다. 그래서 간단히라도 동일 프롬프트를 여러 번(seed/샘플링) 반복 실행해서 “항상 통과하는 비율”을 보고 싶습니다(개념적으로 pass^k에 가까운 관점). 이 관점이 왜 중요한지는 pass@k vs pass^k 논의에서 잘 정리되어 있습니다.5
아래는 “temperature를 약간 주고(0.2) N회 반복 → HumanEval pass@1의 평균/최소값을 기록”하는 스크립트입니다(회귀 테스트에 유용).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import json, subprocess, time, statistics, pathlib
OUT = pathlib.Path("./eval_out")
OUT.mkdir(exist_ok=True)
def run_eval(model_path: str, tag: str, run_id: int):
out_file = OUT / f"{tag}_humaneval_run{run_id}.json"
cmd = [
"lm-eval", "run",
"--model", "vllm",
"--model_args", f"pretrained={model_path},max_model_len=8192,tensor_parallel_size=2",
"--tasks", "humaneval",
"--num_fewshot", "0",
"--batch_size", "auto",
"--gen_kwargs", "temperature=0.2,top_p=0.95,max_gen_toks=512",
"--output_path", str(out_file),
]
subprocess.check_call(cmd)
return out_file
def extract_humaneval_pass1(path: pathlib.Path) -> float:
data = json.loads(path.read_text())
# lm-eval 출력 스키마는 버전에 따라 다를 수 있어 방어적으로 접근
# 보통 results 아래 태스크 키에 metric이 들어감
results = data.get("results", {})
humaneval = results.get("humaneval", {})
# metric 이름도 버전에 따라 pass@1 / pass_at_1 등 변형 가능
for k in ["pass@1", "pass_at_1", "pass_rate"]:
if k in humaneval:
return float(humaneval[k])
raise KeyError(f"Can't find pass@1 metric keys in {humaneval.keys()}")
def summarize(model_path: str, tag: str, n_runs: int = 5):
scores = []
for i in range(n_runs):
p = run_eval(model_path, tag, i)
s = extract_humaneval_pass1(p)
scores.append(s)
time.sleep(0.5)
summary = {
"tag": tag,
"n_runs": n_runs,
"mean_pass1": statistics.mean(scores),
"min_pass1": min(scores),
"max_pass1": max(scores),
"stdev_pass1": statistics.pstdev(scores),
"all": scores,
}
(OUT / f"{tag}_humaneval_stability_summary.json").write_text(
json.dumps(summary, indent=2)
)
print(summary)
if __name__ == "__main__":
summarize("/models/modelA", "modelA", n_runs=7)
이 방식의 장점:
- “우리 서비스는 rerank/검증기가 없으니 pass@10은 의미가 약하다” 같은 상황에서, 출렁임(variance)을 숫자로 볼 수 있음
- 동일 모델이라도 서빙 설정/프롬프트/토크나이저/샘플링에 따라 점수가 흔들리는지 조기 감지
⚡ 실전 팁 & 함정
Best Practice (2~3개)
1) 리더보드 점수는 ‘프로토콜 해시’가 없으면 비교하지 마세요
MMLU-Pro는 “프롬프트 민감도를 낮추려는” 시도가 있지만, 완전히 사라지진 않습니다. 공식/비공식 구현에서 answer extraction(regex), system prompt, few-shot, CoT 유무가 다르면 점수는 쉽게 변합니다.3
2) MMLU는 가능하면 Redux/Pro 계열로 교차 확인
원본 MMLU는 오류 이슈가 널리 지적되었고, MMLU-Redux는 오류 라벨링/수정 방향을 제시합니다. 작은 점수 차이로 모델을 갈아타기 전에, 최소한 “오류 가능성이 큰 구간에서 이득을 본 건 아닌지”를 확인하세요.2
3) HumanEval은 pass@1과 함께 ‘신뢰성 관점’ 지표를 같이 보세요
pass@k는 best-of-n 성격이라 “에이전트/검증기”가 있을 때 유리합니다. 배포 형태가 단발 응답이면, 반복 실행 분산/최소값이 더 의사결정에 가깝습니다.5
흔한 함정/안티패턴
- 디코딩 budget(샘플 수) 올려놓고 성능 향상이라 착각: pass@k는 k에 민감합니다. k를 바꾸거나 temperature를 주고 샘플을 늘리면 점수가 오르는 건 자연스러운데, 이를 모델 개선으로 오해하는 경우가 많습니다.9
- HumanEval 고득점 → 레포 기반(SWE-bench류)도 잘할 것이라는 착각: 함수 단위 테스트 통과와 실제 레포 이슈 해결은 다릅니다(상관이 낮다는 리뷰도 존재).1
- pass@k 구현/정의 확인 없이 숫자만 수집: 2026년에도 pass@k가 잘못 적용되는 사례가 지적됩니다. 평가 코드에서 n/k의 정의(독립 시도 수 vs 다른 무엇)를 명확히 하세요.6
비용/성능/안정성 트레이드오프
- MMLU류(MCQA)는 비교적 싸게 돌릴 수 있지만, “정답 선택지 추출”이 평가 품질을 좌우합니다. parsing이 불안정하면 비용을 들여도 쓰레기 데이터가 됩니다.
- HumanEval은 테스트 실행이 포함되므로, 대량 샘플(pass@10 등)로 갈수록 비용이 급증합니다. 실제 배포가 single-shot이면, pass@10 대신 반복 실행 분산 같은 더 직접적인 지표가 비용 대비 효율적일 때가 많습니다.
🚀 마무리
- MMLU/HumanEval은 여전히 유용하지만, 2026년 8월 기준으로는 “모델 능력의 절대값”이라기보다 프로토콜 포함 상대 비교 지표로 쓰는 게 안전합니다.
- 도입 판단 기준(실무용): 1) 우리 서비스가 single-shot인가, best-of-n + verifier/reranker가 있는가? → HumanEval은 pass@k 해석이 달라짐
2) MMLU는 오류/포화/프롬프트 변형 리스크를 감안해 Pro/Redux로 교차 확인할 것3
3) 최종 결정은 “공개 벤치마크 + 우리 도메인 회귀 세트”의 2트랙으로
다음 학습/확장 추천:
- LM Evaluation Harness로 내 태스크(도메인 Q&A / 코드베이스 규칙 / RAG 정답성)를 태스크로 추가해, MMLU/HumanEval을 “외부 기준점”으로만 두고 내부 회귀를 주 평가로 올리는 구성을 권합니다. harness 자체가 재현 가능한 실행/설정 중심이라는 점이 이런 운영에 적합합니다.7