lm-evaluation-harness, Inspect AI, HELM 프레임워크 분석과 커스텀 평가 하네스 설계, 벤치마크 스위트 구성, 자동화된 모델 비교 방법을 다룹니다.
새로운 모델이 출시될 때마다 "우리 시스템에 적용하면 어떨까?"라는 질문이 떠오릅니다. 벤치마크 점수가 높다고 해서 우리 용도에 맞으리라는 보장은 없습니다. 범용 벤치마크에서 1등인 모델이 특정 도메인에서는 3등 모델보다 못할 수도 있습니다. 평가 하네스는 이런 판단을 데이터에 기반하여 내릴 수 있게 해주는 도구입니다.
모든 평가 하네스는 4가지 핵심 컴포넌트로 구성됩니다.
EleutherAI가 개발한 lm-evaluation-harness는 가장 널리 사용되는 LLM 평가 프레임워크입니다. HuggingFace의 Open LLM Leaderboard의 백엔드로 사용되며, 60개 이상의 벤치마크를 지원합니다.
# MMLU 벤치마크 실행 (5-shot)
lm_eval --model openai-completions \
--model_args model=gpt-4o \
--tasks mmlu \
--num_fewshot 5 \
--output_path results/
# 여러 벤치마크 동시 실행
lm_eval --model anthropic \
--model_args model=claude-sonnet-4-20250514 \
--tasks mmlu,hellaswag,arc_challenge,gsm8k \
--output_path results/lm-evaluation-harness의 강력한 점은 커스텀 태스크를 쉽게 추가할 수 있다는 것입니다.
# 한국어 도메인 특화 평가 태스크
task: korean_medical_qa
dataset_path: my_org/korean_medical_qa
dataset_name: default
output_type: multiple_choice
training_split: train
test_split: test
doc_to_text: "질문: {{question}}\n선택지:\nA. {{choices[0]}}\nB. {{choices[1]}}\nC. {{choices[2]}}\nD. {{choices[3]}}\n정답:"
doc_to_target: "{{['A', 'B', 'C', 'D'][answer]}}"
metric_list:
- metric: acc
aggregation: mean
higher_is_better: true
- metric: acc_norm
aggregation: mean
higher_is_better: true
num_fewshot: 3lm-evaluation-harness는 주로 모델 수준(model-level)의 평가에 초점을 맞춥니다. 모델의 원시 성능(지식, 추론, 언어 이해)을 측정하는 데 적합하지만, 하네스를 포함한 전체 시스템의 평가에는 한계가 있습니다.
Inspect AI는 UK AI Safety Institute에서 개발한 오픈소스 평가 프레임워크입니다. lm-evaluation-harness와 달리, 모델 수준 평가뿐 아니라 에이전트 수준 평가까지 지원하는 것이 특징입니다.
from inspect_ai import Task, task
from inspect_ai.dataset import json_dataset
from inspect_ai.scorer import model_graded_fact
from inspect_ai.solver import generate, system_message
@task
def korean_qa_eval():
"""한국어 질의응답 평가 태스크"""
return Task(
dataset=json_dataset("data/korean_qa.json"),
solver=[
system_message(
"당신은 한국어에 능통한 AI 어시스턴트입니다. "
"질문에 정확하고 간결하게 답변하세요."
),
generate(),
],
scorer=model_graded_fact(),
)
@task
def agent_coding_eval():
"""코딩 에이전트 평가 태스크"""
return Task(
dataset=json_dataset("data/coding_tasks.json"),
solver=[
system_message("코딩 문제를 해결하세요."),
use_tools([
read_file(),
write_file(),
execute_code(),
]),
generate(),
],
scorer=code_execution_scorer(),
)| 기능 | lm-evaluation-harness | Inspect AI |
|---|---|---|
| 모델 평가 | 강력 | 지원 |
| 에이전트 평가 | 제한적 | 강력 |
| 도구 사용 평가 | 미지원 | 네이티브 지원 |
| LLM-as-Judge | 제한적 | 네이티브 지원 |
| 대화형 평가 | 미지원 | 지원 |
모델의 원시 성능을 벤치마크하려면 lm-evaluation-harness를, 에이전트의 전체 행동을 평가하려면 Inspect AI를 사용하세요. 두 도구는 경쟁 관계가 아니라 보완 관계입니다.
Stanford의 HELM(Holistic Evaluation of Language Models)은 모델을 다차원으로 평가하는 프레임워크입니다. 정확도만이 아니라, 견고성, 공정성, 편향, 효율성, 유해성 등을 동시에 측정합니다.
HELM의 다차원 평가 접근법은 "이 모델이 좋은가?"라는 모호한 질문을 "이 모델이 어떤 측면에서 강하고, 어떤 측면에서 약한가?"라는 구체적인 질문으로 전환시켜 줍니다.
범용 프레임워크로 커버되지 않는 도메인 특화 평가가 필요한 경우, 커스텀 평가 하네스를 구축해야 합니다.
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any
@dataclass
class EvalExample:
"""평가 데이터 항목"""
id: str
input_text: str
expected: Any
metadata: dict = field(default_factory=dict)
@dataclass
class EvalResult:
"""개별 평가 결과"""
example_id: str
model_output: str
scores: dict[str, float]
latency_ms: float
token_usage: dict[str, int]
class Metric(ABC):
"""메트릭 인터페이스"""
@abstractmethod
def name(self) -> str:
...
@abstractmethod
def compute(
self, output: str, expected: Any
) -> float:
...
class ExactMatchMetric(Metric):
def name(self) -> str:
return "exact_match"
def compute(self, output: str, expected: Any) -> float:
return 1.0 if output.strip() == str(expected).strip() else 0.0
class ContainsMetric(Metric):
def name(self) -> str:
return "contains"
def compute(self, output: str, expected: Any) -> float:
return 1.0 if str(expected) in output else 0.0
class SemanticSimilarityMetric(Metric):
def __init__(self, embedding_model):
self.embedding_model = embedding_model
def name(self) -> str:
return "semantic_similarity"
def compute(self, output: str, expected: Any) -> float:
emb_output = self.embedding_model.encode(output)
emb_expected = self.embedding_model.encode(str(expected))
return cosine_similarity(emb_output, emb_expected)
class EvalHarness:
"""커스텀 평가 하네스"""
def __init__(self, model_fn, metrics: list[Metric]):
self.model_fn = model_fn
self.metrics = metrics
async def evaluate(
self,
examples: list[EvalExample],
) -> dict:
results = []
for example in examples:
import time
start = time.monotonic()
output = await self.model_fn(example.input_text)
elapsed = (time.monotonic() - start) * 1000
scores = {}
for metric in self.metrics:
scores[metric.name()] = metric.compute(
output, example.expected
)
results.append(EvalResult(
example_id=example.id,
model_output=output,
scores=scores,
latency_ms=elapsed,
token_usage={}, # 실제로는 모델 응답에서 추출
))
return self._aggregate(results)
def _aggregate(self, results: list[EvalResult]) -> dict:
"""결과 집계"""
summary = {"total": len(results)}
for metric in self.metrics:
scores = [r.scores[metric.name()] for r in results]
summary[metric.name()] = {
"mean": sum(scores) / len(scores),
"min": min(scores),
"max": max(scores),
}
avg_latency = sum(r.latency_ms for r in results) / len(results)
summary["avg_latency_ms"] = avg_latency
return summary새 모델이 출시되면 기존 모델과 체계적으로 비교할 수 있어야 합니다. 자동화된 비교 파이프라인을 구축하면, 모델 교체 결정을 데이터에 기반하여 내릴 수 있습니다.
from dataclasses import dataclass
@dataclass
class ComparisonResult:
model_a: str
model_b: str
metrics: dict[str, dict[str, float]]
winner: str
recommendation: str
async def compare_models(
model_a_fn,
model_b_fn,
model_a_name: str,
model_b_name: str,
eval_examples: list[EvalExample],
metrics: list[Metric],
) -> ComparisonResult:
"""두 모델의 체계적 비교"""
harness_a = EvalHarness(model_a_fn, metrics)
harness_b = EvalHarness(model_b_fn, metrics)
results_a = await harness_a.evaluate(eval_examples)
results_b = await harness_b.evaluate(eval_examples)
# 메트릭별 비교
comparison = {}
a_wins = 0
b_wins = 0
for metric in metrics:
name = metric.name()
score_a = results_a[name]["mean"]
score_b = results_b[name]["mean"]
comparison[name] = {
model_a_name: score_a,
model_b_name: score_b,
"difference": score_b - score_a,
}
if score_b > score_a:
b_wins += 1
elif score_a > score_b:
a_wins += 1
winner = model_a_name if a_wins > b_wins else model_b_name
# 지연시간 및 비용 비교
latency_a = results_a["avg_latency_ms"]
latency_b = results_b["avg_latency_ms"]
recommendation = (
f"{winner}이(가) {max(a_wins, b_wins)}/{len(metrics)} "
f"메트릭에서 우수합니다. "
f"지연시간: {model_a_name}={latency_a:.0f}ms, "
f"{model_b_name}={latency_b:.0f}ms"
)
return ComparisonResult(
model_a=model_a_name,
model_b=model_b_name,
metrics=comparison,
winner=winner,
recommendation=recommendation,
)모델 비교 시 정확도만 보지 마세요. 지연시간이 2배 느리지만 정확도가 2% 높은 모델이 항상 나은 선택은 아닙니다. 비용, 지연시간, 정확도의 트레이드오프(trade-off)를 종합적으로 고려해야 합니다.
6장에서는 AI 시스템의 안전을 책임지는 가드레일 하네스를 다룹니다. 프롬프트 인젝션 방어, 유해 콘텐츠 필터링, Guardrails AI와 NeMo Guardrails 프레임워크의 구조, 그리고 다계층 방어 전략을 살펴봅니다.
이 글이 도움이 되셨나요?
관련 주제 더 보기
프롬프트 인젝션 방어, 유해 콘텐츠 필터링, Guardrails AI와 NeMo Guardrails 프레임워크, 다계층 방어 전략을 통해 AI 시스템의 안전을 보장하는 방법을 다룹니다.
비결정적 출력 테스트, 스냅샷 테스트, 속성 기반 테스트, 회귀 테스트, 에이전트 행동 테스트 등 AI 시스템 테스트의 핵심 기법을 다룹니다.
에이전트 라이프사이클 관리, 도구 오케스트레이션, 서브에이전트 관리, 상태 관리, 에러 복구 등 복잡한 AI 워크플로우를 조율하는 방법을 다룹니다.