ACP大模型应用开发工程师-RAG 自动化评测体系学习-java转AI应用开发学习

面向 Java 高级开发 的技术笔记:先把 Ragas、TruLens、DeepEval 等「以 Python 生态见长」的框架放在同一张认知地图里;第三节展开 Answer Correctness / context_recall / context_precision(含计算与图)、Ragas 其余指标文档入口,以及 如何据分优化(上下文生命线、Lost in the Middle、知识浓度、recall 低时先查知识库);再接 Spring AI / Spring AI Alibaba 的 Java 对标与业务自定义指标领域专家角色——方便复盘与持续学习。
声明以下内容都是本人自学后,统一整理梳理出来了,方便自己后续复盘以及深入实践融入一些个人的认知

一、为什么要做 RAG 自动化评测

RAG 链路长:检索 → 拼上下文 → 生成。任何一环漂移都会导致「看似流畅、实则幻觉或答非所问」。

自动化评测的目标不是取代人工,而是:

  • 可重复的质检从「拍脑袋」变成可度量、可对比、可回归
  • 在迭代检索策略、Prompt、模型版本时,有统一的尺子
  • 为观测与告警提供量化信号(再接到 Prometheus / Grafana 等)。

下面几个维度是业界讨论最多的评测切面(与后文框架指标一一对应):

维度 在问什么
召回质量 (Retrieval Quality) RAG系统是否检索到了正确且相关的文档片段?。检索到的片段是否正确、相关?该召回的有没有漏?
答案忠实度 (Faithfulness) 生成的答案答案是否主要依据检索上下文,而非胡编?
答案相关性 (Answer Relevance) 生成的答案是否准确地回答了用户的问题?
上下文利用 (Context Utilization) 大模型是否有效地利用了所有提供给它的上下文信息?(与「Lost in the Middle」、上下文过长导致稀释等问题相关)?

二、主流开源框架汇总(暂时Python 生态为主,后面会介绍我们熟悉的java如何集成)

2.1 Ragas

定位:用大模型当评委,读「问题 + 检索上下文 + 生成答案」,按预设指标打分。

这是领域里非常出名的一个框架,它的核心思想是“让大模型来帮助你评估RAG系统”。在评测时,Ragas 会调用一个大模型作为评测专家来阅读你的问题、RAG检索到的上下文和生成的答案,然后根据预设的指标给出分数。Ragas的评估指标高度契合RAG系统的痛点,

与 RAG 痛点贴合的指标(概念层)

类型 指标 含义(一句话)
整体回答质量的评估 Answer Correctness 用于评估 RAG 应用生成答案与「标准答案」的准确度(有参考答案时)
生成环节的评估 Answer Relevancy RAG 应用生成的答案与问题的相关性是否相关
生成环节的评估 Faithfulness RAG 应用生成的答案与检索资料的事实一致性(抗幻觉)
召回阶段的评估 Context Precision 用于评估 contexts 中与准确答案相关的条目是否靠前、信噪比高(或者说占比高不)
召回阶段的评估 Context Recall 相关参考资料是否被充分召回(少遗漏)、用于评估有多少相关参考资料被检索到,越高的得分意味着更少的相关参考资料被遗漏。

特点:Python 库集成成本低,几行代码可挂进流水线;指标设计与论文/社区共识较一致,适合作为概念教科书


2.2 TruLens

定位:强调可观测性全链路追溯——单次调用的输入、输出、中间步骤、所用模型、召回上下文等都可记录,并用「反馈函数」自动打分。

这个框架专注于评估的可观测性,它不仅仅告诉你RAG哪里可能有问题,它还能帮你追溯RAG的整个运行过程。包括每次运行的输入、输出、中间步骤、调用的大模型、检索召回的上下文等等,并提供一系列“反馈函数”来自动化评估这些运行。 TruLens 框架可以与LangChain、LlamaIndex等框架无缝集成,并提供了一套可视化工具,展示每次RAG调用的详细过程。

常见反馈维度

指标 含义(一句话)
Groundedness 生成的答案是否是来自于检索召回的知识
Answer Relevance 答案与问题的相关性
Context Relevance 召回内容与问题的相关性

特点:与 LangChain、LlamaIndex 等集成多,可视化追溯强;适合「我要看懂这一次为什么差」而不仅是「平均分多少」。

image.png

访问 TruLens官网了解其他评估指标如(User sentiment、Fairness and bias)等等


2.3 DeepEval

