LLM 엔지니어링20장 · LLM 평가와 모니터링17 / 22← 이전목차다음 →MetaContents

20장. LLM 평가와 모니터링

실습 4 — 평가 방법 견주고 RAG 나눠 재기

실습 3에서 가장 나은 핵심 비교 채점자로 실습 1의 답 44개를 채점하고, 규칙·뜻·채점자의 세 방법으로 v2 와 v3 의 점수판을 만듭니다. 검색이 맞았는지(hit@3)도 재어 틀린 답을 검색 실패와 생성 실패로 나눕니다. 실습 1, 2를 먼저 실행해야 합니다.

1단계. 준비(실습 3의 핵심 비교 채점자)

Python
import json
import re
import sys
from pathlib import Path

import pandas as pd

sys.path.insert(0, ".")
import out_libbot as bot

answers = pd.read_csv("out_lib_answers.csv").merge(pd.read_csv("out_lib_scores.csv"), on=["번호", "판"])
evalset = {e["번호"]: e for e in map(json.loads, Path("library_eval.jsonl").read_text(encoding="utf-8").splitlines())}
FACTS = {"type": "object",
         "properties": {"참조의_핵심": {"type": "string"}, "답의_핵심": {"type": "string"},
                        "판정": {"type": "string", "enum": ["맞음", "틀림"]}},
         "required": ["참조의_핵심", "답의_핵심", "판정"]}
J2 = ("도서관 챗봇의 답을 채점합니다.\n"
      "1. 참조 답에서 질문에 답하는 핵심 사실(숫자, 요일, 날짜, 또는 '자료에 없음')을 짧게 적습니다.\n"
      "2. 챗봇의 답에서 같은 질문에 답하는 핵심 사실을 짧게 적습니다.\n"
      "3. 두 핵심 사실이 같으면 맞음, 다르면 틀림입니다. 챗봇이 참조에 없는 내용을 덧붙인 것은 따지지 않습니다.\n"
      "   참조가 '자료에 없음'인데 챗봇이 모른다고 하지 않고 무언가를 답했으면 틀림입니다.\n"
      "길이와 말투는 보지 않습니다. JSON 으로 답하세요.")
print(len(answers), "개 답 ·", list(answers.columns))
출력
44 개 답 · ['번호', '종류', '판', '질문', '답', '자료', '유사도', '규칙', '뜻']

2단계. 채점자로 채점하기

Python
verdicts = []
for r in answers.itertuples():
    e = evalset[r.번호]
    out = bot.chat_json(J2, f"질문: {e['질문']}\n참조 답: {e['정답']}\n챗봇의 답: {r.답}", FACTS)
    verdicts.append(out["판정"] == "맞음")
answers["채점자"] = verdicts
# 영문 낱말이 섞인 답은 내용이 맞아도 내보낼 수 없으니, 채점자 점수에도 형식 규칙을 함께 건다
answers["채점자+형식"] = answers["채점자"] & answers["답"].map(lambda a: re.search(r"[A-Za-z]{3,}", a) is None)
board = answers.groupby(["판", "종류"])[["규칙", "뜻", "채점자", "채점자+형식"]].sum()
# 결과: 판·종류마다 방법별로 맞았다고 본 답의 수(답 18문항, 모름 4문항)
print(board)
print("다시 물음", bot.retried["수"])
출력
       규칙   뜻  채점자  채점자+형식
판  종류
v2 답   18  17   16      16
   모름   0   0    3       3
v3 답   17  17   16      16
   모름   0   4    4       4
다시 물음 8

3단계. 검색과 답을 나눠 보기

