Cradle框架:基于视觉的通用AI智能体实现计算机控制
人工智能智能体(AI Agent)通过感知环境、规划决策和执行动作来完成复杂任务,其核心在于实现与环境的有效交互。传统方法通常依赖特定API或结构化数据接口,限制了智能体的通用性和适应性。Cradle框架创新性地采用视觉作为统一感知源,以屏幕截图作为智能体的唯一输入,结合多模态大模型进行高层次语义理解和目标检测技术实现精确定位。这种设计使得智能体能够像人类一样,通过观察屏幕像素流来理解非结构化的计
1. 从“看”到“做”:Cradle如何让AI学会像人一样操作电脑
想象一下,你正在玩一款复杂的开放世界游戏,比如《荒野大镖客2》。你需要骑马穿越山谷、与NPC对话、在城镇里购买补给,甚至完成一场紧张的枪战。现在,把这个“你”替换成一个AI智能体。它没有内置的游戏API可以调用,没有上帝视角的地图数据,它唯一能获取信息的“眼睛”就是电脑屏幕的截图,唯一能执行操作的“手”就是模拟键盘和鼠标的输入。这听起来像是科幻电影里的情节,但北京智源人工智能研究院开源的Cradle框架,正在将这一愿景变为现实。
Cradle,这个名字本身就寓意着“摇篮”或“发源地”,它的目标是为“基础智能体”提供一个成长的温床,使其能够通过人类最自然的交互方式——观察屏幕并操作键鼠——来完成通用计算机控制任务。这不仅仅是又一个“AI玩游戏”的项目。传统的游戏AI,无论是DeepMind的AlphaStar(《星际争霸II》)还是OpenAI的Five(《DOTA2》),通常都针对单一游戏、单一环境进行了深度定制和优化,依赖于特定的游戏状态接口。而Cradle的野心在于“通用性”。它试图建立一个统一的框架,让同一个智能体核心,能够适配从《星露谷物语》的田园耕种,到《城市:天际线》的宏观规划,再到Chrome浏览器、Outlook邮件客户端等日常软件操作等截然不同的任务场景。
其核心价值在于,它极大地降低了AI与任意计算机环境交互的门槛。你不再需要为每个新游戏或软件编写复杂的接口解析代码;你只需要让AI学会“看”和“点”。这对于AI研究者和开发者而言,打开了一扇新的大门:我们可以用更自然、更通用的方式,来评估和训练AI的视觉理解、任务规划、工具使用和长期决策能力。无论是想研究多模态大模型在复杂环境下的应用,还是想打造一个能自动处理日常办公事务的智能助手,Cradle都提供了一个极具潜力的起点。接下来,我将带你深入拆解这个框架的设计精髓、实操细节,并分享在复现和探索过程中可能遇到的“坑”与技巧。
2. Cradle框架的核心设计哲学与架构拆解
Cradle的诞生并非凭空想象,它直指当前AI智能体研究中的一个核心痛点:如何让AI智能体像人类一样,在充满不确定性的真实数字世界中生存和完成任务?这个“真实数字世界”的入口,就是我们的计算机屏幕。Cradle的设计哲学可以概括为三点: 感知统一化、技能模块化、决策闭环化 。
2.1 感知统一化:以屏幕为唯一信源
传统AI与环境交互,往往依赖于精心设计的、结构化的状态信息(State)。例如,在棋类游戏中,AI获得的是完整的棋盘矩阵;在API驱动的环境中,AI获得的是格式规范的JSON数据。然而,现实世界(包括计算机桌面)的信息是高度非结构化的像素流。Cradle毅然选择了这条更艰难但更通用的道路: 将屏幕截图作为智能体的唯一视觉输入 。
这意味着智能体必须自己从像素中解读出所有相关信息:图标、文字、按钮位置、角色状态、进度条等等。为了实现这一点,Cradle深度融合了多模态大模型和传统的计算机视觉技术。它利用类似GPT-4V或Claude 3这样的视觉语言模型,对截图进行高层次的理解和描述(例如,“屏幕中央有一个红色的‘攻击’按钮,右下角地图显示前方有敌人”)。同时,对于需要精确定位的操作(如点击某个特定图标),它会结合目标检测模型(如GroundingDINO)来获取图标在屏幕上的精确坐标。这种“大模型理解语义,小模型精确定位”的分层感知策略,是Cradle能处理复杂场景的关键。
2.2 技能模块化:从原子操作到组合技能
人类操作电脑并非每次都是从零开始思考每一个鼠标移动和按键。我们积累了大量“肌肉记忆”和“套路”,比如“保存文件”就是 Ctrl + S ,“关闭窗口”就是点击右上角的 X 。Cradle借鉴了这一思想,引入了 技能(Skill) 体系。
技能分为两个层级:
- 原子技能 :最基础、不可再分的操作单元。例如:
mouse_move_to(x, y)(移动鼠标到坐标(x, y))、mouse_left_click()(左键单击)、key_press(‘w’)(按下W键)、key_press_and_release(‘enter’)(按下并释放回车键)。这些技能直接映射到操作系统级的输入模拟。 - 组合技能 :由多个原子技能按特定顺序组合而成的复杂操作。例如,一个“打开背包”的组合技能,可能包含:按下
I键、等待动画播放、检测背包界面是否成功打开。一个“与NPC对话”的技能,可能包含:移动鼠标到NPC身上、右键点击、等待对话框弹出。
在Cradle的代码结构中,每个游戏或软件(如 rdr2 , stardew )的环境目录下,都有 atomic_skills 和 composite_skills 文件夹。开发者需要为新的环境定义这些技能。这种设计带来了巨大的灵活性:智能体在规划任务时,不需要每次都生成一串原始的键鼠指令,而是可以调用这些预定义的、高可靠性的技能块,大大提高了行动的成功率和效率。
2.3 决策闭环化:规划、执行、反思的循环
拥有了“眼睛”(视觉感知)和“手”(技能库),智能体还需要一个“大脑”来指挥。Cradle的决策核心是一个经典的 “规划-执行-观察-反思” 循环,这深受ReAct等智能体框架的影响。
- 任务推断与规划 :智能体根据当前屏幕截图和最终目标(例如,“在《星露谷物语》中种下所有土豆”),利用大模型进行推理,生成一个分步的行动计划。这个计划由一系列高级指令或技能调用组成。
- 技能执行 :执行模块解析计划,调用相应的原子或组合技能,操作鼠标和键盘。
- 观察与状态更新 :执行后,智能体再次截取屏幕,观察环境变化,更新对当前状态的理解。
- 自我反思 :这是Cradle区别于许多简单执行框架的亮点。如果执行后未能达到预期效果(例如,点击了按钮但没反应,或者走到了错误的位置),反思模块会被触发。大模型会分析“预期结果”和“实际观察”之间的差异,诊断可能的原因(“按钮可能被遮挡了”、“需要等待加载”),并生成修正后的计划或调整策略。
这个闭环使得智能体具备了 自我改进和从错误中学习 的潜力。它不是机械地执行预设脚本,而是在与环境的动态交互中不断调整自己的行为。
3. 环境搭建与核心配置实战指南
纸上谈兵终觉浅,要理解Cradle,最好的方式就是亲手把它跑起来。这里我将以在《星露谷物语》中实现自动化耕种为例,详细拆解从零开始的搭建过程,并穿插关键配置的解读。
3.1 基础环境与依赖安装
Cradle基于Python 3.10,强烈建议使用Conda或Venv创建独立的虚拟环境,避免依赖冲突。
# 1. 克隆仓库
git clone https://github.com/BAAI-Agents/Cradle.git
cd Cradle
# 2. 创建并激活Conda环境(如无conda,可使用 python -m venv cradle-env)
conda create -n cradle python=3.10 -y
conda activate cradle
# 3. 安装核心依赖
pip install -r requirements.txt
requirements.txt 中包含了PyAutoGUI(模拟键鼠)、OpenCV(图像处理)、Pillow(图像)、GroundingDINO(目标检测)等关键库。安装过程通常比较顺利,但需要注意两点:
注意 :GroundingDINO的安装可能会因为网络或编译环境出现问题。如果遇到困难,可以尝试先注释掉相关行,后续再单独安装,或者考虑在配置中暂时禁用目标检测功能,仅依赖纯VLM。
3.2 关键配置:API密钥与环境文件
Cradle的强大推理能力依赖于大语言模型。它支持OpenAI GPT系列和Anthropic Claude系列。你需要准备相应的API Key。
-
获取API Key :
- OpenAI :访问 OpenAI平台 创建API Key。
- Claude :访问 Anthropic控制台 创建API Key。
- Azure OpenAI :如果你使用Azure的服务,也需要准备相应的终结点和密钥。
-
创建
.env配置文件 : 在Cradle项目的根目录下,创建一个名为.env的文件。这个文件用于存放你的敏感信息, 务必将其加入.gitignore避免泄露 。内容格式如下:# OpenAI (推荐,GPT-4o或GPT-4V效果最佳) OA_OPENAI_KEY = "sk-你的OpenAI-API-Key" # Anthropic Claude (备选) OA_CLAUDE_KEY = "你的Claude-API-Key" # Azure OpenAI (如需) AZ_OPENAI_KEY = "你的Azure-OpenAI-Key" AZ_BASE_URL = "https://你的资源名.openai.azure.com/" # 指定运行代码的IDE,用于窗口切换。通常是 'Code' (VSCode) 或 'PyCharm' IDE_NAME = "Code"你不需要填满所有Key,只需提供你计划使用的一种即可。例如,如果你只用OpenAI,就只填
OA_OPENAI_KEY。
3.3 游戏/软件特定配置与启动
Cradle为每个支持的环境提供了详细的配置指南。以《星露谷物语》为例:
-
阅读专属文档 :首先查看
docs/envs/stardew.md。这份文档会告诉你游戏需要以窗口化模式运行、推荐的分辨率、以及可能需要安装的模组(Mod)来优化AI的识别(例如,显示更多UI信息的模组)。 -
配置环境文件 :核心配置位于
conf/目录下。对于星露谷的耕种任务,你会用到env_config_stardew_cultivation.json。用文本编辑器打开它,你需要关注以下几个关键部分:{ "env": "stardew", "task_type": "cultivation", "llm_config_name": "openai_config.json", // 指定使用哪个LLM配置 "max_steps": 500, // 任务最大执行步数,防止死循环 "pause_after_action": true, // 执行动作后是否暂停游戏?对于星露谷这种非即时战斗游戏,通常设为false "action_interval": 1.0, // 动作执行间隔(秒),给游戏反应时间 "retry_times": 3, // 动作失败重试次数 "specific_task": "Plant parsnip seeds on all available tiles in the farm." // 你的具体任务描述 }pause_after_action参数至关重要 :对于《荒野大镖客2》这种需要实时反应的游戏,必须设置为true,让AI在“思考”时暂停游戏;对于星露谷、天际线这类回合制或可暂停的游戏,设置为false可以提升效率。 -
安装OCR工具(可选但推荐) :为了更好识别屏幕上的文字,Cradle集成了spaCy的NLP模型。运行以下命令安装:
python -m spacy download en_core_web_lg如果下载慢,可以按项目README中的Option 2,手动下载
.tar.gz包并安装。 -
启动智能体 :确保游戏已经以正确的窗口模式启动,并处在正确的场景(如农场)。然后在项目根目录下运行:
python runner.py --config conf/env_config_stardew_cultivation.json此时,Cradle会开始工作:截屏 -> 调用VLM分析 -> 规划 -> 执行技能 -> 再截屏观察... 你可以在终端看到详细的日志输出,包括AI“想”了什么、准备“做”什么。
4. 核心模块深度解析与自定义技能开发
要让Cradle在新的游戏或软件中工作,核心在于为其“注入”关于这个新环境的知识。这主要涉及三个部分的开发: 环境控制、技能定义、提示词工程 。
4.1 环境控制: ui_control.py
这个文件定义了如何与目标应用程序窗口交互。对于游戏,通常需要实现两个关键函数:
switch_to_game():将系统焦点切换到游戏窗口。这通常通过调用pyautogui的getWindowsWithTitle查找窗口并激活来实现。pause_game()和resume_game():对于需要“冻结”时间以方便AI思考的实时游戏,必须实现暂停/继续的逻辑。这通常通过模拟按下游戏的暂停快捷键(如ESC或P)来实现。
示例(伪代码) :
# 在 `cradle/environment/stardew/ui_control.py` 中
import pyautogui
import time
class StardewUIControl:
def __init__(self):
self.game_window_title = "Stardew Valley"
def switch_to_game(self):
"""切换到星露谷物语窗口"""
windows = pyautogui.getWindowsWithTitle(self.game_window_title)
if windows:
win = windows[0]
if not win.isActive:
win.activate()
time.sleep(0.5) # 等待窗口激活
return True
else:
print(f"未找到窗口: {self.game_window_title}")
return False
def pause_game(self):
"""星露谷物语无需物理暂停,但可以在这里实现一些准备动作,如打开背包"""
# 对于无需暂停的游戏,此函数可为空或仅返回True
return True
def resume_game(self):
"""同上"""
return True
4.2 技能定义:原子技能与组合技能
这是迁移到新游戏最核心、工作量最大的部分。你需要像教一个婴儿一样,告诉AI在这个环境里能做的所有基本动作。
原子技能 ( atomic_skills/ ):每个原子技能是一个独立的Python函数,使用 @register_skill 装饰器注册。它接收必要的参数,并调用 pyautogui 或 pydirectinput (对游戏兼容性更好)执行。
# 示例:`cradle/environment/stardew/atomic_skills/movement.py`
from cradle.environment.stardew.skill_registry import register_skill
import pyautogui
import time
@register_skill(name="move_forward", description="按住W键向前移动一段时间")
def move_forward(duration: float = 1.0):
"""向前移动。
Args:
duration: 按住W键的持续时间(秒)。
"""
pyautogui.keyDown('w')
time.sleep(duration)
pyautogui.keyUp('w')
return {"status": "success", "message": f"Moved forward for {duration}s"}
@register_skill(name="mouse_click_at", description="在屏幕坐标(x, y)处单击鼠标左键")
def mouse_click_at(x: int, y: int):
"""点击屏幕指定位置。
Args:
x: 屏幕横坐标。
y: 屏幕纵坐标。
"""
pyautogui.moveTo(x, y, duration=0.2) # 平滑移动
pyautogui.click()
return {"status": "success", "message": f"Clicked at ({x}, {y})"}
组合技能 ( composite_skills/ ):组合技能调用多个原子技能,并处理一些简单的逻辑。
# 示例:`cradle/environment/stardew/composite_skills/farming.py`
from cradle.environment.stardew.skill_registry import register_skill, get_skill
import time
@register_skill(name="hoe_tile", description="锄一块地")
def hoe_tile(x: int, y: int):
"""移动到位置(x, y)并锄地。
假设快捷键'1'对应锄头。
"""
move_to = get_skill("mouse_click_at")
move_to(x, y) # 点击走到该位置
time.sleep(0.5) # 等待角色移动
pyautogui.press('1') # 切换到锄头
time.sleep(0.2)
pyautogui.click() # 挥动锄头
time.sleep(0.5) # 等待动作完成
return {"status": "success", "message": f"Hoed tile at ({x}, {y})"}
技能注册 :所有定义好的技能需要在 skill_registry.py 中集中导入和注册,以便框架在运行时能够发现和调用它们。
4.3 提示词工程:引导大模型理解与规划
大模型(LLM/VLM)是Cradle的“大脑”,而提示词(Prompt)就是与这个大脑沟通的“语言”。在 res/[game]/prompts/templates/ 目录下,有几个关键的提示词模板:
task_inference.prompt: 用于根据初始目标和当前屏幕,推断出当前应该执行的 子任务 。例如,目标“种土豆”,当前屏幕是家,子任务可能是“前往农场”。action_planning.prompt: 用于根据子任务和当前屏幕,规划出具体的 技能调用序列 。例如,子任务“锄地”,规划可能是[“move_to(100,200)”, “hoe_tile(100,200)”]。self_reflection.prompt: 当执行结果与预期不符时,用于分析原因并生成修正方案。
编写提示词的技巧 :
- 提供充足的上下文 :在提示词中明确说明游戏规则、UI元素含义、技能库清单。例如,告诉模型“红色心形代表体力值,当它变空时角色无法行动”。
- 结构化输出 :严格要求模型以指定的JSON格式输出,方便程序解析。例如,
{"next_subtask": "go to the blacksmith", "confidence": 0.8}。 - 示例学习 :在提示词中加入少量示例(Few-shot Learning),能显著提升模型输出的准确性和稳定性。
- 迭代优化 :观察AI的失败案例,分析是规划错误、技能参数错误还是识别错误,然后有针对性地修改提示词。这是一个需要不断调试的过程。
5. 实战问题排查与性能优化经验谈
在实际运行Cradle的过程中,你几乎一定会遇到各种问题。以下是我在复现和实验过程中总结的常见“坑”及其解决方案。
5.1 视觉识别不准:图标找不到、文字读错
这是最常见的问题,直接导致后续动作失败。
- 症状 :AI计划点击“商店”按钮,却点在了空白处;或者把“100金”误读为“10金”。
- 排查与解决 :
- 检查截图质量 :首先确认Cradle截取的屏幕图像是否清晰、完整,是否包含了目标窗口。可以在代码中临时保存截图进行检查。
- 图标替换 :对于UI中小而复杂、VLM难以识别的图标,Cradle提供了“图标替换器”功能。你可以在
res/[game]/icons/目录下放置图标的截图,并在配置中启用替换。框架会在将图片送给VLM前,把这些图标区域替换成对应的文字标签(如“[SHOP_ICON]”)。 - 调整VLM提示 :在调用VLM进行场景描述时,提示词可以更具体。例如,不说“描述这个屏幕”,而说“请重点描述屏幕中央和底部的UI栏,列出所有可交互按钮的文字和大概位置”。
- 融合目标检测 :对于需要精确定位的操作,确保GroundingDINO模型已正确加载,并在提示词中明确要检测的对象(如“detect all ‘clickable’ buttons”)。如果检测框不准,可以尝试调整检测阈值。
5.2 动作执行失败:点不准、时机不对
即使识别对了,动作也可能失败。
- 症状 :鼠标移动到了正确位置但点击无效;按键操作被游戏忽略。
- 排查与解决 :
- 坐标系统一 :确保AI输出的坐标、目标检测返回的坐标、以及
pyautogui使用的坐标系统一,都是屏幕绝对坐标。注意多显示器情况下的坐标偏移。 - 游戏窗口焦点 :确保在执行动作前,
switch_to_game()函数确实成功将焦点切换到了游戏窗口。某些全屏游戏可能需要以“窗口化全屏”或“窗口化”模式运行。 - 动作延迟与间隔 :游戏对输入有响应时间。在原子技能中合理添加
time.sleep()。action_interval配置项就是用于控制动作之间的全局间隔,对于较慢的游戏(如《城市:天际线》),可以设置得大一些(如2-3秒)。 - 使用
pydirectinput:对于某些游戏(特别是通过DirectX处理输入的游戏),pyautogui的模拟输入可能被屏蔽。可以尝试使用pydirectinput库,它模拟的是更低层的输入。 - 防误操作 :在关键动作(如点击确认对话框)前,可以增加一个“安全确认”步骤,比如先让AI识别对话框是否确实弹出。
- 坐标系统一 :确保AI输出的坐标、目标检测返回的坐标、以及
5.3 任务规划陷入循环或跑偏
AI有时会卡在一个步骤,或者执行与目标无关的动作。
- 症状 :AI反复在同一个地方转圈;或者开始做一些奇怪的事情,比如不停打开和关闭菜单。
- 排查与解决 :
- 限制步数 :合理设置
max_steps。如果一个简单任务走了几百步还没完成,很可能已经陷入循环,应强制终止。 - 强化反思机制 :检查
self_reflection.prompt是否足够强大。好的反思提示应该能让AI识别出“我过去5步都在做同样的事,这可能是死循环,我需要尝试其他方法”。 - 提供更细粒度的子任务 :有时最终目标(“成为百万富翁”)太宏大,AI无法分解。可以在启动时提供一个更具体的初始任务链(“1.去商店买种子;2.回家锄地;3.播种...”)。
- 检查技能成功率反馈 :确保每个技能执行后都返回了明确的状态(成功/失败)。规划模块应能接收这些反馈,并在失败时触发反思或重试。
- 限制步数 :合理设置
5.4 性能与成本优化
使用GPT-4V等高级VLM,成本(API调用费用)和速度是现实考量。
- 策略 :
- 缓存与记忆 :Cradle的
memory模块会记录历史状态和动作。确保其正常工作,避免AI每一帧都问VLM“我在哪”,对于静态或变化慢的UI,可以复用之前的分析结果。 - 降低截图频率 :不是每一步都需要重新截屏和分析。对于连续移动等操作,可以间隔多步再进行一次视觉确认。
- 使用轻量级模型处理简单识别 :对于“血条是否为空”、“金币数字是否变化”这类简单判断,可以尝试用传统的模板匹配或OCR技术,而非每次都调用昂贵的VLM。
- 本地VLM替代 :如果对延迟和成本非常敏感,可以探索部署开源的轻量级VLM(如Qwen-VL、LLaVA)作为替代,虽然能力可能稍弱,但对于固定场景经过微调后可能表现不错。
- 缓存与记忆 :Cradle的
6. 迁移到新环境:从《天际线》到你的自定义软件
Cradle的官方文档提供了迁移指南,但结合我的经验,将其提炼为一个更实操的清单。假设你想让Cradle控制一个新的策略游戏《文明VI》。
第一步:环境分析
- 交互模式 :《文明VI》是回合制,无需实时暂停,类似于《城市:天际线》。因此,可以以
skylines的代码为蓝本。 - UI复杂度 :分析游戏UI。是否有小地图?资源图标是否清晰?文本是否容易被OCR识别?提前规划哪些地方可能需要“图标替换”。
- 核心操作 :列出最常用的操作,如“选择单位”、“移动单位”、“建造建筑”、“研究科技”等。
第二步:代码骨架创建
- 在
cradle/environment/下创建civilization6目录。 - 复制
skylines目录下的__init__.py,ui_control.py,skill_registry.py以及atomic_skills,composite_skills,prompts目录结构。 - 在
conf/目录下创建env_config_civilization6.json,参考天际线的配置进行修改。 - 在
res/目录下创建civilization6目录,用于存放图标、存档等资源。
第三步:实现核心模块
- 修改
ui_control.py:将窗口标题改为“Sid Meier‘s Civilization VI”,实现switch_to_game函数。由于是回合制,pause_game和resume_game可以留空或简单返回True。 - 开发原子技能 :在
atomic_skills/下创建如unit_selection.py,map_navigation.py(拖动地图),end_turn.py等文件。每个技能函数要尽可能鲁棒。例如,click_research_button()可能需要先检测研究界面是否打开。 - 开发组合技能 :在
composite_skills/下创建如found_city.py(包含移动开拓者、选择建城位置、确认),research_tech.py(打开科技树、选择科技)等。 - 编写提示词 :这是灵魂。在
prompts/templates/下,你需要用自然语言向大模型描述《文明VI》的UI和规则。例如,在task_inference.prompt中,你需要解释“科技树界面”、“生产力图标”、“单位行动力”等概念。大量参考已有游戏的提示词格式。
第四步:集成与测试
- 在
civilization6的__init__.py中创建环境类,并导入所有技能。 - 在
skill_registry.py中确保所有技能被正确导入和注册。 - 创建一个简单的测试配置,任务设为“研究采矿技术”。
- 运行并观察。前几十步一定会错误百出,这是正常的。你需要像一个调试员一样,查看每一步的截图、AI的思考过程和执行结果,然后回头去修改技能的实现逻辑或提示词的描述。
这个过程充满挑战,但一旦跑通,你会获得一个能够以通用方式与全新复杂环境交互的智能体原型,这种成就感是无与伦比的。Cradle的价值不仅在于其已实现的功能,更在于它提供了一套经过验证的、可扩展的方法论,让研究者能够专注于智能体高层能力的探索,而非陷入为每个环境编写特定接口的泥潭。
更多推荐




所有评论(0)