Files
HexTrails/labs/bench/AGENT.md
T
cabinwandClaude Opus 5 c760c23fd1 feat(bench): agent bench session core and CLI
Let any agent with a shell play a level the way a person does: look at the
board, decide what to tap or which way to turn, read the feedback, decide
again. Every step carries the agent's own reason, so a human can watch and
judge the level from how it was played.

observe() returns what the eye sees — each piece's drawn route, which cells it
crosses, who is sitting on it, and who it brushes past — never "which pieces
can leave". act() goes through the real Game rules; metrics() scores the run
afterwards with the solver.

Pieces are wide, so a route with nobody standing on it can still be blocked by
a neighbour the curve hugs. That is invisible in a cell listing, so every
obstacle is reported, on-route and grazing alike: reporting only the leading
one hid the rest, and in 113 of 581 such cases clearing the blocker sprang a
collision the agent had never been shown.

AGENT.md is the single file an agent reads — rules, board reading, commands,
rating scale, worked example.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 14:00:33 +08:00

9.5 KiB
Raw Blame History

给 Agent:来玩一关 HEX TRAILS

你现在是一名玩家,不是程序员。 读完这个文件就直接开始,不需要再读任何别的文档。

你要像人一样玩一关六角轨道解谜:看盘、决定点哪枚或转哪边、看反馈、再决定。有人会在网页上实时看着你操作,所以每一步都要写清楚你为什么这么做。

禁止:读 src/ 下的任何文件、读 levels.json、读 runs/ 里的存档、调用求解器、写脚本或循环批量执行、修改任何文件。 你和棋盘之间只有 node scripts/bench.mjs 这一个命令——你知道的必须全部来自它打印给你的东西。绕过它就等于作弊,这一局的数据也就废了。


第一步:开一局

node scripts/bench.mjs start --model=<你的模型> --agent="<你的运行环境 · 模式>" --level=1 --persona=tapper --no-rules

请如实报告你自己是谁——观察页会把这两项显示在棋盘正上方,人类靠它知道现在是谁在玩:

  • --model:你的模型标识符,例如 claude-opus-5、grok-4.6、deepseek-flash、gpt-5。不确定就写最接近的。
  • --agent:你运行在哪、开了什么模式,一句话,例如 Claude Code · ultracode、Grok Build CLI、Codex · high reasoning、dsh web。包含任何你认为影响自己表现的配置(推理强度、是否联网、是否有思考预算)。不知道就写 harness 名字。
  • --level:关号,不指定就是第 1 关。node scripts/bench.mjs list 可以看有哪些关。
  • --persona:tapper(试错型,默认)/ reader(读盘型)/ turner(转盘型)/ novice(新手)。按这个风格玩。

命令会打印两样东西,都要留意:

  1. 局名(形如 grok-4.6-L1-tapper)——后面每一条命令都要带 --run=<那个局名>,原样抄,别自己改。
  2. 观察页地址——把那一行原样转告人类,他们能实时看你玩。

规则(30 秒)

  • 棋盘上画着轨道。点一枚棋子,它沿自己箭头所指的那条轨道一路走,直到走出棋盘边缘——这就是离场。
  • 路上撞到别的棋子就退回原位,什么都不扣。棋子有宽度,擦到紧挨着的棋子也算撞。
  • 旋转底盘:整块棋盘连轨道转 60°,棋子的位置和箭头不动——所以每枚棋子接上的是另一条轨道,所有路线全变。左右转免费、可撤销,转 6 次回到原样。
  • 目标:让所有棋子离场。没有失败——移走一枚棋子只会让别的路更通,不会把谁困住,所以不存在"点错一步就死"。有步数预算(默认 80 步)。

你会看到什么

最重要的是这一段——每枚棋子当前的路线,就是人眼在屏幕上看到的那条线:

每枚棋子当前的路线(箭头出发 → 依次经过的格 → 出界/闭环;[tX] = 那格上压着棋子 tX):
  t5 @ -2,4 ↙:就在边上,直接出界(0 格)· 路上没有棋子
  t0 @ 4,-4 ↖:3,-4 → 2,-4[t9] → 1,-3 → 0,-3 → 出界(4 格 · 1 弯)· 路上有 t9
  t2 @ 0,-2 ↙:-1,-1 → -2,0 → -3,1 → -4,2 → 出界(4 格 · 0 弯)· 路上没有棋子,但紧贴 t7(会擦到)
  t1 @ 3,-1 ↓:3,0[t6] → 2,1 → 1,2 → 出界(3 格 · 1 弯)· 路上有 t6,另外紧贴 t4(会擦到)
  t3 @ 2,2 ↗:3,1 → 3,0 → 2,1 → 2,2 → 闭环(4 格 · 2 弯)· 路上没有棋子
你看到 意味着
→ 出界 · 路上没有棋子 点它就能走
2,-4[t9] … 路上有 t9 被 t9 压着,先让 t9 走
但紧贴 t7(会擦到) 棋子有宽度,线从 t7 身边擦过去,点了会被挡;同样先让 t7 走
路上有 t6,另外紧贴 t4 两个都挡着,t6 和 t4 都清掉这枚才能走
→ 闭环 这条轨道绕回来了,当前朝向出不去,只有旋转能改变它

坐标 q,r 只是格子的名字,不需要做坐标运算。

这一行把挡住它的棋子全部列全了——路上压着的和身边擦到的都在里面。要让这枚走,得把列出来的全部清掉;反过来,只要这一行说「路上没有棋子」且没有「紧贴」,点它就一定能走。

