평가(Evals)

프롬프트를 변경하고, 한 번 시도해보고, 답변이 더 좋아 보여서 배포했는데, 일주일 후에 사용자가 이전보다 더 나빠진 경우를 마주치게 됩니다. 평가(eval) (evaluation의 약자)는 해결책입니다. AI 기능이 작동하는지를 반복적으로 테스트하는 것으로, 입력값과 그에 대한 좋은 출력값이 무엇인지 짝지어진 세트이고, 매번 같은 방식으로 채점되어 변경사항이 실제로 도움이 되었는지 알 수 있습니다. 모델은 확률론적 블랙박스로 같은 질문에 매번 다르게 답변하므로, 측정이 알 수 있는 유일한 방법이며, 이러한 규율이 데모와 제품을 구분하는 많은 부분입니다.
육안 검사가 실패하는 이유
AI의 답변을 손으로 확인하는 것은 처음에는 괜찮아 보입니다. 프롬프트를 실행하고, 답변을 읽고, 괜찮아 보이므로 계속 진행합니다. 문제는 세 가지가 조용히 당신을 방해하고, 당신이 이미 모두 겪었다는 것입니다.
세 가지는 다음과 같습니다:
- 출력이 변합니다. 같은 프롬프트는 실행마다 다른 답변을 줄 수 있으므로, 한 번의 좋은 결과가 다음 결과도 좋을 것이라고 보장하지 않습니다.
- 변경사항이 회귀를 유발합니다. 한 경우를 고치는 프롬프트 편집은 종종 보고 있지 않은 다른 경우를 깹니다.
- 확장되지 않습니다. 다섯 개의 답변은 읽을 수 있습니다. 한 줄을 변경할 때마다 오백 개를 읽을 수는 없습니다.
이 중 어느 것도 당신이 뭔가 잘못했다는 의미가 아닙니다. 이는 육안 검사가 이 크기의 작업에 적합한 도구가 아니라는 의미이고, 더 평화로운 방법이 있다는 것입니다.
평가 세트 구축
평가 세트는 테스트 경우의 목록입니다. 각 경우에는 입력값과 그에 대한 좋은 출력값이 무엇인지가 있습니다. 작게 시작하세요. 일반적인 상황과 몇 가지 까다로운 경계 사례를 다루는 10개에서 20개의 경우가 없는 것보다 훨씬 더 유용하며, 야생에서 새로운 실패를 발견하면서 세트를 확대할 수 있습니다.
eval_set = [
{"input": "음식이 차갑고 늦었다.", "expected": "NEGATIVE"},
{"input": "내 인생 최고의 식사!", "expected": "POSITIVE"},
{"input": "그냥 괜찮았고, 특별한 건 없었다.", "expected": "NEUTRAL"},
# ...발견하면서 실제 경우와 경계 사례를 추가하세요
]사용자가 나쁜 답변을 보고할 때, 주어졌어야 했던 출력과 함께 세트에 추가합니다. 그러면 평가 세트는 다시 실패하고 싶지 않은 모든 실수에 대한 증가하는 기억이 되고, 고친 버그가 계속 유지하는 테스트가 되는 것처럼 말입니다.
채점 방법
다른 작업은 다른 채점이 필요하므로, 첫 번째 단계는 확인을 기대하는 답변의 종류와 일치시키는 것입니다.
- 정확한 일치는 한 가지 올바른 답변이 있을 때 작동합니다: 분류 레이블, 추출된 필드, 예 또는 아니오. 출력을 기대값과 직접 비교합니다.
- 기준 기반 채점은 요약이나 답변처럼 올바른 단일 답변이 없을 때 작동합니다. 출력이 조건을 충족하는지 확인합니다: 요약이 핵심 사실을 언급하나요? 50단어 이하인가요? 톤이 정중한가요?
- 판사로서의 LLM은 기준에 대한 출력을 채점하기 위해 두 번째 모델 호출을 사용합니다. 간단한 확인이 포착할 수 없는 모호한 품질 질문으로 확장되지만, 판사는 자신이 모델이므로 틀릴 수 있고, 때때로 인간 판단에 대해 정신 수표를 합니다.
# 평가 세트에 대한 정확한 일치 채점
def run_evals(eval_set, classify):
passed = 0
for test in eval_set:
output = classify(test["input"])
if output == test["expected"]:
passed += 1
else:
print(f'FAIL: "{test["input"]}" -> got {output}, wanted {test["expected"]}')
print(f"{passed}/{len(eval_set)} passed")정확한 일치는 시작하기에 가장 친절한 곳이고, 이전 장의 분류 및 추출 작업과 완벽하게 맞습니다. LLM-as-judge 아이디어는 답변이 표준을 충족하는지 확인하는 것이 종종 답변을 생성하는 것보다 더 쉬운 예측이기 때문에 작동합니다. 에세이를 검토하는 것이 쓰는 것보다 쉬운 것과 같은 방식입니다. 하지만 판사는 같은 결함을 가진 또 다른 예측기이므로, 점수를 유용한 추정치로 취급하고, 명확한 루브릭을 주고, 때때로 표본에 대한 자신의 점수에 대해 확인하세요.
모든 변경사항에 대해 실행
평가 세트는 실제로 실행할 때만 유용합니다. 프롬프트를 코드처럼 취급합니다: 프롬프트, 모델 또는 검색의 변경사항을 배포하기 전에, 평가를 실행하고 점수를 이전과 비교합니다. 숫자가 내려갔다면, 당신의 한 손 테스트가 괜찮아 보였더라도, 회귀를 유발했습니다.
이것이 프롬프트 엔지니어링을 추측에서 자신감을 가지고 반복할 수 있는 것으로 바꿉니다. 뭔가를 변경하고, 측정하고, 더 높은 점수를 기록하고, 더 낮은 점수를 기록합니다. 이는 일반 소프트웨어를 신뢰할 수 있게 하는 같은 루프이고, 이제 AI 기능의 모호한 부분에 적용됩니다.
점수가 떨어졌다면, 회귀를 유발했습니다. 한 번의 운 좋은 손 테스트는 세트를 무시하지 않으므로, 매번 숫자를 동점 부수로 놔두세요.
실전에서
마지막 섹션의 run_evals 함수는 완전하고, 작으면, 평가 조랑마입니다. 이를 분류기와 평가 세트로 가리키면, 통과하는 경우와 정확히 실패하는 경우를 알려줍니다:
run_evals(eval_set, classify_review)
# FAIL: "그냥 괜찮았고, 특별한 건 없었다." -> got POSITIVE, wanted NEUTRAL
# 2/3 passed그 하나의 실패 선은 수십 개의 성공한 손 테스트보다 가치가 있습니다. 왜냐하면 고칠 수 있는 실제 약점을 가리키고 다시 측정하기 때문입니다. 마지막 장, 안전 및 제한, 실제 사용자 앞에 놓기 전에 설계할 위험을 다룹니다.
run_evals과 같은 작은 조랑마가 이미 비용을 지불합니다: 점수와 정확히 깨진 경우 목록을 제공합니다. 하나를 고치고, 다시 실행하고, 숫자가 이동하는 것을 보세요. 다음으로, 안전 및 제한은 실제 사용자가 도착하기 전에 보호해야 할 것을 다룹니다. 
