知識庫 / Testing RSS 訂閱

使用 Spring AI 評估器測試 LLM 響應

Artificial Intelligence,Spring AI,Testing
HongKong
5
10:50 AM · Dec 06 ,2025

1. 概述

現代Web應用程序越來越多地與大型語言模型(LLM)集成,以構建諸如聊天機器人和虛擬助手之類的解決方案。

然而,儘管LLM功能強大,但它們容易產生幻覺,並且響應可能不總是相關、適當或準確。

評估LLM響應的一種解決方案是使用另一個LLM本身,最好是獨立的。

要實現這一點,Spring AI 定義了 Evaluator 接口並提供了兩個實現,用於檢查LLM響應的相關性和事實準確性,即 RelevanceEvaluatorFactCheckingEvaluator

在本教程中,我們將探討如何使用 Spring AI Evaluators 測試 LLM 響應。我們將使用 Spring AI 提供的兩個基本實現來評估來自檢索增強生成(RAG)聊天機器人的響應。

2. 構建 RAG 對話機器人

為了開始測試 LLM 的響應,我們需要一個對話機器人進行測試。對於我們的演示,我們將構建一個簡單的 RAG 對話機器人,該機器人根據一組文檔來回答用户的問題

我們將使用 Ollama,這是一個開源工具,用於本地拉取和運行我們的聊天完成模型和嵌入模型。

2.1. 依賴項

讓我們首先將必要的依賴項添加到我們項目的 pom.xml文件中:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
    <version>1.0.0-M5</version>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-markdown-document-reader</artifactId>
    <version>1.0.0-M5</version>
</dependency>

Ollama starter 依賴項 幫助我們與 Ollama 服務建立連接。

此外,我們還導入了 Spring AI 的 Markdown 文檔讀取器依賴項,我們將使用它將 .md 文件轉換為可存儲在向量存儲中的文檔。

由於當前版本 1.0.0-M5 是里程碑發佈,因此我們也需要將 Spring Milestones 倉庫添加到我們的 pom.xml 中:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

此倉庫用於發佈里程碑版本,與標準 Maven Central 倉庫不同。

鑑於我們在項目中使用了多個 Spring AI starter,我們還應該將 Spring AI Bill of Materials (BOM) 添加到我們的 pom.xml 中:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0-M5</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

通過這項添加,我們現在可以將 版本 標籤從我們的所有啓動依賴項中移除。

BOM 消除了版本衝突的風險,並確保我們的 Spring AI 依賴項相互兼容

2.2. 配置聊天完成模型和嵌入模型

接下來,讓我們在 application.yaml 文件中配置我們的聊天完成模型和嵌入模型:

spring:
  ai:
    ollama:
      chat:
        options:
          model: llama3.3
      embedding:
        options:
          model: nomic-embed-text
      init:
        pull-model-strategy: when_missing

這裏,我們指定由 Meta 提供的 llama3.3 模型作為我們的聊天補全模型,以及由 Nomic AI 提供的 nomic-embed-text 模型作為我們的嵌入模型。

您可以隨時嘗試此實現,並使用 不同的模型

此外,我們設置 pull-model-strategywhen_missing。 這確保 Spring AI 在本地沒有指定模型時,會拉取這些模型。

在配置有效模型時,Spring AI 自動創建 ChatModel 和 EmbeddingModel 類型的 Bean, 從而使我們能夠分別與聊天補全模型和嵌入模型進行交互。

讓我們使用它們來定義我們聊天機器人的所需額外 Bean:

@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
    return SimpleVectorStore
      .builder(embeddingModel)
      .build();
}

@Bean
public ChatClient contentGenerator(ChatModel chatModel, VectorStore vectorStore) {
    return ChatClient.builder(chatModel)
      .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
      .build();
}

首先,我們定義一個 VectorStore Bean,並使用 SimpleVectorStore 實現,它是一個基於內存的實現,通過使用 java.util.Map 類模擬向量存儲

在生產應用中,我們可以考慮使用真實的向量存儲,例如 ChromaDB。

接下來,使用 ChatModelVectorStore Bean,我們創建一個類型為 ChatClient 的 Bean,它是我們與聊天完成模型交互的主要入口

我們用一個 QuestionAnswerAdvisor 進行配置,它使用向量存儲根據用户的提問從存儲的文檔中檢索相關部分,並將它們作為上下文提供給聊天模型。

2.3. 填充我們的內存向量存儲

為了演示目的,我們包含了名為 leave-policy.md 的文件,其中包含關於休假政策的樣例文檔,位於 src/main/resources/documents 目錄下。

現在,為了在應用程序啓動時使用我們的文檔填充向量存儲,我們將創建一個名為 VectorStoreInitializer 的類,該類實現 ApplicationRunner 接口:

