跳转到内容

正在加载搜索…

快速导览

两个真实的 episode,从第一次模型请求到结果:agent 1.4.1(1.4.2 只改变了由谁接手传送带任务;1.5.0 把这些运行的设置,即不用 Molmo2、不用世界模型,设为默认),使用 DeepSeek V4.1 Flash,在 RoboDojo 的评测包 0 上,遵循 XPolicyLab 契约(夹爪为指令值,不提供任务名,不报告步数上限)。第一个 episode 中,模型把任务交给学习型策略 Simate;第二个中,模型自己的程序完成任务。第一种是常见情况:在那次运行中(42 个任务,每个三个 layout),125 个 episode 中有 113 个被移交,平均每个 episode 2.3 次模型调用;程序自己完成的 12 个用了 16 次。

Driver模型DeepSeek V4.1 FlashKernel程序Worker仿真器 + 安全层学习型策略Simate循环 · 直到 finish(),或 episode 结束start("A" 或 "C"):任务交出去每个动作块否则:程序自己的 skill每个 skill 的每个控制 tickreset(task, layout)指令、状态、三路相机图像一段短程序运行它benchmark 的观测动作每个动作一个 tick,经过安全层tick(command):先过 guard,再过安全层状态、观测输出、事件、重新测量的场景输出、场景报告、勾出轮廓的图像收尾,然后取结果(模型看不到)
一个 episode,从 reset 到结果。任务要么整体交给学习型策略,要么由程序自己的 skill 完成;无论哪种,每条命令都经过安全层。

“Stack the three bowls together.”(stack_bowls,layout 0)

driver 发送系统提示词(RoboDojo 的 prompt pack,按 agent 的 skill 组装),然后发送一条用户消息:指令、机器人状态和三幅相机图像。决策原因是 start。模型在 28 s 内作答:

# PLAN: three white bowls to stack. Check policy list and locate bowls first.
print(list_policies())
obs = get_observation()
for o in locate("white bowl"):
print(o)

观察类操作可以在 start 之前运行;任何移动手臂的操作都不行。list_policies() 返回了 Simate 的描述(services/simate.toml 中的 client.description),说明它从起始姿态出发能做什么,按操作的种类划分,从不按任务名划分。摘录如下:

It cannot pick one object out of several by reading what identifies it: a name, a number or label
written on it, or a picture shown as the target. [...] Often does part and leaves the rest: packing
several objects into a box; stacking blocks in a pile or tower; [...] nesting bowls or cups; [...]

locate 用 SAM 3 在每个相机中测量了每只碗。循环打印的是 locate 返回的字典的键(objects、text),而不是物体本身,但每个程序结束后,driver 都会重新测量已定位的物体并发送场景报告:

