最新资讯
www.infoq.com Edera 推出 Object Capability Bounded Authority,试图将凭证与 AI Agent 工作负载隔离 wechat 这波杀疯了!旗舰级模型不限量、1个月视频额度免费领 dev.to 如何在专用 GPU 服务器上用 OpenAI 兼容 API 部署 LLM dev.to 审计 153 份 Claude Code 与 Codex 会话记录:User-Agent 与 URL 中的邮箱泄露 dev.to 你的 Agent Harness 应具备的 17 项能力 dev.to 离线 AI 记忆中 0.8 余弦阈值为何失效 dev.to Kimi K3.1 Pro 开放权重:自托管 2.8T 模型前的开发者清单 dev.to 如何通过工具调用引导模型以提升 Harness 质量 dev.to AI Agent 审计轨迹不等于对话记录 dev.to 精简 MCP server 工具数量:更少工具、更小影响面,双重收益 dev.to 为什么 git checkout 无法撤销 AI 编码 agent 的改动? wechat AI短剧门槛降降降!实测即梦短剧工作室:剧本分镜预演一条龙,伙伴计划长期护航
多元动态
登录 注册
智能体 dev.to · @Casey Zhang

不要在不同 token 预算下平均通过率

原文 我的收藏

文章批评 agent 评测中直接平均通过率的做法:通过率只回答测试是否变绿,却不说明消耗了多少 token、预算上限是否被误判为模型失败、两个 agent 是否拥有相同的工具调用额度。作者提出一套可复制的评测协议,包括固定任务包、预先声明预算、用 JSONL 记录每次尝试并同时公布多个指标,并说明这些脚本只是提案。

AI推荐理由 文章指出 agent 评测中直接平均通过率的问题:不同 token 预算下的通过率不可比,预算上限被截断可能被误记为模型失败,工具调用额度也可能不对等。作者提出一套协议:固定小任务包、首次调用前声明预算、把每次尝试写入 JSONL 账本、同时公布三个数字。对做 agent 基准评测的开发者有直接方法论价值,但作者自述脚本是提案而非结论,需注意其未经验证。

78

正文