定位:DeepEval 则将传统软件开发的测试理念引入到RAG应用中。它鼓励你采用单元测试和测试驱动开发(TDD)的思想,在RAG功能开发前就编写评估测试,确保应用性能从一开始就符合预期。 为此,DeepEval提供了一个专门的测试框架,让你能够像编写传统软件的单元测试一样,为RAG系统创建LLM评估测试。它支持为每个测试用例设置明确的通过/失败(Pass/Fail)阈值,这使得DeepEval能轻松集成到你的持续集成/持续部署(CI/CD)流程中,从而实现自动化回归测试。

软件测试 / TDD 思维搬到 LLM 应用:为 RAG 写可执行的评测用例,带 Pass/Fail 阈值,方便进 CI/CD 做回归。

指标:与 Ragas 类似,常见 Faithfulness、Answer Relevance、Context Relevance、Context Recall 等。

特点阈值化、测试套件化清晰,适合工程团队把「评测」当成门禁的一部分(需注意成本与 flaky 问题)。


2.4 三者的快速对比(复盘用)

Ragas TruLens DeepEval
强项 指标与 RAG 论文/实践对齐,上手快 追溯与可观测、排障 单元测试式、CI 友好
典型输出 分项分数 轨迹 + 反馈分数 Pass/Fail + 报告
生态语言 Python 为主 Python 为主 Python 为主
Java 直接复用 需 HTTP/侧车/离线任务 同上 同上

对 Java 开发的启示:三类框架的思想(LLM-as-judge、轨迹、测试阈值)都可以迁移;实现层在 Java 里通常用 Spring AI / Spring AI Alibaba 调 ChatModel,自研「评测器」服务,而不是在 JVM 内嵌 Python 解释器。

2.5 自定义评测框架

除了前面介绍的 Ragas、TruLens、DeepEval,你可能还接触过一些带评估能力的开源开发框架(例如 LlamaIndex、LangChain 等)。这类工具的优势是「构建流程与评估流程可以无缝衔接」;但在真实业务里,很多关键质量要求并不完全等价于通用指标,因此常常需要一层自定义评测框架

换句话说:通用指标告诉你「有没有偏题、有没有幻觉」,但业务方更关心的是「这条答案能不能真正解决问题、是否符合流程与政策」。

下面是两个典型场景:

  • 案例一:报销流程问答
    用户问「报销流程是什么?」时,业务侧可能要求优质答案必须包含:

    1. 报销入口/报销单链接;
    2. 二级主管审批信息;
    3. 引导到费用系统提交申请。
      这类要求本质上属于流程合规 + 可操作性,不是仅靠 Relevance 就能覆盖。
  • 案例二:订单延迟问答
    用户问「订单延迟了怎么办?」时,好的答案不应只有「请耐心等待」,而应包含:

    1. 情绪安抚;
    2. 当前物流状态;
    3. 预计送达时间;
    4. 延误原因(若已知);
    5. 后续处理路径(退款/投诉等)。
      这体现的是情绪安抚度 + 问题解决完备性

因此在工程上,你可以在通用指标之外,增加一组业务自定义维度:

  • 流程可操作性
  • 政策合规性
  • 情绪安抚度
  • 问题解决完备性

这些维度可以通过「规则校验 + LLM 评委」混合实现:能硬规则判断的(如是否包含指定链接)尽量规则化,主观维度再用 LLM 评分并保留 reason 字段,便于复盘。

实践建议:把自定义指标做成可配置模板(版本号、阈值、适用场景),并纳入你的评测流水线,而不是散落在临时 Prompt 中。


三、深入 Ragas:Answer Correctness 与检索指标(实操与计算过程)

Ragas 在 Python 项目中往往只需几行即可做一次全链路或分项评测。下面把你课程中的 Answer Correctnesscontext_precision / context_recall 的数据准备、示例代码与打分逻辑对齐到文档里,便于和第四节 Java 实现对读。

3.1 评估 RAG 应用回答质量:answer_correctness

3.1.1 快速上手(需要 Ground Truth)

计算 Answer Correctness 时,每条样本至少要准备:

  • question:用户问题
  • answer:RAG / 模型实际输出
  • ground_truth:你预先认可的参考答案(一般由业务或专家给定)

下面用同一问题「张伟是哪个部门的?」三组回答,直观看出分数分层(无效回答 / 幻觉 / 正确):