@Component
class VectorStoreInitializer implements ApplicationRunner {
    private final VectorStore vectorStore;
    private final ResourcePatternResolver resourcePatternResolver;

    // standard constructor

    @Override
    public void run(ApplicationArguments args) {
        List<Document> documents = new ArrayList<>();
        Resource[] resources = resourcePatternResolver.getResources("classpath:documents/*.md");
        Arrays.stream(resources).forEach(resource -> {
            MarkdownDocumentReader markdownDocumentReader = new MarkdownDocumentReader(resource, MarkdownDocumentReaderConfig.defaultConfig());
            documents.addAll(markdownDocumentReader.read());
        });
        vectorStore.add(new TokenTextSplitter().split(documents));
    }
}

run() 方法內部,我們首先使用注入的 ResourcePatternResolver 類來從 src/main/resources/documents 目錄中檢索所有 Markdown 文件。 儘管我們僅處理單個 Markdown 文件,但我們的方法具有可擴展性。

然後,我們使用 MarkdownDocumentReader 類將檢索到的 resources 轉換為 Document 對象。

最後,我們使用 TokenTextSplitter 類將文檔分割成較小的塊後,將它們添加到向量存儲中。

當我們調用 add() 方法時,Spring AI 會自動將我們的純文本內容轉換為向量表示形式,然後再將其存儲在向量存儲中。 我們無需顯式使用 EmbeddingModel bean 進行轉換。

3. 使用 Testcontainers 設置 Ollama

為了方便本地開發和測試,我們將使用 Testcontainers 設置 Ollama 服務,其前提是需要一個活躍的 Docker 實例。

3.1. 測試依賴

首先,讓我們為我們的 pom.xml 添加必要的測試依賴:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-spring-boot-testcontainers</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>ollama</artifactId>
    <scope>test</scope>
</dependency>

我們導入了 Spring AI Testcontainers 依賴項,以及 Testcontainers 中的 Ollama 模塊

這些依賴項提供了用於啓動 Ollama 服務的臨時 Docker 實例所需的類。

3.2. 定義 Testcontainers Bean

接下來,讓我們創建一個 @TestConfiguration 類,以定義我們的 Testcontainers Bean:

@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfiguration {
    @Bean
    public OllamaContainer ollamaContainer() {
        return new OllamaContainer("ollama/ollama:0.5.7");
    }

    @Bean
    public DynamicPropertyRegistrar dynamicPropertyRegistrar(OllamaContainer ollamaContainer) {
        return registry -> {
            registry.add("spring.ai.ollama.base-url", ollamaContainer::getEndpoint);
        };
    }
}

我們在創建 OllamaContainer Bean 時,指定 Ollama 圖像的最新穩定版本。

然後,我們定義一個 DynamicPropertyRegistrar Bean,用於配置 Ollama 服務的 base-url

這使得我們的應用程序能夠連接到啓動的容器。

現在,我們可以通過在測試類上添加 @Import(TestcontainersConfiguration.class) 註解,在集成測試中使用此配置。

4. 使用 Spring AI 評估器

現在我們已經構建了 RAG 聊天機器人並設置了本地測試環境,讓我們看看如何利用 Spring AI 的 Evaluator 接口的兩個可用實現來測試其生成的響應

4.1. 配置評估模型

評估模型的質量最終取決於我們使用的評估模型。 我們將選擇目前行業標準,即 bespoke-minicheck 模型,該模型是由 Bespoke Labs 專門為評估測試訓練的開源模型。 它在 LLM-AggreFact 榜單 中名列前茅,並且只會產生是/否的響應。

讓我們在我們的 application.yaml 文件中進行配置:

com:
  baeldung:
    evaluation:
      model: bespoke-minicheck

接下來,我們將創建一個單獨的 ChatClient Bean,用於與我們的評估模型進行交互:

@Bean
public ChatClient contentEvaluator(
  OllamaApi olamaApi,
  @Value("${com.baeldung.evaluation.model}") String evaluationModel
) {
    ChatModel chatModel = OllamaChatModel.builder()
      .ollamaApi(olamaApi)
      .defaultOptions(OllamaOptions.builder()
        .model(evaluationModel)
        .build())
      .modelManagementOptions(ModelManagementOptions.builder()
        .pullModelStrategy(PullModelStrategy.WHEN_MISSING)
        .build())
      .build();
    return ChatClient.builder(chatModel)
      .build();
}

在這裏,我們使用 Spring AI 創建的 OllamaApi bean 以及我們的自定義評估模型屬性,定義了一個新的 ChatClient bean,並通過 @Value 註解注入。

