一台自动售货机,比又一张对话排行榜更像样的智能体基准
💡 工具推荐:JSON 格式化, AI Token 计数器, 哈希生成器, 文本差异对比
大多数智能体基准是问一个问题、判一个答案。Prosus AI 发布的那个,直接把一门生意交给你。2026 年 9 月以 Apache 2.0 开源的 Vending Bench,让智能体经营分布在三个地点的六台模拟自动售货机,跑 30 个模拟日,起始资金 €1,500,有 22 个用于采购、定价、补货和退款的 MCP 工具,最后只有一个数字:银行余额。在首批公布的结果里,Claude Opus 5 花掉 $13.55 的 API 费用、最终 €4,497.21;GPT-5.6 Sol 用 $1.91 做到 €3,357.76;而 Claude Haiku 4.5 结束时 €1,337.67,比启动资金还少。最后这个结果最有用,因为一个答题漂亮却在自动售货机上亏钱的模型,正是对话排行榜永远看不出来的失败模式。
六台机器、一个银行账户、一个工作日:资源分配因此可观测,而不是修辞。
为什么商业模拟胜过又一张排行榜
跨 30 天做计划,和在 30 秒内做回答,是两种不同的能力。订单、配送、销售和租金随着模拟时间展开,所以「周一决策得很好、周二忘了」的智能体会被抓出来。六台机器抢一个银行账户、一个仓库、一个八小时工作日,资源分配因此变成可观测的事实而不是修辞。不同的顾客、变化的促销、不可靠的供应商逼出适应能力。笔记和提醒功能存在,是为了让智能体追踪未完成的活儿,而忘记用它们,会直接出现在余额上。
每一次工具调用都会推进模拟时间,这是让整个设计成立的关键决定。没有免费的内省:查库存和改价格花的是同样的分钟数,所以一个无限探索的模型会在想法用尽之前先把工作日用完。
团队自己对目标的概括值得引用,因为它定住了合理的预期:目标是让一家公司的经营可以被基准化到「AI 能研究怎么把它经营得更好」的程度。自动售货机是他们能编码的最小生意,而不是「零售已被解决」的声明。
# The cheapest useful thing you can do today: watch a reference operator run the
# business with no model, no API key, and no Docker. Requires Python 3.11+.
git clone https://github.com/ProsusAI/vending-bench.git
cd vending-bench
python3 scripts/local_run.py --seed 1
# Expected output for seed 1 with the default configuration:
# days operated 30
# tool calls 506
# units sold 998
# FINAL BALANCE €3,302.96
#
# Read the caveat in the README before you quote that number: the scripted reference
# has privileged catalogue knowledge. It is a calibration reference, not an AI result.
# If your agent scores below it, you have not proven the agent is bad; you have
# proven the environment is measuring something your agent has not learned to use.
五分钟跑起来,以及让它保持诚实的两个上限
参考操作器只需要 Python 3.11,别的都不要:不用模型、不用 API key、不用 Docker。在默认配置、seed 1 下,它用 506 次工具调用经营 30 天、卖出 998 件、最终结余 €3,302.96。README 特意说明这个脚本操作器拥有高级的目录知识、是校准参考而不是 AI 结果——这一点很重要,因为它定义了「一次像样的运行」该有的水位。
让模型来管需要 uv 和一个已认证的 Claude CLI,而且每次试验都被限制在 $5 的等价 API 费用和 1,800 秒。关键是,项目明确说这些限制不保证跑完,而未完成的运行记零分。这一个设计选择,正好去掉了毁掉长程评估的那个激励:让智能体慢慢烧预算、然后自信地汇报。
保持批次干净。一个批次一个输出目录、一套参数、一组 seed。我见过的绝大多数基准争议不是关于模型,而是某人第二次跑的时候悄悄换了参数。
# Now put a model in charge. The runner needs uv and an authenticated Claude CLI,
# and every trial is capped so a loop cannot quietly spend your month.
uv run --with fastmcp==2.11.3 python scripts/run_models.py \
--models haiku \
--seeds 1 \
--workers 1 \
--budget 5 \
--timeout 1800 \
--output results/my-first-run
# Two caps, both load-bearing: $5 API-equivalent per run and a 1,800-second limit.
# The README is explicit that these do not guarantee completion -- an unfinished run
# scores zero. That is a feature. A benchmark where running out of budget still
# counts as a result teaches agents to be slow and confident.
#
# Use a fresh output directory for every batch. Mixing runs from different flags in
# one directory is how leaderboards end up comparing apples to a Docker image.
「跑完了」不等于「会做生意」,数字会说话
五个前沿模型都完成了 30 天,所以完成这件事本身不提供任何质量信息。把它们分开的是经济性。Opus 5 把 €1,500 变成 €4,497.21,约 200% 回报,代价 $13.55。Sol 变成 €3,357.76,约 124%,只花 $1.91。Luna 收在 €1,601.59——刚过盈亏平衡——花了八美分。Haiku 4.5 亏了 €162.33。
算比值,别只排名次。Sol 用 Opus 14% 的 API 账单拿到了 88% 的利润,这句话才是采购决策需要的那句。Haiku 的绝对成本也很小,但它毁掉了本金,正确的读法不是「它便宜」,而是「这个任务超出了它」。
两个诚实的提醒。这是一个模拟 seed,活的模型采样不构成显著性——项目自己也这么说。第二,上面这批数据跑在基准 v2 规则下,而仓库已经把 v2 标记为被 v3 取代:工作时间缩短、现金改为隔夜入账、补货变成 45 分钟的跑腿、换货位加 30 分钟、并且不再向生意收取每次工具调用的费用。这些数字与 v3 不可比,维护者也没有重写它们。
# The headline failure this benchmark is designed to expose: an agent can complete
# every day and still be a terrible shopkeeper. Bank balance alone hides that, because
# a high balance might mean good decisions, a better location, or a competitor that
# gave snacks away. So compute the economics per run, not just the ending cash.
def economics(final_balance, start=1500.00, api_cost=0.0, tool_calls=0):
profit = final_balance - start
return {
"profit": round(profit, 2),
"profit_per_tool_call": round(profit / tool_calls, 3) if tool_calls else None,
"return_on_start_pct": round(profit / start * 100, 1),
"eur_profit_per_usd_cost": round(profit / api_cost, 1) if api_cost else None,
}
# Published 30-day batch, seed 1 (benchmark v2 rules -- see the next snippet):
# Opus 5 4,497.21 cost 13.55
# GPT-5.6 Sol 3,357.76 cost 1.91
# Sonnet 5 3,289.12 cost 5.77
# Luna 1,601.59 cost 0.0770
# Haiku 4.5 1,337.67 cost 1.98
print(economics(4497.21, api_cost=13.55, tool_calls=506))
print(economics(1337.67, api_cost=1.98, tool_calls=506))
# Sol returning 88% of Opus's profit for 14% of the API bill is the number a
# procurement conversation actually needs. Rank by profit, then read the cost column.
先按利润排名,再读 API 成本那一列:Sol 用 14% 的账单拿到了 88% 的利润。
不重造管道,也能做出自己的长程评估
值得借鉴的是它的封装方式。售货机世界被做成一个 Harbor 任务,而 Harbor——Terminal-Bench 的作者们做的框架——提供容器环境、智能体适配器和试验运行基础设施。模拟器遵循 Harbor 的 MCP sidecar 模式,通过 Model Context Protocol 暴露那 22 个工具,于是这个基准成为一块基础设施,而不是一堆定制脚本。Prosus 说借助这套脚手架,他们不到一周就搭完了。
这告诉你自己的评估该长什么样:一个容器、一个通过 MCP 暴露工具的 sidecar、一个起始状态、一个封闭的计分步骤,以及一个记录来源信息的 results 目录。你不需要为你的领域发明新框架;你需要一个领域、一条随时间累积的经济规则,以及一个被测智能体无法作弊的分数。
安全说明是设计的一部分而不是补丁,而且可以直接搬到你的项目上。模拟器在一个进程里只装一个世界、没有认证,所以每次试验都必须隔离。没有实时的分数端点,finalize 会在返回分数之前不可逆地封存一次运行,于是碰到验证器的智能体是作废而不是获利。配置通过环境变量从 TOML 加载,意味着那些路径只能指向你自己控制的文件。
# The trap in every public benchmark: comparing runs that were not comparable.
# This one changed rules between versions. v3 shortened the working day to 09:00-17:00,
# replaced cash boxes with overnight banking, made filling a machine a 45-minute errand,
# added a 30-minute swap_item, and stopped charging the business for tool calls.
# The published model batch predates all of that and is kept as a record, not a live
# leaderboard. Tag every result with its provenance and refuse to average across tags.
import json, hashlib, subprocess
from datetime import datetime, timezone
def provenance(extra=None):
return {
"captured_at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
"commit": subprocess.check_output(
["git", "-C", "vending-bench", "rev-parse", "HEAD"], text=True).strip(),
"benchmark_version": "v3.0.0", # read from the repo, do not trust memory
"seed": 1,
"harness": "harbor",
**(extra or {}),
}
def comparable(a, b):
keys = ("benchmark_version", "seed", "harness", "commit")
return all(a.get(k) == b.get(k) for k in keys)
run_a = provenance({"model": "kimi-k3.1-pro"})
run_b = provenance({"model": "your-incumbent"})
print(json.dumps([run_a, run_b], indent=2))
print("comparable:", comparable(run_a, run_b))
# If you change one flag, change the version tag too. A benchmark you cannot audit
# is a vibe with a table around it.
把它当评估而不是演示的清单
引用任何分数之前,六项检查。每次试验把模拟器隔离在私有网络。哈希你实际用过的配置 TOML,因为配置加载接近于任意代码,一次静默覆盖就能让整次运行作废。把基准版本、框架、commit、seed 跟着每个结果一起记。把 $5 和 1,800 秒的上限写在命令行里,而不是写在某个 wiki 上。别让 API key 落进 results 目录,因为公开的轨迹里是模型的原始文本。并且提前决定失败运行怎么处理——未完成记零分是一个你不该随手覆盖的设计选择。
然后把 365 天变体当成另一个问题,而不是更难的问题。一个月测的是运营;一年测的是策略能不能扛住季节性和漂移。如果你的智能体在 30 天里赢、在 365 天里崩,那就是你的评估能产出的最有价值的一句话。
最后,别急着把它变成你团队的排行榜。这个基准真正的价值是可重复的对照实验:改一条指令、改一套记忆方案、或者改一个工具,重跑,看余额动不动。这就是「按结果衡量智能体,而不是按感觉」的全部论据。
#!/usr/bin/env bash
# Pre-flight for running the benchmark as an evaluation rather than a demo.
set -euo pipefail
echo "== isolation =="
# The simulator is not multi-tenant: one world per process, no authentication,
# meant to run on a private network inside a single trial's Docker Compose project.
# Exposing it to a shared network is a deployment mistake, not a supported config.
docker network ls | grep -c vending || echo "no vending network yet (fine on first run)"
echo "== scoring integrity =="
# There is no live /state or /score endpoint. POST /verifier/finalize seals a run
# irreversibly before returning the score, so an agent that reaches it forfeits.
grep -R "finalize" vending-bench/tasks/vending-bench/environment 2>/dev/null | head -3
echo "== config provenance =="
# VENDING_CONFIG, VENDING_SET and other VENDING_* variables load and override a TOML
# file from disk. Only point them at files you control, and hash the config used.
sha256sum vending-bench/tasks/vending-bench/environment/sim-server/vending/config.toml 2>/dev/null \
|| shasum -a 256 vending-bench/tasks/vending-bench/environment/sim-server/vending/config.toml
echo "== budget and time caps =="
echo "per run: --budget 5 --timeout 1800; unfinished run scores zero"
echo "== keys =="
test -n "${OPENROUTER_API_KEY:-}" && echo "openrouter key present" || echo "set OPENROUTER_API_KEY in an env file you pass explicitly"
echo "== results dir =="
mkdir -p results/$(date +%Y%m%d)-$(git -C vending-bench rev-parse --short HEAD)
每次试验都隔离:一个进程一个世界、不共享网络、没有实时分数端点。
📌 常见问题 FAQ
Prosus Vending Bench 是什么?
一个 Apache 2.0 开源的基准:智能体经营分布在三个地点的六台模拟自动售货机,跑 30 个模拟日,起始 €1,500,使用 22 个 MCP 工具,分数是最终银行余额。另有 365 天变体用于更长周期的测试。
跑一次要花多少钱?
运行器给每次试验设了 $5 等价 API 费用和 1,800 秒的上限,未跑完记零分。参考操作器完全不需要模型或 API key。
为什么 Claude Haiku 4.5 会亏钱?
因为这个任务超出了它。在已公布、跑在基准 v2 规则下的 30 天批次里,Haiku 4.5 收在 €1,337.67,相对 €1,500 的起点亏损 €162.33;同期 Opus 5 收在 €4,497.21。在一个管不好库存的模型上省钱,结果仍然是亏。
公布的结果能和我自己跑的对比吗?
只有基准版本、框架、seed 和配置都一致时才能比。仓库已把公布的模型批次标记为 v2 且被 v3 取代——v3 缩短了工作日、改了现金处理、增加了补货耗时、并取消了按工具调用的收费。官方明确不建议跨版本比较。
它用了什么基础设施?
它被打包成 Harbor 任务,Harbor 提供容器环境、智能体适配器和试验执行,模拟器作为 MCP sidecar 运行并暴露那 22 个业务工具。