Spring AI RAG 模型评估详解

在这里插入图片描述

📋 目录

  1. 为什么需要模型评估
  2. 评估器类型与对比
  3. 使用方式详解
  4. 使用场景分析
  5. 评估的意义与价值
  6. 代码示例分析
  7. 最佳实践
  8. 常见问题

为什么需要模型评估

RAG 系统的局限性

虽然 RAG(检索增强生成)能够基于真实资料减少幻觉,但并不能完全消除幻觉。RAG 系统仍然可能出现以下问题:

问题类型 描述 影响
事实性幻觉 上下文提供了明确事实,但模型未读取或匹配,凭常识胡乱生成 回答不准确,误导用户
虚构细节 模型"看"到的背景信息有限,但仍然自信地"虚构"细节回答问题 产生错误信息,降低可信度
相关性不足 模型回答与用户问题不相关,或与检索到的文档不匹配 用户体验差,系统价值低

现实中的常见问题场景

场景 1:上下文提供了明确事实,但模型未读取
上下文文档:
"取消费用:经济舱 75 美元,豪华经济舱 50 美元,商务舱 25 美元。"

模型回答:
"经济舱取消费用是 100 美元。"  ❌ 错误!未读取上下文中的 75 美元
场景 2:模型虚构细节
用户问题:"我叫什么名字?"

检索到的文档:
"预订航班时需要确保个人信息(姓名、ID 等)的准确性..."

模型回答:
"根据文档,您的名字是张三。"  ❌ 错误!文档中并未提及用户姓名

评估的必要性

原因 说明 业务影响
质量保证 确保 RAG 系统回答的准确性和可靠性 避免用户收到错误信息
持续改进 通过评估发现系统问题,指导优化方向 提升系统整体质量
风险控制 及时发现和修复事实性错误 降低法律和声誉风险
成本优化 评估不同模型和配置的效果,选择最优方案 降低运营成本

评估器类型与对比

评估器分类

Spring AI 提供了两种主要的评估器:

评估器 英文名称 评估维度 核心功能
事实性评估器 FactCheckingEvaluator 事实准确性 检查 AI 回答是否与提供的上下文文档一致
相关性评估器 RelevancyEvaluator 相关性 检查 AI 回答是否与用户问题相关,是否基于检索到的文档

详细对比

特性 FactCheckingEvaluator RelevancyEvaluator
评估目标 事实准确性 回答相关性
输入参数 List<Document>(上下文)+ String(AI 回答) String(用户问题)+ List<Document>(上下文)+ String(AI 回答)
评估逻辑 检查回答中的事实是否能在上下文中找到依据 检查回答是否与问题相关,是否基于上下文
适用场景 事实性检查、知识库问答 相关性检查、RAG 系统整体评估
评估粒度 细粒度(逐条事实检查) 粗粒度(整体相关性)
LLM 调用 需要调用 LLM 进行事实对比 需要调用 LLM 进行相关性判断
返回结果 EvaluationResponse(包含评分和解释) EvaluationResponse(包含评分和解释)

评估维度对比

维度 FactCheckingEvaluator RelevancyEvaluator
事实准确性 ✅ 主要评估维度 ⚠️ 间接评估
回答相关性 ⚠️ 不直接评估 ✅ 主要评估维度
上下文利用 ✅ 严格检查 ✅ 检查是否基于上下文
幻觉检测 ✅ 能检测事实性幻觉 ✅ 能检测无关回答

使用方式详解

1. FactCheckingEvaluator(事实性评估器)

基本用法
// 1. 创建评估器
var factCheckingEvaluator = new FactCheckingEvaluator(
    ChatClient.builder(chatModel)
);

// 2. 准备上下文文档
List<Document> documents = List.of(
    Document.builder()
        .text("""
            取消预订:
            - 最晚在航班起飞前 48 小时取消。
            - 取消费用:经济舱 75 美元,豪华经济舱 50 美元,商务舱 25 美元。
            - 退款将在 7 个工作日内处理。
            """)
        .build()
);

// 3. AI 回答
String response = "经济舱取消费用75 美元";

// 4. 创建评估请求
EvaluationRequest evaluationRequest = new EvaluationRequest(
    documents,  // 上下文文档
    response    // AI 回答
);

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

