一台自动售货机,比又一张对话排行榜更像样的智能体基准

·11 分钟阅读·Evergreen Tools Team

大多数智能体基准是问一个问题、判一个答案。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 个业务工具。