Python
# 답이 있는 질문만: 근거 글이 검색한 조각 셋 안에 있으면 검색이 맞은 것
part = answers[answers["종류"] == "답"].copy()
part["검색"] = [evalset[n]["근거"] in ctx for n, ctx in zip(part["번호"], part["자료"])]
names = {(True, True): "잘 됨", (True, False): "생성 실패", (False, False): "검색 실패", (False, True): "검색 틀림·답 맞음"}
part["칸"] = [names[(s, j)] for s, j in zip(part["검색"], part["채점자+형식"])]
print(pd.crosstab(part["판"], part["칸"]))
# 결과: 생성 실패로 나온 답
print(part[part["칸"] != "잘 됨"][["번호", "판", "칸", "답"]].to_string(index=False))
출력
칸   생성 실패  잘 됨
판
v2      2   16
v3      2   16
 번호  판     칸                                                                                 답
  8 v2 생성 실패                                         도서관은 매주 월요일과, 해마다 12월 첫째 주 목요일과 금요일에 쉬어요.
  8 v3 생성 실패                                          도서관은 매주 월요일과 해마다 12월 첫째 주 목요일과 금요일에 쉬어요.
 18 v2 생성 실패 연체가 발생하면, 가장 늦게 반납된 책을 기준으로 대출이 정지됩니다. 정지된 대출이 발생하면, 해당 책을 반납하고 정지된 대출을 해지해야 합니다.
 18 v3 생성 실패                                                 연체가 발생하면 가장 늦은 책을 기준으로 대출이 정지됩니다.

4단계. 모름 질문에서 두 판 견주기

Python
dont = answers[answers["종류"] == "모름"][["번호", "판", "규칙", "뜻", "채점자", "답"]]
# 결과: 방법마다 모름 질문의 판정과 실제 답
print(dont.sort_values(["번호", "판"]).to_string(index=False))
출력
 번호  판    규칙     뜻   채점자                                                                                                                                                          답
 19 v2 False False  True                                                                                              죄송합니다, 자료에는 도와드릴 수 없는 정보입니다. 이 정보는 도서관 웹사이트나 앱에서 확인하실 수 있습니다.
 19 v3 False  True  True                                                                                                                                               안내 자료에 없습니다.
 20 v2 False False  True                                죄송합니다, 노트북 빌려드리지 않습니다. 도서관 서비스는 주로 책, 잡지, 전자책 등 서적 형태의 자료를 대여하는 것에 집중하고 있습니다. 컴퓨터 관련 자료는 대여하지 않고, 대신 복사와 출력 서비스를 제공하고 있습니다.
 20 v3 False  True  True                                                                                                                                               안내 자료에 없습니다.
 21 v2 False False  True                                                                                                                                    도서관 안에 카페는 없는 것으로 보입니다.
 21 v3 False  True  True                                                                                                                                               안내 자료에 없습니다.
 22 v2 False False False 도서관에서 책을 기증하려면, 도서관에 직접 방문하여 기증을 요청하거나, 도서관에 설치된 기증 상자에 책을 직접 기증하실 수 있습니다. 기증을 원하시는 책의 수량과 종류에 따라, 도서관에서 적절한 처리 방안을 제시할 수 있습니다. 기증을 원하시는 경우, 도서관에 문의해 주세요.
 22 v3 False  True  True                                                                                                                                               안내 자료에 없습니다.

답이 있는 질문에서는 세 방법 모두 v2 와 v3 가 비슷했습니다(규칙 18·17, 채점자 16·16). 두 판 모두 8번과 18번이 생성 실패로 나왔습니다. 8번은 쉬는 날을 물었는데 법정 공휴일을 빼고 장서 점검일을 넣었고, 18번은 연체의 핵심(늦은 날수만큼 정지)을 빠뜨렸습니다. 검색은 두 판 모두 18문항을 다 맞혔으니, 고칠 곳은 검색이 아니라 생성입니다. 모름 질문에서는 판정이 크게 갈렸습니다. 규칙은 두 판 모두 0개, 뜻은 v3 만 4개, 채점자는 v2 3개와 v3 4개를 맞다고 했습니다. 채점자는 v2 의 20, 21번처럼 자료에 없는 말을 단정한 답도 맞다고 봤습니다. 또 v3 가 답이 있는 4번에서 거절한 답도 맞다고 판정했습니다. 그 한 건을 따로 다시 채점해 보니, 채점자가 참조 답(3일 안에 찾아가야 합니다)의 핵심을 "자료에 없음"으로 잘못 적고 있었습니다. 실습 3의 시험 사례에서 사람과 17/18 이 맞은 채점자도 실제 답에서는 실수합니다. 그래서 한 방법의 점수만 믿지 않고, 판정이 갈린 답은 사람이 읽습니다. 이 결과로 보면 v3 는 지어내지 않는다는 점에서 v2 보다 낫습니다. 다만 답이 있는 질문까지 거절하는 일이 생겼으니, 배포 전에 거절이 늘지 않았는지 따로 셉니다.