// 6. 查看结果
System.out.println(evaluationResponse);
参数说明
参数 类型 说明 示例
documents List<Document> 检索到的上下文文档,包含事实依据 知识库文档列表
response String AI 模型生成的回答 “经济舱取消费用75 美元”
工作原理
1. 将上下文文档和 AI 回答发送给 LLM
2. LLM 分析回答中的每个事实声明
3. 检查每个事实是否能在上下文中找到依据
4. 返回评估结果:
   - 评分(0.0 - 1.0)
   - 解释(哪些事实正确,哪些错误)

2. RelevancyEvaluator(相关性评估器)

基本用法
// 1. 创建评估器
var evaluator = new RelevancyEvaluator(
    ChatClient.builder(chatModel)
);

// 2. 准备评估数据
String query = "我叫什么名字";  // 用户问题
List<Document> context = chatResponse.getMetadata()
    .get(RetrievalAugmentationAdvisor.DOCUMENT_CONTEXT);  // 检索到的上下文
String response = chatResponse.getResult()
    .getOutput().getText();  // AI 回答

// 3. 创建评估请求
EvaluationRequest evaluationRequest = new EvaluationRequest(
    query,     // 用户问题
    context,   // 检索到的上下文
    response   // AI 回答
);

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

// 5. 查看结果
System.out.println(evaluationResponse);
参数说明
参数 类型 说明 示例
query String 用户的实际查询问题 “我叫什么名字”
context List<Document> 从向量数据库检索到的相关文档 RAG 检索结果
response String AI 模型生成的答案 “根据文档,您的名字是…”
工作原理
1. 将用户问题、上下文文档和 AI 回答发送给 LLM
2. LLM 分析:
   - 回答是否与用户问题相关?
   - 回答是否基于提供的上下文?
   - 回答是否回答了用户的问题?
3. 返回评估结果:
   - 评分(0.0 - 1.0)
   - 解释(相关性分析)

3. 在完整 RAG 流程中使用评估

完整示例(基于 RagEvalTest)
@Test
public void testRag(
        @Autowired VectorStore vectorStore,
        @Autowired DashScopeChatModel dashScopeChatModel) {
    
    // 1. 准备知识库
    List<Document> documents = List.of(...);
    vectorStore.add(documents);
    
    // 2. 构建 RAG Advisor
    RetrievalAugmentationAdvisor advisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(VectorStoreDocumentRetriever.builder()
            .vectorStore(vectorStore)
            .build())
        .build();
    
    // 3. 执行 RAG 查询
    String query = "我叫什么名字";
    ChatResponse chatResponse = ChatClient.builder(dashScopeChatModel)
        .build()
        .prompt(query)
        .advisors(advisor)
        .call()
        .chatResponse();
    
    // 4. 提取评估所需的数据
    String userQuery = query;  // 用户问题
    List<Document> retrievedContext = chatResponse.getMetadata()
        .get(RetrievalAugmentationAdvisor.DOCUMENT_CONTEXT);  // 检索到的上下文
    String aiResponse = chatResponse.getResult()
        .getOutput().getText();  // AI 回答
    
    // 5. 创建评估请求
    EvaluationRequest evaluationRequest = new EvaluationRequest(
        userQuery,        // 用户问题
        retrievedContext, // 检索到的上下文
        aiResponse        // AI 回答
    );
    
    // 6. 执行相关性评估
    RelevancyEvaluator evaluator = new RelevancyEvaluator(
        ChatClient.builder(dashScopeChatModel)
    );
    EvaluationResponse evaluationResponse = evaluator.evaluate(evaluationRequest);
    
    // 7. 查看评估结果
    System.out.println(evaluationResponse);
    System.out.println("AI 回答: " + aiResponse);
}

使用场景分析

场景 1:开发和测试阶段

目的:在集成测试中验证 RAG 系统的质量

实现方式

@Test
public void testRagQuality() {
    // 执行 RAG 查询
    ChatResponse response = executeRagQuery("退票需要多少费用?");
    
    // 评估回答质量
    EvaluationRequest request = new EvaluationRequest(
        "退票需要多少费用?",
        getRetrievedContext(response),
        getAiResponse(response)
    );
    
    RelevancyEvaluator evaluator = new RelevancyEvaluator(chatClient);
    EvaluationResponse evalResult = evaluator.evaluate(request);
    
    // 断言:相关性评分应该 >= 0.8
    assertTrue(evalResult.getScore() >= 0.8, 
        "回答相关性不足: " + evalResult.getExplanation());
}

价值

  • ✅ 自动化质量检查
  • ✅ 防止回归问题
  • ✅ 确保系统稳定性

