前言
在前两篇中,我们构建了 Agent 的身体(架构)和眼睛(视觉感知)。现在,我们来到了最核心、最性感的部分——大脑。
当一张标注了坐标的屏幕截图(SoM Image)传给大模型后,它如何决定是“点击左上角的菜单”还是“按下 W 键向前走”?更重要的是,当它撞墙了或者点错了,它怎么知道自己搞砸了?
本篇将深入 Cradle 的推理引擎,剖析其 ReAct (Reasoning + Acting) 循环的源码实现,以及至关重要的 Self-reflection(自我反思) 机制。
1. 推理的核心:Context 的组装艺术
在源码层面,所谓的“推理”,本质上是一次精心构造的 llm.chat() 调用。但 LLM 没有长时记忆,Cradle 必须在每一次请求中,把所有必要的上下文“喂”给它。
在 cradle/agent/core.py (或类似逻辑路径) 中,决策函数通常遵循这样的数据流:
Cradle 将 Context 像千层饼一样堆叠起来,构建最终的 Prompt:
-
System Prompt (人设):
"你是一个精通《荒野大镖客2》的专家玩家..."
-
Long-term Goal (宏观指令):
"当前任务:前往瓦伦丁镇的杂货铺购买苹果。"
-
Skill Context (技能检索):
这里用到了 RAG。 Cradle 会根据当前任务,从技能库中检索相关的操作说明。例如检索到“如何骑马”、“如何打开地图”的文本描述。
-
History (短期记忆):
"过去 3 步的操作:[按下 W, 移动鼠标, 点击确认]..."
这是为了保持操作的连贯性。
-
Observation (当前视觉):
传入上一篇提到的 SoM 标注图。
2. 思考链 (Chain of Thought) 的代码实现
Cradle 并不希望 LLM 直接输出一个按键动作(如 Key.W),因为这样缺乏鲁棒性。它要求 LLM 输出一段 JSON 格式的思考过程。
在源码的 Prompt 模板中,我们能看到强制的输出格式要求:
JSON
{
"reasoning": "我看到前方有障碍物,且地图显示目的地在左侧。刚才我已经尝试直行但被挡住了。",
"plan": "我应该先向左转视角,然后继续前进。",
"action": {
"type": "key_press",
"key": "a",
"duration": 0.5
}
}
为什么要有 reasoning 字段?
在代码调试中,这是极其宝贵的。它迫使模型生成 CoT (Chain of Thought)。如果 Agent 卡住了,开发者查看 Log 中的 reasoning 字段,就能知道是因为模型“没看见路”还是“逻辑判断错误”。
3. 动态规划:下一步动作预测
Cradle 的规划并不是一次性生成整个任务的所有步骤(因为游戏环境变化太快),而是采用 Receding Horizon Control (滚动时域控制) 的思路。
逻辑流程:
-
评估差距:对比
Current State(截图) 和Goal。 -
生成原子动作:LLM 预测能缩短这个差距的下一个最小动作单元(Atomic Action)。
-
执行:将动作发给执行器。
-
循环:进入下一帧。
这种“走一步看一步”的策略,在源码中体现为一个 while 循环,直到 task_status 变为 SUCCESS。
4. 关键机制:反思 (Self-reflection)
这是 Cradle 区别于普通脚本机器人的核心。如果动作执行失败了怎么办?
在 cradle/agent/reflection.py 中,实现了一个闭环反馈系统。当 Agent 执行动作后,系统不会立刻进入下一步,而是会捕获一张**“执行后”的截图**。
Cradle 会发起一次特殊的 LLM 调用,也就是“反思裁判”:
Input:
-
Image_Pre: 执行前的图 -
Action: 刚才执行的动作 (例如:点击坐标 200,300) -
Image_Post: 执行后的图
Prompt:
"我试图执行这个动作。请对比前后两张图,判断动作是否生效?如果失败,请分析原因。"
Output:
-
Success: 比如菜单弹出来了,或者人物位置变了。 -> Update Memory (成功经验)
-
Fail: 画面没有任何变化,或者出现了错误弹窗。 -> Update Memory (失败教训) & Retry
源码视角的反思逻辑:
Python
# 伪代码逻辑演示
def step(self):
# 1. 决策
action = self.reasoning_engine.predict(current_obs)
# 2. 执行
self.executor.execute(action)
time.sleep(1) # 等待渲染
# 3. 后处理观察
next_obs = self.environment.capture()
# 4. 反思 (Reflection)
success, feedback = self.reflector.judge(current_obs, action, next_obs)
if not success:
print(f"Action Failed: {feedback}")
# 将失败信息加入短期记忆,防止下一轮重复同样的错误
self.short_term_memory.add_error(action, feedback)
# 可能会触发恢复策略 (Recovery Policy),比如按 ESC 返回
self.recover()
else:
self.long_term_memory.store_skill(action) # 巩固成功路径
5. 总结
Cradle 的大脑中枢实际上是一个**“带状态的无限状态机”**。
-
Reasoning 依靠 Prompt 堆叠 Context 来弥补 LLM 的失忆。
-
Planning 采用滚动预测,保证了对动态环境的适应性。
-
Reflection 提供了容错能力,让 Agent 具备了“自我纠正”的雏形。
正是这套机制,让 Cradle 能够处理《荒野大镖客2》中那些不可预测的 NPC 互动和复杂的菜单逻辑。
下一篇预告:
大模型想好了要“向左转”,但代码怎么知道鼠标该移动多少像素?怎么模拟按下键盘的动作才不会被系统判定为脚本?在下一篇 【Cradle 源码解析四】手眼协同:IO 控制层与动作执行 (Action Execution) 中,我们将下沉到最底层,研究 HID 模拟与技能库的实现。
Cradle决策与规划源码解析


被折叠的 条评论
为什么被折叠?



