评估测试

测试 AI 应用程序需要评估生成的内容,以确保 AI 模型没有产生幻觉响应。 评估响应的一种方法是使用 AI 模型本身进行评估。选择最佳 AI 模型进行评估,该模型可能与用于生成响应的模型不同。 Spring AI 用于评估响应的接口是 Evaluator,定义如下:

@FunctionalInterface
public interface Evaluator {
    EvaluationResponse evaluate(EvaluationRequest evaluationRequest);
}

评估的输入是 EvaluationRequest,定义如下:

public class EvaluationRequest {

	private final String userText;

	private final List<Content> dataList;

	private final String responseContent;

	public EvaluationRequest(String userText, List<Content> dataList, String responseContent) {
		this.userText = userText;
		this.dataList = dataList;
		this.responseContent = responseContent;
	}

  ...
}
  • userText: 用户的原始输入,类型为 String

  • dataList: 上下文数据,例如来自检索增强生成 (Retrieval Augmented Generation),附加到原始输入。

  • responseContent: AI 模型的响应内容,类型为 String

相关性评估器

RelevancyEvaluatorEvaluator 接口的一个实现,旨在评估 AI 生成响应与所提供上下文的相关性。此评估器通过确定 AI 模型的响应是否与用户输入以及检索到的上下文相关,帮助评估 RAG 流程的质量。

评估基于用户输入、AI 模型的响应和上下文信息。它使用一个提示模板来询问 AI 模型响应是否与用户输入和上下文相关。

这是 RelevancyEvaluator 使用的默认提示模板:

您的任务是评估查询的响应
是否与提供的上下文信息一致。

您有两种回答选项。是或否。

如果查询的响应与上下文信息一致,则回答“是”,否则回答“否”。

查询:
{query}

响应:
{response}

上下文:
{context}

回答:

您可以通过 .promptTemplate() 构建器方法提供自己的 PromptTemplate 对象来定制提示模板。详情请参见 _custom_template

在集成测试中的使用

以下是 RelevancyEvaluator 在集成测试中使用的示例,它使用 RetrievalAugmentationAdvisor 验证 RAG 流程的结果:

@Test
void evaluateRelevancy() {
    String question = "Where does the adventure of Anacletus and Birba take place?";

    RetrievalAugmentationAdvisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(VectorStoreDocumentRetriever.builder()
            .vectorStore(pgVectorStore)
            .build())
        .build();

    ChatResponse chatResponse = ChatClient.builder(chatModel).build()
        .prompt(question)
        .advisors(ragAdvisor)
        .call()
        .chatResponse();

    EvaluationRequest evaluationRequest = new EvaluationRequest(
        // 原始用户问题
        question,
        // 从 RAG 流程中检索到的上下文
        chatResponse.getMetadata().get(RetrievalAugmentationAdvisor.DOCUMENT_CONTEXT),
        // AI 模型的响应
        chatResponse.getResult().getOutput().getText()
    );

    RelevancyEvaluator evaluator = new RelevancyEvaluator(ChatClient.builder(chatModel));

    EvaluationResponse evaluationResponse = evaluator.evaluate(evaluationRequest);

    assertThat(evaluationResponse.isPass()).isTrue();
}

您可以在 Spring AI 项目中找到几个使用 RelevancyEvaluator 来测试 QuestionAnswerAdvisor(参见 测试)和 RetrievalAugmentationAdvisor(参见 测试)功能的集成测试。

自定义模板

RelevancyEvaluator 使用默认模板来提示 AI 模型进行评估。您可以通过 .promptTemplate() 构建器方法提供自己的 PromptTemplate 对象来定制此行为。

自定义 PromptTemplate 可以使用任何 TemplateRenderer 实现(默认情况下,它使用基于 StringTemplate 引擎的 StPromptTemplate)。重要的要求是模板必须包含以下占位符:

  • 一个 query 占位符,用于接收用户问题。

  • 一个 response 占位符,用于接收 AI 模型的响应。

  • 一个 context 占位符,用于接收上下文信息。

事实核查评估器

FactCheckingEvaluator 是 Evaluator 接口的另一个实现,旨在评估 AI 生成响应相对于所提供上下文的事实准确性。此评估器通过验证给定陈述(主张)是否得到所提供上下文(文档)的逻辑支持,帮助检测和减少 AI 输出中的幻觉。

“主张”和“文档”将提交给 AI 模型进行评估。有专门用于此目的的更小、更高效的 AI 模型,例如 Bespoke 的 Minicheck,与 GPT-4 等旗舰模型相比,它有助于降低执行这些检查的成本。Minicheck 也可以通过 Ollama 使用。

用法

FactCheckingEvaluator 构造函数接受一个 ChatClient.Builder 作为参数:

public FactCheckingEvaluator(ChatClient.Builder chatClientBuilder) {
  this.chatClientBuilder = chatClientBuilder;
}

评估器使用以下提示模板进行事实核查:

文档: {document}
主张: {claim}

其中 {document} 是上下文信息,{claim} 是要评估的 AI 模型的响应。

示例

以下是如何将 FactCheckingEvaluator 与基于 Ollama 的 ChatModel(特别是 Bespoke-Minicheck 模型)一起使用的示例:

@Test
void testFactChecking() {
  // 设置 Ollama API
  OllamaApi ollamaApi = new OllamaApi("http://localhost:11434");

  ChatModel chatModel = new OllamaChatModel(ollamaApi,
				OllamaOptions.builder().model(BESPOKE_MINICHECK).numPredict(2).temperature(0.0d).build())


  // 创建 FactCheckingEvaluator
  var factCheckingEvaluator = new FactCheckingEvaluator(ChatClient.builder(chatModel));

  // 示例上下文和主张
  String context = "地球是距离太阳第三颗行星,也是已知唯一能孕育生命的行星。";
  String claim = "地球是距离太阳第四颗行星。";

  // 创建 EvaluationRequest
  EvaluationRequest evaluationRequest = new EvaluationRequest(context, Collections.emptyList(), claim);

  // 执行评估
  EvaluationResponse evaluationResponse = factCheckingEvaluator.evaluate(evaluationRequest);

  assertFalse(evaluationResponse.isPass(), "该主张不应得到上下文的支持");

}