DeepEval에서는 LLM의 평가결과에 대해 확인하는 방법이 크게는 3가지가 있다. (다른 방법도 있음)
| API | 실행 단위 | 주된 목적 | 기준 미달 시 |
|---|---|---|---|
metric.measure() | 테스트 케이스 1개 × Metric 1개 | 점수와 이유를 빠르게 확인 | 자동으로 테스트를 실패시키지 않음 |
evaluate() | 여러 테스트 케이스 × 여러 Metric | 실험·분석·일괄 평가 | 결과를 수집하며 실행 자체는 실패시키지 않음 |
assert_test() | 테스트 케이스 1개 × 여러 Metric | pytest·CI 회귀 테스트 | AssertionError를 발생시킴 |
measure() = 답안 하나를 채점기로 직접 채점
evaluate() = 여러 답안을 모아 성적표 생성
assert_test() = 합격선 미달이면 테스트 실패 처리
개별적인 평가지수(metric)에 대해서 디버깅을 한다. 특정한 테스트케이스에 대해서 반환하는 점수와 왜그렇게 판단했는지 이유를 확인해본다.
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase
test_case = LLMTestCase(
input="환불 기간은 얼마나 되나요?",
actual_output="상품 수령 후 30일 이내에 환불할 수 있습니다.",
)
metric = AnswerRelevancyMetric(threshold=0.7)
score = metric.measure(test_case)
print(score)
print(metric.score)
print(metric.reason)
print(metric.is_successful())
AnswerRelevancyMetric (답변 연관성 지표) 에 대해, 해당 테스트케이스의 결과가 어떻게 나오는지를 디버깅하는 예제다.
Jupyter Notebook을 사용하는 환경이라면 좋은 내용인데, 주로 테스트케이스 최적화를 하는 경우에 이 방법을 이용해서 조정한다.
evaluate() 는 여러 케이스와 평가지표들에 대해 분석해서 결과를 보여준다. measure() 가 특정 테스트케이스가 특정 지표에 대해서 어떤 점수를 보여주는지를 확인하는데 사용한다면, evaluate() 는 여러 케이스에 대해 여러 지표를 확인할 수 있다.
from deepeval import evaluate
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase
test_cases = [
LLMTestCase(
input="환불 기간은 얼마나 되나요?",
actual_output="상품 수령 후 30일 이내에 환불할 수 있습니다.",
),
LLMTestCase(
input="배송비는 무료인가요?",
actual_output="5만 원 이상 주문하면 무료입니다.",
),
]
metrics = [
AnswerRelevancyMetric(threshold=0.7),
]
results = evaluate(
test_cases=test_cases,
metrics=metrics,
)
위 코드는 2개의 테스트케이스에 대해 AnswerRelevancyMetric 지표를 측정했을 때 어떻게 되는지를 확인한다. 동시에 다른 지표를 확인하려면 아래와 같이 한다.
from deepeval.metrics import (
AnswerRelevancyMetric,
FaithfulnessMetric,
)
evaluate(
test_cases=test_cases,
metrics=[
AnswerRelevancyMetric(threshold=0.7),
FaithfulnessMetric(threshold=0.7),
],
)
역시 Jupyter notebook을 사용해서 비교를 한다거나, 여러 테스트케이스를 평가/조정 해야한다거나 혹은 살짝씩 다른 2개 이상의 프롬프트에 대해 비교분석해야하는 경우 유용하다. 또는 결과를 프로그램에서 후처리해야할때도 사용가능하다.
만약 평가해야할 앱이 tracing 기능을 구현하고 있다면, @observe 와 함께 evals_iterator() 를 사용하는 것도 좋다.
assert_test() 는 DeepEval 평가를 pytest assertion으로 바꾼다. 실행 시 실패하면 AssertionError 를 발생시키는데, 이를 이용해서 유닛테스트나 CI/CD에도 이용할 수 있다.
from deepeval import assert_test
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase
def test_refund_answer_is_relevant() -> None:
test_case = LLMTestCase(
input="환불 기간은 얼마나 되나요?",
actual_output="상품 수령 후 30일 이내에 환불할 수 있습니다.",
)
metric = AnswerRelevancyMetric(threshold=0.7)
assert_test(
test_case=test_case,
metrics=[metric],
)
특정한 지표에 대해 해당 테스트케이스가 적정수중 (threshold)를 충족하는지를 체크한다.
assert_test() 는 evaluate() 와는 다르게 단 하나의 테스트케이스에 대해 여러 지표에 대한 테스트를 실행할 수 있다.
assertion 코드이기 때문에 pytest의 parameterize를 활용할 수도 있다.
import pytest
from deepeval import assert_test
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase
TEST_CASES = [
pytest.param(
LLMTestCase(
input="환불 기간은?",
actual_output="상품 수령 후 30일 이내입니다.",
),
id="refund-period",
),
pytest.param(
LLMTestCase(
input="배송비는 무료인가요?",
actual_output="5만 원 이상 주문하면 무료입니다.",
),
id="free-shipping",
),
]
@pytest.mark.parametrize("test_case", TEST_CASES)
def test_customer_support_answer_is_relevant(
test_case: LLMTestCase,
) -> None:
assert_test(
test_case=test_case,
metrics=[
AnswerRelevancyMetric(threshold=0.7),
],
)
즉, 테스트케이스에 사용하는 프롬프트나 threshold 조정을 위해 measure() 나 evaluate() 를 사용하고, 어느정도 값이 완성되면 이것을 assert_test() 를 이용해 회귀테스트나 CI/CD의 파이프라인에 추가해서 사용할 수 있다.
ref