question ground_truth answer
张伟是哪个部门的? 张伟是教研部的成员。 根据提供的信息,没有提到张伟所在的部门。如果您能提供更多关于张伟的信息,我可能能够帮助您找到答案。(无效)
张伟是哪个部门的? 张伟是教研部的成员。 张伟是人事部门的。(幻觉)
张伟是哪个部门的? 张伟是教研部的成员。 张伟是教研部的。(正确)

以这三条样本做评测时,典型结果会与直觉一致:越贴近事实的答案,answer_correctness 越高(示例量级约:0.17 / 0.19 / 0.99,具体小数会随模型与评测实现细节波动)。

Java 对标实现(Spring AI Alibaba,自定义 Answer Correctness pipeline)

如果你在 Java 栈里不直接跑 Python Ragas,可用「语义相似度 + 事实准确度」两段式实现同构指标。下面示例沿用同一组三条样本,最终打印 answer_correctness 分数表,便于和上面的 Python 输出对齐复盘。

package com.baoma.ai.evaluation;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 示例:用 Spring AI Alibaba 复刻 Answer Correctness 思路
 * score = 0.25 * semanticSimilarity + 0.75 * factualF1
 */
@Component
public class AnswerCorrectnessDemoRunner implements CommandLineRunner {

    private final ChatClient chatClient;
    private final EmbeddingModel embeddingModel;

    public AnswerCorrectnessDemoRunner(ChatModel chatModel, EmbeddingModel embeddingModel) {
        this.chatClient = ChatClient.create(chatModel);
        this.embeddingModel = embeddingModel;
    }

    @Override
    public void run(String... args) {
        List<Sample> samples = List.of(
            new Sample("张伟是哪个部门的?",
                "根据提供的信息,没有提到张伟所在的部门。如果您能提供更多关于张伟的信息,我可能能够帮助您找到答案。",
                "张伟是教研部的成员"),
            new Sample("张伟是哪个部门的?",
                "张伟是人事部门的",
                "张伟是教研部的成员"),
            new Sample("张伟是哪个部门的?",
                "张伟是教研部的",
                "张伟是教研部的成员")
        );

        System.out.println("question\tanswer\tground_truth\tanswer_correctness");
        for (int i = 0; i < samples.size(); i++) {
            Sample s = samples.get(i);
            double semantic = cosine(embeddingModel.embed(s.answer), embeddingModel.embed(s.groundTruth));
            FactStat fact = compareFactsByLlm(s.answer, s.groundTruth);
            double factualF1 = fact.tp > 0 ? (double) fact.tp / (fact.tp + 0.5 * (fact.fp + fact.fn)) : 0.0;
            double answerCorrectness = 0.25 * semantic + 0.75 * factualF1;
            System.out.printf("%d\t%s\t%s\t%s\t%.6f%n",
                i, s.question, s.answer, s.groundTruth, answerCorrectness);
        }
    }

    /**
     * 让 LLM 输出 JSON:{"tp":1,"fp":1,"fn":0}
     * 这里为了示例简洁,省略 JSON 解析异常处理与重试。
     */
    private FactStat compareFactsByLlm(String answer, String groundTruth) {
        String prompt = """
            你是RAG评估专家。请比较 answer 与 ground_truth 的事实一致性。
            要求:
            1) 先在心里将两段文本拆成原子观点;
            2) 统计 TP/FP/FN(定义:answer中可被ground_truth支持的观点=TP;answer里无依据=FP;ground_truth里answer未覆盖=FN);
            3) 只输出 JSON,不要其他内容:{"tp":0,"fp":0,"fn":0}

            answer: %s
            ground_truth: %s
            """.formatted(answer, groundTruth);

        String raw = chatClient.prompt().user(prompt).call().content();
        // 生产实现建议用 ObjectMapper 严格解析 + fallback
        int tp = parseInt(raw, "tp");
        int fp = parseInt(raw, "fp");
        int fn = parseInt(raw, "fn");
        return new FactStat(tp, fp, fn);
    }

    private static double cosine(float[] a, float[] b) {
        double dot = 0, na = 0, nb = 0;
        for (int i = 0; i < Math.min(a.length, b.length); i++) {
            dot += a[i] * b[i];
            na += a[i] * a[i];
            nb += b[i] * b[i];
        }
        if (na == 0 || nb == 0) return 0.0;
        return dot / (Math.sqrt(na) * Math.sqrt(nb));
    }