You taped two terminal panes to a Friday review. The left pane showed Agent A with eight greens; the right pane showed Agent B with six. Someone asked which one to keep. You almost said A. Then you scrolled the traces. Agent A retried until the cap cried. Agent B stopped after one compile and one test run. Same tasks. Different permission to spend. The ranking was a poster, not a measurement. A pass rate answers one question: did the tests go green. It is silent on three others. How many tokens did the run burn before that green. Did a budget cap get scored as a model failure. Were the two agents even allowed the same tool-call envelope. If you cannot answer those, you do not have a benchmark. You have a vibe with a percentage sign. This article is a protocol, not a leaderboard. You will pin a tiny task pack, declare a budget before the first call, write every attempt to a JSONL ledger, and publish three numbers together. The scripts below are a proposal you can copy. They are not a claim about any vendor eval, and they are not executed numbers from a production fleet. Why the single percentage is usually marketing Engineering reviews launder vibe-coding into a metric when the budget is a footnote. Two agents can share a task list and still live in different universes. One is allowed 40 tool calls and four repair loops. The other gets one shot and a 2k-token ceiling. Averaging their pass rates is like averaging two race times after giving one car a second tank of fuel. You need the budget in the same table as the outcome. Not in a blog paragraph. In the file you commit. The protocol below treats tokens, tool calls, and truncations as first-class results. Pass/fail is column four, not the headline. What you will actually produce Work in a single directory. Keep it boring. A pinned task pack with SHA-256 hashes. A budget envelope declared before any model call. A JSONL ledger with one object per attempt, including the dull failures. Three numbers you publish together, or you publish none of them: pass rate, truncation rate, and tokens-per-success. You can run this on a laptop. You can also run it on a free server so the cost of being honest is not why the controls get skipped. Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode's free model access and free server option matter here only as a lab: you can execute the ledger without folding a billed retry policy into the ranking. Strip the product name out and the method still stands. Free is still a cap. Write that cap in the same file as the tasks. Step 1 — Pin a task pack you can hash Do not point at "the latest suite on the internet." Snapshot files. Hash them. If a fixture changes, the run id changes. That is the whole point. Proposed layout: eval_pack/ TASKS.md budget.yaml tasks/ 01_csv_summary/ prompt.md src/app.py tests/test_app.py 02_retry_header/ prompt.md src/app.py tests/test_app.py hashes.sha256 Enter fullscreen mode Exit fullscreen mode Keep the pack small on purpose. Eight to twelve tasks is enough to debug the protocol. It is not enough to crown a winner. Label it that way in TASKS.md. Each task needs three things: a prompt the agent may read, a hidden test file the agent must not edit, and a definition of done that is a command, not a feeling. # tasks/01_csv_summary/prompt.md Read src/app.py. Make summarize(path) return a dict with keys rows, empty_rows, numeric_columns. Do not edit tests/. Enter fullscreen mode Exit fullscreen mode Hash after you freeze the files: cd eval_pack find tasks -type f | sort | xargs sha256sum > hashes.sha256 sha256sum budget.yaml TASKS.md >> hashes.sha256 cat hashes.sha256 Enter fullscreen mode Exit fullscreen mode If hashes.sha256 drifts, you are not comparing agents. You are comparing days. Step 2 — Declare the budget before the first call Write the envelope first. Then refuse to start a run that does not load it. This is a control, not a comment. # budget.yaml envelope_id: "lab-2026-09-19-a" max_input_tokens_per_task: 8000 max_output_tokens_per_task: 2000 max_tool_calls_per_task: 12 max_repair_loops: 2 wall_clock_seconds_per_task: 180 hidden_tests_are_read_only: true Enter fullscreen mode Exit fullscreen mode Pick numbers that fit your lab. Do not copy these as if they were a standard. The standard is that both agents get the same envelope, and that truncation is recorded as its own outcome class. Outcome classes you will allow: pass — hidden tests exit 0 inside the envelope. fail — tests exit non-zero, budget still remaining. truncated — a cap fired before tests could pass. invalid — the agent edited a forbidden path, or the runner crashed in a way you cannot attribute. truncated is not fail. Mixing them is how a stingy envelope looks like a weak model. Step 3 — Log every attempt, including the boring ones JSONL beats a screenshot of a dashboard. One object per task attempt. No silent retries. Proposed record (label: schema proposal): { "run_id": "20260919T1400Z-lab-a", "envelope_id": "lab-2026-09-19-a", "task_id": "01_csv_summary", "agent_id": "agent-a", "pack_hash": "REPLACE_WITH_SHA256_OF_hashes.sha256", "input_tokens": 2410, "output_tokens": 880, "tool_calls": 5, "repair_loops": 1, "wall_clock_seconds": 47, "outcome": "pass", "test_exit_code": 0, "notes": "" } Enter fullscreen mode Exit fullscreen mode Append only. If a row is wrong, write a correction row. Do not silently edit history. mkdir -p runs touch runs/20260919T1400Z-lab-a.jsonl Enter fullscreen mode Exit fullscreen mode Your runner should dump token counts from the provider response, not from a guess. Tokenizers differ. That is a limitation, not an excuse to skip the column. Step 4 — Score three numbers, never one Proposal, not a published score. After the JSONL exists, compute: pass_rate = passes / tasks truncation_rate = truncated / tasks tokens_per_success = sum(input_tokens + output_tokens for passes) / max(passes, 1) If passes is zero, tokens_per_success is undefined. Print NA. Do not print infinity and call it a ranking. # score_ledger.py — proposal, unexecuted example import json import sys from collections import defaultdict REQUIRED = { "run_id", "envelope_id", "task_id", "agent_id", "pack_hash", "input_tokens", "output_tokens", "tool_calls", "repair_loops", "wall_clock_seconds", "outcome", } def load(path): rows = [] with open(path, encoding="utf-8") as handle: for line_no, line in enumerate(handle, 1): line = line.strip() if not line: continue row = json.loads(line) missing = REQUIRED - row.keys() if missing: raise SystemExit(f"line {line_no} missing {sorted(missing)}") rows.append(row) return rows def score(rows): grouped = defaultdict(list) for row in rows: grouped[(row["agent_id"], row["envelope_id"], row["pack_hash"])].append(row) reports = [] for key, items in grouped.items(): n = len(items) passes = [r for r in items if r["outcome"] == "pass"] trunc = [r for r in items if r["outcome"] == "truncated"] tokens = sum(r["input_tokens"] + r["output_tokens"] for r in passes) reports.append({ "agent_id": key[0], "envelope_id": key[1], "pack_hash": key[2], "n": n, "pass_rate": round(len(passes) / n, 3) if n else None, "truncation_rate": round(len(trunc) / n, 3) if n else None, "tokens_per_success": round(tokens / len(passes), 1) if passes else "NA", }) return reports if __name__ == "__main__": for report in score(load(sys.argv[1])): print(json.dumps(report, indent=2)) Enter fullscreen mode Exit fullscreen mode Run it: python3 score_ledger.py runs/20260919T1400Z-lab-a.jsonl Enter fullscreen mode Exit fullscreen mode Compare agents only when envelope_id and pack_hash match. If they do not match, the script still prints two blocks. You do the adult thing and refuse the average. A useful derived check: if truncation_rate differs by more than one task, you are mostly measuring the envelope, not the agent. Widen the budget and rerun both. Or keep the tight budget and say so in the first sentence of the writeup. Step 5 — Decision table: measurement vs advertisement Use this table before anyone pastes a percentage into Slack. Situation Quote a single pass rate? Publish instead Same pack_hash, same envelope_id, both agents logged No The three-number triple, plus n Different token caps, "same" tasks No Two separate triples, never averaged Hidden tests were edited by the agent No invalid count and a patch diff n under 8 tasks No The ledger, labeled as a protocol debug Truncation rate > 0.25 for one agent only No "envelope-bound" and the raw traces Latency on a shared free server No Tokens and outcomes only; drop wall-clock from the headline Homepage hero or vendor one-pager No Link the recipe, or do not cite the lab If a cell says no, the percentage is marketing even when the arithmetic is correct. Step 6 — Pairwise only inside the same envelope When you must pick a winner, do not subtract two pass rates. Count paired outcomes on the same task_id. Proposal rule: Drop any task where either agent is invalid. On the rest, score +1 for the agent that passed when the other did not. If both passed, award +1 to the lower token total only when the gap is larger than 15 percent. Otherwise call it a tie. If both truncated, call it a tie. You learned about the envelope, not the model. That 15 percent band is a knob. Write the knob in budget.yaml. Do not tune it after you see which agent you like. What this protocol refuses to claim It does not detect training-set contamination. It does not prove an agent is safe to ship. It does not turn a free server into a latency benchmark. Shared CPUs lie. Tokenizers lie in smaller ways. Your hidden tests lie if they only cover the happy path. It also does not make a 12-task pack into a scientific paper. Twelve tasks can falsify a sloppy ranking. They cannot support a superlative. Who should not use this Skip this approach if you need a homepage number this afternoon. Skip it if your "agent" is allowed network access the other agent is not. Skip it if you will not log truncated runs because they look ugly. Skip it if the real question is production SLA, not coding-agent comparison. And skip it if you planned to treat free-tier queue time as intelligence. If you want a lab that already offers free model access and a free server option, MonkeyCode is one place to run the ledger. The protocol does not depend on it. The only number worth quoting is the triple you can rebuild from JSONL and a hash file.

来源报道 · 1 篇 · 以下链接均前往原始媒体

Casey Zhang 不要在不同 token 预算下平均通过率 09-19 · 原文发布
← 返回精选动态 原文

更多内容