面向 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 等集成多,可视化追溯强;适合「我要看懂这一次为什么差」而不仅是「平均分多少」。

访问 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 等)。这类工具的优势是「构建流程与评估流程可以无缝衔接」;但在真实业务里,很多关键质量要求并不完全等价于通用指标,因此常常需要一层自定义评测框架。
换句话说:通用指标告诉你「有没有偏题、有没有幻觉」,但业务方更关心的是「这条答案能不能真正解决问题、是否符合流程与政策」。
下面是两个典型场景:
-
案例一:报销流程问答
用户问「报销流程是什么?」时,业务侧可能要求优质答案必须包含:- 报销入口/报销单链接;
- 二级主管审批信息;
- 引导到费用系统提交申请。
这类要求本质上属于流程合规 + 可操作性,不是仅靠 Relevance 就能覆盖。
-
案例二:订单延迟问答
用户问「订单延迟了怎么办?」时,好的答案不应只有「请耐心等待」,而应包含:- 情绪安抚;
- 当前物流状态;
- 预计送达时间;
- 延误原因(若已知);
- 后续处理路径(退款/投诉等)。
这体现的是情绪安抚度 + 问题解决完备性。
因此在工程上,你可以在通用指标之外,增加一组业务自定义维度:
- 流程可操作性
- 政策合规性
- 情绪安抚度
- 问题解决完备性
这些维度可以通过「规则校验 + LLM 评委」混合实现:能硬规则判断的(如是否包含指定链接)尽量规则化,主观维度再用 LLM 评分并保留 reason 字段,便于复盘。
实践建议:把自定义指标做成可配置模板(版本号、阈值、适用场景),并纳入你的评测流水线,而不是散落在临时 Prompt 中。
三、深入 Ragas:Answer Correctness 与检索指标(实操与计算过程)
Ragas 在 Python 项目中往往只需几行即可做一次全链路或分项评测。下面把你课程中的 Answer Correctness、context_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 裁判,再合成一个标量:
-
语义相似度
- 将
answer与ground_truth向量化,常用 余弦相似度(Ragas 默认实践之一)。 - 反映「字面/语义有多像」,但单靠向量难以区分「部分一致 + 局部事实错误」。
- 将
-
事实准确度(Factual agreement)
- Ragas 用 LLM 把
answer与ground_truth各拆成若干原子观点(statements),再比较两边是否互相支撑,归纳出 TP / FP / FN(判断过程也由大模型完成)。
- Ragas 用 LLM 把
下图可以帮助你理解 Ragas 衡量事实准确度的方法:

直观例子(与你的教材一致):
| 文本 | LLM 拆出的观点列表示意 |
|---|---|
answer:张伟是教研部负责大模型课程的同事。
|
「张伟是教研部的」「张伟负责大模型课程」 |
ground_truth:张伟是教研部负责大数据方向的同事。
|
「张伟是教研部的」「张伟负责大数据方向」 |
对齐规则简述:
- 对 answer 生成的每个观点:若能在 ground_truth 侧找到依据 → TP;否则 → FP(可理解为「多出或无法证实」的主张)。
- 对 ground_truth 生成的每个观点:若 answer 侧没有依据 → FN(可理解为「该提的未覆盖」)。
事实分用的 Fβ 家族形式(课件中的 F1 变体写法):

下图对应「如何从 answer / ground_truth 生成观点并入 TP / FP / FN」的流程(与原课图一致):
分数汇总(课件常用权重):