o1 'white bowl' at (-0.275, -0.066, 0.805) (seen in cam_head and cam_left_wrist; SAM 3 match 0.98),
12 x 11 cm, long side at 83 deg, a container; reached straight down by the left arm; too wide for
the open jaws: pick takes it by an edge.
o2 'white bowl' at (0.044, -0.127, 0.785) (seen in cam_head only, so assumed 0.02 m above the table; ...
o3 'white bowl' at (0.248, -0.039, 0.804) (seen in cam_head and cam_right_wrist; SAM 3 match 0.98), ...

下一条消息带有输出、场景报告、每个物体的特写(用于核对每个物体确实是所指名的那个),以及勾勒出物体轮廓的相机图像。

# PLAN: three white bowls (o1 left, o2 center, o3 right) — task is nesting/stacking bowls.
# Policy lists "nesting bowls or cups" under "Often does part and leaves the rest" -> strategy C.
start("C", "stacking/nesting three bowls together")

start("C", ...) 记录这一选择并立即运行策略,与 RoboDojo 自己的评测客户端的做法相同:从未被动过的起始姿态出发,使用任务本身的指令和两只手臂,每个动作块完整执行,每个 tick 都取新的观测。(A:移交并监督,用于描述中说它通常能完成的种类;C:先交给策略,再完成它留下的部分;B:用程序自己的工具。)Simate 把碗叠好,在第 230 步 RoboDojo 的成功检查通过,并在程序内部结束了该 episode,此时距程序开始 173 s,因此之后没有模型调用:

{"reward": 1.0, "success": true, "terminated": true, "truncated": false, "process_score": 100.0, "steps": 230}
{"status": "episode_ended", "success": true, "steps": 230, "model_calls": 2, "verifier_calls": 0,
"cells": 2, "decisions": {"start": 1, "program_end": 1}, "input_tokens": 19874, "output_tokens": 428,
"cost_usd": 0.0025,
"strategy": {"strategy": "C", "kind": "stacking/nesting three bowls together", "policy": "simate",
"step": 0, "policy_ran": true}}

如果策略在任务未完成时停下(手臂静止 5 s),程序就会在那里结束,模型会看到重新测量的场景,并剩下 4 次调用(post_policy_calls)来处理明显剩下的部分;用完之后,策略继续运行到 episode 结束。

“Pick up the blue race toy car by 10 cm.”(general_pickup,layout 4)

# PLAN: Task = pick up the blue race toy car and lift it 10 cm. It is named in the
# instruction -> strategy B, my own tools. Step 1: start(B), locate the blue car.
start("B", "pick up the blue race toy car by 10 cm")
res = locate("blue toy car; blue race car")
print(res["text"])
for o in res["objects"]:
print(o["id"], o["name"], o["position"], "reach:", o["reach"], "jaws:", o["jaws"], "size:", o["length"], o["width"])

桌上还有其他物体;要拿哪一个需从指令中读出,因此提示词中的规则把任务交给 B。start("B", ...) 记录这一选择,不移动任何东西。SAM 3 匹配到相同像素的两个名称是同一个物体:

o1 'blue toy car' (also what 'blue race car' matched: the same pixels) at (0.255, -0.170, 0.790)
(seen in cam_head and cam_right_wrist; SAM 3 match 0.91), 10 x 6 cm, long side at -13 deg;
reached straight down by the right arm; the jaws close across its width.
r = pick("right_arm", "blue toy car", lift=0.10)
ValueError: No object 'blue toy car' in the scene; locate first (ids: o1)

工具接收的是场景报告中的 id。程序抛出了异常,kernel 把 traceback 裁剪到程序自己的栈帧,然后以原因 error 调用模型。

# PLAN: o1 blue car at (0.255,-0.170,0.790). Use id "o1". Right-arm pick, lift 0.10, then finish holding.
r = pick("right_arm", "o1", lift=0.10)
print(r)
print("holding:", holding("right_arm"))

pick 是一次接触,程序在它之后结束,以便模型查看。其中的每个 skill 调用都是一次以事件结束的有界执行:

执行 Tick 数 事件
move_eef(抓取点上方 6 cm,夹爪转到横跨小车的方向) 23 COMPLETED
move_eef x4(下降:快速到抓取点上方 3 cm,然后 2、1、0) 7, 9, 7, 9 COMPLETED
close_gripper、hold(夹紧 0.24 s) 10, 6 COMPLETED
move_eef(抬起 10 cm) 11 COMPLETED
{'ok': True, 'arm': 'right_arm', 'object': 'o1', 'grasp': 'across its width',
'grasp_point': [0.266, -0.1787, 0.7777], 'yaw_deg': 77.1, 'pitch_deg': 0.0, 'lift': 0.1,
'check': "'blue toy car' rose with the jaws (measured with SAM 3): held",
'note': 're-measured from above, the object was +11, -9 mm off; the grasp followed'}
holding: True

在抓取点上方,腕部相机重新测量了小车,抓取点随差值移动。契约不提供测得的夹爪开度,因此 pick 的检查测量物体是否随夹爪一起升起;只有无法测量时,视觉模型才会查看腕部相机,就像 holding() 那样。随后的场景报告显示小车(现在是 o2)被右臂抓着、高了 8 cm,并给出抓握情况:

Grip, right_arm holds o2 'blue race car': measured now in the air, the held object's centre is
(-0.007, +0.006) from the grasp point (on the table before the pick it was (+0.000, +0.000));
release applies this offset. Its lowest point hangs about 0.013 m below the grasp point.
# PLAN: Task = pick up the blue race toy car by 10 cm. Done: right_arm holds o2 'blue race car'
# lifted ~0.10 m (grasp point 0.778 -> now 0.871). Task is to lift it, so keep holding and finish.
print("holding right:", holding("right_arm"))
finish("Picked up the blue race toy car with the right arm and lifted it 10 cm (held in air).")

finish 结束了程序。driver 执行收尾,这是大多数 RoboDojo 任务需要的:每个没有抓着东西的夹爪张开(右夹爪抓着小车,保持闭合),然后两只手臂回到起始姿态。收尾期间 RoboDojo 在第 95 步因成功结束了该 episode。driver 用一个模型从不会看到的 token 读取结果:

{"reward": 1.0, "success": true, "terminated": true, "truncated": false, "process_score": 0.0, "steps": 95}
{"status": "finished", "success": true, "steps": 95, "model_calls": 4, "verifier_calls": 0,
"cells": 4, "decisions": {"start": 1, "program_end": 2, "error": 1}, "input_tokens": 43673,
"output_tokens": 1601, "cost_usd": 0.0029, "vision_calls": 2,
"strategy": {"strategy": "B", "kind": "pick up the blue race toy car by 10 cm", "policy": null, "step": 0}}

四次模型调用,四个短程序:观察、一个错误的参数、一次接触、结束。vision_calls 统计程序内部发出的视觉请求(两次 holding() 查看)。程序与决策点解释设计;episode 运行时解释每个部分。