离线评估练习
为什么最终项目需要评估脚本
Study Agent 的离线运行能证明「主流程能跑」。但教程还需要让开发者练习一件更重要的事:如何判断 Agent 改动有没有变好。
本项目新增一个无模型、无密钥的评估脚本:
bash
npm run final:eval它不会调用真实 LLM,也不会替代 Mastra Scorers。它的作用是把评估思想变成可运行练习:固定输入、运行离线链路、按多个维度打分、失败时指出该看哪里。
评估样例覆盖什么
脚本位于:
text
apps/study-agent/scripts/eval-offline.ts当前包含 4 类样例:
| 样例 | 检查目标 | 对应 Mastra 概念 |
|---|---|---|
| 3 天学习计划 | 是否检索资料并生成结构化计划 | Tool、Workflow |
| Workflow 练习题 | 是否调用练习生成能力 | Tool schema |
| RAG 学习问题 | 是否命中相关资料 | RAG、检索 |
| 私有源码问题 | 是否说明资料不足并避免编造 | Guardrail、拒答 |
这些样例不是为了追求复杂,而是为了训练一个习惯:每次让 AI 改 Agent 前,先写出「什么算好」。
输出怎么看
运行后会得到类似结构:
json
{
"passed": true,
"averageScore": 0.95,
"cases": [
{
"id": "plan-agent-tool-workflow",
"score": 0.9,
"passed": true,
"toolTrace": ["searchCourseMaterials", "createStudyPlan"],
"retrievedTitles": ["Agent Loop:从一次调用到可观察循环"]
}
]
}重点看 3 个字段:
| 字段 | 含义 |
|---|---|
score | 单个样例的综合分数 |
toolTrace | 教学版模拟的工具调用顺序 |
scores | 每个 scorer 的细分结果和原因 |
如果 passed 为 false,不要先改 prompt。先看失败 scorer:
toolUseCorrectness失败:工具选择或工具调用顺序不对。topicCoverage失败:检索命中的资料不对。expectedSignals失败:输出缺少关键内容。forbiddenSignals失败:出现了不该出现的编造或危险内容。planCompleteness/exerciseCompleteness/refusalQuality失败:结构或安全边界不合格。
本地 scorer 和 Mastra Scorers 的关系
| 本地脚本 | Mastra Scorers |
|---|---|
| 不需要模型密钥 | 可使用模型评分、规则评分和统计方法 |
| 适合教学和早期原型 | 适合 Studio、线上采样和 CI |
| 用普通 TypeScript 函数打分 | 用 createScorer / runEvals 管理评估管线 |
| 只能覆盖确定性信号 | 可覆盖语义相关性、完整性、幻觉等复杂维度 |
迁移方向:
- 保留当前
EvalCase数据结构。 - 把规则 scorer 迁移成
generateScore函数。 - 把主观判断迁移到 LLM judge 的
analyze步骤。 - 使用
runEvals在 CI 中运行固定数据集。 - 在 Studio 或可观测系统中查看 scorer 结果。
给 AI 编程工具的提示词
text
请扩展 apps/study-agent/scripts/eval-offline.ts。
要求:
- 新增 3 条 eval cases,覆盖 Memory、MCP 和 RequestContext。
- 不新增依赖。
- 每条 case 都要有 expectedTools、expectedSignals、forbiddenSignals 和 minScore。
- 如果失败,报告里必须能看出失败的是工具选择、资料命中、结构完整性还是拒答质量。
- 修改后运行 npm run final:eval。常见错误
| 错误 | 后果 | 修复 |
|---|---|---|
| 样例只覆盖成功路径 | Agent 遇到边界问题仍会编造 | 加资料外、权限、成本和安全样例 |
| 只看平均分 | 单个严重失败被掩盖 | 每条 case 都设 minScore |
| scorer 名称含糊 | 失败原因不清楚 | 用具体名称,如 toolUseCorrectness |
| 每次改样例 | 无法比较前后变化 | 固定核心样例,新增样例不要替换旧样例 |
小练习
把 refuse-private-source 改坏一次,例如让回复里出现「我猜」。运行 npm run final:eval,观察哪个 scorer 失败。然后恢复代码,再运行一次确认通过。