场景 2:批量质量检查

目的:对一批历史对话进行离线评估

实现方式

public void batchEvaluate(List<Conversation> conversations) {
    FactCheckingEvaluator factChecker = new FactCheckingEvaluator(chatClient);
    RelevancyEvaluator relevancyChecker = new RelevancyEvaluator(chatClient);
    
    List<EvaluationResult> results = new ArrayList<>();
    
    for (Conversation conv : conversations) {
        // 事实性评估
        EvaluationRequest factRequest = new EvaluationRequest(
            conv.getContext(),
            conv.getResponse()
        );
        EvaluationResponse factResult = factChecker.evaluate(factRequest);
        
        // 相关性评估
        EvaluationRequest relevancyRequest = new EvaluationRequest(
            conv.getQuery(),
            conv.getContext(),
            conv.getResponse()
        );
        EvaluationResponse relevancyResult = relevancyChecker.evaluate(relevancyRequest);
        
        results.add(new EvaluationResult(factResult, relevancyResult));
    }
    
    // 生成评估报告
    generateReport(results);
}

价值

  • ✅ 发现系统性问题
  • ✅ 识别低质量回答模式
  • ✅ 指导系统优化方向

场景 3:系统监控

目的:定期抽样评估生产环境中的对话质量

实现方式

@Component
public class RAGQualityMonitor {
    
    private final RelevancyEvaluator evaluator;
    private int requestCount = 0;
    private static final int SAMPLE_RATE = 100;  // 每100次评估1次
    
    @EventListener
    public void onRagResponse(RagResponseEvent event) {
        requestCount++;
        
        // 抽样评估
        if (requestCount % SAMPLE_RATE == 0) {
            EvaluationRequest request = new EvaluationRequest(
                event.getQuery(),
                event.getContext(),
                event.getResponse()
            );
            
            EvaluationResponse result = evaluator.evaluate(request);
            
            // 记录评估结果
            logEvaluationResult(result);
            
            // 如果评分过低,发送告警
            if (result.getScore() < 0.6) {
                sendAlert("RAG 质量下降", result);
            }
        }
    }
}

价值

  • ✅ 实时监控系统质量
  • ✅ 及时发现质量问题
  • ✅ 支持 SLA 保障

场景 4:模型验证

目的:当更换 AI 模型或调整 RAG 配置时,验证新配置的效果

实现方式

public class ModelComparison {
    
    public ComparisonResult compareModels(
            ChatModel oldModel, 
            ChatModel newModel,
            List<TestQuery> testQueries) {
        
        List<EvaluationResult> oldResults = new ArrayList<>();
        List<EvaluationResult> newResults = new ArrayList<>();
        
        RelevancyEvaluator evaluator = new RelevancyEvaluator(chatClient);
        
        for (TestQuery testQuery : testQueries) {
            // 测试旧模型
            ChatResponse oldResponse = executeRag(oldModel, testQuery);
            EvaluationResponse oldEval = evaluator.evaluate(
                new EvaluationRequest(testQuery, oldResponse)
            );
            oldResults.add(oldEval);
            
            // 测试新模型
            ChatResponse newResponse = executeRag(newModel, testQuery);
            EvaluationResponse newEval = evaluator.evaluate(
                new EvaluationRequest(testQuery, newResponse)
            );
            newResults.add(newEval);
        }
        
        // 对比分析
        return analyzeComparison(oldResults, newResults);
    }
}

价值

  • ✅ 客观对比不同模型效果
  • ✅ 数据驱动的决策支持
  • ✅ 降低模型切换风险

场景对比表

场景 评估频率 评估范围 主要评估器 业务价值
开发测试 每次构建 测试用例 RelevancyEvaluator 质量保证
批量检查 定期(如每周) 历史对话 FactCheckingEvaluator
RelevancyEvaluator
问题发现
系统监控 实时抽样(如1%) 生产对话 RelevancyEvaluator 质量监控
模型验证 模型切换时 测试集 RelevancyEvaluator 决策支持

评估的意义与价值

1. 质量保证

维度 说明 价值
事实准确性 确保回答基于真实资料,避免幻觉 提高用户信任度
回答相关性 确保回答与用户问题相关 提升用户体验
上下文利用 确保回答充分利用检索到的文档 发挥 RAG 系统价值

2. 风险控制