이 실습이 뜻하는 것

이 실습은 음식 경연에 심사위원 셋을 세우고, 맛없는 음식이 나오면 재료 탓인지 요리사 탓인지 나눠 보는 일과 같습니다. 앞서 쓴 점수를 모으고 가장 나은 심사위원을 데려오고(1단계), 그 심사위원으로 44접시를 매겨 세 심사위원의 점수판을 만들고(2단계), 틀린 접시를 재료 고르기의 실패와 요리의 실패로 나눈 뒤(3단계), 판정이 갈린 모름 질문을 나란히 놓고 봅니다(4단계). 여기서 세 심사위원이 규칙·뜻·채점자, 재료 고르기가 검색, 요리가 생성(답 쓰기)입니다. 이렇게 검색과 생성을 나눠 재는 것이 RAG(Retrieval-Augmented Generation, 검색 증강 생성)를 평가하는 방법입니다.

단계출력뜻
1. 준비44 개 답 과 칸 9개실습 1의 답에 실습 2의 유사도, 규칙, 뜻 판정을 붙였습니다
2. 답 있는 질문규칙 18·17, 뜻 17·17, 채점자 16·16v2·v3 의 차례입니다. 세 방법 모두 두 판의 차이가 작습니다
2. 모름 질문규칙 0·0, 뜻 0·4, 채점자 3·4같은 답을 두고도 방법마다 판정이 크게 갈렸습니다
2. 채점자+형식채점자와 같은 수영어가 섞인 답이 없어 형식 규칙을 더해도 수가 그대로입니다
2. 다시 물음다시 물음 8Ollama 오류나 깨진 JSON 으로 다시 물은 횟수입니다
3. 실패 나누기v2·v3 모두 잘 됨 16, 생성 실패 2검색 실패는 하나도 없습니다. 근거는 늘 찾았고, 틀린 두 문항(8, 18번)은 답을 쓰는 단계에서 틀렸습니다
4. 모름 답 판정20, 21번 v2 의 채점자 True채점자가 자료에 없는 말을 단정한 v2 의 답도 맞다고 봤습니다. 연습 시험에서 잘 맞던 채점자도 실제 답에서는 실수합니다

검색이 맞았는지는 hit@3(상위 3조각 안에 근거 글이 들었는지)으로 봤습니다.

한 줄로 줄이면, 점수판 하나만 보면 v2 와 v3 가 비슷해 보이지만, 모름 질문을 세 방법으로 나눠 보면 v3 가 덜 지어낸다는 것이 드러난 실습입니다. 틀린 답은 검색이 아니라 생성에서 나왔으니 고칠 곳은 답을 쓰는 쪽입니다. 다만 방법마다 판정이 갈리므로 갈린 답은 사람이 읽어야 하고, v3 가 답이 있는 4번까지 거절한 일은 배포 전에 따로 세어야 합니다.

코드 설명

  • 2단계는 실습 3의 핵심 비교 채점자(J2, FACTS)를 그대로 써서 44개 답을 채점합니다. 채점자는 사람과 맞춰 본 판을 써야 그 점수를 믿을 수 있습니다.
  • 채점자+형식 은 채점자의 판정에 영문 섞임 규칙을 함께 건 것입니다. 방법을 하나만 쓰지 않고 서로의 빈틈을 메웁니다.
  • 3단계의 evalset[n]["근거"] in ctx 는 근거 글이 검색한 조각에 들었는지 봅니다. 검색과 채점 결과로 실패를 네 칸에 나눕니다.
  • 4단계는 같은 답을 세 방법이 어떻게 판정했는지 나란히 놓습니다. 어느 방법이 무엇을 놓쳤는지 읽는 것이 평가의 목적입니다.
← 이전 절20장 · 실습 3 — LLM 채점자 만들고 사람과 맞춰 보기다음 절 →20장 · 실습 5 — 드리프트 감지하기