这样既惩罚「话术像但胡说」,也兼顾「事实对但措辞差」的中间态。
3.2 评估检索召回效果:context_precision 与 context_recall
两者侧重不同,可以同时使用:
- Context precision:contexts 里相关片段是否靠前、信噪比如何;侧重相关性。
- Context recall:ground_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 的计算过程(概念)
- LLM 将 ground_truth 拆成 (n) 条原子观点(statements)。
- 由大模型判断每个观点能在检索到的参考资料(contexts)中找到依据,或者说 context 是否能支撑 ground_truth 的观点。
-
被支撑观点数 / 总观点数 =
context_recall。 然后 ground_truth 观点列表中,能在 contexts 中找到依据的观点占比,作为 context_recall 分数。
例:ground_truth → ["张伟是教研部的"],contexts 中有「张伟 教研部工程师…」可支撑 → 若仅此一条观点,则 recall = (1/1 = 1)。
3.2.3 Context Precision 的计算过程(概念,与排序有关)
简述课件版算法(细则以 Ragas 源码为准):
- 按 contexts 的顺序逐个处理 (\text{context}_i):结合 question + ground_truth,由 LLM 判断该片段是否「相关」(相关记 1,否则 0)。
- 对每个位置 (i),构造一个类似 前缀精度:分子为「前 (i) 个里相关个数之和」,分母为 (i)(位置权重体现是否把相关条目排在前面)。
- 再对各项指标按 Ragas 定义做归一(如除以相关 context 个数等),得到标量
context_precision。
直觉:相关片段越早出现、越少噪声,分越高。若你愿意啃实现,直接去读 Ragas 对应 metric 的实现即可。
3.3 其他推荐了解的指标
Ragas 还内置了 Faithfulness、Answer Relevancy、Answer Similarity 等大量指标;本文只展开了与课程衔接最紧的 Answer Correctness、context_recall、context_precision。其余指标的适用场景、输入字段与计算原理,建议直接查阅官方指标索引(随版本更新):
Ragas — Available metrics(官方文档)
阅读时建议对照三件事:需要哪些列(question / contexts / answer / ground_truth)、更偏检索还是更偏生成、是否必须 Ground Truth。
3.4 如何根据 Ragas 指标进行优化
做评测的终点不是「刷出一个分数」,而是用分数定位瓶颈、决定下一轮改检索、改知识库还是改 Prompt / 模型。你已掌握 answer_correctness、context_recall、context_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 Recall 与 Context Precision 正是在衡量「召回到的上下文是否覆盖该有的事实、是否信噪比高、排序是否合理」——你可以用这两条曲线的升降来验证「召回侧优化是否真的有效」,而不是只看生成模型换没换。
3.4.2 context recall 偏低时,优先从哪改?
context_recall 衡量的是 RAG 检索阶段:ground_truth 中的观点有多大比例能被当前 contexts 支撑。该指标长期偏低时,说明「该进上下文的没进来」,优化要从数据与检索链路下手,而不是先怀疑生成模型「不够聪明」。
第一步:确认知识库以及实现方面的定位优化:
知识库是 RAG 应用的源头。 若库内内容不完备,召回的参考信息必然不充分,context_recall 会被直接拉低。建议将知识库内容与测试样本做系统对比:对每一条用例,判断「库中是否存在能支撑标准答案的表述」(可人工表格式检查,也可借助大模型做辅助对账,重要结论仍建议人工抽检)。若多例表现为缺知识、缺版本、缺同义说法,应优先增补文档、结构化字段、FAQ、术语表,而不是先加大 topK 或盲目换 embedding。
在确认「知识在库」之后,再进入下列排查(可与 Bad case、检索日志联动):
检查知识库与内容治理(源头)
除「有没有」之外,还要看是否过时、是否冲突、权限与可见范围是否导致线上检索域里根本搜不到该条。再查切分与索引
已有文档但 recall 仍低:看 chunk 是否切太碎/太粗、标题与正文是否分离、元数据(部门、产品、时间)是否进不了检索条件;必要时调整 chunk 策略、层级摘要、父子块 等。最后调检索策略
库里有但召不回:再调 embedding 模型、混合检索(关键词 + 向量)、重排(rerank)、查询改写、HyDE 等,或者最终策略还是切换更强大的embedding模型。
第二部分:也可以尝试对用户的query改写
作为开发者,对用户的提问方式做过多要求是不现实的,因此你可能会得到这样缺少信息的问题:“教研部”、“请假”、“项目管理”。如果直接将这样的问题输入RAG应用中,大概率无法召回有效的文本段。你可以通过对员工常见问题的梳理来设计一个prompt模板,使用大模型来改写query,提升召回的准确率。

