LLM 서비스 평가 실습 정리: ROUGE, BERTScore, G-Eval
LLM 서비스 평가를 정리하면서 남은 생각은 “평가 지표가 많다”가 아니었다. 같은 출력도 무엇을 보려는지에 따라 지표가 달라진다는 점이었다.
요약 품질을 볼 때와 업무 리포트 품질을 볼 때, RAG 답변의 근거성을 볼 때는 평가 질문이 다르다.
flowchart TD
O["LLM Output<br/>요약, 리포트, QA 답변"] --> R["ROUGE<br/>표면 단어 overlap"]
O --> B["BERTScore<br/>의미 유사도"]
O --> G["G-Eval<br/>rubric 기반 judge"]
O --> F["Groundedness<br/>근거 밖 생성 여부"]
R --> D["Metric Reading<br/>무엇을 좋은 출력으로 볼 것인가"]
B --> D
G --> D
F --> D
D --> C["Claim Boundary<br/>데이터셋, 기준, 한계와 함께 해석"]
ROUGE
ROUGE는 생성 결과와 기준 답변의 단어 overlap을 본다.
| 장점 | 한계 |
|---|---|
| 계산이 빠르다 | 의미가 같아도 표현이 다르면 낮게 나올 수 있다 |
| 요약 baseline 비교에 좋다 | 사실성 검증은 어렵다 |
| 정답 요약문이 있을 때 쓰기 쉽다 | 좋은 글인지까지 보진 못한다 |
메일 요약이나 문서 요약처럼 기준 요약문이 있는 경우에는 빠른 비교 지표로 쓸 수 있다. 하지만 ROUGE가 높다고 답변이 항상 좋은 것은 아니다.
BERTScore
BERTScore는 embedding 기반으로 의미 유사도를 본다.
| 장점 | 한계 |
|---|---|
| 표현이 달라도 의미가 비슷하면 반영된다 | 근거 기반 사실성은 따로 봐야 한다 |
| 요약의 semantic similarity를 보기 좋다 | 도메인 특화 용어에는 모델 영향이 있다 |
| ROUGE보다 유연하다 | 해석이 직관적이지 않을 수 있다 |
여기서는 ROUGE를 표면 비교, BERTScore를 의미 비교에 가깝게 이해했다.
G-Eval
G-Eval은 LLM을 평가자로 쓰는 방식이다. 요약, 리포트, QA처럼 기준이 복합적인 결과를 볼 때 유용하다.
| 평가 축 | 예 |
|---|---|
| 정확성 | 중요한 내용이 맞는가 |
| 충실성 | 근거 밖의 내용을 만들지 않는가 |
| 완결성 | 사용자가 이해할 만큼 충분한가 |
| 형식 준수 | 요구한 포맷을 지켰는가 |
| 실행 가능성 | 리포트나 액션 아이템으로 쓸 수 있는가 |
G-Eval은 사람이 채점하듯 rubric을 만들 수 있다는 점이 장점이다. 대신 judge 모델이 항상 공정하다고 믿으면 안 된다.
지표를 함께 읽기
정리하면서 가장 설득력 있었던 방식은 개별 요약은 ROUGE와 BERTScore로 보고, 최종 리포트는 G-Eval로 비교하는 흐름이었다.
출력의 성격이 다르기 때문이다.
| 출력 | 적합한 평가 |
|---|---|
| 짧은 요약 | ROUGE, BERTScore |
| 긴 리포트 | G-Eval, rubric 기반 평가 |
| RAG 답변 | Groundedness, Faithfulness, G-Eval |
| Agent 실행 결과 | tool call 성공 여부, task completion |
지표는 하나만 고르는 것이 아니라 출력 유형에 맞게 조합해야 한다.
평가 수치를 쓸 때의 주의
평가 수치는 글에 넣기 좋지만, 조심해서 써야 한다.
| 체크 | 이유 |
|---|---|
| 평가셋 크기 | 작은 데이터셋은 우연 영향이 크다 |
| baseline | 무엇과 비교했는지 없으면 의미가 약하다 |
| judge 기준 | rubric이 바뀌면 점수도 바뀐다 |
| 실패 사례 | 평균 점수만 보면 위험한 실패가 가려질 수 있다 |
예를 들어 어떤 조건에서 G-Eval 점수가 가장 높았다는 기록이 있어도, 그것은 해당 데이터와 rubric 안에서의 결과다. 일반적인 서비스 품질로 바로 확장하면 안 된다.
평가 지표를 config로 분리하는 코드
평가 코드를 직접 적어보면 지표를 함수 안에 고정하지 않고 config에서 선택하는 편이 자연스럽다. 같은 요약 결과라도 ROUGE, BERTScore, G-Eval은 보는 관점이 다르다. 그래서 평가 코드는 “하나의 점수 계산기”보다 “여러 평가 질문을 실행하는 runner”에 가깝다.
짧게 적으면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def run_evaluation(outputs: list[str], references: list[str], metrics: list[str]):
# 하나의 점수로 합치기 전에, 어떤 질문에 답하는 지표인지 나눠서 본다.
results = {}
if "rouge" in metrics:
results["surface_overlap"] = rouge_score(outputs, references)
if "bertscore" in metrics:
results["semantic_similarity"] = bert_score(outputs, references)
if "g_eval" in metrics:
# G-Eval은 모델보다 rubric을 어떻게 쓰는지가 더 중요했다.
results["rubric_judgement"] = g_eval(
outputs=outputs,
references=references,
rubric=["accuracy", "coverage", "faithfulness"],
)
return results
평가 지표를 이렇게 나누면 결과 해석도 같이 달라진다. ROUGE가 낮아도 의미가 맞을 수 있고, G-Eval이 높아도 judge 기준이 느슨하면 위험하다.
지표보다 평가 질문
LLM 서비스 평가는 “정답률” 하나로 설명하기 어렵다. 요약은 ROUGE/BERTScore, 리포트는 G-Eval, RAG는 groundedness를 함께 봐야 한다.
지표를 고르기 전에 평가 질문을 정해야 한다. “무엇을 좋은 출력이라고 볼 것인가”가 정해져야 점수도 의미를 가진다.