    private static int parseInt(String json, String key) {
        // 演示版:生产请改为 Jackson
        String hit = "\"" + key + "\":";
        int i = json.indexOf(hit);
        if (i < 0) return 0;
        int s = i + hit.length();
        int e = s;
        while (e < json.length() && Character.isDigit(json.charAt(e))) e++;
        return Integer.parseInt(json.substring(s, e));
    }

    private record Sample(String question, String answer, String groundTruth) {}
    private record FactStat(int tp, int fp, int fn) {}
}

说明:上面是「Ragas 思路的 Java 同构实现」,不是官方 Python 库的逐行移植。若你追求与 Ragas 完全一致,请以 Python Ragas 作为离线基准,再逐步校准 Java 版本的 prompt、解析和权重。

3.1.2 Answer Correctness 的计算过程(语义 + 事实)

从整体上看,打分同时用到 Embedding 模型LLM 裁判,再合成一个标量:

  1. 语义相似度

    • answerground_truth 向量化,常用 余弦相似度(Ragas 默认实践之一)。
    • 反映「字面/语义有多像」,但单靠向量难以区分「部分一致 + 局部事实错误」
  2. 事实准确度(Factual agreement)

    • Ragas 用 LLM 把 answerground_truth 各拆成若干原子观点(statements),再比较两边是否互相支撑,归纳出 TP / FP / FN(判断过程也由大模型完成)。

下图可以帮助你理解 Ragas 衡量事实准确度的方法:


image.png

直观例子(与你的教材一致):

文本 LLM 拆出的观点列表示意
answer:张伟是教研部负责大模型课程的同事。 「张伟是教研部的」「张伟负责大模型课程」
ground_truth:张伟是教研部负责大数据方向的同事。 「张伟是教研部的」「张伟负责大数据方向」

对齐规则简述:

  • answer 生成的每个观点:若能在 ground_truth 侧找到依据 → TP;否则 → FP(可理解为「多出或无法证实」的主张)。
  • ground_truth 生成的每个观点:若 answer 侧没有依据 → FN(可理解为「该提的未覆盖」)。

事实分用的 Fβ 家族形式(课件中的 F1 变体写法):

image.png

下图对应「如何从 answer / ground_truth 生成观点并入 TP / FP / FN」的流程(与原课图一致):

分数汇总(课件常用权重):

image.png

这样既惩罚「话术像但胡说」,也兼顾「事实对但措辞差」的中间态。


3.2 评估检索召回效果:context_precisioncontext_recall

两者侧重不同,可以同时使用

  • Context precision:contexts 里相关片段是否靠前、信噪比如何;侧重相关性。
  • Context recallground_truth 拆出的观点里,有多大比例能被 contexts 整体支撑,侧重事实准确度。

3.2.1 快速上手(需要 contexts + ground_truth)

question / answer / ground_truth 外,增加:

  • contexts检索返回的片段列表(有序,一般与线上 RAG 一致)。

示例(三组 contexts 差异化,第三条同时体现 recall 与 precision 的中间态):

from langchain_community.llms.tongyi import Tongyi
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import context_recall, context_precision

data_samples = {
    'question': ['张伟是哪个部门的?'] * 3,
    'answer': [
        '根据提供的信息,没有提到张伟所在的部门。如果您能提供更多关于张伟的信息,我可能能够帮助您找到答案。',
        '张伟是人事部门的',
        '张伟是教研部的',
    ],
    'ground_truth': ['张伟是教研部的成员'] * 3,
    'contexts': [
        ['提供行政管理与协调支持,优化行政工作流程。 ', '绩效管理 部 … 人力资源'],
        ['李凯 教研部主任 ', '牛顿发现了万有引力'],
        ['牛顿发现了万有引力', '张伟 教研部工程师,他最近在负责课程研发'],
    ],
}

dataset = Dataset.from_dict(data_samples)
score = evaluate(
    dataset=dataset,
    metrics=[context_recall, context_precision],
    llm=Tongyi(model_name="qwen-plus"),
)
score.to_pandas()

与教材解读一致:第三组答案正确,context_recall≈1 表示 ground_truth 中的观点能被 contexts 支撑到;但列表里混入「牛顿…」类噪声,使得 precision 未到 1(示例中常为 0.5 量级)。前两组检索与结论均差,precision / recall 易呈 0

3.2.2 Context Recall 的计算过程(概念)

  1. LLM 将 ground_truth 拆成 (n) 条原子观点(statements)
  2. 由大模型判断每个观点能在检索到的参考资料(contexts)中找到依据,或者说 context 是否能支撑 ground_truth 的观点。
  3. 被支撑观点数 / 总观点数 = context_recall。 然后 ground_truth 观点列表中,能在 contexts 中找到依据的观点占比,作为 context_recall 分数。

