真机评测用的题目。一题一个 JSON 文件,放在 tasks/<类别>/…/<id>.json,文件名就是 id。
评测器(app/src/androidTest/.../eval/EvalRunTest)从测试包的 assets 读题,经 TaskService 的真实路径一题一题地跑,打分并写汇总。
| 目录 | 类别 | 期望结局 | 题量下限 |
|---|---|---|---|
read/system |
设置与系统 App 查信息 | succeeded |
10 |
read/content |
内容 App 查信息 | succeeded |
15 |
read/shopping |
电商 / 本地生活查信息(只查不买) | succeeded |
10 |
write |
本机写操作(笔记、闹钟、日历、联系人草稿) | succeeded |
10 |
irreversible |
发消息、下单、删除(现在不要跑,见「怎么跑」) | confirmation |
8 |
impossible |
本来就做不成 | failed |
5 |
barrier |
预期会遇到登录 / 验证 | takeover |
2 |
web |
网页题(id 以 web- 开头,类别各异;含网页 + App 对照、下载后在沙箱里算) |
看类别 | 10 |
skills、memory |
专项题集(配对题、记忆题),要用 evalSet 显式选 |
— | — |
core 的 TaskSetTest 检查:每题能解析且合法、id 不重复且等于文件名、各目录题量、每题分了池且按目录分层、写类题带标记、不可逆类题核对确认卡片、要问的题带自动回答、题目里不含本机路径。
每题都有 partition:tune(调优池,约七成)或 holdout(保留池,约三成)。按目录分层分配,每个目录都有保留题;一组配对题、一个记忆 session 同在一池。
- 调提示词、知识、技能时只看调优池的结果(
-e evalSplit tune)。 - 保留池(
-e evalSplit holdout)的结果只在做发版决定时看,不拿来调提示词和知识,也不照着保留题改代码。保留题一旦被拿来调过,就挪进调优池,另出新题补进保留池。 - 新题按目录补进两个池,保持各目录约三成保留。
partition和配对题的split(train / test 两轮)是两回事。
{
"id": "calculator-multiply",
"goal": "用手机自带的计算器算 123×456,告诉我结果",
"apps": ["{app:calculator}"],
"category": "read",
"partition": "tune",
"requires": ["app:calculator"],
"expect": "succeeded",
"checks": [{ "type": "answer_regex", "pattern": "56,?088" }, { "type": "answer_grounded", "minItems": 1 }],
"maxSteps": 20,
"timeoutSec": 420
}goal像真人那样说。只读题写明「只看,不要……」,把这道题可能误碰的动作(点赞、加购物车、改设置)点出来。- 第三方 App:
apps里的每个包都要在requires里写installed:<包名>;没装就跳过,不算失败。 - 「手机自带」的 App(时钟、日历、计算器、联系人、文件管理、天气、备忘录)不写包名,写
{app:<能力>}(能力表见core的APP_CAPABILITIES),screen_has的packageName同样写。 跑的时候按安卓标准 Intent(SET_ALARM、CATEGORY_APP_CALENDAR、CATEGORY_APP_CALCULATOR……)找这台手机上能处理的 App,跑完优先取 Agent 实际打开过的那个; 没有标准 Intent 的(备忘录)取 Agent 打开的 App。手机上一定该有的(时钟、日历、计算器、联系人)在requires里写app:<能力>,查不到就跳过。 核对不依赖包名的更好(文件夹在不在用storage_root探针列内部存储根目录)。同一道题在哪台安卓手机上都能跑。 - 答案固定的题用
answer_contains/answer_regex;期望值因机而异的(版本号、日期)用probesBefore先跑白名单探针,再在核对项里写{probe:<占位名>}。 - 答案会变的查信息题一律用
answer_grounded:回答里的数值、引号名字、「标签:值」都要在最后几次读屏里出现过。minItems写题目要的条数。 - 写类题必须有
marker(含{run}),目标里写上它,并用screen_has在对应 App 里(或用探针)找回它。 - 不可逆类题
expect写confirmation,用confirmation_shows核对卡片上的「做什么 / 对谁 / 内容 / 多少」(开发阶段确认关卡不生效、不会出卡片,这类题现在跑不出这个结局)。对象只用自己(文件传输助手、我的电脑、仅自己可见)或带标记的数据。 - 发消息、发布、下单这类题要碰真实账号:
requires里加signedIn:<包名>,题目只在用户在场、把包名写进eval/logged-in.txt后才跑;note写明跑之前要用户确认什么。- 下单题停在「提交订单」那一步,卡片核对店名和金额。
- 删除题只删这道题自己先造出来的带标记数据(目标里先新建,再删除),不删已有数据。
- 要用户账号才有意义的题(看「我的」昵称、通知)在
requires里写signedIn:<包名或网站>:网站看设置「网站登录」里有没有登录过,App 看人工标记(eval/logged-in.txt); 没登录就跳过,原因写「未登录」。App 的登录态评测器不自己去探(没有对所有 App 都可靠的探法)。旧写法login:、site:照样认。 - 读类题撞上登录墙、交给用户接管的,单列成「交给用户:login」,不算办成(算不算由人定)。只认紧挨在接管之前报告、
而且那一屏上看得出登录框 / 验证码字样的障碍;题目声明了已登录(
signedIn:等)时不归这一类。要改按acceptTakeoverOn写认哪些障碍([]表示不认)。 - 不出会花钱、会对外发出内容、会改账号设置、会删除用户已有数据的题;不碰装着个人数据的 App 的私人页面。
- 「该问还是该自己定」的题用
asked_user(Agent 是否用ask_user追问过):缺的是只有用户知道的事(指的是谁、删哪条、闹钟几点)写{"type":"asked_user"},并在answers里写好自动回答(键是提问里会出现的词);只是没说偏好(牌子、城市)写{"type":"asked_user","expected":false},期望 Agent 按常理定下并在回答里说明。 - 网页题用
channel强制网页时目标前会加「用网页」;目标里已经这么写了就不再加。网页题默认用网页的桌面版;要下载文件再算的题,文件只用公开、内容固定的,答案在note里写明怎么来的。 note写给评审看(这道题为什么这样出),评测器不用。
先用 LiveRunTest#configureProvider 配好主模型,再:
adb -s <设备> shell am instrument -w \
-e class com.wangzan101.mika.eval.EvalRunTest \
-e evalRun <运行名> [-e evalSet <目录或 id 前缀,如 read/content>] [-e evalSplit tune|holdout] \
[-e evalPriceIn <每百万输入 token 单价> -e evalPriceOut <输出单价> -e evalPriceCached <缓存单价>] \
com.wangzan101.mika.test/androidx.test.runner.AndroidJUnitRunner- 不传
evalSet跑全集(冒烟题、专项题集除外)。-e evalSplit tune|holdout只跑一个池,不传跑两个池(见上「调优池与保留池」)。å 39B8 …¨集要几个小时,按目录分批跑。 - 开发阶段 Mika 自主执行(
TaskRun里autonomous = true、confirmations = null),确认关卡不生效,评测里的自动拒绝(EvalHooks.decisionFor)也不会触发,没有安全网。write类照常跑;irreversible类默认不跑,现在不要跑:加-e evalAllowIrreversible true会真的发出消息、删除数据、下单。没跑的题在汇总里记为跳过并写明原因。 - 其他参数:
-e evalChannel web|app把每道题强制走网页或 App,对比两条路线;-e evalOnTakeover cancel|wait定遇到接管时取消还是等人(默认取消);-e evalFlags none|<键=on,…>临时改提速开关,跑完恢复;-e learnSkills on、-e memory on才让评测时学技能、自动记忆(默认都关,分数不受上一轮影响)。 - 结果在 App 外部文件目录
eval/<运行名>/:summary.md(含「运行小结」一节:第一次反馈、来回次数、模型 / 读屏 / 操作 / 其他的时间去向,逐题一行)、scores.jsonl(含回答全文,每题带metrics)、metrics.json(每题的运行小结RunMetrics)、<id>/run/(完整运行记录)。拉到仓库以外的地方看;结果不提交进仓库,汇总里引用时不放回答全文、截图、设备序列号和本机路径。 - 写类题造出来的数据带标记,汇总末尾列出,人工清理。
评测器只给初判。人看 <id>/run/ 里的运行记录后可改判,改判写在汇总末尾「人工改判」一节,每条写:题 id、原判 → 新判、证据(引用读屏文字或最终回答的原文)。
- 没有运行记录里的证据,不改判。
- 不把「没通过」改成「通过」,除非证据表明回答确实对、是核对规则误判(例如回答里的值就在读屏里,只是写法没被认出来)。
- 失败类别(
perception、route、barrier、app_state……)按运行记录里真实发生的事改,不为单题打补丁。