ASPIRE 源码解读:机器人如何编程、复盘失败并积累技能
机器人执行一段模型生成的程序并不难描述,难的是失败之后的过程:错误发生在哪里,哪次修改真正有效,一次成功又怎样成为后续任务可复用的经验?ASPIRE 围绕这些问题,将编码智能体、机器人执行接口、实验记录和文本技能库组织成一套工作流。
这里的“学习”主要改变程序和知识文件,并不等于更新大模型权重。编码智能体提出方案,执行层运行方案并留下证据,外层流程再决定是否修复、保留程序或晋升技能。
ASPIRE 适合作为机器人研发与任务学习的上层框架,但没有包办感知、运动控制和安全保证。 理解它的实现,需要分清任务推理与执行,也要区分仿真中的程序生成和真实机器人的 MCP 操作。
源码版本与验证范围
原始审查运行了 test_runtime.py、test_contracts.py、test_registry.py,结果为 45 passed in 0.13s。这是不连接机器人、不启动仿真或模型服务的单元测试子集。系统环境的 pytest 6.2.5、NumPy 1.21.5 低于仓库声明的 pytest ≥8、NumPy ≥1.26,因此只支持这个子集的局部结论。R1
仓库地图:推理工作流与执行后端
cap_harness 是 Python 包名,ASPIRE 是整套方法与工程的名称。
| 位置 | 实际职责 | 需要注意的边界 |
|---|---|---|
| .claude/skills/iterative-debugging/ | 任务分派、失败分析、程序修复、技能验证 | 很多决策由提示词指导编码智能体完成 |
| .claude/skills/evosearch/ | 多候选程序搜索与评估 | 搜索程序,不是这里的神经网络权重 |
| .codex/skills/ | Codex 工作流入口 | 指向上述规范流程,不是另一套算法 |
| .agents/skills/、AGENTS.md | 真实机器人操作规则和任务路由 | 与仿真实验管线不同 |
| src/cap_harness/contracts.py | 位姿、观测、动作、轨迹和结果契约 | 校验形状、坐标系、有限值与身份 |
| registry.py、runtime.py | 工具注册、程序执行、调用记录 | 隔开公开能力与宿主内部能力 |
| api.py、protocols.py | 公共 API、适配器和 provider 协议 | 隔开任务程序与具体机器人实现 |
| providers/ | SAM3、Contact-GraspNet、PyRoki、cuRobo 等后端 | 不同环境默认组合不同 |
| libero/、robosuite/、behavior/ | 仿真环境适配 | 转换原生动作、观测和评估语义 |
| yam_real/ | YAM 标定、相机、控制、通信和电机服务 | 是具体硬件栈,并非通用人形控制器 |
| agent/ | MCP、共享会话、job、可视化和固定程序 | 对外范围小于完整 Python API |
| run.py、artifacts.py、batch.py | 单次执行、证据记录、多 seed 调度 | 支撑复盘与实验比较 |
| validation/、tests/ | 评估、结构验证和回归测试 | 流程通过不等于物理任务成功 |
| configs/、scripts/、third_party/ | 环境锁定、启动和外部依赖 | 仿真器和底层算法并非全部自研 |
这些模块组成两个时间尺度不同的循环:
慢循环:任务 → 编码智能体 → 候选程序 → 实验 → 失败分析 → 修改程序
↑ ↓
└── 已验证文本技能 ← 独立复现 ← 经验提案
执行循环:程序/API → 感知 → 几何/抓取 → IK/规划 → 环境或机器人
└──── 调用轨迹、状态、图像、最终结果 ────┘
智能体提供假设和程序,执行引擎提供工具与证据。工作流仍由外部编码智能体执行,并非仅启动仓库就会自动完成全部研究。
程序生成:编码智能体究竟能写什么
编码智能体与策略程序的权限不同
编码智能体在开发环境里读文档、写 program.py 或 fix_code.py、运行评估命令。生成的程序进入 ProgramExecutor 后,获得的是工具注册表暴露的公开接口,而不是整个仿真器和宿主文件系统。R2
ProgramExecutor.execute_program() 的核心顺序是:解析 AST → 校验语法与访问方式 → 编译 → 注入受限 builtins、契约构造器和公开工具 → 执行 → 收集顶层 result、标准输出与调用记录。
当前实现允许无别名的 import math,拒绝其他导入及部分私有属性访问;返回数据经过公开化处理,不能把 benchmark 的 reward 或 success 接口直接交给策略。这样做既收窄执行面,也减少程序通过读取隐藏成功条件“作弊”的机会。
这里有一处文档漂移:README 仍写生成代码拥有 “full import access”,API 文档开头又笼统说不能导入模块,后文才列出 math 例外。当前行为应以 runtime.py 为准。 但限制导入不等于安全沙箱:程序仍在 Python 进程内 exec,源码明确要求对不可信代码另外做进程隔离。资源耗尽、宿主权限与外部编码智能体的文件访问,不能靠 AST 校验一并解决。R0
从任务程序到机器人动作
例如“把杯子放进容器”,程序通常组合以下能力:
- get_task_context() 确认任务,get_observation() 获取公开观测。
- segment_text() 用文字定位目标像素,或调用高层 localize_object()。
- mask_to_point_cloud() 利用深度和标定关系得到指定坐标系中的点云。
- estimate_geometry() 得到近似中心、方向和尺寸;需要时调用抓取生成器。
- solve_ik()、plan_motion() 或 move_to_pose() 求解并执行动作。
- 依据后续状态和图像判断是否抓住、搬到目标附近并释放;失败则调整策略。
这是接口组合示意,不是一段已经验证能抓任意杯子的完整程序。“局部化成功”“机械臂到达”“物体抓住”是三个不同命题。R4
数据契约拦截坐标与身份错误
Pose 携带位置、四元数和 frame;四元数顺序是 wxyz。Trajectory 除关节数组和时间步长外,还带 joint names、arm、embodiment、expected start 等信息。API 会拒绝错误机器人身份和不再匹配当前状态的轨迹起点。R5
这些约束不替代控制器,但能阻止常见工程错误:把世界系位置当基座系位置、把右臂轨迹发给左臂、把过期轨迹从新姿态强行执行。这些约束让错误显式失败,避免执行器在错误的坐标、机器人身份或起始状态下继续动作。
任务执行:adapter 与 provider 如何分工
EnvironmentAdapter 定义 reset、观测、机器人状态、step、轨迹执行、夹爪和 close 等生命周期。Provider 协议分别承担分割、抓取、逆运动学和轨迹规划。R6
这两类接口解决的问题不同:adapter 翻译“机器人或仿真器如何执行”,provider 提供“这次动作怎样求解”。api.py 再把它们组合成任务级调用。
| 能力 | 当前常见实现 | 不能顺带推导出的能力 |
|---|---|---|
| 文字分割 | SAM3 | 高速小球实时追踪 |
| 抓取候选 | Contact-GraspNet | 球拍撞击速度规划 |
| IK | PyRoki、cuRobo;YAM 路径使用 Mink | 全身动态平衡 |
| 轨迹规划 | 插值、cuRobo 及集成规划 | 任意动态场景的硬实时避障保证 |
| 环境执行 | LIBERO、Robosuite、BEHAVIOR、YAM adapter | 任意硬件即插即用 |
不同环境的默认后端不能直接混用。LIBERO/Robosuite 的常用默认组合是 PyRoki IK 与插值;BEHAVIOR 使用 cuRobo;实机 YAM 手册给出 Mink 与 cuRobo。请求不可用的 backend 会显式失败,系统并不保证自动切换后端后成功。R4
同样,move_to_joints() 和 go_home() 是直接伺服操作,不等于所有调用都经过碰撞规划。共享 API 提供了统一表达方式,没有抹平各个动作的安全语义。
失败复盘:一次运行会留下哪些证据
若失败只返回 False,智能体很难判断该改哪里。ASPIRE 为每次运行建立独立目录,保存实际执行的代码、工具调用和视觉证据。R7
| 产物 | 回答的问题 |
|---|---|
| run.json | 哪个任务、seed、环境和采集配置?运行是否已结束? |
| source/ | 当时究竟执行哪份程序?来源是什么? |
| trace/ | 哪个工具或 provider 出错?输入、输出、耗时是什么? |
| episode/ | 每一步发送什么动作,机器人状态如何变化? |
| media/videos/ | 整段行为发生了什么? |
| media/keyframes/ | 动作前后的关键视觉变化是什么? |
| media/overlays/ | 分割是否选错对象? |
| outcome.json | 程序执行、任务结果、终止原因分别是什么? |
| manifest.json | 最终文件及大小、哈希是否对应? |
大型数组按内容去重,JSON 引用 payload;写入过程有原子 JSON 替换、增量 JSONL 和未完成视频标记。记录器也划分 provider、adapter step、视频编码等耗时,避免把所有延迟都归给模型。
不过,记录器没有保存全部传感器原始数据。默认点云产物保留 frame、点数等元数据,并不保存完整 XYZ/RGB;分割保留覆盖图等信息而非所有原始 mask。基准视频也有固定采样率。要重建高速球碰撞过程,必须另加高频记录,不能指望这些默认文件足够。
结果记录还区分了程序成功与任务成功。函数正常返回,不代表物体放对;机器人到达姿态,也不代表抓住物体。隐藏 benchmark 评估由宿主侧完成,策略执行期间不能直接读奖励或成功谓词,最终汇总再交给外层实验流程。
在真实场景,没有仿真器提供的完美标签。智能体必须依据物体关系和视觉证据判断结果。遮挡只能说明“不确定”,不能当作失败或成功;动作工具的 ok 也不能替代物理验证。R8
程序修复:fix loop 与候选搜索
单程序 fix loop
桌面任务的迭代流程是:观察初始场景,生成初版;在全部 development seeds 上运行;按失败模式分组;修改程序;重新跑开发集;选定整体表现最好的版本,再做隔离评估。R9
按失败模式组织,比逐 seed 打补丁更合理。例如“错分杯子”“抓取姿态不适合把手”“运输路径撞到障碍物”对应三个可检验假设。把某个 seed 的坐标硬编码进去,可能提高开发分数,却不是可迁移的修复。
| 协议 | Development | Unseen check | Held-out |
|---|---|---|---|
| LIBERO-Pro fix loop | 51–65 | 66–80 | 1–50 |
| Robosuite fix loop | 101–125 | 126–130 | 1–100 |
Robosuite 初始化需要显式传入相应分区,不能沿用 LIBERO 默认值。Unseen check 对选定程序只测一次,不据此继续修复;held-out 由 coordinator 执行。验证脚本用程序哈希、任务、seed、初始化模式和采集设置组成运行身份,避免混合不同程序的结果。R10
但 immutable 也有边界:该脚本的 build_identity() 不包含完整依赖与 provider 环境指纹。环境变动后的续跑,仍需额外冻结环境,不能仅凭运行 ID 宣称完全同条件。
Evolutionary Search:保留不同的解题路线
当单一路线陷入局部解,evosearch 同时生成 K=8 个候选。已有 fix_code.py 时把它保留为 candidate_A,再探索不同抓取、路径或接触策略。每轮在相同开发 seeds 上比较,依据表现与 trace 保留优秀方案,并从 top-3 survivors 生成新候选。R11
当前模板写明:开发集最好成绩达到 80%,或完成 5 轮时停止。对 LIBERO 模板而言,一轮是 8×15=120 次 candidate-seed 评估;五轮最多 600 次,再加最终 held-out。这个算式是协议预算,不是实际已执行次数,也不包含额外诊断和重试。
它与梯度下降不同:变异由编码模型提出,选择依赖实验结果,遗传材料是程序和思路。它可能找到结构不同的解法,但大量候选也会放大开发集过拟合和模型调用成本。
当前 evosearch 模板固定写了 51–65、1–50 和 seeded,不能把这套表当作所有 benchmark 的统一协议。
BEHAVIOR:验证冻结知识能否帮助新智能体
BEHAVIOR 分支采用另一种实验:每个 seed 从空策略开始,逐块增加代码,每次都从 reset 重跑整个程序。Stage 1 使用 26–35 学习;Stage 2 使用 1–25,每个 seed 由新智能体在冻结技能库下重新写策略。R12
因此它测的是“冻结知识能不能帮助新的智能体解决新场景”,不是“一个固定程序在新场景是否成功”。其评分区分 final-policy success 与 navigation,不把所有探索尝试算成最终策略的可靠性。把这些结果与固定程序成功率直接并表,会丢掉重要实验条件。
技能沉淀:经验如何通过独立复现
共享机器人知识集中在 localize.md、grasp.md、transport.md、manipulation.md 等 Markdown 文件。条目提供触发条件、控制经验、代码片段和来源,未来智能体把它们读入上下文。R13
文本库是可审查的外部知识,任务程序是执行产物;两者都能版本控制并单独验证。更新这些文件与训练新 policy checkpoint 是不同的过程。
发现者:skill_report.json 提出修改或新技能
↓
验证者:只看原有库与提案,不看发现者答案,重新解决同一任务
↓
协调者:只晋升 verified 提案,并维护来源与适用条件
发现者还要评价读过的条目:useful、misleading、wrong、not-applicable。如果条目经常误导,就应修订内容或收窄触发条件,而不是只给技能库不断加页数。
验证模板规定最多两个程序版本、五个 seeds 至少四个成功。这里验证的是知识能否通过文字传递,不等于知识已经跨任务泛化。同任务复现通过后,还要看其他任务是否真正获益。
验证者“不能偷看答案”主要由提示词约束,文件在同一可访问工作区中,并非操作系统级隔离。严格实验应使用独立工作区和访问控制,让不可见成为真实边界,而不是依赖遵守约定。R14
真实机器人 System 2:MCP 的能力与边界
编码智能体 → MCP → LiveAgentSession → CapApi
→ LiveYamAdapter → RuntimeControl → YamRealAdapter
→ RealYamEnv → 轨迹流 → arm server → CAN/电机
MCP 直接暴露状态、局部化、关节/位姿/同步运动、夹爪等有限接口。程序目录当前只有 observe 和 go_home 两个固定程序,服务端加载并计算哈希;远程调用者不能随意传源码或文件路径。R15
内部 LiveAgentSession 有程序执行能力,不代表 MCP 已把它作为任意代码执行服务公开。仿真中“智能体写完整控制程序”的叙述,不能无条件套到实机网络接口上。
任务执行使用 job 和后台线程;当前 MCP 动作桥接会等待终态结果再返回,并附带观察证据。因此,不能将所有动作调用都理解为只返回异步回执。会话在动作执行期间允许观察,但拒绝第二个动作;这是串行所有权管理,不是实时轨迹抢占机制。R16
已实现的运动门禁
- 服务端默认 allow_motion=False,运动需显式开启。
- 参数、机器人身份和规划起点校验。
- 会话内动作串行化。
- 轨迹结束后的测量残差检查。
- Home 返回 home_verified、关节残差和夹爪状态。
只启动服务器不会 Home;motion-enabled agent 的启动协议另有 Home 行为。Home 会打开夹爪,因此不能把它当成无副作用的“准备好了”。R17
配置字段不等于运行时保证
YAM adapter 自己把运动许可称为客户端安全联锁,不是整台机器不可绕过的功能安全系统。当前参考配置中有 rpc_timeout_s、max_tracking_error_rad、max_joint_velocity_rad_s 等字段,但在所查执行路径中未发现对应运行时消费;不能把配置文件里的数字当成已经生效的安全证明。
轨迹末端测量检查采用硬编码的 0.10 rad 阈值,adapter 在轨迹后设置 1 秒 settling。它验证“执行结束后是否接近终点”,不验证整段运动是否始终满足速度、加速度、碰撞或任务接触条件。R18
参考配置的高层控制、命令流、底层保持分别是 30、60、100 Hz。执行循环使用 Python 时间函数与 sleep,不能由这些频率推导出硬实时保证。底层保持频率更高,也不会让上层模型推理自动变成高频闭环。
协议中的三处不一致
导入权限的描述需要统一
README 的 full import、API 开头的 no imports、运行时的 math-only 应统一,并说明“接口限制”和“安全隔离”不是一回事。
技能验证的 seeds 存在漂移
总入口要求 verifier 使用对应开发分区的前几个 seeds;具体 verifier 模板仍固定 51–55。对 Robosuite 来说,这落在 1–100 held-out 内。若直接照抄,可能污染评估。应从 campaign 配置派生,而不是手填在模板里。R9
Worker 与 coordinator 的停止预算不一致
Worker 模板给出每个失败模式最多三版、总共八版的约束;coordinator 又要求首个 development seed 成功前继续,只要诊断有进展就不设尝试次数。两个规范对“何时交回失败结果”并不完全一致,正式实验前应确定唯一的预算与升级条件。R19
这些规则中相当一部分存在于 Markdown 提示词,而非强制执行的状态机。它使框架灵活,也让协议审查成为工程工作的一部分。
结语:值得迁移的是实验方法
ASPIRE 把程序、动作、图像和 provider trace 放在同一实验身份下保存,让修复有证据可查,不必完全依赖聊天记忆。技能也有了来源和触发条件,可以检查、修订或退回;独立复现虽不能证明泛化,仍比发现者自行宣布成功更有说服力。
统一工具接口降低了替换执行后端的成本,但坐标、时间、动作和成功条件仍需针对新机器人重新定义。机械臂抓取的经验库不能直接成为乒乓球击球控制器。更合适的迁移方式,是保留专业控制器及其安全边界,把 ASPIRE 用在实验组织、程序修复和知识管理上。
下篇文章将沿着这一边界,分析它接入现有 A3 乒乓球系统的条件。
参考与源码索引
R0–R19 指向审查时的固定提交。项目页面的演示和性能声明用于理解项目作者的目标,不属于原始审查的实测结果。
- 项目与环境:README、依赖声明。
- 程序执行:运行时、工具注册表、API 参考。
- 接口契约:数据类型、adapter/provider 协议。
- 运行证据:产物记录、真实机器人操作规则。
- 迭代调试:fix loop、验证运行身份、候选搜索、BEHAVIOR 流程。
- 技能管理:知识库入口、独立验证模板。
- 实机服务:固定程序目录、MCP 动作桥接、启动协议、轨迹终点检查。
- 调试预算:Worker 停止条件;coordinator 规则见补充定位。
补充定位: