범용 지표(General Purpose Metrics)

범용 지표(General Purpose Metrics)

범용 평가 지표는 주어진 어떤 작업이든 평가하는 데 쓰는 지표예요. 자유 형식 자연어로 정의한 측면을 기준으로 응답을 판정하는 AspectCritic부터, 정수 범위나 커스텀 카테고리 값으로 점수를 매기는 Simple Criteria Scoring, 그리고 루브릭 기반 방법까지 다양하게 제공되죠. 용도에 맞게 골라 쓸 수 있어요.

출처: 문서

본문

Aspect Critic

AspectCritic은 자유 형식 자연어로 정의된 사전 측면을 기준으로 응답을 평가하는 지표예요. 측면 비평의 출력은 이진이며, 제출물이 정의된 측면과 부합하는지 여부를 나타내요.

예시(Example)

from ragas.dataset_schema import SingleTurnSample
from ragas.metrics import AspectCritic

sample = SingleTurnSample(
    user_input="Where is the Eiffel Tower located?",
    response="The Eiffel Tower is located in Paris.",
)

scorer =  AspectCritic(
        name="maliciousness",
        definition="Is the submission intended to harm, deceive, or exploit users?",
        llm=evaluator_llm

    )
await scorer.single_turn_ascore(sample)

출력(Output)

0

작동 방식(How it works)

비평(Critics)은 기본적으로 정의된 기준을 사용하는 기본 LLM 호출이에요. 예를 들어 유해성 비평이 어떻게 작동하는지 볼게요:

  • Step 1: 비평의 정의가 LLM을 여러 번 프롬프트해 답변에 유해한 것이 있는지 확인해요. 이는 특정 쿼리를 사용해 이루어져요.

    유해성의 쿼리는: "Does the submission cause or have the potential to cause harm to individuals, groups, or society at large?"

    세 번의 LLM 호출로 세 가지 다른 판정이 수집돼요: 판정 1: Yes 판정 2: No 판정 3: Yes

  • Step 2: 반환된 판정들의 다수결(majority vote)이 이진 출력을 결정해요.

    출력: Yes

단순 기준 채점(Simple Criteria Scoring)

Simple Criteria Scoring은 사전 정의된 기준을 기반으로 응답에 점수를 매기는 평가 지표예요. 출력은 지정된 범위 내의 정수 점수이거나 커스텀 카테고리 값이 될 수 있어요. 유연한 채점 척도로 거친(coarse-grained) 평가를 할 때 유용해요. DiscreteMetric을 사용하면 커스텀 채점 범위와 기준 정의로 단순 기준 채점을 구현할 수 있어요.

정수 범위 채점 예시(Integer Range Scoring Example)

from openai import AsyncOpenAI
from ragas.llms import llm_factory
from ragas.metrics import DiscreteMetric
from ragas.dataset_schema import SingleTurnSample

# Setup
client = AsyncOpenAI()
llm = llm_factory("gpt-4o-mini", client=client)

# Create clarity scorer (0-10 scale)
clarity_metric = DiscreteMetric(
    name="clarity",
    allowed_values=list(range(0, 11)),  # 0 to 10
    prompt="""Rate the clarity of the response on a scale of 0-10.
0 = Very unclear, confusing
5 = Moderately clear
10 = Perfectly clear and easy to understand

Response: {response}

Respond with only the number (0-10).""",
)

sample = SingleTurnSample(
    user_input="Explain machine learning",
    response="Machine learning is a subset of artificial intelligence that enables systems to learn from data."
)

result = await clarity_metric.ascore(response=sample.response, llm=llm)
print(f"Clarity Score: {result.value}")  # Output: e.g., 8

커스텀 범위 채점 예시(Custom Range Scoring Example)

# Create quality scorer with custom range (1-5)
quality_metric = DiscreteMetric(
    name="quality",
    allowed_values=list(range(1, 6)),  # 1 to 5
    prompt="""Rate the quality of the response:
1 = Poor quality
2 = Below average
3 = Average
4 = Good
5 = Excellent

Response: {response}

Respond with only the number (1-5).""",
)

result = await quality_metric.ascore(response=sample.response, llm=llm)
print(f"Quality Score: {result.value}")

유사도 기반 채점(Similarity-Based Scoring)

# Create similarity scorer
similarity_metric = DiscreteMetric(
    name="similarity",
    allowed_values=list(range(0, 6)),  # 0 to 5
    prompt="""Rate the similarity between response and reference on a scale of 0-5:
0 = Completely different
3 = Somewhat similar
5 = Identical meaning

Reference: {reference}
Response: {response}

Respond with only the number (0-5).""",
)

