摘要很多 AI 应用刚开始效果不错真正接入业务后却反复出现“昨天能答今天答错”“换个模型全线漂移”“Prompt 改了一行没人知道影响多大”。本文从 Java 后端视角讲一套最小可用的 AI 评测体系样本怎么建、指标怎么定、Spring Boot 怎么跑、结果怎么落库、上线前怎么卡口。目录为什么 AI 应用一定要做评测一套最小可用评测体系长什么样测试集不要一上来追求大而全指标准确率之外还要看什么Java 侧如何组织评测代码RAG 和 Agent 场景怎么评上线前的评测卡口总结1. 为什么不是继续调 Prompt我一开始接触大模型应用时也容易把问题归因到 Prompt回答不稳定改 Prompt格式不对改 Prompt知识库召回差还是改 Prompt。后来发现这种方式最大的问题不是“没用”而是不可复现。比如下面这些问题靠感觉很难回答问题没有评测时的状态有评测后的状态Prompt 改了有没有变好看几条样例凭印象跑固定样本看指标变化模型升级能不能上线手动试几个问题同一批样本对比新旧模型RAG 召回是不是拖后腿只看最终回答拆开看召回、引用、答案线上投诉能不能复盘翻日志找 prompt用 trace 重放当时请求大模型应用和传统 CRUD 最大的不同是传统代码的输出大多是确定的而大模型输出天然有随机性。既然输出不稳定就更需要一个稳定的尺子。2. 最小可用评测体系先别把评测平台想复杂。真正落地时第一版只需要四个东西固定测试集统一调用入口自动评分器评测报告是否允许上线对应到工程里可以拆成模块作用第一版建议eval_cases存问题、标准答案、标签JSON/YAML 文件即可model_runner调用当前模型或 RAG 服务复用线上 servicescorer评分规则评分 少量人工复核report输出报告Markdown/CSV 都行这里的关键不是平台多漂亮而是每次变更都用同一批样本跑一遍。只要样本固定模型、Prompt、召回策略、参数变更就都有了可对比基础。3. 测试集怎么建测试集不要从“我要收集一万条问题”开始。个人项目或团队内部工具先做 50-100 条高质量样本更现实。我一般按这几类建类型示例目的高频问题用户每天都问的配置、流程、报错保证基础体验边界问题文档里没有、信息不足、时间冲突看模型会不会瞎编反问场景缺少设备编号、缺少日志看是否能要求补充信息权限场景查询别人项目、导出敏感数据看是否越权格式场景必须输出 JSON、表格、工单字段看结构化稳定性一个样本不需要很复杂可以这样写{id:rag_001,tags:[rag,high_frequency],question:知识库里有多份版本文档时系统应该优先参考哪一份,expected_keywords:[最新版本,生效时间,版本号],must_not_include:[随便,无法判断但强行回答],expected_behavior:应该说明按版本号或发布时间优先并在冲突时提示人工确认}如果你做的是故障诊断类 AI还可以按业务标签补一层标签说明telemetry遥测数据解释alarm告警含义判断diagnosis故障原因分析operation操作建议safety高风险动作和人工确认样本的核心不是“像考试题”而是覆盖真实业务里最容易出错的地方。4. 指标怎么定AI 评测最容易误入一个坑只看最终答案对不对。但在 RAG、Agent、工具调用场景里错可能发生在多个环节。用户问题召回文档组装 Prompt模型生成格式校验最终答案建议至少拆成 5 个指标指标看什么评分方式answer_score最终回答是否解决问题0/1 或 1-5 分citation_score是否引用正确资料命中文档 IDformat_score是否满足 JSON/表格/字段要求Schema 校验safety_score是否拒绝危险操作规则判断latency_ms是否慢到不可用统计耗时第一版评分器不用上来就搞“模型评模型”。能规则判断的先规则判断。比如 JSON 格式、必须包含字段、禁止出现敏感词这些都应该用代码判断。5. Java 里怎么跑可以建一个简单的评测 runner核心逻辑只有三步读样本、调用服务、打分。publicrecordEvalCase(Stringid,ListStringtags,Stringquestion,ListStringexpectedKeywords,ListStringmustNotInclude,StringexpectedBehavior){}publicrecordEvalResult(Stringid,booleanpassed,intkeywordHits,longlatencyMs,Stringanswer){}评分逻辑先写朴素版本publicEvalResultrunCase(EvalCaseevalCase){longstartSystem.currentTimeMillis();StringansweraiService.ask(evalCase.question());longlatencySystem.currentTimeMillis()-start;inthits0;for(Stringkeyword:evalCase.expectedKeywords()){if(answer.contains(keyword)){hits;}}booleanhasForbiddenevalCase.mustNotInclude().stream().anyMatch(answer::contains);booleanpassedhitsMath.max(1,evalCase.expectedKeywords().size()/2)!hasForbiddenlatency10_000;returnnewEvalResult(evalCase.id(),passed,hits,latency,answer);}这段代码很简单但已经能解决一个大问题当你改 Prompt、换模型、调整知识库切分方式时能立刻知道有没有伤到已有能力。6. 报告怎么输出报告不要只输出一堆日志。最好能一眼看出结论## 本次评测结果 - 总样本数80 - 通过68 - 失败12 - 通过率85% - 平均耗时1860ms - P95 耗时4200ms ## 失败样本 TOP | ID | 标签 | 原因 | |---|---|---| | rag_017 | rag | 未引用最新版本文档 | | json_004 | format | JSON 字段缺失 | | safety_002 | safety | 未提示人工确认 |真正有价值的是失败样本。成功样本只说明“当前没坏”失败样本才告诉你下一轮改哪里。7. RAG 场景要单独评召回如果最终答案错了不一定是模型的问题。很多时候是召回阶段已经把错误文档塞给了模型。RAG 评测建议额外记录字段说明expected_doc_ids这道题应该命中的文档retrieved_doc_ids实际召回文档top_k召回数量rerank_score重排后的分数answer_citations答案实际引用的资料只要把召回记录下来问题会清楚很多召回没命中先调切分、Embedding、过滤条件召回命中了但排序靠后看 rerank召回正确但答案错再看 Prompt 或模型答案正确但没引用补引用约束和输出格式这比“模型不行”四个字有用得多。8. Agent 场景要评工具调用Agent 不是只看最后一句话。它中间会计划、调用工具、读返回、继续决策所以评测对象也要变成轨迹。阶段应该检查什么plan是否拆出合理步骤tool_call是否调用正确工具args参数是否完整、是否越权observation是否正确理解工具返回final是否给出可执行结论比如一个“生成故障工单处理建议”的 Agent不能只评最终建议还要看它有没有查设备、有没有查历史告警、有没有在高风险操作前要求人工确认。9. 上线卡口我建议把评测接到 CI 或发布脚本里但第一版不用太重。可以先约定变更类型是否必须跑评测改 Prompt必须换模型必须改知识库切分必须改召回 topK必须改 UI 文案可选上线门槛也别一开始定得太复杂核心样本通过率 95% 全量样本通过率 85% 安全样本必须 100% 通过 P95 延迟不能超过线上阈值 失败样本必须有人确认安全类样本不能用平均分掩盖。只要涉及权限、删除、导出、执行命令、生产操作就应该一票否决。10. 写给 Java 程序员的落地建议如果你现在正在做 AI 应用我建议按这个顺序来先从线上真实问题里整理 30 条样本。给每条样本打标签不要混在一起。写一个最简单的 Java runner能批量调用当前服务。先用关键词、禁用词、JSON Schema 做规则评分。每次改 Prompt 或模型前后都跑一次。把失败样本沉淀回测试集。这套东西不花哨但它会让 AI 应用从“玄学调参”变成“工程迭代”。总结Prompt 很重要但只调 Prompt 不够。AI 应用真正进入业务后评测体系才是底座。它不需要一开始就很大也不需要第一天就做成平台。固定测试集、统一调用入口、规则评分、评测报告这四件事先跑起来就已经能挡住很多线上问题。对 Java 后端来说最现实的做法不是追最新框架而是把大模型调用纳入熟悉的软件工程流程有样本、有指标、有回归、有上线门禁。这样你才能知道每一次改动到底让系统变好了还是只是看起来更会说话了。
别再只会调 Prompt:Java 程序员如何给 AI 应用加一套可复现评测体系
摘要很多 AI 应用刚开始效果不错真正接入业务后却反复出现“昨天能答今天答错”“换个模型全线漂移”“Prompt 改了一行没人知道影响多大”。本文从 Java 后端视角讲一套最小可用的 AI 评测体系样本怎么建、指标怎么定、Spring Boot 怎么跑、结果怎么落库、上线前怎么卡口。目录为什么 AI 应用一定要做评测一套最小可用评测体系长什么样测试集不要一上来追求大而全指标准确率之外还要看什么Java 侧如何组织评测代码RAG 和 Agent 场景怎么评上线前的评测卡口总结1. 为什么不是继续调 Prompt我一开始接触大模型应用时也容易把问题归因到 Prompt回答不稳定改 Prompt格式不对改 Prompt知识库召回差还是改 Prompt。后来发现这种方式最大的问题不是“没用”而是不可复现。比如下面这些问题靠感觉很难回答问题没有评测时的状态有评测后的状态Prompt 改了有没有变好看几条样例凭印象跑固定样本看指标变化模型升级能不能上线手动试几个问题同一批样本对比新旧模型RAG 召回是不是拖后腿只看最终回答拆开看召回、引用、答案线上投诉能不能复盘翻日志找 prompt用 trace 重放当时请求大模型应用和传统 CRUD 最大的不同是传统代码的输出大多是确定的而大模型输出天然有随机性。既然输出不稳定就更需要一个稳定的尺子。2. 最小可用评测体系先别把评测平台想复杂。真正落地时第一版只需要四个东西固定测试集统一调用入口自动评分器评测报告是否允许上线对应到工程里可以拆成模块作用第一版建议eval_cases存问题、标准答案、标签JSON/YAML 文件即可model_runner调用当前模型或 RAG 服务复用线上 servicescorer评分规则评分 少量人工复核report输出报告Markdown/CSV 都行这里的关键不是平台多漂亮而是每次变更都用同一批样本跑一遍。只要样本固定模型、Prompt、召回策略、参数变更就都有了可对比基础。3. 测试集怎么建测试集不要从“我要收集一万条问题”开始。个人项目或团队内部工具先做 50-100 条高质量样本更现实。我一般按这几类建类型示例目的高频问题用户每天都问的配置、流程、报错保证基础体验边界问题文档里没有、信息不足、时间冲突看模型会不会瞎编反问场景缺少设备编号、缺少日志看是否能要求补充信息权限场景查询别人项目、导出敏感数据看是否越权格式场景必须输出 JSON、表格、工单字段看结构化稳定性一个样本不需要很复杂可以这样写{id:rag_001,tags:[rag,high_frequency],question:知识库里有多份版本文档时系统应该优先参考哪一份,expected_keywords:[最新版本,生效时间,版本号],must_not_include:[随便,无法判断但强行回答],expected_behavior:应该说明按版本号或发布时间优先并在冲突时提示人工确认}如果你做的是故障诊断类 AI还可以按业务标签补一层标签说明telemetry遥测数据解释alarm告警含义判断diagnosis故障原因分析operation操作建议safety高风险动作和人工确认样本的核心不是“像考试题”而是覆盖真实业务里最容易出错的地方。4. 指标怎么定AI 评测最容易误入一个坑只看最终答案对不对。但在 RAG、Agent、工具调用场景里错可能发生在多个环节。用户问题召回文档组装 Prompt模型生成格式校验最终答案建议至少拆成 5 个指标指标看什么评分方式answer_score最终回答是否解决问题0/1 或 1-5 分citation_score是否引用正确资料命中文档 IDformat_score是否满足 JSON/表格/字段要求Schema 校验safety_score是否拒绝危险操作规则判断latency_ms是否慢到不可用统计耗时第一版评分器不用上来就搞“模型评模型”。能规则判断的先规则判断。比如 JSON 格式、必须包含字段、禁止出现敏感词这些都应该用代码判断。5. Java 里怎么跑可以建一个简单的评测 runner核心逻辑只有三步读样本、调用服务、打分。publicrecordEvalCase(Stringid,ListStringtags,Stringquestion,ListStringexpectedKeywords,ListStringmustNotInclude,StringexpectedBehavior){}publicrecordEvalResult(Stringid,booleanpassed,intkeywordHits,longlatencyMs,Stringanswer){}评分逻辑先写朴素版本publicEvalResultrunCase(EvalCaseevalCase){longstartSystem.currentTimeMillis();StringansweraiService.ask(evalCase.question());longlatencySystem.currentTimeMillis()-start;inthits0;for(Stringkeyword:evalCase.expectedKeywords()){if(answer.contains(keyword)){hits;}}booleanhasForbiddenevalCase.mustNotInclude().stream().anyMatch(answer::contains);booleanpassedhitsMath.max(1,evalCase.expectedKeywords().size()/2)!hasForbiddenlatency10_000;returnnewEvalResult(evalCase.id(),passed,hits,latency,answer);}这段代码很简单但已经能解决一个大问题当你改 Prompt、换模型、调整知识库切分方式时能立刻知道有没有伤到已有能力。6. 报告怎么输出报告不要只输出一堆日志。最好能一眼看出结论## 本次评测结果 - 总样本数80 - 通过68 - 失败12 - 通过率85% - 平均耗时1860ms - P95 耗时4200ms ## 失败样本 TOP | ID | 标签 | 原因 | |---|---|---| | rag_017 | rag | 未引用最新版本文档 | | json_004 | format | JSON 字段缺失 | | safety_002 | safety | 未提示人工确认 |真正有价值的是失败样本。成功样本只说明“当前没坏”失败样本才告诉你下一轮改哪里。7. RAG 场景要单独评召回如果最终答案错了不一定是模型的问题。很多时候是召回阶段已经把错误文档塞给了模型。RAG 评测建议额外记录字段说明expected_doc_ids这道题应该命中的文档retrieved_doc_ids实际召回文档top_k召回数量rerank_score重排后的分数answer_citations答案实际引用的资料只要把召回记录下来问题会清楚很多召回没命中先调切分、Embedding、过滤条件召回命中了但排序靠后看 rerank召回正确但答案错再看 Prompt 或模型答案正确但没引用补引用约束和输出格式这比“模型不行”四个字有用得多。8. Agent 场景要评工具调用Agent 不是只看最后一句话。它中间会计划、调用工具、读返回、继续决策所以评测对象也要变成轨迹。阶段应该检查什么plan是否拆出合理步骤tool_call是否调用正确工具args参数是否完整、是否越权observation是否正确理解工具返回final是否给出可执行结论比如一个“生成故障工单处理建议”的 Agent不能只评最终建议还要看它有没有查设备、有没有查历史告警、有没有在高风险操作前要求人工确认。9. 上线卡口我建议把评测接到 CI 或发布脚本里但第一版不用太重。可以先约定变更类型是否必须跑评测改 Prompt必须换模型必须改知识库切分必须改召回 topK必须改 UI 文案可选上线门槛也别一开始定得太复杂核心样本通过率 95% 全量样本通过率 85% 安全样本必须 100% 通过 P95 延迟不能超过线上阈值 失败样本必须有人确认安全类样本不能用平均分掩盖。只要涉及权限、删除、导出、执行命令、生产操作就应该一票否决。10. 写给 Java 程序员的落地建议如果你现在正在做 AI 应用我建议按这个顺序来先从线上真实问题里整理 30 条样本。给每条样本打标签不要混在一起。写一个最简单的 Java runner能批量调用当前服务。先用关键词、禁用词、JSON Schema 做规则评分。每次改 Prompt 或模型前后都跑一次。把失败样本沉淀回测试集。这套东西不花哨但它会让 AI 应用从“玄学调参”变成“工程迭代”。总结Prompt 很重要但只调 Prompt 不够。AI 应用真正进入业务后评测体系才是底座。它不需要一开始就很大也不需要第一天就做成平台。固定测试集、统一调用入口、规则评分、评测报告这四件事先跑起来就已经能挡住很多线上问题。对 Java 后端来说最现实的做法不是追最新框架而是把大模型调用纳入熟悉的软件工程流程有样本、有指标、有回归、有上线门禁。这样你才能知道每一次改动到底让系统变好了还是只是看起来更会说话了。