사실 정확성(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
atomicity와 coverage 파라미터로 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 수는 애플리케이션에 필요한 atomicity와 coverage 수준에 따라 결정돼요.
예시(Example)
scorer = FactualCorrectness(mode="precision",atomicity="low")
출력(Output)
1.0
Atomicity와 Coverage 이해하기
claim 분해에서 두 가지 중요한 파라미터가 출력에 영향을 줘요:
- Atomicity
- 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