20장. LLM 평가와 모니터링
규칙으로 채점하기
OX 시험은 채점 열쇠만 있으면 누구나 같은 점수를 매깁니다. 빠르고, 몇 번을 채점해도 같습니다. 대신 열쇠에 없는 표현으로 쓴 답은 틀렸다고 합니다.
그림의 네 카드가 자주 쓰는 규칙입니다. 열쇠 낱말은 사실을, 형식은 엉뚱한 외국어나 깨진 글자를, 길이는 장황한 답을, 금지어는 나와서는 안 되는 말(비밀번호, 남의 정보)을 봅니다. 채점 열쇠가 규칙이고, 열쇠와 다르게 쓴 맞는 답이 규칙 채점의 빈틈입니다.
규칙 견주기
| 규칙 | 잡는 것 | 놓치는 것 |
|---|---|---|
| 열쇠 포함 | 숫자, 날짜가 빠지거나 다른 답 | 같은 뜻의 다른 표현("2주"), 열쇠는 있는데 다른 틀린 말 |
| 형식 | 영어 낱말 섞임, 깨진 글자 | 내용의 잘못 |
| 길이 | 너무 길거나 빈 답 | 짧고 틀린 답 |
| 금지어 | 새면 안 되는 말 | 금지어 목록에 없는 새 말 |
규칙 채점 함수
import re
def rule_check(answer, keys, max_len=120):
"""규칙마다 통과(True)·실패(False)를 돌려준다"""
return {
"열쇠": any(k in answer for k in keys.split("|")),
"형식": re.search(r"[A-Za-z]{3,}", answer) is None, # 영문 낱말이 섞였나
"길이": 0 < len(answer) <= max_len,
}
print(rule_check("대출 기간은 14일입니다.", "14일"))
print(rule_check("대출 기간은 2주입니다.", "14일")) # 맞는 답인데 열쇠가 없다
print(rule_check("컬러는 한 장에 Consists of 300원.", "300원")) # 열쇠는 있는데 엉뚱한 영어가 섞였다코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
import re | 정규 표현식(regular expression, 글자의 꼴을 적는 규칙) 표준 라이브러리를 불러온다 |
keys.split(...) | 열쇠 글을 세로줄 | 자리에서 잘라 목록으로 만든다. "안내 데스크|문의" 는 낱말 둘이 된다 |
any(...) | 안의 값 가운데 하나라도 True 면 True 다. 열쇠 낱말 가운데 하나만 들어 있어도 통과다 |
re.search(pattern, text) | 글에서 꼴에 맞는 첫 자리를 찾는다. 찾으면 Match(맞은 자리) 객체, 못 찾으면 None 이다 |
r"[A-Za-z]{3,}" | r 은 raw(날것) 글자로, 역슬래시를 그대로 둔다. [A-Za-z] 는 영문 대문자나 소문자 한 글자, {3,} 는 그것이 3번 이상 이어진다는 뜻이다 |
... is None | 못 찾았으면 True 다. 영문 낱말이 없어야 형식 통과다 |
max_len=120 | 인자를 주지 않으면 120 을 쓴다. 답의 글자 수 상한이다 |
이 코드가 뜻하는 것
택배 접수 창구를 떠올려 봅니다. 받는 사람 이름이 적혔는지, 주소 칸에 엉뚱한 글자가 없는지, 상자가 규격 크기 안인지를 차례로 봅니다. 여기서 받는 사람 이름 확인이 열쇠 규칙, 주소 칸 확인이 형식 규칙, 상자 규격이 길이 규칙입니다. 비유와 다른 점이 하나 있습니다. 창구 직원은 눈치로 이상한 상자를 알아채지만, 규칙 함수는 적어 둔 세 가지만 봅니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
def rule_check(answer, keys, max_len=120) | 답과 열쇠를 받아 규칙마다 판정한다 | 접수 창구 |
"열쇠": any(...) | 열쇠 낱말이 하나라도 들었나 | 받는 사람 이름 확인 |
"형식": re.search(...) is None | 영문 세 글자 이상 덩어리가 없나 | 주소 칸에 엉뚱한 글자 확인 |
"길이": 0 < len(answer) <= max_len | 비지 않고 120자 이하인가 | 상자 규격 확인 |
둘째 결과는 "2주"라고 쓴 맞는 답인데 '열쇠': False 입니다. 셋째 결과는 열쇠 '300원' 은 들었지만 영어가 섞여 '형식': False 로 걸립니다. 규칙마다 따로 판정을 남겨 두면 어느 규칙에서 걸렸는지 바로 보입니다.
작게 줄여서 눈으로 보기
형식 규칙의 [A-Za-z]{3,} 가 무엇을 잡고 무엇을 놓치는지 봅니다. 문장은 설명하려고 지어낸 것입니다.
import re
for s in ["대출은 14일", "OK 입니다", "Wi-Fi 가 됩니다", "Consists of 300원"]:
# 영문자가 3개 이상 이어진 덩어리를 모두 찾는다
print(f"{s:18s}", re.findall(r"[A-Za-z]{3,}", s))대출은 14일 []
OK 입니다 []
Wi-Fi 가 됩니다 []
Consists of 300원 ['Consists']| 결과 | 읽는 법 |
|---|---|
대출은 14일 [] | 영문이 없어 빈 목록이다. 형식 통과다 |
OK 입니다 [] | 영문이 두 글자뿐이라 3번 이상에 못 미친다. 짧은 영어는 봐준다 |
Wi-Fi 가 됩니다 [] | 하이픈이 끊어 Wi, Fi 가 두 글자씩이다. 영어 낱말인데 빠져나간다 |
Consists of 300원 ['Consists'] | 세 글자 이상 영문 덩어리를 찾았다. "of" 는 두 글자라 목록에 없다 |
re.findall 은 find all(모두 찾기)로, 맞는 자리를 모두 찾아 목록으로 돌려줍니다. "OK" 를 봐주는 것도, "Wi-Fi" 를 놓치는 것도 {3,} 라는 숫자 하나에서 나옵니다. 규칙은 이렇게 정한 꼴만 봅니다.
주의할 점
- 열쇠를 좁게 잡으면 맞는 답을 틀렸다고 합니다. 열쇠를 넓게 잡으면 틀린 답을 맞았다고 합니다. 실습 1에서 이 일이 실제로 일어납니다.
- 규칙 채점은 빠르고 값이 들지 않아 모든 답에 먼저 돌립니다. 규칙이 놓치는 것은 다음 두 방법이 맡습니다.