为什么这件事值得看
2026 年 3 月,Andrej Karpathy 发了一个实验演示:用 OpenClaw 写了一个叫 Dobby 的 Agent,只用自然语言,就控制了家里所有设备——扫描网络、发现设备、逆向未文档化的协议、调 Sonos、开关灯。整个过程没有打开任何 App,纯靠 Agent 跑。
这件事值得细看,不是因为它”震撼”——说实话,智能音箱也能做到类似的事。值得看的是:这是一个完整的、可复现的技术路径。它把 App 的 UI 层抹掉,让 Agent 直接操作底层协议。
这篇文章会聚焦在技术层面:Agent 替代 App,到底是怎么做到的?你如果要复现一个类似系统,需要哪些关键技术?有哪些坑是必踩的?
1. Agent 替代 App:不是”调用 API”,是”打穿协议层”
大多数人理解 Agent 替代 App,会想到”一个 Agent 调用一堆 API”。比如你让 Agent 帮你订外卖,它背后调美团外卖的 API。
但 Dobby 做的事情不一样:它不是在调用开放 API,而是在逆向设备协议。Sonos 没有公开”用自然语言放歌”的 API,Dobby 是先扫描网络、发现 Sonos 设备、找到了 UPnP 控制接口,然后直接对设备发包。
这带来的技术难度完全不同:
- 开放 API:Agent 只需理解文档、正确调用
- 协议逆向:Agent 需要发现设备、分析协议、构造报文、处理异常
Dobby 的技术价值在于:它证明了当下最强的 Agent,已经能在一定程度上自己完成协议层打通。这不是”调用能力”,而是”探索能力”。
2. 核心技术分解:Dobby 做对了什么
2.1 网络扫描与设备发现
Dobby 的第一件事:扫描本地网络,发现所有可交互设备。
这部分的典型技术栈:
# 使用 nmap 快速扫描局域网设备
nmap -sn 192.168.1.0/24 # 扫描整个网段,快速发现存活主机
# 识别设备类型(通过 MAC 厂商前缀)
nmap -O 192.168.1.100 # 尝试识别操作系统和设备类型
Agent 需要做的不是手动敲 nmap,而是:
- 自动判断网段范围
- 对每个存活 IP 做服务探测
- 根据开放端口推测设备类型(如 1400 端口常见于 UPnP 设备)
一个简单的设备发现逻辑(伪代码):
def discover_devices(network_range):
"""扫描网络,返回设备列表"""
devices = []
alive_ips = nmap_ping_scan(network_range) # 快速 ping 扫描
for ip in alive_ips:
services = nmap_service_scan(ip, ports=[1400, 80, 443, 8080])
if services:
device_type = infer_device_type(services)
devices.append({
'ip': ip,
'services': services,
'type': device_type # 'sonos', 'hue', 'unknown' 等
})
return devices
这里的核心难点不是扫描本身——工具都很成熟——而是:如何让 Agent 在拿到扫描结果后,能自己做判断:这个设备是什么?有什么可能的控制方式?
2.2 协议逆向:Agent 怎么”猜”出控制方法
Dobby 的第二个关键能力:对发现到的设备,自己摸索出控制协议。
以 Sonos 为例,它的控制接口是基于 UPnP 的 SOAP 协议。文档存在,但分散且复杂。真正实用的做法是:抓包 + 推断。
Agent 在这个阶段需要做:
- 抓取已有 App 的通信流量:如果能让 Agent 监听到你用官方 App 操作时的流量,它就能看到”点击播放”对应的是哪个 HTTP 请求
- 分析协议结构:识别出这是 SOAP 还是 REST,请求格式是什么
- 尝试构造控制命令:根据抓包结果,自己生成类似的请求
一个抓包 + 分析的示例流程:
# 中间人代理抓取 HTTPS 流量
mitmproxy --mode transparent --showhost
# 或者用 tcpdump 抓未加密流量
tcpdump -i any port 1400 -w sonos_traffic.pcap
协议逆向的精简示例(伪代码):
def reverse_engineer_protocol(device):
"""尝试推断设备的控制协议"""
# 判断是否是已知的协议类型
if has_upnp_service(device):
# UPnP 设备通常有设备描述文件
desc_url = f"http://{device.ip}:1400/xml/device_description.xml"
desc = fetch(desc_url)
# 解析可用动作(Play, Pause, SetVolume 等)
actions = parse_upnp_actions(desc)
return {'type': 'upnp', 'actions': actions}
# 如果不是已知协议,尝试抓包分析
traffic = capture_traffic(device.ip, duration=60)
patterns = analyze_patterns(traffic)
return {'type': 'unknown', 'patterns': patterns}
难点在这里:Agent 需要有足够的”协议知识”,才能判断一个设备的控制方式。比如看到 1400 端口 + SSDP 广播,要能联想到 UPnP。当前的 Agent 还做不到完全自动,需要一定的人类提示或预置知识。
2.3 自然语言到控制命令的映射
Dobby 的第三步:把你的自然语言指令,转换成具体的协议命令。
这里的核心是:结构化指令生成。不是”让 Agent 猜”,而是”让 Agent 知道有哪些可执行动作,然后选一个”。
典型的做法:
- 维护一个”动作库”:对于发现的设备,记录它支持的动作(如 Sonos 支持 Play, Pause, SetVolume 等)
- 接收用户指令后,让 LLM 在动作库中选择合适的动作 + 参数
示例(伪代码):
# 动作库示例
DEVICE_ACTIONS = {
'sonos': [
{'name': 'play', 'params': []},
{'name': 'pause', 'params': []},
{'name': 'set_volume', 'params': [{'name': 'level', 'range': [0, 100]}]},
],
'hue': [
{'name': 'turn_on', 'params': [{'name': 'light_id'}]},
{'name': 'turn_off', 'params': [{'name': 'light_id'}]},
{'name': 'set_color', 'params': [{'name': 'light_id'}, {'name': 'color'}]},
]
}
def parse_user_command(command, devices):
"""将自然语言指令解析为具体动作"""
prompt = f"""
用户指令:{command}
可用设备:{devices}
可用动作:{DEVICE_ACTIONS}
请选择最合适的动作和参数,以 JSON 格式返回。
"""
action = llm_call(prompt)
return action # 例如: {"device": "sonos", "action": "set_volume", "params": {"level": 50}}
这一步的难点:参数提取。用户说”放首周杰伦的歌”,Agent 需要识别出”播放”动作,同时知道 Sonos 的播放接口需要 URI 参数,然后去音乐源搜索”周杰伦”,拿到 URI 再调用。这个链条一旦拉长,出错概率就会急剧上升。
3. 可复现的技术架构
如果你要自己搭一个类似的系统,整体架构大概是这样:
[用户自然语言指令]
↓
[意图理解层] —— 解析用户要干什么
↓
[设备管理层] —— 维护已发现设备 + 可用动作
↓
[协议执行层] —— 具体调用 HTTP / WebSocket / SOAP 等
↓
[设备]
关键技术选型:
| 层级 | 推荐技术 | 说明 |
|---|---|---|
| 意图理解 | OpenAI GPT / Claude | 多轮对话 + 指令解析 |
| 设备发现 | nmap + SSDP + mDNS | 三种方式覆盖大部分设备 |
| 协议逆向 | mitmproxy + Wireshark | 初期可用,后期可以固化协议知识 |
| 协议执行 | Python requests / aiohttp | UPnP 用 upnpclient 库 |
一个最小可行架构示意图:
┌─────────────────────────────────────────────┐
│ 用户接口(语音/文本) │
└─────────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Agent 核心(LLM + 任务规划 + 记忆) │
└─────────────────┬───────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 设备抽象层(统一的设备操作接口) │
│ - play(device_id) │
│ - set_brightness(device_id, level) │
│ - scan_network() │
└─────────────────┬───────────────────────────┘
↓
┌────────────┬────────────┬────────────┐
│ UPnP 客户端│ HTTP 客户端│ 其他协议 │
└────────────┴────────────┴────────────┘
↓
[物理设备]
4. 必须面对的工程问题
Dobby 是一个实验,距离生产可用还有几道坎。
4.1 协议逆向不等于稳定接口
逆向出来的协议,随时可能变。厂家一次固件升级,你的 Agent 就可能失效。
现实做法:需要有一层适配层,把协议细节封装起来,设备变了只需改适配代码,不用动 Agent 逻辑。
class DeviceAdapter(ABC):
"""设备适配器基类"""
@abstractmethod
def play(self):
pass
@abstractmethod
def pause(self):
pass
class SonosAdapter(DeviceAdapter):
def __init__(self, ip):
self.client = UpnpClient(f"http://{ip}:1400")
def play(self):
# 调用 Sonos 的 Play 动作
self.client.action('Play', InstanceID=0, Speed=1)
def pause(self):
self.client.action('Pause', InstanceID=0)
4.2 多设备的协调问题
Dobby 演示的是单个设备控制。但现实中,你可能一句话要协调多个设备:说”准备睡觉”,需要关灯、拉窗帘、调低空调、把音乐改成白噪音。
这里涉及:场景编排。Agent 需要知道”场景”的概念,而不是一个指令一个指令地发。
一个场景定义示例:
# scenes.yaml
sleep:
description: "准备睡觉"
actions:
- device: hue_light_1
action: turn_off
- device: hue_light_2
action: turn_off
- device: living_room_ac
action: set_temperature
params: {temperature: 26}
- device: bedroom_sonos
action: play_playlist
params: {playlist: "white_noise"}
Agent 在解析”准备睡觉”时,需要能映射到这个场景定义,然后逐个执行。
4.3 错误处理与回滚
Agent 控制设备,有一个致命问题:错了怎么办。
你让 Agent”把客厅灯关了”,它不小心关成了书房灯。这时候需要:
- 用户反馈机制(”你关错了”)
- 回滚能力(记录操作历史,能撤销)
目前 Dobby 没有展示这方面的能力,但生产环境必须处理。
5. 你能直接上手的技术路径
如果你看完想自己试一下,可以按这个顺序:
第一步:能控制一个设备
选一个你家里已有的设备,先做到能用代码控制。比如:
# 用 Python 控制 Yeelight(支持标准协议)
from pywizlight import wizlight
light = wizlight("192.168.1.100")
await light.turn_on()
await light.set_brightness(128)
第二步:加上自然语言接口
用一个简单的指令解析:
import openai
openai.api_key = "你的 key"
def control_by_voice(command):
prompt = f"""
用户指令:{command}
可用动作:
- turn_on_light()
- turn_off_light()
- set_brightness(level: 0-255)
请返回要执行的 Python 函数调用。
"""
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
# 执行返回的函数
eval(response.choices[0].message.content)
第三步:加上设备发现
用 nmap 或 SSDP 自动发现设备:
import subprocess
def discover_upnp_devices():
# 发送 SSDP 发现消息
msg = (
'M-SEARCH * HTTP/1.1\r\n'
'HOST: 239.255.255.250:1900\r\n'
'MAN: "ssdp:discover"\r\n'
'MX: 1\r\n'
'ST: upnp:rootdevice\r\n'
'\r\n'
).encode()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(msg, ('239.255.255.250', 1900))
devices = []
while True:
try:
data, addr = sock.recvfrom(2048)
devices.append(addr[0])
except socket.timeout:
break
return devices
这个顺序的好处:从小处验证,逐步扩展,不会一开始就卡在复杂协议逆向上。
6. 这件事到底意味着什么
Dobby 的技术路径如果走通,影响的不是”App 消失”,而是”交互入口改变”。
手机 App 的本质:厂家给你一个 UI,你通过 UI 操作设备。Agent 替代 App,本质是:把交互的入口从 UI 变成了自然语言。背后的协议层还是那个协议层。
这不是说 App 会死——大量的复杂操作、信息展示、多步骤流程,App 依然是最优解。但对于”一个动作就可以完成的事”,Agent 会吃掉这部分入口。
真正值得关注的是:Agent 能做到什么程度的协议逆向,以及对未知设备的自适应能力。Dobby 今天能做到的,还是”已知协议类型的设备 + 少量人类辅助”。距离”自动搞懂任何设备”,还有一段路。
但对于开发者来说,这条技术路径已经清晰:设备抽象层 + 意图解析层 + 协议执行层。现在就可以开始试。
关键词建议
Agent 协议逆向、OpenClaw、设备自动化、自然语言交互、智能家居
摘要建议
Dobby 实验展示了 Agent 如何通过协议逆向替代手机 App。本文拆解了其核心技术:网络发现、协议推断、自然语言到控制命令的映射,提供了可复现的技术架构和代码示例。