一个能在 ARC-Bench Web 赛道完整跑通的最小 agent:
打包 → 上传 → 解压 → 执行 → 生成 frontend/ 和 backend/ → 构建 → 启动后端 → 进入评测。
它不实现任何业务需求。它只做一件事:把链路打通,让你确认目录结构和打包方式没问题, 再去接真正的生成逻辑。
专治这个错:
web template is incomplete: expected frontend/ and backend/ directories
它不是说你的包坏了,也不是平台挂了。
平台执行完你的 agent 之后,会去工作目录根部找 frontend/ 和 backend/ 两个目录。
找不到就判定「模板不完整」,流程停在 Running agent,一个测试都不会跑。
最容易误判的一点是:日志里会同时出现
Generation agent finished successfully
web template is incomplete: expected frontend/ and backend/ directories
前一句是说「你的进程退出码是 0」,后一句是说「但你什么都没交付」。 agent 正常退出 ≠ 产物合格。
所以直接上传官方空模板一定会报这个错 —— 空模板本来就不生成应用。这是预期行为,不是 bug。
| # | 要求 | 不满足的后果 |
|---|---|---|
| 1 | 工作目录根部有 frontend/ 和 backend/ |
web template is incomplete,停在 Running agent |
| 2 | 进度写进 .arc/runner-events.jsonl 和 .arc/traceability/*.json |
节点进度条一直是空的 |
| 3 | 进程退出码 0 | 整个运行判失败 |
再往下,评测阶段会做这三件事,所以你的应用还得扛得住:
cd frontend && npm install && npm run build # 产出 frontend/dist
cd backend && npm install && PORT=<n> npm start
# 等端口连得上,然后用 Playwright 打这个端口跑测试两个推论,很多人栽在这里:
- 后端必须读
process.env.PORT,不能写死 3000。评测用的端口是平台指定的。 - 后端要把
../frontend/dist当静态目录服务出去。测试是访问页面,不是调 API; 前端单独起一个 dev server 是没用的,只有后端那个端口会被访问。
arcbench-web-minimal/
├── main.py # agent 入口,平台执行的就是它
├── arc_contract.py # 落盘契约的最小实现(零依赖)
├── requirements.txt # 平台会 pip install
├── app_template/ # 要交付的应用骨架
│ ├── frontend/
│ │ ├── package.json # build = 把 src/ 拷成 dist/
│ │ └── src/index.html
│ └── backend/
│ ├── package.json # start = node server.js
│ └── server.js # 读 PORT,服务 ../frontend/dist
├── sample_task/requirements.yaml # 本地自检用的需求样例
├── verify_local.py # 上传前的本地自检
├── pack.sh # 打包(自带层级校验)
└── README.md
app_template/frontend/package.json 和 backend/package.json 的形状,
是从一个真实跑到 34/34 全通过的运行里扒出来的,两个都零依赖:
零依赖是刻意的:npm install 拉不到包是这条链路上最常见的失败点。排除掉它,
出问题时你就知道一定是目录结构或入口的问题。
平台解压后,会在压缩包根部找 main.py。多套一层就找不到入口。
# ❌ 错:在上一级目录打包
cd ~
zip -r agent.zip arcbench-web-minimal/
# -> 包里是 arcbench-web-minimal/main.py 找不到入口
# ✅ 对:进到项目目录里再打包
cd ~/arcbench-web-minimal
zip -r agent.zip . -x '.git/*' -x '*/node_modules/*' -x '*/dist/*' -x '*.DS_Store'
# -> 包里是 main.py直接用脚本更省事,它打完会自己验一遍层级:
./pack.sh✅ main.py 在 zip 根部,层级正确
✅ app_template/frontend/package.json
✅ app_template/backend/server.js
✅ arc_contract.py
自己检查的话:
unzip -l agent.zip | head第一列文件名里应该直接看到 main.py,不是 某个目录/main.py。
macOS 的「压缩」右键菜单会把选中的文件夹整个装进去,等于上面那个错误示范。 用命令行,别用 Finder。
python3 verify_local.py它把平台会做的事在本机做一遍,18 项检查:
[1/4] 执行 agent main.py 退出码 0
[2/4] 校验目录结构与 SDK 落盘 frontend/ backend/ 在根部、七张表齐全、事件流合法
[3/4] 前端构建 npm install / npm run build / 产出 dist/index.html
[4/4] 后端启动 npm start 绑定 PORT、/api/health 返回 ok、首页可访问
平台上失败很贵 —— 一次运行几分钟起步,还占并发额度。先在本地过一遍。
如果这一步报
RemoteDisconnected而curl打同一个地址却正常: 那是你机器上的系统代理把127.0.0.1的请求也劫走了。verify_local.py里已经用ProxyHandler({})绕开了,不用改。
网页上传:Playground → Task bank → 选一道 web 任务 → 上传 agent.zip → Run。
命令行(需要浏览器登录后导出的 cookie):
# 1. 建 submission
curl -b cookies.txt -F requirement_id=ticketbooking -F runtime=python \
-F catalog=playground -F agent_source=upload \
-F display_name=minimal -F api_key=unused -F model=deepseek-v4-flash \
-F file=@agent.zip https://arc-bench.com/api/submissions
# 2. 建 run(拿上一步返回的 submission.id)
curl -b cookies.txt -F submission_id=<SUBMISSION_ID> -F requirement_id=ticketbooking \
https://arc-bench.com/api/runs
# 3. 启动
curl -b cookies.txt -X POST https://arc-bench.com/api/runs/<RUN_ID>/startapi_key 这个示例用不到(它不调模型),填占位串即可。接了真模型再换成你的 key。
跑通的标志是 start_agent 这一步变成 completed、run_tests 开始跑:
deploy_agent: completed
start_agent: completed ← 没有 web template is incomplete
run_tests: running ← Test progress 0/30
测试挂掉是正常的 —— 这个示例没实现 ticketbooking 的任何需求。 你要确认的是它进了评测,不是它得了几分。
改 main.py 里的 generate_app() 一个函数就行:
def generate_app(output_dir: Path) -> None:
# 换成你的模型调用 / 代码生成
# 唯一不能变的是落盘位置:
# output_dir/frontend/
# output_dir/backend/
# 必须在根部,不能套在 output_dir/<应用名>/ 下面main.py 里的 check_structure() 会在退出前自己查一遍,
顺手把「应用被生成到了 工作目录/<应用名>/frontend」这种套了一层的情况提到根部
—— 这是真实踩过的坑,agent 跑得好好的,就因为多了一层被判不合格。
如果你想用官方 SDK 而不是这里的 arc_contract.py:
把 requirements.txt 里的 arcbench-runtime 那行取消注释,
或者从官方 bundle 里 vendor 一份 arcbench_agent_runtime/ 目录。
落盘格式是一样的,换过去不用改 main.py 的调用方式。
| 症状 | 原因 | 怎么办 |
|---|---|---|
web template is incomplete: expected frontend/ and backend/ directories |
工作目录根部没有这两个目录 | 看 [check] 工作目录树 那段日志确认生成到哪去了;套了一层的话提到根部 |
| 传上去说找不到入口 | zip 多套了一层 | cd 进项目目录再 zip -r agent.zip .,或直接 ./pack.sh |
Generation agent finished successfully 但还是报模板不完整 |
退出码 0 不代表有产物 | 在 agent 退出前自己查一遍结构,别依赖平台报错 |
| 卡在等后端就绪,然后超时 | 后端端口写死了 | 改成 process.env.PORT |
| 后端起来了但测试全 404 | 后端没服务 ../frontend/dist |
前端必须由后端那个端口服务出去 |
npm install 失败 |
依赖拉不到 | 最小示例零依赖;自己的应用尽量少依赖 |
本地自检 RemoteDisconnected,curl 却正常 |
系统代理劫持了 127.0.0.1 |
请求时用 ProxyHandler({}) 关掉代理 |
| 节点进度条一直空着 | 没写 .arc/ 下的事件和表 |
看 arc_contract.py,七张表都要建出来,缺表比空表更糟 |
这个示例在平台上实跑过,不是纸上谈兵。任务用的就是最容易踩坑的那道
ticketbooking(Playground / Task bank,30 个测试)。
三个阶段全部 completed,平台日志原文:
deploy_agent: completed
Traceability initialized with 10 requirements and 30 scenarios
Environment preflight passed
start_agent: completed
Installing agent dependencies
Agent dependencies installed
Launching generation agent
Generation agent finished successfully ← 没有 web template is incomplete
run_tests: completed
Installing dependencies for frontend
Building template frontend
Template frontend built ← npm run build 成功
Installing dependencies for backend
Starting template application server
Template application server started (pid=132)
Template application is reachable on http://127.0.0.1:3000 ← 后端绑定端口成功
Generated application is reachable on http://127.0.0.1:3000
Test environment ready with 1 workers
Playwright results parsed: passed=0, failed=30, score=0.0
- 整个日志里 没有出现
template is incomplete,也没有expected frontend - 平台读到了 agent 写的 SDK 事件,6 个叶子节点的状态都更新了
- 最终
FAILED,0/30—— 这是预期的:示例没实现 ticketbooking 的任何需求。 要确认的是链路通了,不是分数。 - 本地自检:18 项全过
- 打包产物:18 KB,
main.py位于 zip 根部 - 消耗:这个 agent 不调模型,
token_count为空,没有计费
MIT