사실 정확성(Factual Correctness)

사실 정확성(Factual Correctness)

사실 정확성은 생성된 response의 사실적 정확성을 reference와 비교해 평가하는 지표예요. 응답과 reference를 하나씩 claim으로 쪼갠 뒤 자연어 추론으로 사실적 겹침을 판단하죠. 점수는 0에서 1 사이이며 높을수록 좋아요. mode 파라미터로 정밀도·재현율·F1 중 어떤 방식으로 계산할지 정할 수 있어요.

출처: 문서

본문

사실 정확성(Factual Correctness)

FactualCorrectness는 생성된 response의 사실적 정확성을 reference와 비교·평가하는 지표예요. 이 지표는 생성된 응답이 reference와 얼마나 정렬되는지 판단하는 데 사용돼요. 사실 정확성 점수는 0에서 1 사이이며, 값이 높을수록 성능이 좋다는 뜻이에요. 응답과 reference의 정렬을 측정하기 위해, 이 지표는 LLM을 사용해 먼저 응답과 reference를 claim으로 쪼갠 다음 자연어 추론을 사용해 응답과 reference 사이의 사실적 겹침을 결정해요. 사실적 겹침은 정밀도(precision), 재현율(recall), F1 점수로 정량화되며 mode 파라미터로 제어할 수 있어요.

예시(Example)

from openai import AsyncOpenAI
from ragas.llms import llm_factory
from ragas.metrics.collections import FactualCorrectness

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

# Create metric
scorer = FactualCorrectness(llm=llm)

# Evaluate
result = await scorer.ascore(
    response="The Eiffel Tower is located in Paris.",
    reference="The Eiffel Tower is located in Paris. It has a height of 1000ft."
)
print(f"Factual Correctness Score: {result.value}")

출력(Output):

Factual Correctness Score: 0.67

기본적으로 mode는 f1로 설정돼요. mode 파라미터를 설정해 precision이나 recall로 바꿀 수 있어요:

# Precision mode - measures what fraction of response claims are supported by reference
scorer = FactualCorrectness(llm=llm, mode="precision")
result = await scorer.ascore(
    response="The Eiffel Tower is located in Paris.",
    reference="The Eiffel Tower is located in Paris. It has a height of 1000ft."
)
print(f"Precision Score: {result.value}")

출력(Output):

Precision Score: 1.0

atomicitycoverage 파라미터로 claim 분해 세분도를 구성할 수도 있어요:

# High granularity - more detailed claim decomposition
scorer = FactualCorrectness(
    llm=llm,
    mode="f1",
    atomicity="high",  # More atomic claims
    coverage="high"    # Comprehensive coverage
)

동기 사용법(Synchronous Usage) 동기 코드를 선호한다면 .ascore() 대신 .score() 메서드를 쓸 수 있어요: result = scorer.score( response="The Eiffel Tower is located in Paris.", reference="The Eiffel Tower is located in Paris. It has a height of 1000ft." )