需要注意的是,我們使用自定義的評估模型屬性,並手動創建其對應的 ChatModel 類,因為 Spring AI 的 OllamaAutoConfiguration 類僅允許通過 spring.ai.ollama.chat.options.model 屬性配置單個模型,我們已經為此內容生成模型使用了該屬性。

4.2. 使用 RelevancyEvaluator 評估 LLM 響應的相關性

Spring AI 提供 RelevancyEvaluator 實現,用於檢查 LLM 響應是否與用户查詢和從向量存儲檢索到的上下文相關

首先,讓我們創建一個 Bean 以進行此操作:

@Bean
public RelevancyEvaluator relevancyEvaluator(
    @Qualifier("contentEvaluator") ChatClient chatClient) {
    return new RelevancyEvaluator(chatClient.mutate());
}

我們使用 @Qualifier 註解來注入我們先前定義的 relevancyEvaluator ChatClient Bean,並創建 RelevancyEvaluator 類的實例。

由於其構造函數期望一個 Builder 而不是直接的 ChatClient 實例,我們調用 mutate() 方法,該方法返回一個使用我們現有客户端配置初始化的 ChatClient.Builder 對象。

現在,讓我們測試聊天機器人的響應是否具有相關性:

String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
  .user(question)
  .call()
  .chatResponse();

String answer = chatResponse.getResult().getOutput().getContent();
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, answer);

EvaluationResponse evaluationResponse = relevancyEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isTrue();

String nonRelevantAnswer = "A lion is the king of the jungle";
evaluationRequest = new EvaluationRequest(question, documents, nonRelevantAnswer);
evaluationResponse = relevancyEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isFalse();

我們首先通過調用我們的 contentGenerator ChatClient,並傳入一個 問題,從返回的 ChatResponse 中提取生成的 答案 以及生成該答案所使用的 文檔

然後,我們創建一個 EvaluationRequest,其中包含 問題、檢索到的 文檔 和聊天機器人的 答案。我們將它傳遞給 relevancyEvaluator Bean,並斷言答案的相關性,使用 isPass() 方法。

然而,當我們傳入關於獅子的完全不相關的答案時,評估器正確地將其識別為不相關。

4.3. 使用 FactCheckingEvaluator 評估 LLM 響應的事實準確性

類似於地,Spring AI 提供了一個 FactCheckingEvaluator 實現,用於驗證 LLM 響應的事實準確性,與檢索到的上下文進行對比。

讓我們使用我們的 contentEvaluator ChatClient 創建一個 FactCheckingEvaluator Bean:

@Bean
public FactCheckingEvaluator factCheckingEvaluator(
    @Qualifier("contentEvaluator") ChatClient chatClient) {
    return new FactCheckingEvaluator(chatClient.mutate());
}

最後,讓我們測試聊天機器人響應的事實準確性:

String question = "How many days sick leave can I take?";
ChatResponse chatResponse = contentGenerator.prompt()
  .user(question)
  .call()
  .chatResponse();

String answer = chatResponse.getResult().getOutput().getContent();
List<Document> documents = chatResponse.getMetadata().get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
EvaluationRequest evaluationRequest = new EvaluationRequest(question, documents, answer);

EvaluationResponse evaluationResponse = factCheckingEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isTrue();

String wrongAnswer = "You can take no leaves. Get back to work!";
evaluationRequest = new EvaluationRequest(question, documents, wrongAnswer);
evaluationResponse = factCheckingEvaluator.evaluate(evaluationRequest);
assertThat(evaluationResponse.isPass()).isFalse();

類似於之前的方案,我們創建一個 EvaluationRequest,其中包含 question(問題)、檢索到的 documents(文檔)和聊天機器人的 answer(答案),並將其傳遞給我們的 factCheckingEvaluator Bean。

我們斷言聊天機器人的 response(回覆)在檢索到的上下文中是事實上正確的。此外,我們使用一個硬編碼的、事實上錯誤的答案重新測試評估過程,並斷言 isPass() 方法在這種情況下返回 false

值得注意的是,如果我們將硬編碼的 wrongAnswer(錯誤的答案)傳遞給 RelevancyEvaluator(相關性評估器),則評估將通過,即使回覆在事實上不正確,但它仍然與用户所詢問的關於病假的議題相關

5. 結論

在本文中,我們探討了使用 Spring AI 的 Evaluator 接口測試 LLM 響應的方法。

我們構建了一個簡單的 RAG 聊天機器人,該機器人根據一組文檔回答用户的問題,並使用 Testcontainers 設置 Ollama 服務,從而創建一個本地測試環境。

然後,我們使用 Spring AI 提供的 RelevancyEvaluatorFactCheckingEvaluator 實現來評估聊天機器人響應的相關性和事實準確性。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.