例:ground_truth → ["张伟是教研部的"],contexts 中有「张伟 教研部工程师…」可支撑 → 若仅此一条观点,则 recall = (1/1 = 1)。

3.2.3 Context Precision 的计算过程(概念,与排序有关)

简述课件版算法(细则以 Ragas 源码为准):

  1. 按 contexts 的顺序逐个处理 (\text{context}_i):结合 question + ground_truth,由 LLM 判断该片段是否「相关」(相关记 1,否则 0)。
  2. 对每个位置 (i),构造一个类似 前缀精度:分子为「前 (i) 个里相关个数之和」,分母为 (i)(位置权重体现是否把相关条目排在前面)。
  3. 再对各项指标按 Ragas 定义做归一(如除以相关 context 个数等),得到标量 context_precision

直觉:相关片段越早出现、越少噪声,分越高。若你愿意啃实现,直接去读 Ragas 对应 metric 的实现即可。

3.3 其他推荐了解的指标

Ragas 还内置了 Faithfulness、Answer Relevancy、Answer Similarity 等大量指标;本文只展开了与课程衔接最紧的 Answer Correctnesscontext_recallcontext_precision。其余指标的适用场景、输入字段与计算原理,建议直接查阅官方指标索引(随版本更新):

Ragas — Available metrics(官方文档)

阅读时建议对照三件事:需要哪些列(question / contexts / answer / ground_truth)更偏检索还是更偏生成是否必须 Ground Truth

3.4 如何根据 Ragas 指标进行优化

做评测的终点不是「刷出一个分数」,而是用分数定位瓶颈、决定下一轮改检索、改知识库还是改 Prompt / 模型。你已掌握 answer_correctnesscontext_recallcontext_precision 的含义后,可以按指标组合看「哪一段掉了链子」。

下面是一张粗粒度对照表(实际要结合 Bad case 与是否缺 Ground Truth 一起看):

观察 可能含义 优化方向(优先序供参考)
context_recall 检索到的上下文盖不住标准答案里的事实 先知识库/切分,再检索策略(见 3.4.2)
context_precision 上下文里噪声多相关条目不靠前 重排、压缩上下文、混合检索、控 topK、Prompt 约束引用
answer_correctness 低,但 recall/precision 尚可 生成阶段曲解、漏答、风格不符 Prompt、引用约束、模型、后处理
answer_correctness 低且 recall 上游就没给到证据 不要先换大模型,回到知识库与召回

3.4.1 上下文是 RAG 的生命线

用户提问后,模型主要依据你喂进去的 上下文(Context) 组织答案。上下文若缺关键事实有错充斥无关内容,上限就被锁死——例如上下文里根本没有「张伟所在部门」,模型很难凭空答对。

另一个常见误区是「把全部资料一股脑塞进 prompt,让模型自己筛」。即便关键句藏在海量文本里,模型也可能视而不见,即社区常说的 「Lost in the Middle」中文含义叫中间迷失:注意力被噪声稀释,关键信息被淹没(好比「张伟,技术部,工号…」混在几百页考勤、会议纪要、食堂菜单里)。

因此,RAG 精度往往首先卡在上下文的「知识浓度」:相关信息是否够、准、靠前、噪音少,能否让模型稳定聚焦问题核心。

Context RecallContext Precision 正是在衡量「召回到的上下文是否覆盖该有的事实、是否信噪比高、排序是否合理」——你可以用这两条曲线的升降来验证「召回侧优化是否真的有效」,而不是只看生成模型换没换。

3.4.2 context recall 偏低时,优先从哪改?

context_recall 衡量的是 RAG 检索阶段:ground_truth 中的观点有多大比例能被当前 contexts 支撑。该指标长期偏低时,说明「该进上下文的没进来」,优化要从数据与检索链路下手,而不是先怀疑生成模型「不够聪明」。

第一步:确认知识库以及实现方面的定位优化:

知识库是 RAG 应用的源头。 若库内内容不完备,召回的参考信息必然不充分,context_recall 会被直接拉低。建议将知识库内容与测试样本做系统对比:对每一条用例,判断「库中是否存在能支撑标准答案的表述」(可人工表格式检查,也可借助大模型做辅助对账,重要结论仍建议人工抽检)。若多例表现为缺知识、缺版本、缺同义说法,应优先增补文档、结构化字段、FAQ、术语表,而不是先加大 topK 或盲目换 embedding。

