从零搭建 OpenClaw:教你养一只“会自己干活”的数字小龙虾
【万字硬核实战】从零搭建 OpenClaw:教你养一只“会自己干活”的数字小龙虾!
导语:
在上一期的 GitHub Trending 盘点中,我们提到了霸榜的黑马项目 OpenClaw——一个能让 AI 长出“手脚”,直接接管你的鼠标键盘、跨应用操作 GUI 的系统级自动化 Agent。很多同学在评论区惊呼:“这玩意太酷了,但怎么用?”“会不会把我的电脑搞崩?”“能不能自己手搓一个类似的核心?”
答案是:当然能!而且自己手搓的过程,就是彻底理解 AGI 时代“具身智能(Embodied AI)”在数字世界映射的最佳途径。
今天,我将用超万字的篇幅,带你从零开始,一行行代码、一个个模块地搭建属于你自己的 OpenClaw 核心引擎。我们将这只系统级 Agent 亲切地称为 “数字小龙虾”。它不仅有着敏锐的“复眼”(视觉感知),聪明的“神经节”(VLM 大脑),还有一对能精准点击、拖拽的“大钳子”(动作执行)。
准备好你的 Python 环境和咖啡,我们开始“孵虾”!建议先收藏,这绝对是你 2026 年最硬核的实战指南。
📊 核心概览:“数字小龙虾”的解剖学图谱
在动手写代码之前,我们必须先搞清楚这只“小龙虾”的生理构造。一个完整的 GUI 自动化 Agent,本质上是一个感知-决策-执行(Perception-Action Loop) 的闭环系统。
| 生物学隐喻 | OpenClaw 技术模块 | 核心技术栈 / 算法 | 核心功能描述 |
|---|---|---|---|
| 复眼 (Eye) | 视觉与状态感知层 | 屏幕截图、Accessibility API、OCR、YOLO | 看懂当前屏幕内容,提取 UI 元素坐标与层级关系。 |
| 神经节 (Brain) | 规划与决策大脑 | 多模态大模型 (VLM)、LangGraph 状态机 | 理解用户意图,结合当前屏幕状态,规划下一步动作。 |
| 大钳子 (Claw) | 动作执行引擎 | PyAutoGUI、pynput、xdotool、ADB | 将大脑的抽象指令转化为物理级的鼠标移动、点击和键盘输入。 |
| 记忆腺 (Memory) | 上下文与纠错记忆 | 向量数据库、滑动窗口、执行日志 | 记住之前的操作步骤,在遇到弹窗或报错时进行自我纠错。 |
【架构全景图】
graph TD
User[用户自然语言指令] --> Brain
subgraph 感知层 Eye
Screen[屏幕截图] --> Vision[视觉编码器 / OCR]
DOM[系统 Accessibility API] --> Tree[虚拟 DOM 树]
Vision --> State[当前环境状态 State]
Tree --> State
end
subgraph 决策层 Brain
State --> VLM{多模态大模型 VLM}
History[历史动作记忆] --> VLM
Prompt[系统 Prompt 与约束] --> VLM
VLM -->|思考与规划| Plan[动作序列 Action Plan]
end
subgraph 执行层 Claw
Plan --> Parser[指令解析器]
Parser -->|Click(x,y)| Mouse[鼠标控制]
Parser -->|Type(text)| Keyboard[键盘控制]
Parser -->|Scroll| Scroll[滚轮控制]
end
Mouse -->|改变屏幕| Screen
Keyboard -->|改变屏幕| Screen
Brain -->|任务完成/失败| User
第一阶段:建缸与备水(环境准备与依赖安装)
养虾先养水。我们需要为小龙虾搭建一个稳定的运行环境。为了保证跨平台兼容性(Windows/macOS/Linux),我们主要使用 Python,并辅以一些底层系统库。
1.1 创建虚拟生态缸
# 创建并激活虚拟环境
conda create -n openclaw python=3.10
conda activate openclaw
# 安装核心依赖
pip install pyautogui pynput pillow paddleocr
pip install langchain langgraph openai
pip install pygetwindow uiautomation # Windows UI 树提取
pip install pyobjc-framework-Quartz # macOS 屏幕截取与 Accessibility
1.2 核心依赖说明
- PyAutoGUI / pynput:小龙虾的“大钳子”,用于跨平台的键鼠模拟。
- PaddleOCR:小龙虾的“复眼”辅助,用于识别屏幕上的文字(尤其是无法通过 DOM 树获取的 Canvas 或图片内文字)。
- LangGraph:小龙虾的“神经节”框架,用于构建带有循环、条件判断和状态记忆的 Agent 工作流。
- 系统级 API (pygetwindow / pyobjc):用于获取当前活跃窗口的句柄和基础的 UI 元素树,这比纯视觉识别更精准、更省算力。
第二阶段:培育“复眼”(视觉与状态感知层开发)
小龙虾要干活,首先得“看清”屏幕。纯靠截图发给大模型(VLM)不仅慢,而且 Token 成本极高,大模型还容易产生坐标幻觉。因此,我们采用 “视觉截图 + 结构化 DOM 树”的双轨感知机制。
2.1 屏幕截图与网格化(Grid System)
为了让大模型能准确输出点击坐标,我们在截图上覆盖一层带编号的网格(Grid)。
import pyautogui
from PIL import Image, ImageDraw, ImageFont
def capture_screen_with_grid(grid_size=50):
"""截取屏幕并绘制坐标网格,辅助 VLM 定位"""
screenshot = pyautogui.screenshot()
draw = ImageDraw.Draw(screenshot)
width, height = screenshot.size
# 绘制网格线和坐标标签
for x in range(0, width, grid_size):
draw.line([(x, 0), (x, height)], fill="red", width=1)
draw.text((x + 2, 2), str(x), fill="red")
for y in range(0, height, grid_size):
draw.line([(0, y), (width, y)], fill="red", width=1)
# 保存并返回图片路径(后续转为 Base64 传给 VLM)
img_path = "current_screen_grid.png"
screenshot.save(img_path)
return img_path
2.2 提取系统虚拟 DOM 树(Accessibility API)
这是 OpenClaw 区别于普通“套壳 Agent”的核心杀手锏。通过操作系统的无障碍 API,我们可以直接获取按钮的真实文本和边界框(Bounding Box),这相当于给小龙虾戴上了“透视眼镜”。
【Windows 平台示例:使用 uiautomation】
import uiautomation as auto
def get_ui_tree(max_depth=3):
"""获取当前活跃窗口的 UI 元素树"""
root = auto.GetFocusedControl()
ui_elements = []
def traverse(control, depth):
if depth > max_depth: return
# 提取关键属性:名称、类型、边界框
bbox = control.BoundingRectangle
if bbox.width() > 0 and bbox.height() > 0:
ui_elements.append({
"name": control.Name,
"type": control.ControlTypeName,
"bbox": [bbox.left, bbox.top, bbox.right, bbox.bottom]
})
for child in control.GetChildren():
traverse(child, depth + 1)
traverse(root, 0)
return ui_elements
💡 极客洞察:为什么要双轨制?
纯 DOM 树抓不到游戏画面、Flash 或某些自绘 UI(如 Electron 的 Canvas);纯视觉截图又容易在密集 UI 中迷失。DOM 树提供“语义”,截图提供“像素”,两者结合,天下无敌。
第三阶段:注入“神经节”(VLM 大脑与 LangGraph 状态机)
有了眼睛,我们需要一个聪明的大脑来理解“用户想干嘛”以及“下一步该怎么点”。这里我们引入 多模态大模型(VLM,如 GPT-4o 或 Qwen-VL),并使用 LangGraph 来管理小龙虾的“思考循环”。
3.1 定义小龙虾的“动作空间(Action Space)”
为了防止小龙虾乱点,我们必须严格限制它能执行的动作指令集(JSON 格式)。
ACTION_SCHEMA = """
你必须输出一个 JSON 格式的动作指令,包含以下字段:
- "thought": 你的思考过程(分析当前屏幕,决定下一步)。
- "action": 动作类型,仅限以下枚举值:
- "click": 点击指定坐标。参数: {"x": int, "y": int}
- "type": 输入文本。参数: {"text": str}
- "scroll": 滚动屏幕。参数: {"direction": "up"|"down", "amount": int}
- "wait": 等待页面加载。参数: {"seconds": int}
- "finish": 任务完成。参数: {"summary": str}
- "fail": 任务无法完成。参数: {"reason": str}
"""
3.2 构建 LangGraph 思考循环
小龙虾不是一次性执行命令的,它需要 “看一步,走一步,再纠错”。这是一个典型的 ReAct(Reasoning + Acting)循环。
stateDiagram-v2
[*] --> 接收指令
接收指令 --> 感知环境: 获取截图与DOM
感知环境 --> 大脑思考: 组装 Prompt 调用 VLM
大脑思考 --> 解析动作: 解析 JSON 输出
解析动作 --> 执行动作: 调用 PyAutoGUI
执行动作 --> 状态评估: 检查是否完成/报错
状态评估 --> 感知环境: 未完成,继续循环
状态评估 --> 任务结束: 完成或失败
任务结束 --> [*]
核心代码实现:
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
import json, base64
# 定义 Agent 的状态结构
class AgentState(TypedDict):
task: str # 用户原始指令
history: List[dict] # 历史动作与观察记录
current_screenshot: str # 当前屏幕 Base64
ui_tree: list # 当前 UI 元素树
next_action: dict # 大脑输出的下一步动作
def perceive_node(state: AgentState):
"""感知节点:截图并获取 UI 树"""
img_path = capture_screen_with_grid()
with open(img_path, "rb") as f:
img_base64 = base64.b64encode(f.read()).decode('utf-8')
ui_tree = get_ui_tree()
return {
"current_screenshot": img_base64,
"ui_tree": ui_tree
}
def brain_node(state: AgentState):
"""大脑节点:调用 VLM 进行决策"""
prompt = f"""
你是一个系统级自动化 Agent。你的任务是:{state['task']}
这是你之前的操作历史:{json.dumps(state['history'], ensure_ascii=False)}
这是当前屏幕的 UI 元素树(JSON):{json.dumps(state['ui_tree'], ensure_ascii=False)}
请结合附带的屏幕截图(带坐标网格),决定下一步动作。
{ACTION_SCHEMA}
"""
# 调用多模态大模型 (伪代码)
# response = vlm_client.chat(prompt, image=state['current_screenshot'])
# next_action = parse_json(response)
# 模拟大脑输出
next_action = {"thought": "看到登录按钮在坐标(450, 300)", "action": "click", "params": {"x": 450, "y": 300}}
return {"next_action": next_action}
def action_node(state: AgentState):
"""执行节点:挥动大钳子"""
act = state['next_action']
if act['action'] == 'click':
pyautogui.click(act['params']['x'], act['params']['y'])
elif act['action'] == 'type':
pyautogui.typewrite(act['params']['text'], interval=0.05)
# ... 其他动作
# 记录历史
history = state['history'] + [{"action": act, "status": "success"}]
return {"history": history}
def should_continue(state: AgentState):
"""路由判断:是否继续"""
if state['next_action']['action'] in ['finish', 'fail']:
return "end"
if len(state['history']) > 20: # 防止死循环
return "end"
return "continue"
# 组装 LangGraph 工作流
workflow = StateGraph(AgentState)
workflow.add_node("perceive", perceive_node)
workflow.add_node("brain", brain_node)
workflow.add_node("action", action_node)
workflow.set_entry_point("perceive")
workflow.add_edge("perceive", "brain")
workflow.add_edge("brain", "action")
workflow.add_conditional_edges("action", should_continue, {
"continue": "perceive",
"end": END
})
app = workflow.compile()
第四阶段:打磨“大钳子”(动作执行与底层钩子)
PyAutoGUI 虽然好用,但在某些高权限窗口(如 Windows 的任务管理器、macOS 的系统设置)或全屏游戏中,它会失效。为了让小龙虾的“钳子”无坚不摧,我们需要引入底层系统钩子(Hooks)。
4.1 跨平台的高阶执行策略
| 操作系统 | 基础方案 (PyAutoGUI) | 进阶方案 (OpenClaw 推荐) | 适用场景 |
|---|---|---|---|
| Windows | pyautogui.click() | win32api.SendMessage / ctypes 调用底层鼠标事件 | 绕过 UAC 弹窗、后台窗口静默点击 |
| macOS | pyautogui.click() | cliclick 工具 / CGEventCreateMouseEvent (Quartz) | 解决 macOS 辅助功能权限限制、高 DPI 缩放问题 |
| Linux | pyautogui.click() | xdotool / xte | 兼容 Wayland/X11 不同的显示服务器协议 |
4.2 解决“高 DPI 缩放”导致的坐标偏移(经典大坑)
很多新手在 Windows 上写自动化,发现鼠标总是点偏。这是因为 Windows 的显示缩放(如 150%)导致逻辑坐标与物理坐标不一致。
避坑代码(Windows 平台):
import ctypes
# 强制当前进程感知真实的物理 DPI,忽略系统缩放
ctypes.windll.shcore.SetProcessDpiAwareness(2)
# 此时 pyautogui 获取的屏幕尺寸和坐标,将与物理像素 1:1 对应
第五阶段:高级进阶——赋予小龙虾“长期记忆”与“自我纠错”
一只只会死板执行的小龙虾是脆弱的。如果网页加载慢了半拍,或者突然弹出一个“是否允许 Cookie”的弹窗,小龙虾就会点错位置,导致全盘崩溃。我们需要给它加上异常处理与自我纠错机制。
5.1 视觉异常检测(Anomaly Detection)
在执行动作后,我们不能盲目认为成功了。我们需要对比“执行前”和“执行后”的屏幕差异。
import cv2
import numpy as np
def check_screen_change(img_before, img_after, threshold=0.05):
"""通过 SSIM 或像素差异判断屏幕是否发生了预期变化"""
# 转换为灰度图并计算差异
diff = cv2.absdiff(img_before, img_after)
non_zero_count = np.count_nonzero(diff)
total_pixels = diff.size
change_ratio = non_zero_count / total_pixels
return change_ratio > threshold
5.2 弹窗拦截与“条件反射”
我们可以在 LangGraph 中增加一个 “环境扫描(Scan)”节点。在每次执行主任务前,先快速扫描屏幕上是否出现了已知的“干扰弹窗”(如广告、更新提示、Cookie 确认)。
Prompt 设计技巧:
"在规划主任务动作之前,请先检查屏幕四周是否有弹窗、遮罩层或 Cookie 提示。如果有,优先执行 'click_close_button' 动作清除干扰,然后再继续主任务。"
第六阶段:安全护栏——防止小龙虾“拆家”
这是最重要的一环!系统级 Agent 拥有极高的权限,如果大模型产生幻觉,它可能会帮你把桌面上的文件全选删除,或者在微信群里乱发消息。我们必须为小龙虾戴上“紧箍咒”。
6.1 物理级“急停开关(Kill Switch)”
不要依赖软件层面的暂停,必须监听全局硬件热键,一旦触发,瞬间切断所有鼠标键盘模拟。
from pynput import keyboard
import sys
import os
def on_press(key):
# 监听 Ctrl + Shift + Q 作为紧急停止快捷键
if key == keyboard.Key.esc:
print("🚨 触发紧急停止!小龙虾已强制休眠!")
# 强制结束进程,防止 PyAutoGUI 队列继续执行
os._exit(1)
listener = keyboard.Listener(on_press=on_press)
listener.start()
6.2 危险区域围栏(Geo-Fencing)
限制小龙虾的鼠标移动范围,或者禁止它在特定窗口(如“回收站”、“CMD 终端”、“微信聊天框”)内执行点击和输入。
DANGEROUS_WINDOWS = ["cmd.exe", "powershell", "Terminal", "Recycle Bin"]
def is_safe_to_act(current_window_title):
for danger in DANGEROUS_WINDOWS:
if danger.lower() in current_window_title.lower():
print(f"⚠️ 拦截:检测到危险窗口 [{current_window_title}],拒绝执行动作!")
return False
return True
6.3 人类在环(Human-in-the-Loop)确认机制
对于涉及“支付”、“删除”、“发送”等高危动作,强制要求人类按下回车键确认。
HIGH_RISK_KEYWORDS = ["支付", "删除", "清空", "发送", "转账", "submit", "delete"]
def require_human_confirmation(action_plan):
action_str = json.dumps(action_plan).lower()
if any(kw in action_str for kw in HIGH_RISK_KEYWORDS):
print("⚠️ 检测到高危操作意图!")
confirm = input("是否允许小龙虾执行此操作?(y/n): ")
return confirm.lower() == 'y'
return True
第七阶段:实战演练——让小龙虾帮你“自动抓取并整理竞品数据”
光说不练假把式。现在,我们用搭建好的 OpenClaw 核心,给它下达一个真实的复杂任务:
🎯 任务指令:
“打开浏览器,访问某电商网站,搜索‘机械键盘’,把前 5 个商品的名称、价格和评论数提取出来,保存为 Excel 文件。”
7.1 小龙虾的执行轨迹(Trace)
| 步骤 | 小龙虾的“思考 (Thought)” | 小龙虾的“动作 (Action)” | 屏幕状态变化 |
|---|---|---|---|
| 1 | 需要打开浏览器,寻找桌面的 Chrome 图标。 | click(120, 450) | Chrome 启动,显示新标签页。 |
| 2 | 浏览器已打开,需要点击搜索框并输入网址。 | click(400, 60), type("jd.com"), press("enter") | 跳转至电商首页。 |
| 3 | 首页加载完成,定位到顶部搜索框,输入关键词。 | click(500, 150), type("机械键盘"), click_search_btn | 进入搜索结果列表页。 |
| 4 | 看到商品列表。需要提取 DOM 树中的商品节点数据。 | extract_data(css_selector=".gl-item") | (内部数据抓取,无 UI 变化) |
| 5 | 数据提取完成,需要打开 Excel 并粘贴。 | open_app("Excel"), paste_data() | Excel 打开并填入数据。 |
| 6 | 任务完成,保存文件。 | press("ctrl+s"), type("竞品数据.xlsx"), press("enter") | 文件保存成功。 |
| 7 | 汇报结果。 | finish("已成功提取 5 条数据并保存至桌面。") | 任务结束。 |
(注:在实际运行中,步骤 4 通常不需要真的去“看”屏幕,而是直接通过注入 JS 或解析 DOM 树获取数据,这体现了 OpenClaw 视觉与代码执行混合的强大能力。)
总结与展望:从“数字小龙虾”到“硅基打工人”
恭喜你!跟着这篇万字长文,你已经亲手搭建出了一个具备视觉感知、逻辑规划、底层控制和自我纠错能力的系统级 Agent 核心引擎。
这只“数字小龙虾”虽然目前还略显稚嫩(可能会在复杂的验证码面前卡壳,可能会被奇葩的 UI 布局绕晕),但它所代表的技术范式,正是 2026 年乃至未来十年 AI 发展的绝对主线:AI 正在从“对话框里的谋士”,变成“操作系统里的执行者”。
🚀 给开发者的进阶建议
- 拥抱多模态(VLM):不要再用纯文本 LLM 去猜 UI 了,视觉才是数字世界的原生语言。关注 Qwen-VL、LLaVA 等开源多模态模型的微调。
- 深耕 OS 底层 API:只会调 Python 库是不够的。去学学 Windows 的
Win32 API、macOS 的AppleScript / Accessibility、Linux 的D-Bus。谁能最优雅地绕过系统的权限壁垒,谁的 Agent 就最稳定。 - 敬畏安全:能力越大,责任(风险)越大。在设计 Agent 架构时,“沙盒隔离”和“权限最小化” 必须写在第一行代码里。
未来,你的电脑上可能不再需要安装几十个 APP。你只需要养几只不同技能的“数字小龙虾”:一只负责回邮件,一只负责做报表,一只负责抢演唱会门票。而你,只需要喝着咖啡,对它们说一句:“把活儿干了。”
💬 极客互动时间:
- 在搭建“复眼”时,你觉得纯视觉截图和DOM树提取,哪个在未来的 Agent 开发中更有潜力?
- 如果你的“数字小龙虾”为了帮你完成任务,不小心点开了一个奇怪的广告链接,你会怎么优化它的“避障逻辑”?
- 你最希望这只小龙虾帮你自动化处理哪项最让你抓狂的日常重复工作?
欢迎在评论区留下你的代码片段、踩坑记录或奇思妙想!如果这篇万字实战指南让你大呼过瘾,请务必【点赞】+【收藏】+【转发】给你的极客朋友们,让我们一起迎接“硅基打工人”的时代!
(本文作者系资深 AI 架构师,代码与架构基于 2026 年主流 Agent 框架与多模态技术栈深度提炼。开源有风险,“养虾”需谨慎。未经允许,禁止转载。)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)