跳到主要内容

03 · 任务定义与执行式判分

这一章讲 OSWorld 最有辨识度的一半:任务不是代码而是声明式 JSON;判分不看 agent 自述,而是进真机取证再按规则比对(execution-based evaluation)。读完你能看懂任意一个任务 JSON,并知道它最后是怎么变成一个 0~1 的分数。

3.1 一个任务就是一份 JSON

369 道题(10 个 domain)每题一个 JSON,放在 evaluation_examples/examples/<domain>/<id>.jsontest_all.json 是总清单({domain: [id,...]},共 369 项)。任务数分布:

domain题数domain题数
multi_apps101os24
libreoffice_calc47vs_code23
libreoffice_impress47libreoffice_writer23
chrome46vlc17
gimp26thunderbird15

一个任务 JSON 的骨架(字段取自 evaluation_examples/examples/libreoffice_calc/1954cced-...json):

字段作用
id任务唯一 id(也是结果目录名)
snapshot该题基于哪个 VM 快照
instruction给 agent 的自然语言指令
config初始状态布置:一串 setup 动作(reset 时执行)
related_apps涉及哪些软件
evaluator怎么判分:func + result + expected + options + postconfig
proxy / possibility_of_env_change是否需代理、环境易变度等元信息

那道透视表任务的 config 就两步:download 下载 Invoices.xlsx,再 open 用 LibreOffice 打开它——干净利落地把「初始文件」摆好。

3.2 setup:声明式地布置初始状态

config 里每一项形如 {"type": "download", "parameters": {...}}SetupController.setupcontrollers/setup.py:57)按 type 拼出方法名 _{type}_setup 反射调用(setup.py:92)。常用 setup 动作:

type干什么方法
download从 URL 下文件到 VM(带缓存、重试)_download_setup (setup.py:108)
open用默认程序打开某文件_open_setup (setup.py:280)
launch起一个进程/命令_launch_setup (setup.py:300)
execute在 VM 里跑一条命令_execute_setup (setup.py:324)
chrome_open_tabs预置浏览器标签页_chrome_open_tabs_setup (setup.py:579)
login预登录某服务_login_setup (setup.py:753)
sleep等一会(等界面稳定)_sleep_setup (setup.py:457)

_download_setup 有个务实设计:先按 URL 的 uuid5 在本地 cache_dir 找缓存,命中就不重下(setup.py:120-126),失败重试 3 次。跑一次全量榜要拉大量初始文件,缓存能省掉重复下载。

3.3 判分的心法:去真机取证,而非信自述

OSWorld 判分的核心信念是:agent 说完成了不算,去系统里查最终状态才算。 这落成 DesktopEnv.evaluate()desktop_env.py:458)里一套「getter 取证 + metric 打分」的两段式:

evaluate()
① 跑 evaluator.postconfig(收尾动作,如 Ctrl+S 保存文件) desktop_env.py:463
② result_getter(self, result_config) → 进真机把「实际产物」取回 host(如下载改后的 xlsx)
③ expected_getter(self, expected_cfg) → 取回「标准答案」(如云端 golden 文件) [可选]
④ metric(result_state, expected_state, **options) → 比对,返回 0~1

getter = 取证员,metric = 判卷员。 二者在 evaluator 里用字符串名字声明,_set_evaluator_infodesktop_env.py:369)用反射把名字变成函数:

  • metric = getattr(metrics, func)desktop_env.py:380)——如 compare_table
  • result_getter = getattr(getters, "get_" + result["type"])desktop_env.py:385)——如 type=vm_fileget_vm_file

所以那道透视表任务的 evaluator(func: compare_table、result 是 VM 上的 Invoices.xlsx、expected 是云端 golden xlsx)判分流程就是:

postconfig 里先 Ctrl+S 存盘
→ get_vm_file 把 VM 里改后的 Invoices.xlsx 拉回 host
→ get_cloud_file 下载标准答案 xlsx
→ compare_table(实际, 标准, rules=[{type:pivot_table,...}]) → 0/1

compare_tablemetrics/table.py:260)用 openpyxl/pandas 把两个 xlsx 读进来,按 options.rules 里的一条条规则(sheet 名、透视表结构、单元格值…)逐条比对。这是「执行式校验」的典型:不解析 agent 说了什么,只解析它产出的真实文件对不对

3.4 getter 有哪些「取证」手段

getter 覆盖了「怎么从真机/真软件里把可判分的证据取回来」的各种方式(evaluators/getters/):

getter 类型取什么证据文件
get_vm_fileVM 上的某个文件(拉回 host)getters/file.py
get_cloud_file云端标准答案文件getters/file.py
get_vm_command_line在 VM 里跑命令、拿 stdoutgetters/general.py
get_rule直接把 JSON 里写死的期望值当证据getters/misc.py
get_open_tabs_info / get_historyChrome 的标签页/历史/书签getters/chrome.py
get_accessibility_tree当前无障碍树getters/misc.py

配对的 metric 也按软件/文件类型分门别类(evaluators/metrics/):compare_table/compare_csv(表格)、compare_docx_lines(Word)、compare_pdfs(PDF)、is_expected_tabs(浏览器)、check_include_exclude(命令输出含/不含某串)等。每个 metric 都是一个纯函数 (result[, expected], **options) -> floatMetric 类型别名见 desktop_env.py:21)。

3.5 多指标合取:and / or

一道题可以挂多个 metric(func 是列表)。evaluatemetric_conj"and"/"or")合取(desktop_env.py:481-509):

and:任一 metric == 0 → 立刻返 0;全过 → 返平均分
or :任一 metric == 1 → 立刻返 1;否则 → 返最大值

设计上 funcresultexpectedoptions 四个列表必须等长一一对应(desktop_env.py:412 的断言),即使某个 metric 不需要 expected 也要在列表里占个 None。这让「一道题=多条独立校验规则」表达得很整齐。

3.6 一类特殊题:infeasible(本就做不到)

OSWorld 里有一批「陷阱题」——任务其实不可能完成,正确行为是 agent 认清现实并回 FAIL。这由 evaluate 开头的特判处理(desktop_env.py:469):

若 evaluator.func == "infeasible":
最后一个动作是 FAIL → 得 1(对:识破了不可行)
否则 → 得 0(错:硬做/瞎报完成)
否则(普通题):
若最后动作是 FAIL → 直接 0(不该放弃)

这把「知道什么时候该放弃」也变成了可打分的能力,专治 agent 的过度自信与幻觉完成。test_infeasible.json 是这类题的清单。

3.7 判分全景一图

env.evaluate()

┌────────┴─────────┐
infeasible? 普通题
│ │
末动作FAIL? 末动作FAIL? ──是──▶ 0
是→1 否→0 │否

postconfig(如 Ctrl+S 存盘)

result_getter 取真机产物 ──┐
expected_getter 取标准答案 ─┤
▼ │
metric(实际, 标准, options) → 0~1
│(多 metric 时按 and/or 合取)

写 result.txt

至此三条主线(环境执行、agent 决策、任务判分)都讲完了。想看巧妙设计、边界与坑、以及可 grep 的代码地图,见 04-internals-and-map.md