简记:recall 低 → 先问「知识在不在库里」再问「搜不搜得到」。
3.4.3 context precision 偏低时,优先从哪改?
context_precision 与 context_recall 一样都在评估检索阶段,但它更关注「相关片段是否排在前面、噪声是否被压下去」。
当 context_precision 低时,可先复用 context_recall 的排查步骤(知识库、切分、检索策略),再额外重点做两件事:
- 加入重排序(rerank)
在向量检索召回topK后,用 cross-encoder / rerank 模型按「问题-片段相关性」重排,把更相关的文本段前置。
- 控制上下文噪声
通过更严格的 metadata 过滤、召回阈值、场景路由、去重与相似片段合并,减少“看起来像相关、实则无关”的上下文进入生成阶段。
经验上,context_precision 的改善往往直接提升回答稳定性,尤其在长上下文场景中能显著缓解「Lost in the Middle」。
3.4.4 answer correctness 偏低时,怎么定位生成侧问题?
answer_correctness 是一个综合指标。若它偏低,但 context_recall 与 context_precision 都较高,通常说明检索阶段没太大问题,瓶颈在生成阶段。
可按下面顺序优化:
- 优化 Prompt 契约:明确“只依据上下文回答、禁止编造、引用关键依据、信息不足要显式说明”。
-
调整生成参数:适当降低
temperature、收紧top_p,减少发散与臆测。 - 升级模型能力:切换更强模型(必要时分场景路由)。
- 考虑微调或偏好对齐:在高价值场景用业务数据做监督微调/偏好优化。
一句话定位:前两项(recall/precision)高而 correctness 低 = 重点改生成;前两项低 = 先回到检索与知识库。
五、打造卓越的评测运营体系
自动化评测确实能提升执行效率,但更大的挑战来自:高质量评测样本构建与领域知识持续沉淀。因此,除了技术实现,还需要结合业务特征建立一套评测运营体系。
5.1 构建高质量评测集
自动化评测的有效性,本质上取决于评测集质量。一个好的评测集应反映真实业务需求,而不是技术侧的想象问题。
评测集中的问题(question)从哪里来?
- 用户问题抽样:从线上真实问答中按频率、类型分层抽样;
- 用户工单/反馈:工单、投诉、客服反馈通常最能反映真实痛点;
- 业务场景覆盖:既覆盖高频主路径,也覆盖边界和异常场景。
标准答案(Ground Truth)从哪里来?
评测集中的标准答案必须由业务领域专家提供与审定:
- 为什么是业务专家:只有业务专家能判断“什么答案是对的、好的、合规的”;
- 技术人员的局限:技术侧能判断“是否检索到相关内容”,但不一定能判断“业务上是否正确、完整、可执行”;
- 关键认知:正因为“问题来自真实用户 + 答案来自业务专家”,自动化评测结果才真正能映射业务效果。
5.2 评测先行的优化策略
在大模型应用开发中,评测应走在优化前面,而不是“先优化,再看效果”。
下图展示了一个评测先行的闭环流程(目标→评测集→自动化评测→优化→验证→上线→持续迭代):

为什么要“评测先行”?
- 避免盲目优化:没有评测基线,很难判断优化是否有效;
- 量化改进效果:从“感觉变好了”变成“指标提升了 15%”;
- 防止跷跷板效应:局部优化可能拖累全局,评测可及时发现副作用。
5.3 业务指标与评测指标对齐
Ragas 的 context_recall、context_precision、answer_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 问答链路对齐):
- 在回答生成完成后(非流式
chat()返回前,或流式done回调中)异步调用evaluate(...); - 持久化
traceId / scenario / question / score / reason / raw; - 用 Micrometer 上报
faithfulness_score(分布)与evaluation_error_count(计数)。
Answer Relevance 则主要使用 {question} + {answer};Context Precision / Recall 往往需要参考答案或人工标注的「应出现片段」,实现上比纯 Faithfulness 更重。
实现要点:
- 评测模型可与业务对话模型分离(更小、更便宜的通用模型),控制成本与延迟。
- 异步执行:用户先拿到回答,评测在后台跑,结果进日志 / DB / Micrometer(见第八节)。
- Context 截断:拼接检索片段时设 最大字符数,避免评测 Prompt 比生成还贵。
-
解析失败要有降级:JSON 解析失败记
evaluation_error,勿拖垮主链路。
5.3 与「TruLens 式追溯」在 Java 里的轻量对标
不必一次上一套完整 TruLens,可先做最小可追溯结构:
-
traceId、question、retrievedDocIds、拼接后的context摘要、answer、model、latency; - 评测结果:
faithfulness_score、relevancy_score、raw_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 开发的一条务实路线
- 概念层:以 Ragas 指标为纲(第三节含公式与 Python 最小样例),TruLens 想追溯、DeepEval 想门禁。
-
实现层:Spring AI / Spring AI Alibaba + ChatClient + JSON 契约,按指标拆评测 Prompt(Answer Correctness 可对齐
0.25·相似度 + 0.75·事实 F1类 pipeline),异步跑、可配置模型。 - 业务层:在 Faithfulness / Relevance 之上加 Checklist 式业务评委。
- 组织层:专家建集与定标,开发做流水线与观测。
这样你可以在不依赖 Python 主栈的前提下,建立与业界框架同构的 RAG 自动化评测能力,并与现有 Java 微服务自然融合。