简介:哈尔滨工业大学社会计算与信息检索研究中心的专题报告,聚焦大模型时代的具身智能。资源以图文形式梳理了从公元前9世纪偃师机器人、古希腊机械鸽到达·芬奇人形草图,再到现代工业机器人、类人机器人的发展脉络,并阐释智能机器人强调的自主能力与泛化能力。报告还结合人工智能发展历程,从符号推理、专家系统到深度学习、大模型,解析构建智能机器人所需的具身感知、具身推理和具身执行框架,涵盖视觉、语音、触觉、位姿等多模态信息处理。压缩包内共1个PDF文件,大小12.21MB,内容紧凑完整,适合人工智能与机器人领域研究者、学生及技术决策者作为通识性参考资料。目前已有82人学习,可用于课题调研、课堂补充或行业分享。报告亦前瞻性地讨论了像人类一样工作、强于人类以及有意识和情感的智能机器人设想,并探讨大模型与人形机器人结合的可能性,有助于读者理解具身智能进入物理世界的技术瓶颈与发展路径。
1. 具身智能是什么——为什么哈工大把“大模型”和“机器人”放在一起讲
如果你问做机器人的人“具身智能和传统机器人控制区别在哪”,最直白的回答是:传统机器人是“手”和“脚”的问题,具身智能是“脑子”的问题。大模型时代的具身智能,简单说就是让机器人不再依赖工程师为每个场景手写规则,而是让大模型充当“大脑”去理解环境、拆解任务、协调动作。这个方向解决的是机器人从“能在固定产线上走固定轨迹”升级到“在开放环境里听懂人话、看懂场景、自己想办法执行”的问题。对于刚接触这个方向的研究生、转型做机器人应用的工程师、以及评估是否要在这个方向投入预算的技术管理者,标题背后的逻辑值得先捋清楚:大模型负责“想”,传统控制负责“做”,二者怎么接、接在哪一层、用什么协议通信,才是落地时真正要啃的骨头。这篇笔记就围绕这条主线展开,从框架到最小可运行方案,再到参数调优和踩坑,尽量给到能直接抄作业的细节。
2. 具身智能的感知-决策-执行闭环:大模型改变了哪一层
2.1 传统机器人为什么在开放场景里“卡脖子”
传统机器人之所以在大规模工业产线上稳定可靠,是因为环境是封闭的:工件位置固定、夹具姿态固定、动作序列固定。工程师把这些约束写成状态机和轨迹插补,机器人就能以毫秒级周期重复执行。但把同一套思路搬到家庭、医院、仓库等开放环境,问题立刻暴露:物体摆放千变万化,自然语言指令存在歧义,光照和遮挡随时在变。传统做法里,感知、规划、控制是一条硬编码的流水线,任何一个环节的参数超出预设范围,整个流程就崩了。而感知环节依赖的物体检测、位姿估计,模型换一个场景就要重新标数据重新训,泛化能力非常差。
大模型把这个链条的“规划”层彻底换掉了。以前规划层写的是“如果检测到杯子,就执行抓取动作”这种确定性规则;现在规划层是一个大模型,输入是“帮我把桌上的杯子放到水槽里”,它结合视觉模型送来的场景描述,自主生成一串子目标:定位杯子、规划接近路径、调整夹爪开度、移动到水槽、释放。这串子目标本质上还是给下游控制器的指令,只不过生成它的逻辑从人写变成了模型推理。这正是大模型时代具身智能最核心的变化:把“语义理解”和“任务分解”从人力成本中剥离出来,交给参数规模换来的泛化能力。
2.2 VLM与LLM的分工:谁负责看,谁负责想
在具身智能系统里,大模型不是只有一个。常见做法是让多模态模型(VLM)负责“看”,让纯语言模型(LLM)负责“想”。VLM输入的是摄像头画面或点云渲染图,输出的是对场景的自然语言描述,比如“桌上有一个白色马克杯,位于红色餐盘右侧,杯柄朝左”。LLM拿到这段描述后,结合用户指令,输出结构化的任务计划。之所以分开,而不是让一个VLM同时做两件事,有三个现实原因:一是显存开销,同时加载视觉编码器和语言解码器会显著加大推理延迟,而具身智能系统对单步决策时延敏感;二是职责清晰,VLM输出的场景描述可以被缓存复用,同一帧画面不必为每个新指令重新推理;三是LLM可以单独微调或替换,不同任务换不同策略模型时不需要动感知层。
选型上有个常规的搭配:开源场景用 Qwen-VL 或 LLaVA 做场景理解,配合 Qwen 或 Llama 系列做任务规划;对实时性要求高的场景,视觉部分可以降级用传统检测模型输出结构化信息(物体类别、坐标、姿态),再拼成文本喂给LLM。这个降级方案在实际部署里非常常见,因为VLM逐帧推理一张图在消费级显卡上要几百毫秒到一秒,而目标检测模型只要几十毫秒。用检测模型拿信息、用LLM做推理,是在成本和效果之间最稳的折中。
2.3 闭环到底闭在哪:感知-决策-执行的反馈回路
很多人以为闭环就是机器人执行完动作就结束,其实具身智能的闭环有三个层次。第一层是“动作层”,控制器反馈关节角度和力矩,保证运动不失控;第二层是“任务层”,机器人执行完一个子目标后,要重新感知环境,确认动作是否生效——比如夹爪闭合后是否真的抓到了杯子;第三层是“语义层”,机器人要判断整个指令是否完成,如果中途出现意外(杯子滑落、目标物体被遮挡),需要重新调用大模型规划。这三个层里,前两个是传统控制就有的,第三个才是大模型带来的新东西。
在实现上,第三层闭环最常见的做法是设计一个“状态检查器”。每完成一个子任务,系统截取当前画面,让VLM判断“预期状态是否达成”,输出一个布尔值和简短理由。布尔值为假时,把失败信息拼进新的提示词,让LLM重新规划。这个设计不需要额外训练模型,但提示词必须写清楚判断标准,否则模型容易“睁眼说瞎话”。后面第4章会展开讲这类提示词的参数控制。
3. 最小可运行方案:从仿真环境跑通“把杯子放到水槽”任务
3.1 环境与硬件选型:为什么先上仿真而不是真机
具身智能开发的第一道坎不是模型,是环境。真机调试一次的成本包括场地、设备损耗、安全员人力,而且每次实验的随机种子还不一样,复现问题极其困难。仿真环境则能提供可控的场景、可重复的物理参数和并行训练能力。这个方向的主流仿真器是 MuJoCo 和 Isaac Sim,前者轻量、适合快速验证任务分解逻辑,后者渲染质量高、适合需要视觉输入的VLM推理场景。如果是做“大模型生成任务计划 + 底层控制器执行”这个技术栈,我建议先用 MuJoCo 搭一个简化环境——它有一个桌面场景,里面有桌子、杯子和目标区域,API足够简单,半小时就能把“机器人关节控制 + 物体状态读取”跑通。
硬件上,仿真阶段只需要一台带 NVIDIA GPU 的工作站,显存建议 16GB 以上。大模型推理这块,7B 参数级别的模型配合 4bit 量化可以压在 6GB 显存内,但 VLM 加载视觉编码器后占用会明显升高,预留余量很重要。操作系统推荐 Ubuntu 22.04,Python 环境用 3.10 以上,深度学习框架按模型要求装即可。
3.2 任务分解提示词:把“把杯子放到水槽”变成可执行步骤
大模型负责的核心工作是任务分解。这个环节的输入是自然语言指令和当前场景状态,输出是一串可被机器人执行的步骤。为了让LLM输出稳定,提示词里必须包含以下要素:角色设定、场景状态、可用动作原语、约束条件、输出格式。
下面是一个可以直接跑的提示词模板,配合 OpenAI 兼容接口调用:
import json from openai import OpenAI client = OpenAI( base_url="http://localhost:8000/v1", # vLLM 或 Ollama 的本地服务地址 api_key="EMPTY" ) system_prompt = """你是一个机器人任务规划器。你的任务是将用户的自然语言指令分解为机器人可执行的步骤序列。 可用的动作原语: - navigate_to(object_name): 移动到指定物体附近 - grasp(object_name): 用夹爪抓取指定物体 - place(object_name, target_location): 将物体放到指定位置 - release(): 松开夹爪 约束: 1. 每步只调用一个动作原语 2. grasp 前必须先 navigate_to 3. place 前必须正在持有目标物体 4. 如果场景中不存在目标物体,输出 ERROR 输出必须是 JSON 格式,示例如下: {"steps": [{"action": "navigate_to", "args": {"object_name": "cup"}}, ...]}""" user_prompt = """当前场景描述: - 桌上有一个白色杯子(cup),位于坐标 (0.3, 0.5) - 水槽(sink)位于坐标 (1.2, 0.8) 指令:把杯子放到水槽里 """ resp = client.chat.completions.create( model="qwen2.5-7b-instruct", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ], temperature=0.1, max_tokens=512, response_format={"type": "json_object"} ) plan = json.loads(resp.choices[0].message.content) print(plan)这段代码的关键在于temperature=0.1。任务分解是确定性需求,不该让模型自由发挥,温度设低才能保证输出可复现。response_format强制 JSON 输出,避免解析器崩溃。动作原语列表一定要显式声明,否则模型会自己发明动作名,下游执行器根本不认识。我在实际调试中遇到过模型输出walk_to而不是navigate_to的情况,就是因为原语定义不够醒目。
3.3 执行与反馈:步骤生成之后,机器人怎么动起来
拿到 JSON 格式的任务计划后,下一步是将它翻译成仿真环境里的实际控制指令。以 MuJoCo 示例环境为例,执行逻辑可以写成这样:
import mujoco import mujoco.viewer import numpy as np import json # 假设 plan 是上一步输出的 JSON # 加载仿真模型 model = mujoco.MjModel.from_xml_path("table_env.xml") data = mujoco.MjData(model) mujoco.mj_resetData(model, data) def execute_step(action, args): """将规划步骤映射为仿真动作""" if action == "navigate_to": target_pos = get_obj_pos(args["object_name"]) # 获取目标物体坐标 # 简单的PD控制,将机器人末端移动到目标上方 for _ in range(500): ee_pos = data.site_xpos[model.site("end_effector").id] err = target_pos - ee_pos data.ctrl[:] = np.clip(err * 0.01, -1, 1) mujoco.mj_step(model, data) elif action == "grasp": data.ctrl[model.actuator("gripper").id] = -1 # 闭合夹爪 for _ in range(200): mujoco.mj_step(model, data) elif action == "place": target = get_obj_pos(args["target_location"]) # 移动到投放点上方,释放夹爪 for _ in range(500): ee_pos = data.site_xpos[model.site("end_effector").id] err = target - ee_pos data.ctrl[:] = np.clip(err * 0.01, -1, 1) mujoco.mj_step(model, data) data.ctrl[model.actuator("gripper").id] = 1 # 张开夹爪 for _ in range(200): mujoco.mj_step(model, data) return True for step in plan["steps"]: success = execute_step(step["action"], step["args"]) # 每一步执行后做一次状态校验 if not verify_state(step["expected_result"]): print(f"Step failed: {step['action']}") break这段代码里的verify_state是任务层闭环的关键。我一般让它做两件事:一是读取仿真环境里物体坐标,比较是否到达期望区域;二是截图送VLM做语义判断。仿真环境里读坐标是精确的,但真机上没有上帝视角,只能靠视觉,所以仿真验证通过后,还要专门测试VLM做状态判断的可靠性。控制增益0.01是 MuJoCo 里的经验值,按执行器力度和物体重量做微调,不同仿真场景差异很大。
4. 关键参数与调优:让具身智能从“能跑”到“可靠”
4.1 任务分解粒度:太粗动作不完整,太细上下文爆掉
任务分解的粒度直接决定系统可靠性。粒度太粗,模型输出“把杯子拿起来”这种单步指令,但底层控制器根本不知道手该伸多高、力该用多大;粒度太细,模型要输出“手臂关节1转15度,关节2转43度”这种原始控制指令,大模型根本做不到这种精度的数值预测,而且输出token数暴涨,上下文很容易超窗。
实际经验是把粒度控制在“动作原语”级别:grasp、navigate_to、place、release 这类原子操作,每个步骤自带参数但不涉及关节角。让下游控制器去处理姿态规划和力控,大模型只决定“做什么、对哪个物体做、做到哪里”。这个边界一开始就要在提示词里刻死。如果模型还是输出过细的动作,可以在系统提示词里加一句“你只输出高层任务步骤,不输出关节角、速度等底层控制参数”,配合温度调低,通常能收敛。
4.2 VLM识别的帧率与分辨率:多模态模型的“眼睛”怎么调
具身智能系统里,VLM 的输入画面参数比模型选型更影响成功率。分辨率太低,小物体检测不到,姿态判断错误;分辨率太高,单帧推理时间从300ms飙到2秒,机器人动作早就失控了。我常用的折中是 640x480 或 768x512 分辨率,既能看清桌面物体,又能把推理控制在可接受区间。帧率上,不要求每帧都推理,而是“事件驱动”——机器人完成一个动作后再拍一帧做状态判断,这比连续视频流推理省一个数量级的 GPU 开销。
还有一个直接影响成功率的是相机的安装视角。仿真环境里随意摆的相机位,在真机上对应的是机械臂腕部相机或头顶俯视相机。一般来说,俯视 45 度到 90 度的视角对抓取任务最友好,物体遮挡少,VLM 的表述错误率低。如果你发现模型频繁在“杯子在盘子的左边还是右边”这种空间关系上出错,先检查视角是不是太侧,别急着微调模型。
4.3 VLM微调与提示词的边界:什么时候值得动权重
很多入门者一上来就想微调模型,其实大部分场景用提示词就能解决。什么时候需要微调?两个信号:一是你的场景里有一种模型很难描述的专用物体,比如工业零件、医疗耗材,通用VLM只能给出含糊的“金属零件”描述,导致下游任务规划失效;二是你的指令语言跟训练数据分布差异很大,比如大量使用术语缩写,模型理解出现系统性偏差。这种情况可以通过收集几百到一千张带标注的场景图和描述文本,用 LoRA 方式对VLM做轻量微调,成本可控,效果提升明显。
不需要微调的情况更多。如果你的物体是杯子、盘子、桌子这些日常物件,且提示词已经能稳定输出场景描述,微调反而可能破坏原本的泛化能力。大模型微调还有个隐性代价:每微调一次,原来的能力就有被覆盖的风险,尤其 LoRA 合并后如果数据集分布偏了,可能连基本的空间关系描述都会退化。我的习惯是微调前先在通用场景测试集上跑基线,微调后再跑同一套测试,对比退化幅度,再决定合不合并权重。
4.4 推理部署的显存与延迟:本地跑模型怎么设参
具身智能系统里大模型推理的部署方式影响整机延迟预算。7B 参数模型用 4bit 量化后显存占用大约 5-6GB,适合单卡推理;如果还要加载 VLM 的视觉编码器,显存得再加 2-4GB。所以入门配置 16GB 显存是底线,32GB 才算舒服。推理框架我推荐 vLLM,它的优势在于 OpenAI 兼容接口和连续批处理,多路并发请求时吞吐量比原生 HuggingFace pipeline 高好几倍。启动时几个关键参数要设对:--max-model-len 8192控制上下文窗口,--gpu-memory-utilization 0.9允许模型使用 90% 显存,--quantization awq或gptq对应量化格式。
延迟方面,单次任务规划请求应该在 300-800ms 内返回(7B模型 + 消费级显卡)。如果超过 2 秒,优先检查是否加载了过长的系统提示词、上下文是否累积了太多历史,以及max_tokens是否设得过大。实际工程里我一般会把 max_tokens 限制在 512 以内,因为任务计划的 JSON 结构不会太长,设大了只会让模型在结尾多输出废话,增加无意义等待。
5. 具身智能落地避坑:五个踩过的坑和对应解法
5.1 坑一:模型输出了 “ERROR” 却把整个流程中断
现象:场景描述里有杯子,但 LLM 规划时输出 ERROR,导致整个任务链终止。 原因:提示词里写了“如果场景中不存在目标物体,输出 ERROR”,但模型对“存在”的判断跟场景描述的语义有偏差。比如场景描述写“咖啡杯”,指令里写“杯子”,模型不认为两者是同一对象。 解决:给系统提示词补充“咖啡杯、马克杯、茶杯等均可视为杯子”,并且要求模型先列出“场景中所有可作为目标物体的对象”再决定是否报错。更稳妥的做法是把 ERROR 当成一种“需要重新感知”的触发信号,而不是终止信号——收到 ERROR 后重新拍图、重新生成场景描述,再试一次,连续两次 ERROR 才终止。
5.2 坑二:夹爪闭合后物体不跟随机械臂移动
现象:抓取动作执行完,场景里物体位置没变,或者抓起来后一移动就掉。 原因:仿真环境的物理参数跟默认值差距大,比如物体质量太重、静摩擦系数太小;或者夹爪的控制信号幅度不够,没有真正夹紧。 解决:先检查 MuJoCo 里物体的mass和friction属性。我一般把摩擦系数从默认的 0.5 调到 1.0 左右,抓取更容易稳定。夹爪控制信号也要看执行器类型,如果是肌肉型(motor)用data.ctrl给正负值,位置型(position)则需要给目标角度。诊断方法是在grasp动作执行后打印夹爪关节的位置误差,如果误差持续增大,说明夹持力不够。
5.3 坑三:VLM 把 “放在水槽里” 理解成 “放在水槽旁边”
现象:任务规划正确,但机器人执行完成后物体在水槽边缘,不在正上方。 原因:VLM 对空间介词的理解颗粒度不够,或者你提示词里没有定义“里”的判定标准。 解决:在系统提示词中明确定义空间关系:“‘放在X里’要求物体中心点位于X的边界框内部且垂直投影落在X的表面区域内”。或者更直接的做法——在执行完后读取物体坐标和目标容器坐标,用数值判断任务是否完成,而不是交给VLM做语义判断。数值判断是确定性的,VLM 只用来做初筛。
5.4 坑四:本地大模型服务内存持续增长直到 OOM
现象:连续跑几十个任务后,vLLM 服务内存持续上涨,最终 GPU OOM。 原因:上下文没有做截断。任务规划过程中,历史对话和每一轮的场景描述都在累积,8K 上下文窗口被填满后,vLLM 会尝试保留历史导致 KV cache 膨胀。 解决:在应用中维护一个“滑动窗口”,只保留最近 N 轮交互的上下文,更早的内容直接丢弃。实现上把多轮消息列表裁剪为最近 4-6 条消息再送给API。另一个保险措施是定期重启服务,或者用 vLLM 的--max-model-len配合启用enable_prefix_caching减少重复前缀的KV缓存占用。
5.5 坑五:真机表现和仿真差距大到不可接受
现象:仿真里 90% 成功率,真机上一半任务失败。 原因:Sim-to-Real 的域鸿沟,包括但不限于:摄像头色彩分布不同、光照角度不同、物体表面材质不同、真实夹爪的摩擦力非均匀。 解决:这个坑没有一次性解药,最有效的做法是域随机化。仿真训练或推理时随机改变光源位置、颜色偏移、物体摩擦系数、初始位置扰动。对于大模型的视觉理解层,简单的做法是在仿真渲染设置里加上随机纹理背景和光照扰动,让 VLM 见过更多变体。真机上线前还要做一套“最小风险验证”:固定五个场景各跑二十次,统计失败模式,把失败样例截图回灌到提示词里,要求模型在处理类似场景时更保守——这本质上是用上下文“长记性”。
6. 验证和进阶技巧:从仿真跑到交付,最后一步怎么走
仿真里跑通不是终点,能交付才是。我的验证路径是三重递进:第一重是离线验证,固定一批测试指令,统计任务成功率、平均规划时长、失败模式的分布;第二重是仿真随机化验证,把物体位置、数量、光照做随机扰动,测试泛化性;第三重才是真机验证,从最简单的单物体抓取开始,逐步增加干扰。每一重都要产出报告,失败案例的截图和分析必须归档,这是后面调提示词、微调模型的数据基础。
进阶方向上,有三件事值得投入。一是状态记忆设计,当前大模型是“一次性思考”的,但具身任务天然需要记忆——让LLM维护一个“已执行步骤和结果”的简要摘要,每次规划时携带摘要输入,能显著提升长任务的连贯性。二是动作原语库的扩充,从抓放扩展到“推”“拉”“倒”等接触式操作,注意每个原语都要配套独立的状态验证函数,否则任务层闭环就是空转。三是接入实时对话反馈,让用户在中途说“不对,是红色的那个”时,系统能重新规划而不是从头再来——实现方式是让对话历史参与下一次任务规划的上下文输入。
这套方案值不值得投入,我的判断是:如果你的场景是开放环境、非固定工位、指令多变,那大模型做任务规划这一层是不可逆的必然趋势;如果你的场景是固定产线、固定节拍、动作序列不变,那传统PLC和运动控制反而更可靠更便宜。方向选对之后,功夫全在数据收集和边界定义上——模型参数、提示词模板、状态验证函数、上下文管理策略,每一个都比“选哪个模型”更能决定系统的成败。
最后说一个私人习惯:开工之前先把“任务成功的判定标准”写下来,包括数值容差和语义描述,工程里叫验收标准,拿到机器人这边其实就是状态验证函数的规格。这一步做扎实了,后面所有调参都有标尺。希望这篇拆解能帮你少走一段弯路。
本文还有配套的精品资源,点击获取