Dobby 实验解析:用 Agent 替代手机 App 的技术路径


为什么这件事值得看

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,而是:

  1. 自动判断网段范围
  2. 对每个存活 IP 做服务探测
  3. 根据开放端口推测设备类型(如 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 在这个阶段需要做:

  1. 抓取已有 App 的通信流量:如果能让 Agent 监听到你用官方 App 操作时的流量,它就能看到”点击播放”对应的是哪个 HTTP 请求
  2. 分析协议结构:识别出这是 SOAP 还是 REST,请求格式是什么
  3. 尝试构造控制命令:根据抓包结果,自己生成类似的请求

一个抓包 + 分析的示例流程:

# 中间人代理抓取 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 知道有哪些可执行动作,然后选一个”。

典型的做法:

  1. 维护一个”动作库”:对于发现的设备,记录它支持的动作(如 Sonos 支持 Play, Pause, SetVolume 等)
  2. 接收用户指令后,让 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。本文拆解了其核心技术:网络发现、协议推断、自然语言到控制命令的映射,提供了可复现的技术架构和代码示例。


文章作者: 左哥
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 左哥 !
  目录