- server 的 src/modules/*/__tests__ 挪到 test/<模块>/;e2e 去掉 eN- 前缀, w5a2 / v2 / search2 / *-dh1 / *-md1 / *-md2、web 的 agui3 / search2、domain 的 id2 / id3 改为按行为命名 - vitest 分三组:unit、pg(真实 PG + 假引擎,文件并行,最多 6 个)、serial(真实引擎 / worker / e2e,串行); pg 组用例超时放宽到 60s(迁移类用例并行时排队等 schema 锁)。server 测试 615s → 约 350s - CLAUDE.md 补测试约定;待办补 harness 去重与 continuous-series 偶发超时(疑似 Slot 评估竞争) - ADR-004 补充:维持 Deno,记录实际只用到 --allow-run 白名单 Co-Authored-By: Claude Opus 5.5 <[email protected]>
6.8 KiB
AG-5 智能体提示评测:前后对比
对照样本:docs/design/agent-report-sample-bad.md(用户 2026-09-30 贴的反例与期望样子)。实现与跑法见 docs/runbook/agent.md「提示分层与 Skill」。
- 前:main(
0023872)的packages/agent/src/system-prompt.ts,一段 15 条"必须遵守" + 6 条汇报格式 + 工作方式 + 约束里一行"可用能力:…"。 - 后:分层提示(角色与边界 / 当前环境 / 能力地图 / Skill / 行为规则 / 汇报格式 / 本次目标)+ 6 个 Skill + 新能力
download.list。
1. 反例的问题逐条对应
| 反例里的问题 | 前:提示里有什么 | 后:改了什么 |
|---|---|---|
| 不知道有下载器,汇报"系统里没有它们的登记对象" | 一条规则"下载器…用 downloader.list 查;站点列表里没有下载器不代表没配置",混在 15 条里 | 「当前环境」层直接写出"下载器 1 个:「家里的 qB」qBittorrent,正常(刚刚),本工具管理 3 个任务…""媒体服务器:还没有接入",并说明"还没有接入就是真的没有";能力地图第一条路线就是"问下载器、媒体服务器、站点是否正常:downloader.list → site.list → site.user_data → site.health_check(需要批准)";「巡检」Skill 第 1–2 步 |
| 要用户给下载任务 ID / 种子 hash | 没有能列下载任务的能力,只有 `download.inspect {id | hash}` |
原始字节数 upload 17008345370067 |
汇报格式没提单位 | 汇报格式"大小写成 GB / TB,时间写相对时间;不写原始字节数和 ISO 时间";download.list 输出直接给 "18.6 GB""63%""3 小时前";环境层也全是人话 |
| 表格列 ID / adapter | "不写函数名、工具名、字段名、参数、UUID 或 hash" | 加上 adapter、英文状态码;表格"只放名称和用户关心的 2–3 列" |
| "无证据不等于故障"式说教 | 无 | 行为规则"不说教",点名这句 |
| 授权缺失写成一段 | "工具返回 unauthorized 时如实报告缺少哪项授权" + 约束"被拒时说明缺少哪项授权"——等于鼓励展开 | "只写一句「没做:<动作>,需要你批准」,界面会给批准按钮;不解释授权机制";Skill 的「需要批准」节给出每个动作的一句话写法 |
| 结论"无法确认"、开头"检查结果",整体太长 | "第一句写结论";"不超过 10 行" | "第一句就是结论…不写「检查结果」「结论:」「以下是…」这类开头";≤8 行;异常放前、正常合并一句;每个 Skill 带期望汇报模板(巡检模板就是用户给的期望样子) |
2. 提示体积
同一套能力(不含浏览器 / 网页搜索 / 子会话)、三条提示,字符数:
| 提示 | 前 | 后 | 载入的 Skill |
|---|---|---|---|
| 检查站点、下载器和媒体服务器是否正常 | 2057 | 5516 | 巡检 |
| 把《沙丘 2》4K 收进来 | 2052 | 5336 | 收录一部作品 |
| 为什么沙丘2没入库 | 2048 | 5400 | 入库 / 整理问题排查 |
后者多约 3.4k 字符(中文约 2k token),主要是一个 Skill 全文(约 1.5–2k 字符)和环境层。每次只载入命中的 1–2 个 Skill,其余只列一行索引;前者约束里那行"可用能力:(30 多个能力名)"去掉了(工具定义里已有)。
3. fake 模型评测(e16,CI)
apps/server/test/e2e/agent-prompt-eval.test.ts,测试库数据仿反例现场:下载器「家里的 qB」(mock qB,3 个任务:下载中 / 文件缺失 / 已入库做种)、站点「憨憨」(上次检查正常,账号带原始用户数据)、没有媒体服务器、《沙丘2》(追更中订阅 + 1080p / 2160p 两个收录版本、一条 2160p 资源)、4 条已取消订阅、1 条待处理。
| # | 提示 | 载入的 Skill | 能力调用顺序 | 结果 |
|---|---|---|---|---|
| 1 | 检查站点、下载器和媒体服务器是否正常 | 巡检 | downloader.list → site.list → site.health_check(被拒)→ decision.list | 通过 |
| 2 | 把《沙丘 2》4K 收进来 | 收录一部作品 | catalog.lookup → inventory.query → download.list → release.search → download.plan → download.submit(被拒) | 通过 |
| 3 | 为什么沙丘2没入库 | 入库 / 整理问题排查 | inventory.query → download.list → download.inspect(ID 来自上一步) | 通过 |
| 4 | 订阅追更情况 | 订阅追更检查 | subscription.list | 通过 |
| 5 | 有没有失败的下载任务 | 下载排查 | download.list → download.inspect | 通过 |
| 6 | 空间不够了,看看能清理什么 | 数据清理与存储 | downloader.list → download.list | 通过 |
| 7 | 待处理里有什么要我处理的 | (不载入) | decision.list | 通过 |
| 8 | 站点憨憨的登录是不是掉了 | 巡检 | site.list | 通过 |
每条都断言:系统提示里有「当前环境」的下载器 / 媒体服务器 / 站点事实且不含地址;调用顺序;只读调用全部成功、需要批准的被拒绝;合格汇报(只用工具结果写)过 lintReport(无 UUID / hash / 原始字节 / ISO 时间 / 内部字段 / 能力名,≤8 行,开头不是套话)。反例原文过 lintReport 报 7 类问题(太长、原始字节、ISO 时间、内部字段、开头不是结论、向用户要 ID、说教),期望样子 0 个问题。
fake 模型只能证明"按提示的路线走得通、数据够写出合格汇报",不能证明真实模型会这么走,所以还要真实模型对比。
4. 真实模型对比(DeepSeek V4.1 Flash,OpenCode Go)
本次没有跑,真跑 0 次。 任务说明里的凭据文件 .local/admin-credentials 只有管理员、TMDB、Brave 搜索与 qB 的条目,没有 OpenCode Go 的 key;用户栈里配置的模型服务按约束不能碰。评测脚手架已就绪:
apps/server/test/e2e/agent-prompt-eval.real.test.ts:同一套测试库数据,"前"用 main 的buildSystemPrompt(git show main:packages/agent/src/system-prompt.ts)+ 旧约束 + 不含download.list的能力集,"后"用分层提示;缺省跑反例那条 + 收录 + 入库排查共 3 条 × 2 组 = 6 次会话(上限 12)。- 结果写 JSON:每次的能力调用序列(含是否成功)、汇报原文、
lintReport结果、行数、token / 费用。 - 跑法见 runbook;拿到 key 后执行一次,把结果按下表补进本节:
| 提示 | 组 | 调用序列 | 行数 | lintReport | 摘要 |
|---|---|---|---|---|---|
| 检查站点、下载器和媒体服务器是否正常 | 前 | 待跑 | |||
| 同上 | 后 | 待跑 | |||
| 把《沙丘 2》4K 收进来 | 前 | 待跑 | |||
| 同上 | 后 | 待跑 | |||
| 为什么沙丘2没入库 | 前 | 待跑 | |||
| 同上 | 后 | 待跑 |
看点:前组是否复现"没有下载器 / 要用户给 ID / 原始字节 / 长段授权说明";后组第一句是否是结论、是否 ≤8 行、是否先 downloader.list、下载任务 ID 是否来自 download.list、被拒是否只写一句。