ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Perfetto Agent Evals:用一个 regex Grader 验证 ANR 原因——anr-why 案例与评分机制详解

Perfetto Agent Evals:用一个 regex Grader 验证 ANR 原因——anr-why 案例与评分机制详解 Perfetto Agent Evals用一个 regex Grader 验证 ANR 原因——anr-why 案例与评分机制详解【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto本文以 Perfetto 仓库中ai/evals评测框架里的anr-why案例为切入点逐行解读它的reason评分器grader是如何定义、如何被 runner 加载并执行判定的并结合trace_processor标准库中 ANR 数据视图的源码说明为什么这个正则模式能成为ANR 原因这一开放题的可靠真值依据。读完你能掌握 Perfetto 面向 coding agent 的评测体系case / condition / grader 三层结构的工作原理以及确定性评分器优先、LLM 裁判兜底这一设计在真实案例中的落地方式。一、评测体系概览一个 trial 是怎么跑的Perfetto 在ai/evals/下维护了一套针对 coding agent 的评测框架它回答的问题是当让 agent 拿着一条 trace 调试性能问题时某次改动skill 内容、trace_processor的输出、文档到底有没有让 agent 干得更好、代价是多少。其核心定义来自 ai/evals/README.md一个 trial 一个 agent 一个 prompt 一个 condition。一次 trial 的完整流程如下新建隔离工作区在系统临时目录创建一个全新 workspace把案例的输入文件test/data里的 trace、脚本拷贝进去。除此之外什么都没有——没有用户配置、插件或记忆agent 能用的 Perfetto 知识只有模型自带加上 condition 显式注入的部分。condition 决定 agent 能看到什么装没装 skill、PATH上有没有某个trace_processor构建。条件在 ai/evals/conditions.json 中命名实际指向的资产打包好的 skill、二进制位于源码树之外由 ai/evals/setup_assets.py 组装。agent 以非交互模式运行通过其自身 CLI 启动Claude Code 的claude -p、Codex 的codex exec --json仓库检出目录和 wrapper 的预构建缓存对 agent 隐藏完整事件流被保留为 transcript。transcript 归一化后评分先做正则、工具调用这类确定性评分只有正则无法检查的判据回答是否基于证据而非编造才交给 LLM 裁判同时计算一组过程指标是否调用了 skill、是否保持 warm session、trace_processor调用次数、SQL 报错次数、花费、耗时、是否通过翻到本地构建作弊。每个 case 在每个 condition 下跑多次非确定性 agent 的单次运行是噪声报告按 case 和 condition 聚合得分、成本与过程指标compare子命令可把多个结果目录并排对比。anr-why就是这个框架下的一个标准案例目录结构为ai/evals/cases/anr-why/ prompt.md # 案例定义frontmatter 提问正文 graders/ reason.md # 本篇主角ANR 原因必须被说对 videos-process.md # 事实检查videos 进程必须被找到 gms-process.md # 事实检查gms 进程也必须被找到不能只报第一个二、案例定义prompt.md 的 frontmatter 与提问ai/evals/cases/anr-why/prompt.md 完整内容如下--- name: Which app ANRd and why tags: [android, anr, adhoc] runs: 3 files: - src: {repo}/test/data/android_anr.pftrace.gz dst: anr.pftrace.gz --- QA is reporting app not responding dialogs on our test devices. I have a Perfetto trace from one device that covers the incident: ./anr.pftrace.gz. Which app(s) hit an ANR, and what does the trace say the reason was?几个字段各有含义tags: [android, anr, adhoc]标签只服务于--tag/--exclude-tag选择子集不参与评分。按 ai/evals/README.md 的分类android/anr是领域标签adhoc是路由标签——意味着这道题没有现成的 workflow runbookagent 需要对核心表写裸 SQL 来回答。runs: 3该 case 默认每 condition 跑 3 次可在命令行用--runs覆盖。files声明输入文件。{repo}是 runner 内置变量指向仓库根目录会被展开后从test/data拷贝 trace 到工作区并重命名为anr.pftrace.gz。注意 trace 本体在仓库中通常只有校验和文件 test/data/android_anr.pftrace.gz.sha256实际 trace 需要通过tools/install-test-deps拉取ai/evals/README.md 的 Running 一节明确要求先确保 test traces 就位。提问本身刻意模拟真实用户口吻不出现 Perfetto 术语但注意该 prompt 提到了.pftrace文件属于no-mention标签之外的常规案例答案空间开放——哪个应用 ANR 了trace 说什么原因。正是trace 说什么原因这半句构成了reasongrader 的评分对象。三、reason grader 逐字段解读ai/evals/cases/anr-why/graders/reason.md 全文只有 6 行--- type: regex pattern: failed to complete startup|complete startup|startup timeout flags: i --- The ANR subject for the videos process must be surfaced.3.1 frontmatter 字段语义type: regex五种评分器类型之一regex|bash|tool_used|file_exists|llm。pattern要匹配的 POSIX 风格正则|提供三个可接受表述——failed to complete startup、complete startup、startup timeout。这是一个宽容但锚定的模式它不要求 agent 逐字复现 subject 行但要求最终答案里出现启动未完成/启动超时这一核心事实。flags: i忽略大小写即 Startup Timeout 与 startup timeout 等效。正文部分---之后的 Markdown 文本是评分器的描述会被 runner 读入description字段供报告与人工审计阅读不参与判定。3.2 runner 如何执行这个 grader评分逻辑在 ai/evals/run_evals.py 中。案例加载时load_cases()约 L95-L121遍历cases/id/graders/*.md用parse_frontmatter()L78-L85按 YAML 解析 frontmatter文件名去掉扩展名作为 grader 名把每个 grader 解析成 dict 挂到 case 上。判定入口是grade_regex()约 L751-L767关键行为确定目标文本_target_text()L735-L748按target字段取文本reason未声明target取默认值last_message——即 transcript 归一化后的最后一段实质性回答_pick_final()优先选长度 ≥200 的末块以规避 agent 以 Session cleaned up. 之类一句话收尾的情况。也就是说只有用户实际看到的最终答案被这个 grader 检查中间过程说对不算。组装 flagsi in flags加re.Is in flags加re.S。本例只有i。匹配模式re.findall(pattern, text, flags)统计命中次数nmatch字段默认containsn 0即通过也支持not_contains和count:N精确计数。本例为 contains 模式——最终答案里出现一次任一候选短语即通过。落盘证据返回(ok, evidence)evidence 形如1 match(es) for /failed to complete startup|.../ in last_message连同scored默认true、type、name一起写入该次运行的grading.json。scored: false的 grader 只作为过程指标记录、不计入得分grade_run()中score 通过的分值 grader 数 / 分值 grader 总数。reason是分值 grader答不出原因这个 case 的得分直接受损。3.3 为什么这个模式是真值而非猜测reason的宽松三选一背后是 trace 里确实存在的系统事件。这条 trace 中 videos 进程 ANR 的 subject 是Process ... failed to complete startup一类文本进程绑定阶段 15 秒超时未完成启动而trace_processor的标准库正是按 GLOB 模式从这类 subject 中识别 ANR 类型的src/trace_processor/perfetto_sql/stdlib/android/anrs.sql 中WHEN $subject GLOB Process ProcessRecord{*} failed to complete startup THEN BIND_APPLICATION并把BIND_APPLICATION的 AOSP 默认超时定为 15000ms_default_anr_durL77。该文件最终产出的android_anrs视图L191-L218每行一个 ANR包含process_name、pid、ts、subject、anr_type、anr_dur_ms等列其数据来源是system_server下的 process counter track——ErrorId:process#UUID标记 ANR 事件、Subject(for ErrorId UUID):subject携带原因行。grader 的正文描述也点明了这一点videos-process.md 写道Ground truth fromandroid.anrscom.google.android.videos (pid 4464), subject Process ... failed to complete startup。三个 grader 构成一组互补的判据grader类型模式验证的事实reason.mdregexfailed to complete startup\|complete startup\|startup timeoutflagsivideos 进程的 ANR原因subject被如实说出videos-process.mdregexcom\.google\.android\.videos找到 videos 进程pid 4464gms-process.mdregexgms\.persistent第二个 ANRcom.google.android.gms.persistentpid 30647broadcast-of-intent 类型组件com.google.android.gms.tron.ALARM也被报告gms-process.md的正文特意说明Both ANRs should be reported, not just the first one found——这条 trace 里有两个 ANR只找到第一个的 agent 不能算答对。而reason则防止另一种失分找到了进程却编不出/说不出原因。三者都是分值 regex grader全部命中该 case 才能满分。四、端到端运行从资产准备到对比报告4.1 准备资产评测资产必须放在仓库外agent 的 sandbox 会把仓库目录藏起来由setup_assets.py一次性组装git fetch origin ai-agents ai/evals/setup_assets.py --out ~/perfetto-eval-assets \ --tp-binary out/mac_release/trace_processor_shell export EVAL_ASSETS~/perfetto-eval-assets该脚本ai/evals/setup_assets.py做三件事从ai-agents分支git archive出发布版 skill 到assets/skill-published/plugins/perfetto用tools/release/build_ai_agents.py把当前检出的ai/skills/打包成skill-local把编译好的trace_processor_shell复制到assets/bin/trace_processor并建立trace_processor_shell符号链接conditions.json的path: [{assets}/bin]指的就是它。修改ai/skills/或重新构建后需重跑该脚本。4.2 运行 anr-why 并评分# 有 skill vs 无 skill仅有 trace_processor on PATH每 case 3 次5 路并行 ai/evals/run_evals.py run --conditions baseline-tp,skill-local --runs 3 --jobs 5 # 只跑 ANR 域的案例 ai/evals/run_evals.py run --cases anr-* --conditions baseline-tp,skill-local # 改完 grader 后重新评分保留已有 LLM 判定不再为 judge 付费 ai/evals/run_evals.py grade ai/evals/results/name --skip-llm # 多个结果目录并排对比 ai/evals/run_evals.py compare ai/evals/results/a ai/evals/results/b \ --conditions baseline-tp,skill-localrunner 对每个 trial 的处理要点均在 ai/evals/run_evals.py 中可查隔离sandbox_wrap()L405-L432在 macOS 用sandbox-exec拒绝读取仓库与~/.local/share/perfetto/prebuilts在 Linux 用 bubblewrap 把隐藏路径覆盖为空 tmpfs每个 trial 有独立短路径TMPDIRwarm session socket 放这里。compute_indicators()L608-L727中的contaminated指标通过正则检测 agent 是否碰到了隐藏路径本地 checkout、out/构建目录、prebuilt 缓存命中的运行会被标记以便丢弃——ai/evals/README.md 记载首轮评测时 agent 确实从工作区一路向上找到仓库并使用了其中的构建隔离机制由此而来。确定性优先GRADERS注册表L848-L854把五种类型映射到实现只有llm类型会启动一个独立的claude -p --json-schema ... --model haiku进程做裁判且裁判提示词要求必须给出具体证据才给 PASS不施以无罪推定。reason这类 regex grader 则便宜、可复现、无法被话术说服。聚合与报告aggregate()把grading.json汇总为每 (condition, case) 的得分均值、全通过率、分 grader 通过率及过程指标均值/比率report()输出 Markdown 表格compare()生成跨目录矩阵单元格为 均分 / 均成本 / 均耗时 / warm-session 率。按 README 给出的量级适用前提Claude Opus、11 个 case、每 condition 3 次、5 并行单 condition 全量矩阵约 $30 与 40 分钟Sonnet 约为其五分之一单次 trial 成本 $0.1~$3。五、这套 grader 写法体现的设计原则reason这个 6 行小文件浓缩了 ai/evals/README.md Adding a case 一节的几条军规值得作为撰写新 grader 的参照一个 regex grader 只验证一个事实One fact per regex grader。reason只问原因是否被说出进程名拆到另两个文件里便于定位失分点。真值来自trace_processor本身每个 grader 的正文记录产生期望值的查询依据且当同一条 trace 存在两种都站得住的解读时grader 模式会同时接受如reason接受三种措辞。首轮评测的教训正在于此agent 合理地排除了参考脚本计入的一条容器 track报出了另一个但正确的结果。过程检查默认scored: falsebash/tool_used类型的过程性断言除非过程本身就是考点否则只作指标记录——因为答案对比路径对重要走非预期路径答对的 agent 仍然应通过。frontmatter 是 YAML正则要正确引号模式必须双引号并转义反斜杠\\d或单引号直书\d否则parse_frontmatter()的yaml.safe_load会解析出意外内容。reason中的|与短语无需转义但像videos-process那样含.的模式写成了com\.google\.android\.videos以精确匹配字面点号。先跑三遍 baseline 再信任 case所有 condition 都能过的 case 没有信息量baseline 过不去的 case 才是改动能显形的地方。六、小结ai/evals/cases/anr-why/graders/reason.md是 Perfetto agent 评测体系中最小评分单元的典型样本一段带iflag 的宽松正则锚定在 trace 中真实存在的 ANR subjectfailed to complete startup对应标准库BIND_APPLICATION类型只检查 agent 最终回答与另两个进程名 grader 共同保证找全所有 ANR 且原因说对这一完整答案。它的价值不仅在于判对一道题更在于演示了如何把一条开放式的性能调试题拆解为可复现、可聚合、可与 LLM 裁判分层的确定性判据——这也是 ai/evals/README.md 强调只有把 agent 真的跑一遍才知道 skill 有没有用的方法论落地方式。【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进