做自动化的人都有个执念:确定性。
在我的舒适区里,世界是严丝合缝的。电机转动 90 度就是 90 度,PID 的参数调好了,波形就是收敛的。但是,这种确定性也意味着死板。
大二做垃圾分类比赛的时候,我写了大概几百行 if-else:
- 如果是红色 -> 舵机转到 A 点。
- 如果是蓝色 -> 舵机转到 B 点。
- 如果光线太暗识别失败 -> 呃,听天由命。
最近 LLM(大语言模型)火得一塌糊涂,我就在想:能不能把这玩意儿塞进我的机器人里,让它不再是只会执行死命令的“人工智障”?
于是,我开始了这个名为 “Robo-Agent” 的坑爹(划掉)探索项目。
🛠️ 硬件与架构:草台班子
我的目标很简单:对着机械臂说一句“把那个红色的方块放到蓝色盒子里”,它能自己搞定剩下的一切。
手头只有之前比赛剩下的破烂:
- 本体:一个 6 自由度的机械臂(也就是 6 个串联的舵机)。
- 大脑:树莓派 4B(负责跑 Agent 逻辑 + 视觉处理)。
- 小脑:STM32F103(负责解算运动学,控制舵机 PWM)。
- 眼睛:一个 30 块钱的 USB 摄像头。
架构设计上,我决定用 LangChain 来做胶水。
🧠 第一回合:让 LLM 学会“用工具”
刚开始,我天真地以为把 API 接进去就行了。结果 LLM 根本不知道怎么控制硬件。它会一本正经地给我输出一段 Python 代码,让我自己去跑。
不行,我要的是 Agent,是它自己去跑!
我引入了 ReAct (Reasoning + Acting) 模式。简单来说,就是教 LLM 一个思考范式:
思考 (Thought) -> 选择工具 (Action) -> 观察结果 (Observation) -> 再思考…
我给它定义了几个“工具 (Tools)”:
scan_environment(): 调用 OpenCV 识别视野里的物体,返回一个 JSON 列表(比如[{'obj': 'red_block', 'pos': [100, 200]}, ...])。calculate_ik(x, y, z): 逆运动学解算,把坐标变成 6 个舵机的角度。execute_move(angles): 通过串口把角度发给 STM32。gripper_control(state): 控制爪子开合。
遇到的第一个坑:幻觉
第一次测试,我输入:“把螺丝刀递给我”。 Agent 输出:
Thought: 用户想要螺丝刀。我需要先找到螺丝刀。 Action:
scan_environment()Observation:[{'obj': 'red_block', ...}, {'obj': 'blue_box', ...}](根本没有螺丝刀) Thought: 没找到螺丝刀,但我看那个红色方块挺像的,我就拿那个吧。 Action:execute_move(...)
我:??? 它居然学会了“指鹿为马”!
为了解决这个问题,我在 Prompt 里加了超强的约束(System Prompt):“严禁操作未识别到的物体!如果找不到目标,必须立刻停止并报错!” 调整后,它终于老实了:“对不起,我瞎了,没看到螺丝刀。”
🐢 第二回合:无法忍受的延迟
逻辑跑通了,但体验极差。
流程是这样的:
- 我说一句话 -> 录音转文字 (Whisper API) -> 2秒
- 发送给 LLM 思考 -> 3秒
- LLM 决定调用视觉工具 -> 拍照处理 -> 0.5秒
- 把视觉结果回传给 LLM,它再次思考下一步动作 -> 3秒
- …
执行一个简单的抓取动作,中间的“发呆”时间加起来超过 10 秒。看着机械臂悬在半空中一动不动,像是在思考人生,我真的很想帮它掰过去。
优化尝试:
我试着把一些简单的逻辑从 LLM 剥离。比如“视觉识别”不作为工具被动调用,而是作为一个后台线程,实时维护一个 World State(世界状态)。
当 LLM 收到指令时,直接从本地内存读取当前环境状态,不需要再通过网络这一层。
这把响应时间压缩到了 5 秒左右——虽然还是很慢,但至少能用了。
✨ 第三回合:它好像真的“懂”了
最让我震撼的一刻,是我测试复杂指令的时候。
我故意刁难它:“把所有不是红色的东西都扔掉。”
我没有写过“扔掉”这个函数,也没有定义“不是红色”的逻辑。 但是 Agent 的思维链(Chain of Thought)是这样的:
- Thought: 用户想清理非红色物体。我需要先扫描环境。
- Action:
scan_environment()-> 得到[红块, 蓝块, 绿球] - Thought: 蓝块和绿球不是红色的。我需要依次抓取它们。对于“扔掉”这个动作,我可以把它们移动到视野外的区域(比如坐标 [0, 0, 0])然后松开爪子。
- Action:
pick_and_place('blue_block', target=[0,0,0])…
看到它把蓝块抓起来,移动到边缘,松手,然后又去抓绿球。 那一刻,我鸡皮疙瘩都起来了。 它不是在执行代码,它是在理解意图。
📝 总结与反思
这次折腾让我对“智能”有了新的理解。
- 传统控制是小脑,负责精准、快速、稳定(走直线、不抖动)。
- AI Agent是大脑,负责模糊、决策、泛化(理解意图、处理未知)。
现在的 Agent 还很笨重,延迟高,容易发疯。但看着它第一次自主规划出一条我没写过的路径时,我感觉自己窥见了未来机器人的一角。
接下来的计划?我打算试试在树莓派上部署 Llama-3-8B 的量化版本,看看能不能把“大脑”也搬到本地,彻底告别网络延迟。
代码已开源在我的 GitHub,欢迎来提 Issue (或者帮我修 Bug) 😂