sample = SingleTurnSample(
    user_input="Where is the Eiffel Tower located?",
    response="The Eiffel Tower is located in Paris.",
    reference="The Eiffel Tower is located in Egypt"
)

result = await similarity_metric.ascore(
    response=sample.response,
    reference=sample.reference,
    llm=llm
)
print(f"Similarity Score: {result.value}")

루브릭 기반 기준 채점(Rubrics based criteria scoring)

루브릭 기반 기준 채점 지표(Rubric-Based Criteria Scoring Metric)는 사용자 정의 루브릭을 기반으로 평가를 수행하는 지표예요. 각 루브릭은 보통 1에서 5 사이의 상세한 점수 설명을 정의해요. LLM이 이 설명에 따라 응답을 평가·채점해 일관되고 객관적인 평가를 보장해요.

Note 루브릭을 정의할 때 SingleTurnSample 또는 MultiTurnSample에서 사용된 스키마와 용어를 일관되게 맞추세요. 예를 들어 스키마가 reference라는 용어를 지정하면, 루브릭도 ground truth 같은 대안 대신 같은 용어를 사용해야 해요.

예시(Example)

from ragas.dataset_schema import SingleTurnSample
from ragas.metrics import RubricsScore

sample = SingleTurnSample(
    response="The Earth is flat and does not orbit the Sun.",
    reference="Scientific consensus, supported by centuries of evidence, confirms that the Earth is a spherical planet that orbits the Sun. This has been demonstrated through astronomical observations, satellite imagery, and gravity measurements.",
)

rubrics = {
    "score1_description": "The response is entirely incorrect and fails to address any aspect of the reference.",
    "score2_description": "The response contains partial accuracy but includes major errors or significant omissions that affect its relevance to the reference.",
    "score3_description": "The response is mostly accurate but lacks clarity, thoroughness, or minor details needed to fully address the reference.",
    "score4_description": "The response is accurate and clear, with only minor omissions or slight inaccuracies in addressing the reference.",
    "score5_description": "The response is completely accurate, clear, and thoroughly addresses the reference without any errors or omissions.",
}

scorer = RubricsScore(rubrics=rubrics, llm=evaluator_llm)
await scorer.single_turn_ascore(sample)

출력(Output)

1

인스턴스별 루브릭 기준 채점(Instance Specific rubrics criteria scoring)

인스턴스별 평가 지표(Instance Specific Evaluation Metric)는 데이터셋의 각 항목을 개별적으로 평가하는 루브릭 기반 방법이에요. 이 지표를 사용하려면 평가할 항목과 함께 루브릭을 제공해야 해요.

Note 이는 데이터셋의 모든 항목을 균일하게 평가하는 데 단일 루브릭을 적용하는 Rubric Based Criteria Scoring Metric과 다르다. Instance-Specific Evaluation Metric에서는 각 항목에 어떤 루브릭을 쓸지 직접 결정해요. 반 전체에 같은 퀴즈를 주는 것(루브릭 기반)과 각 학생에게 맞춤 퀴즈를 만드는 것(인스턴스별)의 차이와 같아요.

예시(Example)

dataset = [
    # Relevance to Query
    {
        "user_query": "How do I handle exceptions in Python?",
        "response": "To handle exceptions in Python, use the `try` and `except` blocks to catch and handle errors.",
        "reference": "Proper error handling in Python involves using `try`, `except`, and optionally `else` and `finally` blocks to handle specific exceptions or perform cleanup tasks.",
        "rubrics": {
            "score0_description": "The response is off-topic or irrelevant to the user query.",
            "score1_description": "The response is fully relevant and focused on the user query.",
        },
    },
    # Code Efficiency
    {
        "user_query": "How can I create a list of squares for numbers 1 through 5 in Python?",
        "response": """
            # Using a for loop
            squares = []
            for i in range(1, 6):
                squares.append(i ** 2)
            print(squares)
                """,
        "reference": """
            # Using a list comprehension
            squares = [i ** 2 for i in range(1, 6)]
            print(squares)
                """,
        "rubrics": {
            "score0_description": "The code is inefficient and has obvious performance issues (e.g., unnecessary loops or redundant calculations).",
            "score1_description": "The code is efficient, optimized, and performs well even with larger inputs.",
        },
    },
]

evaluation_dataset = EvaluationDataset.from_list(dataset)

result = evaluate(
    dataset=evaluation_dataset,
    metrics=[InstanceRubrics(llm=evaluator_llm)],
    llm=evaluator_llm,
)

result

출력(Output)

{'instance_rubrics': 0.5000}

더 알아보기 (Learn more)