风险类型 评估作用 业务影响
法律风险 及时发现错误的法律信息 避免法律纠纷
声誉风险 防止发布错误信息 保护品牌形象
财务风险 避免错误的业务决策 降低经济损失

3. 持续改进

改进方向 评估指导 效果
模型优化 评估不同模型效果,选择最优模型 提升回答质量
配置调优 评估不同配置参数的效果 优化系统性能
知识库优化 识别知识库不足,指导文档补充 完善知识体系

4. 成本优化

优化点 评估价值 节省成本
模型选择 选择性价比最高的模型 降低 API 调用成本
配置优化 找到最优配置参数 减少资源浪费
质量提升 减少错误回答导致的客服成本 降低运营成本

5. 业务价值总结

业务目标 评估贡献 量化指标
用户满意度 提高回答质量和相关性 满意度评分提升 X%
系统可靠性 及时发现和修复问题 错误率降低 X%
运营效率 减少人工审核和修正 人工成本降低 X%
决策支持 数据驱动的模型和配置选择 决策准确率提升 X%

代码示例分析

示例 1:FactCheckingTest.testFactChecking

代码分析
@Test
void testFactChecking(@Autowired DashScopeChatModel chatModel) {
    // 1. 创建事实性评估器
    var factCheckingEvaluator = new FactCheckingEvaluator(
        ChatClient.builder(chatModel)
    );
    
    // 2. 准备上下文文档(知识库中的真实资料)
    Document doc = Document.builder()
        .text("""
            取消预订:
            - 最晚在航班起飞前 48 小时取消。
            - 取消费用:经济舱 75 美元,豪华经济舱 50 美元,商务舱 25 美元。
            - 退款将在 7 个工作日内处理。
            """)
        .build();
    
    List<Document> documents = List.of(doc);
    
    // 3. AI 回答(需要评估的回答)
    String response = "经济舱取消费用75 美元";
    
    // 4. 创建评估请求
    EvaluationRequest evaluationRequest = new EvaluationRequest(
        documents,  // 上下文:事实依据
        response    // 回答:需要检查的事实
    );
    
    // 5. 执行评估
    EvaluationResponse evaluationResponse = factCheckingEvaluator.evaluate(
        evaluationRequest
    );
    
    System.out.println(evaluationResponse);
}
执行流程
1. 创建 FactCheckingEvaluator
   ↓
2. 准备上下文文档(包含事实:经济舱 75 美元)
   ↓
3. 准备 AI 回答(声明:经济舱取消费用75 美元)
   ↓
4. 创建 EvaluationRequest(documents + response)
   ↓
5. 调用 evaluate() 方法
   ↓
6. LLM 内部处理:
   - 提取回答中的事实声明:"经济舱取消费用75 美元"
   - 在上下文中查找依据:找到"取消费用:经济舱 75 美元"
   - 对比验证:事实一致 ✅
   ↓
7. 返回 EvaluationResponse:
   - score: 1.0(完全正确)
   - explanation: "回答中的事实与上下文一致"
评估结果分析
评估项 结果 说明
事实准确性 ✅ 通过 回答中的"75 美元"与上下文中的"75 美元"一致
上下文依据 ✅ 存在 在提供的文档中找到了明确的事实依据
幻觉检测 ✅ 无幻觉 回答没有虚构或错误的事实
如果回答错误会怎样?

假设 AI 回答是:“经济舱取消费用100 美元”

评估结果:
- score: 0.0(完全错误)
- explanation: "回答中的事实(100 美元)与上下文不符(上下文为 75 美元)"

示例 2:FactCheckingTest.testRelevancyEvaluator

代码分析
@Test
void testRelevancyEvaluator(@Autowired DashScopeChatModel chatModel) {
    // 1. 创建相关性评估器
    var evaluator = new RelevancyEvaluator(
        ChatClient.builder(chatModel)
    );
    
    // 2. 准备评估数据
    String context = "地球是距离太阳的第三颗行星,也是已知唯一孕育生命的天文物体。";
    String claim = "地球是距离太阳的第四颗行星,也是已知唯一孕育生命的天文物体。";
    
    // 3. 创建评估请求
    EvaluationRequest evaluationRequest = new EvaluationRequest(
        context,                    // 上下文文档
        Collections.emptyList(),    // 用户问题(本例中为空)
        claim                       // AI 回答(声明)
    );
    
    // 4. 执行评估
    EvaluationResponse evaluationResponse = evaluator.evaluate(
        evaluationRequest
    );
    
    System.out.println(evaluationResponse);
}
执行流程
1. 创建 RelevancyEvaluator
   ↓