怎么玩得好

  1. 先点路上没有棋子、不紧贴谁、能出界的。
  2. 有 [tX] 或 紧贴 tX 的,先解决 tX;tX 也被挡就顺着往下找,先解最外层。
  3. 一枚都走不了(每条路都被压着/擦着、或都是闭环)→ 旋转。转完所有路线都变,必须重新看盘。
  4. 转一次没打开出口,不代表这一关无解。 有些关要转 2–3 次、甚至换个方向转,出口才出现。转到没见过的朝向去,别在同一个朝向反复点。
  5. 每一步都算预算。有把握再点,不确定就先看清楚。

第二步:反复出招

像人一样连点:看清一次盘面,就把有把握的几步用逗号一起提交,不要每点一枚重新读一遍。

node scripts/bench.mjs act --run=<局名> tap t4, tap t5, tap t8, rotate right --note="三枚路上没人,清完就转"
  • 一次最多 8 个动作。链会在第一个没成功的动作和任何一次旋转之后自动停下,并打印新盘面——所以不会闭眼连点到错的地方。
  • 动作:tap tX · rotate right / rotate left · undo · giveup 原因
  • --note 必填,一句话说明你为什么这么做。这是人类唯一能看到的你的想法。
  • 只想再看一次盘面:node scripts/bench.mjs observe --run=<局名>

如果你觉得这一关无解,不要硬撑,用 act --run=<局名> giveup 我认为无解,因为…… 说明你卡在哪、试过什么。诚实地放弃比勉强通关更有价值——我们正是要找出让人觉得无解的关卡。预算用完局也会自动结束,同样要评分。

命令报错了怎么办

报错 原因 怎么办
没有这局:X(先 start) --run 写错了 用 start 打印的那个局名,原样抄
无效:没有棋子 tX 棋子 id 记错,或它已经离场 先 observe 重新看一遍当前有哪些棋子
act 需要:tap ID | rotate … 动作写法不对 只有 tap tX / rotate left|right / undo / giveup 理由 四种
X 已存在 局名重复 不要自己指定 --run,让 start 自动生成

报错不扣步数,改对了重发就行。


第三步:评分(必做)

清盘、放弃或预算用完之后:

node scripts/bench.mjs rate --run=<局名> --json='{"clarity":4,"rotation":3,"stuck":2,"fun":3,"difficulty":3,"worst":"第 6 步点 t2 被 t7 擦碰挡住,路线上看不出来"}'
键 问题 1 3 5
clarity 路线看得清吗 完全看不清 大致能读 一眼看清
rotation 旋转有意义吗 随便转都行/没用 有点用 每次转都是关键决定
stuck 有没有觉得无解的时刻 从未 卡过一会儿 长时间以为无解
fun 好玩吗 无聊 还行 很好玩
difficulty 难度是否合适 太简单 刚刚好 太难
worst 最困惑的一步是第几步、为什么 一句话

注意 difficulty 是两头都不好:3 分是最佳,1 和 5 都是问题。

请诚实评分,尤其 rotation 和 stuck——我们正是要用这两项判断关卡好不好,一律给高分帮不上忙。

rate 会打印本局统计和回放链接。最后用两三句话向人类汇报:局名、状态(cleared / gave-up / budget)、步数、决策次数、最困惑的一步。


完整示例

$ node scripts/bench.mjs start --model=grok-4.6 --agent="Grok Build CLI" --level=1 --persona=tapper --no-rules
开始 grok-4.6-L1-tapper · 关卡 proto-d5-switchback-r4-s6 · 人设 tapper · 模型 grok-4.6 · Grok Build CLI · 预算 80 步
观察页(人类实时观看):http://localhost:4173/labs/bench/index.html?run=grok-4.6-L1-tapper&live=1
后续命令都用 --run=grok-4.6-L1-tapper
…盘面…

$ node scripts/bench.mjs act --run=grok-4.6-L1-tapper tap t4, tap t5, tap t8 --note="三枚路上没人也不紧贴谁"
点击 t4 → 离场(走了 1 格、0 个弯)
点击 t5 → 离场(走了 1 格、0 个弯)
点击 t8 → 离场(走了 3 格、1 个弯)
…新盘面…

$ node scripts/bench.mjs act --run=grok-4.6-L1-tapper rotate right --note="剩下的互相压着或闭环,一枚都走不了"
右转 → 底盘转到朝向 1,4 枚棋子的出口打开了
(旋转后盘面已变,后面的动作没有执行)
…新盘面…

$ node scripts/bench.mjs rate --run=grok-4.6-L1-tapper --json='{"clarity":4,"rotation":3,"stuck":1,"fun":3,"difficulty":3,"worst":"…"}'
本局:cleared · 15 步 · 4 次决策 · 空点 0(擦碰 0)· 旋转 3/3 · 耗时 82.3 s
回放:http://localhost:4173/labs/bench/index.html?run=grok-4.6-L1-tapper

其它命令(一般用不到)

命令 作用
node scripts/bench.mjs list 列出本组关卡
node scripts/bench.mjs status --run=X 回看自己走过的每一步
node scripts/bench.mjs metrics --run=X 本局指标
node scripts/bench.mjs open --run=X 起服务并打开观察页
--format=full 观察时额外打印每格的端口配对表(读长路线时才需要)
--set=<关卡文件> 换一组关卡;start 和 list 都支持

要玩多关就重复第一步到第三步,每关一个新局,--level 换成下一关。不要写循环一次跑完——一次一关,一次一个决定。