在确认「知识在库」之后,再进入下列排查(可与 Bad case、检索日志联动):

  1. 检查知识库与内容治理(源头)
    除「有没有」之外,还要看是否过时、是否冲突、权限与可见范围是否导致线上检索域里根本搜不到该条。

  2. 再查切分与索引
    已有文档但 recall 仍低:看 chunk 是否切太碎/太粗、标题与正文是否分离、元数据(部门、产品、时间)是否进不了检索条件;必要时调整 chunk 策略、层级摘要、父子块 等。

  3. 最后调检索策略
    库里有但召不回:再调 embedding 模型、混合检索(关键词 + 向量)、重排(rerank)、查询改写、HyDE 等,或者最终策略还是切换更强大的embedding模型。

第二部分:也可以尝试对用户的query改写

作为开发者,对用户的提问方式做过多要求是不现实的,因此你可能会得到这样缺少信息的问题:“教研部”、“请假”、“项目管理”。如果直接将这样的问题输入RAG应用中,大概率无法召回有效的文本段。你可以通过对员工常见问题的梳理来设计一个prompt模板,使用大模型来改写query,提升召回的准确率。


image.png

简记:recall 低 → 先问「知识在不在库里」再问「搜不搜得到」


3.4.3 context precision 偏低时,优先从哪改?

context_precisioncontext_recall 一样都在评估检索阶段,但它更关注「相关片段是否排在前面、噪声是否被压下去」。

context_precision 低时,可先复用 context_recall 的排查步骤(知识库、切分、检索策略),再额外重点做两件事:

  1. 加入重排序(rerank)
    在向量检索召回 topK 后,用 cross-encoder / rerank 模型按「问题-片段相关性」重排,把更相关的文本段前置。
  1. 控制上下文噪声
    通过更严格的 metadata 过滤、召回阈值、场景路由、去重与相似片段合并,减少“看起来像相关、实则无关”的上下文进入生成阶段。

经验上,context_precision 的改善往往直接提升回答稳定性,尤其在长上下文场景中能显著缓解「Lost in the Middle」。

3.4.4 answer correctness 偏低时,怎么定位生成侧问题?

answer_correctness 是一个综合指标。若它偏低,但 context_recallcontext_precision 都较高,通常说明检索阶段没太大问题,瓶颈在生成阶段

可按下面顺序优化:

  1. 优化 Prompt 契约:明确“只依据上下文回答、禁止编造、引用关键依据、信息不足要显式说明”。
  2. 调整生成参数:适当降低 temperature、收紧 top_p,减少发散与臆测。
  3. 升级模型能力:切换更强模型(必要时分场景路由)。
  4. 考虑微调或偏好对齐:在高价值场景用业务数据做监督微调/偏好优化。

一句话定位:前两项(recall/precision)高而 correctness 低 = 重点改生成;前两项低 = 先回到检索与知识库。


五、打造卓越的评测运营体系

自动化评测确实能提升执行效率,但更大的挑战来自:高质量评测样本构建领域知识持续沉淀。因此,除了技术实现,还需要结合业务特征建立一套评测运营体系。

5.1 构建高质量评测集

自动化评测的有效性,本质上取决于评测集质量。一个好的评测集应反映真实业务需求,而不是技术侧的想象问题。

评测集中的问题(question)从哪里来?

  • 用户问题抽样:从线上真实问答中按频率、类型分层抽样;
  • 用户工单/反馈:工单、投诉、客服反馈通常最能反映真实痛点;
  • 业务场景覆盖:既覆盖高频主路径,也覆盖边界和异常场景。

标准答案(Ground Truth)从哪里来?

评测集中的标准答案必须由业务领域专家提供与审定:

  • 为什么是业务专家:只有业务专家能判断“什么答案是对的、好的、合规的”;
  • 技术人员的局限:技术侧能判断“是否检索到相关内容”,但不一定能判断“业务上是否正确、完整、可执行”;
  • 关键认知:正因为“问题来自真实用户 + 答案来自业务专家”,自动化评测结果才真正能映射业务效果。

5.2 评测先行的优化策略

在大模型应用开发中,评测应走在优化前面,而不是“先优化,再看效果”。

下图展示了一个评测先行的闭环流程(目标→评测集→自动化评测→优化→验证→上线→持续迭代):

image.png