2. 准备上下文:"地球是距离太阳的第三颗行星..."
   ↓
3. 准备声明(AI 回答):"地球是距离太阳的第四颗行星..."
   ↓
4. 创建 EvaluationRequest(context + query + claim)
   ↓
5. 调用 evaluate() 方法
   ↓
6. LLM 内部处理:
   - 分析声明:"地球是距离太阳的第四颗行星"
   - 对比上下文:"地球是距离太阳的第三颗行星"
   - 发现不一致:第三颗 vs 第四颗 ❌
   ↓
7. 返回 EvaluationResponse:
   - score: 0.0(完全不相关/错误)
   - explanation: "声明与上下文不符,存在事实错误"
评估结果分析
评估项 结果 说明
相关性 ❌ 不相关 回答与上下文存在矛盾
事实准确性 ❌ 错误 "第四颗"与上下文中的"第三颗"不符
上下文利用 ❌ 未正确利用 模型未正确理解上下文信息

示例 3:RagEvalTest.testRag(完整 RAG 流程评估)

代码分析
@Test
public void testRag(
        @Autowired VectorStore vectorStore,
        @Autowired DashScopeChatModel dashScopeChatModel) {
    
    // 1. 准备知识库
    List<Document> documents = List.of(
        new Document("1. 预订航班\n- 通过我们的网站或移动应用程序预订..."),
        new Document("2. 更改预订\n- 允许在航班起飞前 24 小时更改..."),
        new Document("3. 取消预订\n- 最晚在航班起飞前 48 小时取消...")
    );
    vectorStore.add(documents);
    
    // 2. 构建 RAG Advisor
    RetrievalAugmentationAdvisor advisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(VectorStoreDocumentRetriever.builder()
            .vectorStore(vectorStore)
            .build())
        .build();
    
    // 3. 执行 RAG 查询
    String query = "我叫什么名字";
    ChatResponse chatResponse = ChatClient.builder(dashScopeChatModel)
        .build()
        .prompt(query)
        .advisors(advisor)
        .call()
        .chatResponse();
    
    // 4. 提取评估所需的数据
    EvaluationRequest evaluationRequest = new EvaluationRequest(
        query,  // 用户问题
        chatResponse.getMetadata().get(
            RetrievalAugmentationAdvisor.DOCUMENT_CONTEXT
        ),  // 检索到的上下文
        chatResponse.getResult().getOutput().getText()  // AI 回答
    );
    
    // 5. 执行相关性评估
    RelevancyEvaluator evaluator = new RelevancyEvaluator(
        ChatClient.builder(dashScopeChatModel)
    );
    EvaluationResponse evaluationResponse = evaluator.evaluate(evaluationRequest);
    
    System.out.println(evaluationResponse);
    System.out.println(chatResponse.getResult().getOutput().getText());
}
执行流程
1. 准备知识库(向量存储)
   ↓
2. 构建 RAG Advisor(检索增强生成)
   ↓
3. 用户查询:"我叫什么名字"
   ↓
4. RAG 流程:
   - 向量检索:在知识库中搜索相关文档
   - 检索结果:可能找到"预订时需要确保个人信息(姓名、ID 等)的准确性..."
   - 生成回答:基于检索到的文档生成回答
   ↓
5. 提取评估数据:
   - query: "我叫什么名字"
   - context: 检索到的文档列表
   - response: AI 生成的回答
   ↓
6. 创建评估请求
   ↓
7. 执行相关性评估:
   - 检查回答是否与问题相关?
   - 检查回答是否基于检索到的上下文?
   - 检查回答是否回答了用户的问题?
   ↓
8. 返回评估结果
评估结果分析
评估维度 预期结果 说明
问题相关性 ⚠️ 可能不相关 用户问"我叫什么名字",但知识库中没有用户个人信息
上下文利用 ✅ 正确利用 回答应该基于检索到的文档
回答合理性 ⚠️ 可能不合理 如果回答"您的名字是…"则不合理,因为文档中没有此信息
典型评估结果

场景 A:回答合理

用户问题:"我叫什么名字"
检索上下文:"预订时需要确保个人信息(姓名、ID 等)的准确性..."
AI 回答:"根据文档,我没有找到您的姓名信息。请提供您的姓名以便预订。"
评估结果:
- score: 0.8(高度相关)
- explanation: "回答正确指出文档中没有用户姓名信息,并提供了合理的建议"