계산 방법(How It's Calculated)

TP(True Positive), FP(False Positive), FN(False Negative) 계산 공식은 다음과 같아요:

[ \text{True Positive (TP)} = \text{Number of claims in response that are present in reference} ]

[ \text{False Positive (FP)} = \text{Number of claims in response that are not present in reference} ]

[ \text{False Negative (FN)} = \text{Number of claims in reference that are not present in response} ]

정밀도, 재현율, F1 점수 계산 공식은 다음과 같아요:

[ \text{Precision} = {TP \over (TP + FP)} ]

[ \text{Recall} = {TP \over (TP + FN)} ]

[ \text{F1 Score} = {2 \times \text{Precision} \times \text{Recall} \over (\text{Precision} + \text{Recall})} ]

claim 수 제어하기(Controlling the Number of Claims)

응답과 reference의 각 문장은 하나 이상의 claim으로 쪼갤 수 있어요. 단일 문장에서 생성되는 claim 수는 애플리케이션에 필요한 atomicitycoverage 수준에 따라 결정돼요.

예시(Example)

scorer = FactualCorrectness(mode="precision",atomicity="low")

출력(Output)

1.0

Atomicity와 Coverage 이해하기

claim 분해에서 두 가지 중요한 파라미터가 출력에 영향을 줘요:

  1. Atomicity
  2. Coverage

이 파라미터들은 생성된 claim의 세분도(granularity)와 완전성(completeness)을 제어하는 데 도움을 줘요.

Atomicity

Atomicity는 문장을 가장 작고 의미 있는 구성 요소로 얼마나 잘게 쪼개는지를 의미해요. 매우 상세한 claim이 필요하든 더 통합된 관점이 필요하든 조정할 수 있어요.

  • 높은 Atomicity(High Atomicity): 문장이 근본적이고 분할 불가능한 claim으로 쪼개져요. 그 결과 각각이 별개의 정보 요소를 나타내는 여러 개의 더 작은 claim이 생겨요. 예시:

    • 원문장:
      • "Albert Einstein was a German theoretical physicist who developed the theory of relativity and contributed to quantum mechanics."
    • 분해된 Claim:
      • "Albert Einstein was a German theoretical physicist."
      • "Albert Einstein developed the theory of relativity."
      • "Albert Einstein contributed to quantum mechanics."
  • 낮은 Atomicity(Low Atomicity): 문장이 더 온전하게 유지돼, 여러 정보 요소를 담을 수 있는 더 적은 claim이 생겨요. 예시:

    • 원문장:
      • "Albert Einstein was a German theoretical physicist who developed the theory of relativity and contributed to quantum mechanics."
    • 분해된 Claim:
      • "Albert Einstein was a German theoretical physicist who developed the theory of relativity and contributed to quantum mechanics."

Coverage

Coverage는 claim이 원래 문장의 정보를 얼마나 포괄적으로 나타내는지를 의미해요. 모든 세부사항을 포함하거나 내용을 일반화하도록 조정할 수 있어요.

  • 높은 Coverage(High Coverage): 분해된 claim이 원래 문장에 있는 모든 정보를 포착해 세부사항을 전부 보존해요. 예시:

    • 원문장:
      • "Marie Curie was a Polish and naturalized-French physicist and chemist who conducted pioneering research on radioactivity."
    • 분해된 Claim:
      • "Marie Curie was a Polish physicist."
      • "Marie Curie was a naturalized-French physicist."
      • "Marie Curie was a chemist."
      • "Marie Curie conducted pioneering research on radioactivity."
  • 낮은 Coverage(Low Coverage): 분해된 claim이 주요 지점만 다루며 일부 세부사항을 생략해 더 일반화된 관점을 제공해요. 예시:

    • 원문장:
      • "Marie Curie was a Polish and naturalized-French physicist and chemist who conducted pioneering research on radioactivity."
    • 분해된 Claim:
      • "Marie Curie was a physicist."
      • "Marie Curie conducted research on radioactivity."

Atomicity와 Coverage 결합하기

atomicity와 coverage를 모두 조정하면 특정 사용 사례의 요구에 맞는 세부 수준과 완전성을 커스터마이즈할 수 있어요.

  • 높은 Atomicity & 높은 Coverage: 원문장의 모든 측면을 다루는 매우 상세하고 포괄적인 claim을 생성해요. 예시:

    • 원문장:
      • "Charles Babbage was an English mathematician, philosopher, inventor, and mechanical engineer."
    • 분해된 Claim:
      • "Charles Babbage was an English mathematician."
      • "Charles Babbage was a philosopher."
      • "Charles Babbage was an inventor."
      • "Charles Babbage was a mechanical engineer."
  • 낮은 Atomicity & 낮은 Coverage: 세부사항 없이 주요 아이디어를 요약하는 더 적고 덜 상세한 claim을 생성해요. 예시:

    • 원문장:
      • "Charles Babbage was an English mathematician, philosopher, inventor, and mechanical engineer."
    • 분해된 Claim:
      • "Charles Babbage was an English mathematician."
      • "Charles Babbage was an inventor."

실용적 적용(Practical Application)

  • 높은 Atomicity와 높은 Coverage는 심층 분석이나 정보 추출을 위해 상세하고 포괄적인 분해가 필요할 때 사용해요.
  • 낮은 Atomicity와 낮은 Coverage는 요약처럼 핵심 정보만 필요한 경우에 사용해요.

이렇게 claim 수를 유연하게 제어하면 애플리케이션 요구사항에 맞는 적절한 세분도로 정보를 제시할 수 있어요.

레거시 지표 API(Legacy Metrics API)

다음 예시는 레거시 지표 API 패턴을 사용해요. 새 프로젝트에는 위에서 보여준 컬렉션 기반 API를 권장해요.

폐지 일정(Deprecation Timeline) 이 API는 버전 0.4에서 폐지되고 버전 1.0에서 제거될 예정이에요. 위에 보여준 컬렉션 기반 API로 마이그레이션해주세요.

SingleTurnSample과 함께하는 예시(Example with SingleTurnSample)

from ragas.dataset_schema import SingleTurnSample
from ragas.metrics._factual_correctness import FactualCorrectness

sample = SingleTurnSample(
    response="The Eiffel Tower is located in Paris.",
    reference="The Eiffel Tower is located in Paris. I has a height of 1000ft."
)

scorer = FactualCorrectness(llm = evaluator_llm)
await scorer.single_turn_ascore(sample)

출력(Output):

0.67

모드 변경하기(Changing the Mode)

기본적으로 mode는 F1로 설정돼요. mode 파라미터를 설정해 precision이나 recall로 바꿀 수 있어요.

scorer = FactualCorrectness(llm = evaluator_llm, mode="precision")

출력(Output):

1.0

Atomicity 제어하기(Controlling Atomicity)

scorer = FactualCorrectness(mode="precision", atomicity="low")

출력(Output):

1.0

더 알아보기 (Learn more)