为什么要“评测先行”?

  • 避免盲目优化:没有评测基线,很难判断优化是否有效;
  • 量化改进效果:从“感觉变好了”变成“指标提升了 15%”;
  • 防止跷跷板效应:局部优化可能拖累全局,评测可及时发现副作用。

5.3 业务指标与评测指标对齐

Ragas 的 context_recallcontext_precisionanswer_correctness 是算法指标,但业务最终关心的是业务结果。要让评测服务业务,必须把三层指标打通:

层级 指标示例 说明
业务指标 用户问答满意度 > 90% 最终目标,衡量业务价值
核心技术指标 召回准确率 > 85%、响应时间 < 2s 业务目标的工程化拆解
算法指标 Context Precision、Answer Correctness 自动化评测,支持快速迭代验证

核心原则:算法指标是手段,业务指标才是目标。不要为了提升 context_recall 而优化,而要为了提升用户满意度而优化。

5.4 持续运营评测体系

可以从“找到最懂业务的人,用科学方法深度参与评测”开始:

  • 让业务专家参与 AI 评测:例如电商客服主管评估促销规则回复准确性,物流专员评估时效/运费回复准确性;
  • 从最终用户视角出发:同时看正确性、简洁性、可操作性;
  • 建立闭环机制发现问题 → 改进优化 → 跟踪效果 → 迭代指标,让评测持续驱动系统进化。

下图展示了完整的评测运营体系架构:

评测运营体系架构

5️五、Java 对标实现:用 Spring AI / Spring AI Alibaba 搭「类 Ragas」评测

5.1 为什么选 Spring 生态

  • 与现有 Spring Boot 服务、配置、观测、线程模型一致;
  • Spring AI 提供统一的 ChatModel / ChatClient、Prompt、结构化输出;
  • Spring AI Alibaba 提供通义等模型的自动配置与 DashScope 能力,适合国内部署与密钥管理;
  • 评测本质是另一次 LLM 调用 + JSON 契约,不依赖 Python 运行时;

对照第三节:Answer Correctness 在 Java 里可拆成 (a) Embedding cosine 相似度(Spring AI EmbeddingModel)(b) 观点抽取 + TP/FP/FN + F1(两轮/多轮 LLM JSON);Context recall / precision 同样用 ChatModel + 结构化输出复刻裁判逻辑——权重与阈值建议与 Ragas 文档对齐或按业务微调并版本化管理

5.2 概念到代码的映射(对标 Ragas 指标)

在 Java 中可为每个指标维护一个 Prompt 模板(或 PromptTemplate Bean),占位符例如:

  • {question}{context}{answer}
  • 若有标注:{ground_truth}(Answer Correctness / 部分 Context Recall 需要)

Faithfulness(忠实度)示例(与常见 Ragas 表述同构)

你是 RAG 评估专家,判断答案是否主要仅基于给定上下文生成,无明显幻觉或上下文未提及的断言。
【上下文】
{context}
【答案】
{answer}
请只输出一个 JSON 对象,不要其它文字:
{"score":0.0,"reason":"一句话理由"}
score 取值 0.0~1.0,1.0 表示完全忠实于上下文。

可直接落地的 Java 示例(Spring AI Alibaba,自定义评测器)

package com.baoma.ai.evaluation;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Service;

/**
 * 自定义 Faithfulness 评测器:
 * 输入 question/context/answer,输出 0~1 分数与理由。
 */
@Service
public class FaithfulnessEvaluator {

    private final ChatClient chatClient;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public FaithfulnessEvaluator(ChatModel chatModel) {
        // Spring AI Alibaba 配好后,这里可直接拿到通义模型能力
        this.chatClient = ChatClient.create(chatModel);
    }

    public EvalResult evaluate(String question, String context, String answer) {
        String prompt = """
            你是RAG评估专家,判断答案是否仅基于上下文生成,无幻觉。
            【问题】%s
            【上下文】%s
            【答案】%s
            只输出JSON:{"score":0.0,"reason":"..."}
            """.formatted(question, context, answer);

        String raw = chatClient.prompt()
            .user(prompt)
            .call()
            .content();

        try {
            JsonNode node = objectMapper.readTree(raw == null ? "{}" : raw);
            double score = node.path("score").asDouble(0.0);
            String reason = node.path("reason").asText("");
            return new EvalResult(score, reason, raw);
        } catch (Exception e) {
            // 解析失败降级:记失败分并保留原始输出,便于排查
            return new EvalResult(0.0, "parse_error: " + e.getMessage(), raw);
        }
    }

