1. 项目概述:当大模型学会“动手”,SkillZero如何重塑具身智能
最近在具身智能的圈子里,SkillZero这个名字被讨论得挺多。简单来说,它不是一个单一的模型,而是一个由浙江大学团队提出的、用于训练机器人“技能”的通用框架。它的核心目标,是让大语言模型(LLM)或视觉语言模型(VLM)这类“大脑”,能够真正指挥机器人的“身体”去完成复杂的、需要多步骤操作的长周期任务。想象一下,你给机器人一个指令:“把客厅收拾干净,然后把脏衣服放进洗衣机,再启动它。” 这背后涉及识别物品、规划动作序列、处理过程中的不确定性(比如衣服卡住了),SkillZero要解决的就是这类问题。
传统的机器人任务规划,要么依赖于预先编写好的、极其死板的脚本,换个场景就失效;要么让模型直接生成每一步的底层控制指令(如关节角度),这就像让一个战略家去指挥每一个士兵如何迈腿,效率低下且容易出错。SkillZero的思路很巧妙:它引入了一个“技能库”的概念。这个技能库里的每一个“技能”,都是一个已经验证过的、可执行的原子动作或子任务模块,比如“移动到某位置”、“抓取某物体”、“按下按钮”。大模型不需要从零开始“发明”动作,它只需要像一个项目经理一样,根据当前环境和目标,从技能库中调用、组合并参数化这些已有的技能,形成可执行的计划。
这个项目之所以重要,是因为它试图弥合高层语义理解与底层物理控制之间那道巨大的鸿沟。它适合所有对机器人学、强化学习、大模型应用感兴趣的研究者和工程师,尤其是那些正在苦恼于如何让AI模型在真实物理世界中“落地”的团队。通过SkillZero,你可以更高效地将大模型的认知能力,转化为机器人实实在在的行动力。
2. 核心设计思路:分层抽象与技能复用的哲学
SkillZero的整体架构体现了一种经典而有效的工程思想:分层与抽象。它没有试图用一个“巨无霸”模型解决所有问题,而是将复杂的机器人任务分解为三个清晰的层级:任务规划层、技能调度层和技能执行层。这种设计背后的核心逻辑是“分而治之”,每一层只关注自己职责范围内的问题,通过清晰的接口进行协作。
2.1 三层架构解析:各司其职,协同工作
第一层是任务规划层。这一层通常由大语言模型(如GPT-4)或视觉语言模型担任“大脑”。它的输入是用户的自然语言指令(如“帮我泡杯茶”)和当前环境的观测(可能是文本描述或图像)。它的核心职责是进行高层任务分解和逻辑推理。例如,对于“泡茶”这个指令,LLM需要推理出所需的步骤序列:1. 找到水壶, 2. 找到茶杯, 3. 将水壶移动到水龙头下接水, 4. 将水壶放到加热底座上, 5. 等待水烧开, 6. 将热水倒入茶杯。这一层的输出是一个由高级语义动作组成的计划,它不关心机器人具体如何“找到”或“移动”。
第二层是技能调度层。这是SkillZero框架的核心创新所在。它维护着一个可扩展的“技能库”。技能库中的每个技能都是一个封装好的功能模块,例如NavigateTo(object)、PickUp(object)、Place(object, location)、Press(button)。技能调度层接收来自任务规划层的抽象计划,然后将其“实例化”。具体来说,它需要做两件事:一是为每个抽象步骤选择合适的技能(技能选择),二是为这个技能填充具体的参数(技能参数化)。比如,将“找到水壶”实例化为技能NavigateTo(kettle),并通过视觉模块识别出“kettle”在当前环境中的具体坐标(x, y, z),作为该技能的参数。这一层确保了计划的可行性,将语义映射到了可执行的代码接口。
第三层是技能执行层。这一层是机器人本体的控制核心,它接收来自技能调度层的具体技能调用指令(如PickUp(kettle, pose))。每个技能在底层都关联着一组控制器,可能是传统的运动规划算法(如MoveIt!),也可能是一个训练好的强化学习策略或模仿学习模型。这一层负责处理物理交互中的不确定性,比如抓取时的力控、避障等。技能执行成功后,会返回结果(成功/失败)和新的环境状态给上层,形成一个闭环。
注意:技能库的构建质量直接决定了整个系统的能力上限。一个常见的误区是试图一开始就构建一个庞大而复杂的技能库。在实际操作中,更有效的策略是从最基础、最通用的技能开始(如移动、抓取),然后根据任务需求,逐步抽象和添加更复杂的复合技能(如“拧开瓶盖”可能由“抓取瓶身”和“旋转手腕”两个基础技能组合而成)。
2.2 为什么是“Zero”?零样本泛化与组合泛化能力
项目名中的“Zero”点明了其另一个关键追求:零样本或少样本的泛化能力。这里的“零样本”并非指完全不需要数据,而是指系统能够处理训练时从未见过的新任务、新物体或新环境。
这种能力主要通过两种机制实现:
- 大模型的语义泛化能力:任务规划层的大模型本身具备强大的零样本推理和泛化能力。即使它从未在训练数据中见过“用紫色的马克杯泡花草茶”这个具体指令,它也能基于对“泡茶”一般流程的理解和对“紫色马克杯”、“花草茶”这些概念的理解,生成合理的任务分解。
- 技能的组合泛化能力:这是SkillZero框架的精华。系统不需要为“泡茶”、“煮咖啡”、“倒垃圾”每一个新任务都从头学习一套全新的动作。它只需要学会有限的原子技能(如移动、抓取、放置),并通过不同的顺序和参数进行组合,就能涌现出解决无数新任务的能力。就像用有限的乐高积木块,可以搭建出无限种造型。
这种设计极大地降低了机器人适应新场景的成本。你不需要为每一个新任务收集大量的演示数据或进行漫长的强化学习训练,只需要确保你的技能库覆盖了必要的原子操作,并有一个强大的“大脑”来进行规划和组合。
3. 核心组件深度拆解:技能库、规划器与执行引擎
要真正理解并复现SkillZero的思路,我们需要深入其三个核心组件的内部,看看它们具体是如何工作的,以及在实现时有哪些技术选型和实操要点。
3.1 技能库的设计与实现:从原子操作到宏技能
技能库是系统的基石。一个设计良好的技能库应该具备模块化、可复用、可扩展和鲁棒性强的特点。
技能的定义与接口标准化: 每个技能应该被定义为一个标准的类或函数,具有统一的调用接口。通常,一个技能接口至少包含以下部分:
- 前置条件:执行该技能前,环境必须满足的状态。例如,
PickUp(obj)的前置条件可能是obj.is_graspable and robot.is_near(obj)。 - 执行体:技能的具体实现代码,调用底层的控制器。这可以是一段运动规划代码、一个神经网络策略或一系列预定义的动作序列。
- 后置条件/效果:技能成功执行后,预期会改变的环境状态。例如,
PickUp(obj)的效果是robot.holding == obj。 - 参数空间:技能所需的参数及其类型。例如,
NavigateTo(target)的参数target可以是三维坐标、某个物体的ID或一个语义位置标签(如“厨房”)。
技能的类型与层级:
- 原子技能:最底层的、不可再分的基本操作,通常直接对应机器人的一个控制原语。例如:
MoveBase(x, y, theta),MoveArmToPose(pose),OpenGripper(),CloseGripper()。 - 复合技能/宏技能:由多个原子技能按特定逻辑组合而成,实现一个更复杂的功能。例如,
PickUpFromTable(obj)这个技能,内部可能依次调用了NavigateTo(near_obj),MoveArmToPreGraspPose(obj),OpenGripper(),MoveArmToGraspPose(obj),CloseGripper(),MoveArmToLiftPose()。将常用序列封装成宏技能,可以简化任务规划层的输出,提高系统可靠性。
实操要点:如何构建初始技能库?
- 从仿真环境开始:强烈建议先在PyBullet、MuJoCo或Isaac Sim这类物理仿真器中构建和测试技能。这比在真实机器人上调试安全、高效得多。
- 优先实现移动和抓取:对于移动机器人(如机械臂+移动底盘),
NavigateTo和PickAndPlace是两个最核心的技能。NavigateTo可以基于SLAM地图和路径规划器(如ROS中的move_base)实现。PickAndPlace则涉及物体检测、抓取位姿估计和运动规划。 - 利用模仿学习或强化学习训练技能:对于难以通过传统规划实现的技能(如拧瓶盖、叠衣服),可以收集人类演示数据,通过行为克隆或逆强化学习来训练一个策略网络,然后将该策略封装成一个技能。
- 为技能添加故障检测与恢复机制:这是保证鲁棒性的关键。例如,
PickUp技能在执行CloseGripper后,应通过力传感器或视觉检查是否成功抓取物体。如果失败,应触发恢复例程(如调整位姿重试),而不是简单地报告失败。
3.2 基于大模型的任务规划器:提示工程与上下文管理
任务规划层依赖于大模型的推理能力。这里的关键不是训练一个新模型,而是如何通过精巧的提示工程,引导现成的LLM(如GPT-4、Claude 3或开源的Llama 3)扮演好“规划师”的角色。
核心提示设计: 一个有效的规划提示通常包含以下几个部分:
- 系统角色设定:明确告诉模型“你是一个机器人任务规划专家”。
- 技能清单:将技能库中所有可用的技能名称、描述和参数格式清晰地列给模型。这是模型进行规划的依据。例如:
可用技能: - navigate_to(location: str): 移动机器人底座到指定语义位置(如‘厨房’,‘桌子旁’)。 - pick_up(object_name: str): 抓取指定名称的物体。物体必须在机械臂可触及范围内。 - place(object_name: str, location: str): 将抓取的物体放置到指定位置(如‘桌子’,‘架子’)。 - activate(device_name: str): 激活一个设备(如按下按钮、打开开关)。 - 环境上下文:以文本形式描述当前环境的初始状态。例如:“你看到一个房间。房间里有一张桌子,桌上有一个红色的苹果和一个空杯子。机器人在房间中央。”
- 任务指令:用户的自然语言请求。
- 输出格式约束:严格要求模型以指定的结构化格式(如JSON、或严格的步骤列表)输出规划结果。这对于后续的程序化解析至关重要。
示例提示与解析:
你是一个控制机器人的AI助手。你可以使用以下技能: [navigate_to, pick_up, place, activate] 当前环境:厨房。台面上有一个水壶、一个空茶杯和一个热水壶的加热底座。水壶在洗手池旁边。 任务:请泡一杯茶。 请生成一个分步计划,每一步只能调用一个上述技能,并明确参数。 输出格式: 1. 技能名(参数) 2. 技能名(参数) ...一个理想的模型输出可能是:
1. navigate_to(洗手池旁) 2. pick_up(水壶) 3. navigate_to(水龙头) # 这里假设有一个‘操作水龙头’的技能,或者需要更细分的技能 4. activate(水龙头) # 假设有该技能,用于接水 5. navigate_to(加热底座旁) 6. place(水壶, 加热底座上) 7. activate(加热底座) 8. navigate_to(台面) 9. pick_up(空茶杯) 10. navigate_to(加热底座旁) 11. place(空茶杯, 加热底座旁) # 等待水开,这里可能需要一个‘等待’技能或计时 12. pick_up(水壶) # 水开后 13. place(水壶, 茶杯上方) # 倒水,这里‘place’技能可能需要扩展含义或使用‘pour’技能这个例子也揭示了单纯依赖LLM规划的局限性:它可能缺失“等待水开”这样的隐性步骤,或者对“倒水”这种复杂动作缺乏合适的技能对应。这就需要技能调度层进行补全或修正。
上下文管理与状态跟踪: 规划不是一次性的。机器人每执行完一个技能,环境状态就会改变。因此,系统需要维护一个动态的“世界模型”,并在每次规划或重规划时,将最新的状态更新到提示词中。例如,执行完pick_up(水壶)后,新的环境描述应更新为:“机器人正抓握着水壶。加热底座是空的。茶杯在台面上。” 这可以通过一个状态管理模块来实现,它根据技能执行反馈的后置条件,自动更新环境的状态表示。
3.3 技能调度与参数绑定:连接语义与执行的桥梁
技能调度层是框架中最具工程挑战性的部分之一。它接收LLM生成的、可能模糊或不完整的语义计划,并将其转化为可执行的具体技能调用序列。这个过程主要解决两个问题:技能匹配和参数接地。
技能匹配: LLM输出的步骤描述(如“拿起水壶”)需要映射到技能库中具体的技能(如pick_up)。这可以通过以下方式实现:
- 关键字匹配:最简单的办法,在技能描述中定义关键词。例如,技能
pick_up的描述中包含“抓取”、“拿起”等关键词。 - 语义相似度计算:使用句子嵌入模型(如Sentence-BERT),计算步骤描述与所有技能描述之间的余弦相似度,选择相似度最高的技能。这种方法更灵活,能处理同义词和更复杂的描述。
- 基于规则的逻辑:对于一些特殊步骤,可能需要硬编码的规则。例如,如果步骤描述是“等待10秒”,而技能库中有
wait(seconds)技能,则直接映射。
参数接地: 这是将语义参数(如“水壶”、“桌子旁”)转化为具体、可测量的物理参数(如物体的6D位姿、坐标点)的过程。这是具身智能的核心难题。常见方法包括:
- 视觉感知模块:这是最主要的方式。使用物体检测模型(如YOLO、DETR)识别出“水壶”,并通过相机标定和深度信息,估计出其在机器人坐标系下的3D位置和姿态。对于“桌子旁”这类语义位置,可能需要预先在环境地图中标注一些兴趣点(POI),或者训练一个场景理解模型来预测合适的放置位置。
- 知识库查询:对于一些常识性参数,可以内置一个知识库。例如,对于“把牛奶放进冰箱”这个任务,知识库可以告诉系统冰箱门的典型高度和打开方式所需的力度。
- 交互式感知:有时需要主动探索来获取参数。例如,对于“打开最上面的抽屉”这个任务,机器人可能需要先移动到柜子前,用视觉识别出所有抽屉的把手位置,然后选择最高的那个。
错误处理与重规划: 技能调度层还必须具备容错能力。如果技能执行层返回失败(如抓取滑脱、路径规划失败),调度层不能直接崩溃。它需要:
- 分析失败原因:是参数错误(物体位置估计不准)?还是技能本身在当前环境下不可行(物体太重抓不起)?
- 尝试恢复:如果是参数问题,可以触发重新感知,更新物体位置后重试。如果是技能问题,可以尝试寻找替代技能(如用双手抓取代替单手抓取)。
- 触发重规划:如果恢复尝试多次失败,或者失败表明当前计划根本不可行,则需要将新的环境状态(包含失败信息)反馈给任务规划层,请求生成一个新的计划。
4. 系统集成与实操部署指南
将上述所有组件集成到一个稳定运行的系统中,并在真实机器人或高保真仿真中部署,是最终的挑战。这里我分享一个基于ROS(机器人操作系统)的典型集成方案和实操步骤。
4.1 软件架构与通信设计
一个典型的SkillZero风格系统,其软件节点和话题通信可能如下所示:
[用户接口] -> (自然语言指令) | v [任务规划节点 (LLM客户端)] | (发布:JSON格式的抽象计划) v [技能调度节点] | (订阅:抽象计划; 发布:具体技能目标) v [技能执行管理器] | | | v v v [导航技能节点] [抓放技能节点] [其他技能节点...] | | | v v v [机器人底层驱动/控制器]关键节点说明:
- 任务规划节点:一个Python脚本,负责与LLM API(如OpenAI API)交互,构建提示词,发送请求,解析返回的规划结果,并将其发布到
/abstract_plan话题。 - 技能调度节点:系统的核心。它订阅
/abstract_plan,进行技能匹配和参数接地。参数接地过程会调用视觉服务(如/detect_objects)来获取物体位姿。最终,它将具体的技能目标(如PickUpGoal(object_id=“kettle”, pose=...))通过动作服务器(Action Server)发送给对应的技能执行节点。 - 技能执行管理器:可以是一个简单的状态机,负责按顺序调用各个技能,并监控其执行状态(成功、失败、进行中)。
- 各个技能节点:每个技能都是一个独立的ROS节点或动作服务器。例如,
PickUpSkill节点会订阅/detected_objects话题,接收要抓取物体的ID和位姿,然后调用运动规划库(如MoveIt!)生成轨迹,并最终通过/arm_controller话题发送控制指令。
实操步骤:从零搭建一个演示系统
- 环境准备:安装Ubuntu和ROS(推荐Noetic或Humble版本)。在仿真环境中(如Gazebo)搭建一个简单的场景,包含一张桌子、几个不同形状的物体(方块、圆柱)和一个模拟的移动机械臂(如Fetch或Tiago)。
- 构建基础技能:
- 导航技能:利用ROS的
move_base框架,配置好SLAM(如gmapping)和定位(如AMCL)。你的NavigateTo技能节点接收一个目标位置(坐标或语义标签),然后调用move_base的动作接口。 - 抓取技能:这是难点。首先,你需要一个物体检测节点(可以使用现成的包如
darknet_ros或vision_msgs相关工具)。然后,为简单形状的物体(如方块)预定义几个抓取姿态。你的PickUp技能节点接收到物体位姿后,规划机械臂运动到预抓取点->打开手爪->运动到抓取点->闭合手爪->抬起的整个轨迹。可以使用MoveIt!来规划无碰撞轨迹。
- 导航技能:利用ROS的
- 实现技能调度器:
- 创建一个Python节点,订阅规划指令。
- 实现一个简单的技能映射字典:
{“拿起”: “pick_up”, “移动到”: “navigate_to”}。 - 实现参数接地:当规划指令是“拿起红色的方块”时,调度器需要调用物体检测服务,从所有检测到的物体中筛选出标签为“方块”且颜色特征为红色的那个,获取其3D位姿,然后填充到
PickUpGoal中。
- 集成大模型规划器:
- 使用
openai或anthropicPython库。 - 编写一个函数,将当前场景(可以简单描述为“桌子上有一个红色方块和一个蓝色圆柱”)和任务指令(“把红色方块放到桌子另一端”)构造成提示词,发送给LLM。
- 解析LLM返回的文本,提取出结构化的步骤列表。这里可能需要一些后处理,比如用正则表达式匹配
技能名(参数)的格式。
- 使用
- 联调测试:
- 首先在仿真中,用固定的简单计划测试技能链(如:导航到桌子前->抓取方块->放置到目标点)。
- 然后测试调度器,手动输入“拿起红色方块”,看它是否能正确触发抓取技能。
- 最后,接入LLM规划器,从一个简单的指令开始测试整个闭环。务必做好异常处理,比如LLM返回了无法解析的格式,或者调度器找不到对应的物体。
4.2 仿真与真实机器人部署的差异与挑战
在仿真中跑通流程只是第一步,部署到真实机器人会面临更多挑战:
感知差距:
- 仿真中的视觉感知是干净、完美的。真实环境中,光线变化、物体反光、遮挡、相机噪声都会严重影响检测和位姿估计的精度。解决方案:在真实数据上微调检测模型;使用多传感器融合(如RGB-D相机);在抓取等关键动作前,加入主动对准或接触感知来修正位姿。
控制差距:
- 仿真中的物理引擎是简化的,机器人关节可以精确到达指令位置。真实世界存在摩擦力、弹性、延迟和执行误差。解决方案:技能底层的控制器必须使用更鲁棒的控制算法,如阻抗控制、力位混合控制;对于抓取,使用基于力的抓取策略而非纯粹的位置控制。
技能泛化:
- 在仿真中训练的技能,到真实世界可能完全失效。解决方案:采用域随机化技术在仿真中训练技能,即随机化纹理、光照、物理参数等,让模型学会关注本质特征;或者使用Sim2Real技术,如系统辨识和自适应控制。
安全考量:
- 真实机器人一旦出错可能造成财产损失或人身伤害。解决方案:必须设置严格的安全监控层,如关节力矩限制、碰撞检测、急停按钮;任何技能执行前,在数字孪生(仿真环境)中进行一次快速预测性仿真,检查有无碰撞风险;采用“人在回路”模式,关键步骤需要人工确认。
5. 常见问题、调试技巧与未来展望
在实际开发和实验过程中,你会遇到各种各样的问题。下面我整理了一些典型问题及其排查思路,以及一些提升系统性能的进阶技巧。
5.1 典型问题排查清单
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| LLM规划结果不合理或无法解析 | 1. 提示词设计不佳。 2. LLM对技能库理解有误。 3. 输出格式不稳定。 | 1.优化提示:在提示词中提供更详细的技能描述和1-2个完美规划示例(Few-shot Learning)。 2.简化技能库:初期使用更少、更通用的技能,降低LLM选择难度。 3.后处理与重试:编写更鲁棒的解析代码,对无法解析的输出,可以提取关键信息重新构造查询,或直接请求LLM以指定JSON格式重输。 |
| 技能调度器匹配错误 | 1. 关键字匹配冲突或遗漏。 2. 语义相似度模型不准。 | 1.完善技能描述:为每个技能添加多个同义词和场景描述。 2.结合规则与模型:对关键技能(如 pick_up)使用规则确保匹配,对其他技能使用语义模型。3.引入上下文:匹配时考虑上一步技能的执行结果,例如上一步是 navigate_to(table),那么下一步“拿起”的对象很可能在桌子上。 |
| 参数接地失败(找不到物体) | 1. 物体检测模型漏检。 2. 语义标签与检测标签不匹配(如LLM说“杯子”,检测模型输出“mug”)。 3. 物体不在当前视野内。 | 1.提升感知:使用更大更准的检测模型;融合多帧检测结果。 2.建立标签映射表:维护一个从常见语义名称到检测模型输出标签的映射字典。 3.主动搜索:如果调度器在当前位置找不到目标物体,应触发一个“搜索”行为,例如控制机器人转动或移动到可能的位置。 |
| 技能执行频繁失败 | 1. 参数不准(位姿估计误差大)。 2. 技能本身策略不鲁棒。 3. 环境动态变化(如物体被碰倒)。 | 1.闭环执行:技能应具备在线调整能力。例如,抓取时使用视觉伺服,在接近物体时根据实时图像微调末端位姿。 2.增加重试机制:允许技能在失败后以略微不同的参数(如抓取位姿偏移一点)自动重试1-2次。 3.状态验证:技能执行后,立即通过传感器验证预期效果是否达成(如用手爪的触觉或摄像头看是否抓到了物体),未达成则视为失败。 |
| 任务执行效率低下 | 1. LLM规划速度慢。 2. 技能串行执行,等待时间长。 3. 不必要的重规划。 | 1.缓存与预测:对常见任务模板进行缓存。使用较小、较快的本地VLM处理简单规划。 2.并行技能探索:研究哪些技能可以并行执行(如移动底座的同时准备机械臂姿态)。 3.设置重规划阈值:非关键性失败(如一次抓取滑脱)不触发全局重规划,只进行局部恢复。 |
5.2 进阶优化与扩展方向
当基础系统运行稳定后,可以考虑以下方向进行深化:
技能学习与进化: 当前的技能库是静态的、人工定义的。更先进的思路是让系统能够自动学习新技能。例如,通过人类演示(示教学习),系统可以将一段连续的动作记录封装成一个新的宏技能,并自动推断其前置和后置条件,然后加入技能库供未来使用。这构成了一个自我扩展的生态系统。
分层强化学习: 将SkillZero框架与分层强化学习结合。高层(任务规划层)的LLM作为“元控制器”,负责提出子目标(即调用哪个技能)。中层(技能调度与执行)负责完成子目标,并将其结果(成功/失败、奖励)反馈给高层。高层LLM可以根据这些反馈来调整未来的规划策略,从而实现从交互中学习更优的任务分解方式。
多模态融合与场景理解: 让系统不仅听指令,还能“看”场景。使用强大的VLM(如GPT-4V)作为任务规划器,直接输入场景图像和指令,VLM可以生成更贴合当前视觉上下文的计划。同时,利用VLM的视觉推理能力,可以更好地完成参数接地,例如直接指出图像中“那个最左边的、半满的马克杯”。
长期任务与记忆: 对于需要长时间(数小时甚至数天)间断性执行的任务,机器人需要记忆。可以为系统添加一个外部记忆模块,记录已经执行过的动作、环境状态的变化、以及用户的偏好。当任务被打断后重新开始时,机器人可以查询记忆,恢复到之前的状态,而不是从头开始。
从我个人的实验经验来看,SkillZero这类框架最大的价值在于它提供了一种清晰、模块化的工程范式,让整合大模型与机器人控制变得有章可循。它不会解决所有问题,比如超精细的操作(穿针引线)依然需要专门研究的底层技能,但它极大地加速了在复杂语义任务上的原型开发和验证。在实际操作中,起步阶段切忌贪大求全,从一个有明确边界的简单场景(如“整理桌面上的三种物品”)开始,打通从语言到动作的完整链路,再逐步增加技能、复杂度和环境的不确定性,这样更容易获得正反馈并迭代出鲁棒的系统。