场景 B:回答不合理(幻觉)

用户问题:"我叫什么名字"
检索上下文:"预订时需要确保个人信息(姓名、ID 等)的准确性..."
AI 回答:"根据文档,您的名字是张三。"
评估结果:
- score: 0.2(低相关性)
- explanation: "回答虚构了用户姓名,文档中并未包含此信息,存在幻觉"

最佳实践

1. 评估器选择策略

场景 推荐评估器 原因
知识库问答 FactCheckingEvaluator 重点检查事实准确性
RAG 系统整体评估 RelevancyEvaluator 评估回答与问题的相关性
综合评估 两者结合 同时检查事实性和相关性

2. 评估阈值设置

评估类型 推荐阈值 说明
事实性评估 ≥ 0.9 事实准确性要求高,容错率低
相关性评估 ≥ 0.7 相关性可以有一定灵活性
生产环境监控 ≥ 0.6 低于此值需要告警

3. 评估频率建议

场景 评估频率 说明
开发测试 每次构建 确保代码变更不影响质量
批量检查 每周/每月 定期回顾历史对话质量
生产监控 1%-5% 抽样 平衡监控成本和覆盖度
模型切换 100% 测试集 全面评估新模型效果

4. 评估数据准备

✅ 好的实践
// 1. 使用真实的上下文文档
List<Document> context = vectorStore.similaritySearch(
    SearchRequest.builder()
        .query(userQuery)
        .topK(5)
        .build()
);

// 2. 使用完整的用户问题
String query = "退票需要多少费用?";

// 3. 使用实际的 AI 回答
String response = chatResponse.getResult().getOutput().getText();
❌ 避免的做法
// ❌ 不要使用模拟数据
List<Document> context = List.of(
    new Document("模拟文档内容")  // 不真实
);

// ❌ 不要截断用户问题
String query = "退票";  // 信息不完整

// ❌ 不要使用期望的回答
String response = "经济舱取消费用75 美元";  // 这是期望值,不是实际回答

5. 评估结果处理

结果记录
public class EvaluationLogger {
    
    public void logEvaluation(EvaluationResponse result, 
                              EvaluationRequest request) {
        // 记录评估结果
        EvaluationLog log = EvaluationLog.builder()
            .timestamp(LocalDateTime.now())
            .score(result.getScore())
            .explanation(result.getExplanation())
            .query(request.getQuery())
            .response(request.getResponse())
            .build();
        
        // 保存到数据库
        evaluationLogRepository.save(log);
        
        // 如果评分过低,发送告警
        if (result.getScore() < 0.6) {
            alertService.sendAlert("RAG 质量下降", log);
        }
    }
}
结果分析
public class EvaluationAnalyzer {
    
    public AnalysisResult analyze(List<EvaluationResponse> results) {
        // 计算平均分
        double avgScore = results.stream()
            .mapToDouble(EvaluationResponse::getScore)
            .average()
            .orElse(0.0);
        
        // 统计低分比例
        long lowScoreCount = results.stream()
            .filter(r -> r.getScore() < 0.6)
            .count();
        double lowScoreRate = (double) lowScoreCount / results.size();
        
        // 提取常见问题
        List<String> commonIssues = extractCommonIssues(results);
        
        return AnalysisResult.builder()
            .averageScore(avgScore)
            .lowScoreRate(lowScoreRate)
            .commonIssues(commonIssues)
            .build();
    }
}

6. 性能优化

优化策略 实现方式 效果
异步评估 使用 @Async 异步执行评估 不阻塞主流程
批量评估 批量调用评估 API 减少网络开销
缓存结果 缓存相同问题的评估结果 避免重复计算
抽样评估 只评估部分请求 降低评估成本
@Service
public class AsyncEvaluationService {
    
    @Async
    public CompletableFuture<EvaluationResponse> evaluateAsync(
            EvaluationRequest request) {
        RelevancyEvaluator evaluator = new RelevancyEvaluator(chatClient);
        EvaluationResponse result = evaluator.evaluate(request);
        return CompletableFuture.completedFuture(result);
    }
}

常见问题

Q1: 评估器会消耗额外的 LLM 调用吗?

A: 是的。评估器内部会调用 LLM 来分析和判断,因此会产生额外的 API 调用成本。

评估器 LLM 调用次数 成本影响
FactCheckingEvaluator 1 次 中等
RelevancyEvaluator 1 次 中等

建议

  • 在生产环境中使用抽样评估(如 1%-5%)
  • 在开发测试阶段可以 100% 评估
  • 考虑使用更便宜的模型进行评估

Q2: 评估结果是否可靠?

A: 评估结果由 LLM 生成,存在一定的主观性,但通常比较可靠。

可靠性因素 说明 建议
LLM 能力 评估质量取决于评估器使用的 LLM 使用高质量的模型(如 GPT-4)
提示词设计 评估器的内部提示词影响判断 使用 Spring AI 官方评估器
上下文质量 上下文文档的质量影响评估 确保上下文文档准确完整

最佳实践

  • 使用多个评估器交叉验证
  • 结合人工审核进行关键评估
  • 建立评估结果的置信度阈值

Q3: 如何选择合适的评估器?

A: 根据评估目标选择:

评估目标 推荐评估器 示例场景
检查事实准确性 FactCheckingEvaluator 知识库问答、法律咨询
检查回答相关性 RelevancyEvaluator 客服系统、智能助手
综合评估 两者结合 重要业务场景

Q4: 评估结果如何解读?

A: EvaluationResponse 包含两个主要部分:

EvaluationResponse response = evaluator.evaluate(request);

// 1. 评分(0.0 - 1.0)
double score = response.getScore();
// score >= 0.8: 优秀
// score >= 0.6: 良好
// score < 0.6: 需要改进

// 2. 解释(文本说明)
String explanation = response.getExplanation();
// 包含评估的详细说明和理由

Q5: 评估会影响 RAG 系统的性能吗?

A: 评估是异步的,不会直接影响 RAG 系统的响应时间,但会增加系统负载。

影响维度 说明 缓解措施
响应时间 评估是异步的,不影响主流程 使用异步评估
系统负载 增加 LLM API 调用 使用抽样评估
成本 增加 API 调用成本 优化评估频率和范围

Q6: 如何处理评估失败的情况?

A: 评估可能因为网络、API 限制等原因失败,需要做好异常处理:

try {
    EvaluationResponse result = evaluator.evaluate(request);
    // 处理成功结果
} catch (Exception e) {
    // 记录失败日志
    log.error("评估失败", e);
    
    // 可以选择:
    // 1. 重试评估
    // 2. 标记为未评估
    // 3. 使用默认评分
    // 4. 发送告警
}

Q7: 可以自定义评估器吗?

A: 可以。Spring AI 提供了评估器接口,可以自定义实现:

public class CustomEvaluator implements Evaluator {
    
    @Override
    public EvaluationResponse evaluate(EvaluationRequest request) {
        // 自定义评估逻辑
        // 可以结合业务规则、规则引擎等
        return EvaluationResponse.builder()
            .score(calculateScore(request))
            .explanation(generateExplanation(request))
            .build();
    }
}

Q8: 评估结果如何用于系统优化?

A: 评估结果可以指导多个方面的优化:

优化方向 评估数据来源 优化策略
模型选择 不同模型的评估结果对比 选择平均分最高的模型
参数调优 不同配置下的评估结果 调整 temperature、topK 等参数
知识库优化 低分回答的上下文分析 补充缺失的知识文档
检索优化 相关性评估结果 优化检索策略、调整 topK
提示词优化 评估解释中的问题分析 改进系统提示词设计

示例

// 1. 收集评估数据
List<EvaluationResult> results = collectEvaluationResults();

// 2. 分析低分原因
List<String> lowScoreReasons = results.stream()
    .filter(r -> r.getScore() < 0.6)
    .map(r -> r.getExplanation())
    .collect(Collectors.toList());

// 3. 识别常见问题
Map<String, Long> issueFrequency = analyzeIssueFrequency(lowScoreReasons);

// 4. 针对性优化
if (issueFrequency.containsKey("上下文不足")) {
    // 优化检索策略,增加 topK
    optimizeRetrievalStrategy();
}
if (issueFrequency.containsKey("事实错误")) {
    // 优化知识库,补充文档
    enrichKnowledgeBase();
}

Q9: 评估器与人工审核如何结合?

A: 评估器可以辅助人工审核,提高效率:

方式 说明 优势
预筛选 评估器先筛选,人工只审核低分回答 减少人工工作量
交叉验证 评估器 + 人工双重检查 提高准确性
学习反馈 人工审核结果用于优化评估器 持续改进

实现示例