    public record EvalResult(double score, String reason, String raw) {}
}

建议接入点(与你当前 MediaOps 问答链路对齐)

  1. 在回答生成完成后(非流式 chat() 返回前,或流式 done 回调中)异步调用 evaluate(...)
  2. 持久化 traceId / scenario / question / score / reason / raw
  3. 用 Micrometer 上报 faithfulness_score(分布)与 evaluation_error_count(计数)。

Answer Relevance 则主要使用 {question} + {answer}Context Precision / Recall 往往需要参考答案或人工标注的「应出现片段」,实现上比纯 Faithfulness 更重。

实现要点

  1. 评测模型可与业务对话模型分离(更小、更便宜的通用模型),控制成本与延迟。
  2. 异步执行:用户先拿到回答,评测在后台跑,结果进日志 / DB / Micrometer(见第八节)。
  3. Context 截断:拼接检索片段时设 最大字符数,避免评测 Prompt 比生成还贵。
  4. 解析失败要有降级:JSON 解析失败记 evaluation_error,勿拖垮主链路。

5.3 与「TruLens 式追溯」在 Java 里的轻量对标

不必一次上一套完整 TruLens,可先做最小可追溯结构

  • traceIdquestionretrievedDocIds、拼接后的 context 摘要、answermodellatency
  • 评测结果:faithfulness_scorerelevancy_scoreraw_judge_json

后续再接统一日志、链路追踪或简单管理端查询,即具备「可观测」雏形。

5.4 与「DeepEval 式门禁」在 Java 里的对标

  • JUnit + Spring Boot Test 或独立 评测 Job:固定测试集 JSON(question / context / answer 或端到端调用),断言 score >= threshold
  • CI 中只对小集mock 裁判跑全量,避免每次 MR 都打真实大模型。

六、自定义评测框架:业务规则比通用指标更近「好用」

通用指标解决「有没有胡说、有没有偏题」;业务系统往往还要问「这答案能不能办事」。

案例 自定义维度示例
「报销流程是什么?」 流程合规:是否包含报销入口链接、审批层级、费用系统引导等专家定义要素
「订单延迟了怎么办?」 体验与完备:先安抚情绪 → 物流状态 → 预期时间 → 原因(若已知)→ 退款/投诉路径

这些可建模为:

  • Checklist 式 LLM 评委(输出 JSON:{"items":[{"name":"含报销链接","pass":true},...]});
  • 规则 + LLM 混合(硬规则校验链接域名,软规则用模型评语气与结构)。

注意:自定义指标越多,越要版本化 Prompt 与阈值,并与产品/运营对齐「什么叫通过」。


七、领域专家与 Ground Truth:自动化评测的上限

  • LLM-as-judge 提供的是可扩展的近似标尺,会带模型偏见与方差。
  • 领域专家提供:高价值 Ground Truth通过标准难例与反例——决定评测集是否代表真实业务。
  • 自动化的价值:把专家定义的标准规模化、可重复执行,让专家从重复打分中解放,聚焦难例分析与策略迭代。

没有专家参与的评测,容易变成「模型互相拍马屁」;有专家锚点,才能解释「为什么线上用户仍不满意」。


八、量化观看「评测质量」与系统质量(简要)

  • 系统侧:各指标 0~1 分数 的分布、分场景/分模型版本的趋势,可用 Micrometer → Prometheus → Grafana 展示。
  • 评测体系侧:用人工标注与裁判分数算相关性(如 Spearman),定期抽检 reason 字段,避免分数与直觉长期背离。

二者缺一不可:前者看产品迭代是否「变差了」,后者看「尺子是否还准」。


九、收束:Java 开发的一条务实路线

  1. 概念层:以 Ragas 指标为纲(第三节含公式与 Python 最小样例),TruLens 想追溯、DeepEval 想门禁。
  2. 实现层Spring AI / Spring AI Alibaba + ChatClient + JSON 契约,按指标拆评测 Prompt(Answer Correctness 可对齐 0.25·相似度 + 0.75·事实 F1 类 pipeline),异步跑、可配置模型。
  3. 业务层:在 Faithfulness / Relevance 之上加 Checklist 式业务评委
  4. 组织层:专家建集与定标,开发做流水线与观测。

这样你可以在不依赖 Python 主栈的前提下,建立与业界框架同构的 RAG 自动化评测能力,并与现有 Java 微服务自然融合。


©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容