ragas precision计算的坑
最近在做RAG评测,用到了ragas框架。
在计算ContextPrecision时,发现计算结果跟我理解的不一样。
sample = SingleTurnSample(user_input=user_input,reference=reference,retrieved_contexts=retrieved_contexts,)context_precision = LLMContextPrecisionWithReference(llm=self.evaluator_llm)precision = context_precision.single_turn_score(sample)
调用代码如上,ragas计算precision的原理是通过大模型判断参考答案(reference)与检索到的内容(retrieved_contexts)的相关性。比如检索到两个相关材料,一个相关,一个不相关,则结果为[1,0]。
然后通过如下的函数计算平均精度:
def _calculate_average_precision(self, verifications: t.List[Verification]) -> float:score = np.nanverdict_list = [1 if ver.verdict else 0 for ver in verifications]denominator = sum(verdict_list) + 1e-10numerator = sum([(sum(verdict_list[: i + 1]) / (i + 1)) * verdict_list[i]for i in range(len(verdict_list))])score = numerator / denominatorif np.isnan(score):logger.warning("Invalid response format. Expected a list of dictionaries with keys 'verdict'")return score
这里的坑在于,对于第二个材料的结果0,这种计算方式会忽略这个结果。因为这个材料排在末尾,同时又不相关。对于排序或者全量召回环节,这样计算是没问题的。但是对于rag的检索,一般是从多个doc里检索出相关的几个,应该所有的结果都是正样本,不应该出现结果为0而不影响precision的情况。所以对这里代码做了下修正,修正后结果如下:
def _calculate_average_precision_custom(self, verifications: t.List[Verification]) -> float:"""考虑负样本之后的平均精度计算。同时也考虑位置,比如[1,0]返回0.75,比如[0,1]返回结果0.25"""verdict_list = [1 if ver.verdict else 0 for ver in verifications]if not verdict_list:return 0.0cumulative_positives = 0sum_precision = 0total_samples = len(verdict_list)for i, verdict in enumerate(verdict_list):if verdict == 1:cumulative_positives += 1# 计算当前位置的精度,无论是正例还是负例current_precision = cumulative_positives / (i + 1)sum_precision += current_precision# 使用所有样本的平均精度return sum_precision / total_samples
有用到ragas计算精度的一定要注意这里的影响,尤其是检索结果只有两个的时候影响更为明显,会忽略掉最后一个样本为负时对精度的影响。