public class HybridEvaluationService {
    
    public EvaluationResult evaluateWithHumanReview(
            EvaluationRequest request) {
        
        // 1. 自动评估
        EvaluationResponse autoResult = evaluator.evaluate(request);
        
        // 2. 如果评分低,触发人工审核
        if (autoResult.getScore() < 0.6) {
            HumanReviewRequest reviewRequest = HumanReviewRequest.builder()
                .query(request.getQuery())
                .response(request.getResponse())
                .autoEvaluation(autoResult)
                .build();
            
            // 发送到人工审核队列
            humanReviewQueue.add(reviewRequest);
        }
        
        return EvaluationResult.builder()
            .autoEvaluation(autoResult)
            .requiresHumanReview(autoResult.getScore() < 0.6)
            .build();
    }
}

Q10: 如何建立评估基准(Benchmark)?

A: 建立评估基准有助于持续监控系统质量:

步骤

  1. 准备测试集

    List<TestCase> testCases = List.of(
        TestCase.builder()
            .query("退票需要多少费用?")
            .expectedContext("取消费用:经济舱 75 美元...")
            .expectedResponse("经济舱取消费用75 美元")
            .build(),
        // 更多测试用例...
    );
    
  2. 建立基准分数

    public class BenchmarkService {
        
        public BenchmarkResult establishBaseline(
                List<TestCase> testCases) {
            
            List<EvaluationResponse> results = testCases.stream()
                .map(this::evaluateTestCase)
                .collect(Collectors.toList());
            
            double baselineScore = results.stream()
                .mapToDouble(EvaluationResponse::getScore)
                .average()
                .orElse(0.0);
            
            return BenchmarkResult.builder()
                .baselineScore(baselineScore)
                .testCases(testCases.size())
                .timestamp(LocalDateTime.now())
                .build();
        }
    }
    
  3. 定期对比

    public void compareWithBaseline(BenchmarkResult baseline) {
        BenchmarkResult current = establishBaseline(testCases);
        
        double scoreChange = current.getBaselineScore() - 
                            baseline.getBaselineScore();
        
        if (scoreChange < -0.1) {
            // 质量下降超过 10%,发送告警
            alertService.sendAlert("质量下降", scoreChange);
        }
    }
    

总结

核心要点

要点 说明
为什么评估 RAG 系统不能完全消除幻觉,需要评估来保证质量
评估器类型 FactCheckingEvaluator(事实性)和 RelevancyEvaluator(相关性)
使用场景 开发测试、批量检查、系统监控、模型验证
评估价值 质量保证、风险控制、持续改进、成本优化

评估流程总结

1. 准备评估数据
   ├── 用户问题(query)
   ├── 检索到的上下文(context)
   └── AI 回答(response)
   ↓
2. 选择评估器
   ├── FactCheckingEvaluator(事实性)
   └── RelevancyEvaluator(相关性)
   ↓
3. 创建评估请求
   └── EvaluationRequest(query, context, response)
   ↓
4. 执行评估
   └── evaluator.evaluate(request)
   ↓
5. 处理评估结果
   ├── 记录结果
   ├── 分析问题
   └── 触发优化

最佳实践清单

  • 选择合适的评估器:根据场景选择事实性评估或相关性评估
  • 设置合理的阈值:事实性 ≥ 0.9,相关性 ≥ 0.7
  • 使用抽样评估:生产环境使用 1%-5% 抽样,降低成本
  • 记录评估结果:建立评估日志,便于分析和追踪
  • 建立评估基准:定期对比,监控质量变化
  • 结合人工审核:关键场景使用评估器 + 人工双重检查
  • 持续优化:根据评估结果优化模型、配置和知识库

评估指标参考

指标 优秀 良好 需改进
事实性评分 ≥ 0.9 0.7 - 0.9 < 0.7
相关性评分 ≥ 0.8 0.6 - 0.8 < 0.6
低分比例 < 5% 5% - 15% > 15%
平均评分 ≥ 0.85 0.7 - 0.85 < 0.7

相关资源

  • Spring AI 官方文档:https://docs.spring.io/spring-ai/reference/
  • 评估器 API 文档FactCheckingEvaluatorRelevancyEvaluator
  • 代码示例
    • FactCheckingTest.java - 事实性评估示例
    • RagEvalTest.java - 完整 RAG 流程评估示例

文档版本:v1.0
最后更新:2025年1月
维护者:Spring AI 学习团队

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