番摊机器人 一句话让 Agent 截取真机屏幕
要实现“一句话让 Agent 截取真机屏幕”,核心在于将复杂的底层驱动(如 Appium、ADB、WDA)
封装为标准的 Tool Schema,并配合现代化的设备自动化中间件(如 agent-device)。
以下是基于最新工程实践的最佳实现方案,分为架构选型、Tool 定义规范和代码实现三个部分。
一、 核心架构:为什么传统方式不行?
传统的 GUI 自动化(如纯 Appium 脚本)要求 Agent 理解坐标、XPath 和等待逻辑,这超出了 LLM 的稳定推理能力。
新范式采用 Agent-Device 桥接模式:
Agent 侧:只负责发出高层意图(如“截图”、“点击登录”)。
中间件层(如 agent-device 或自定义 Sandbox):充当“眼睛”和“手”,负责维护 WebSocket/HTTP 连接,处理屏幕流传输。
Tool 层:提供极简的 API,仅暴露 screenshot()、click() 等原子操作,隐藏所有设备连接细节。
二、 Tool Schema 设计规范
一个高质量的截图 Tool 必须包含以下四个要素,以确保 Agent 能正确调用并处理异常:
表格
要素 说明 示例值
Name 工具唯一标识 mobile_screenshot
Description 关键:明确何时用、返回什么格式、注意事项 "Captures the current screen of the connected mobile device. Returns a base64 encoded PNG string. Use this when you need to verify UI state or analyze visual elements."
Parameters 参数定义(尽量简化) {"quality": {"type": "integer", "description": "Image quality 1-100, default 80"}}
Returns 返回值结构 {"status": "success", "image_data": "base64_string", "timestamp": "..."}
三、 实战代码实现
方案 A:使用现代化开源库 agent-device(推荐)
这是目前社区最推崇的方案,它专为 AI Agent 设计,屏蔽了 Appium 的复杂性,支持 iOS/Android/TV。
1. 安装依赖
bash
npm install -g agent-device@latest
# 或者在 Python 环境中通过 subprocess 调用,或使用其提供的 SDK
2. Python 中封装为 LangChain/LlamaIndex Tool
假设你已经启动了 agent-device 服务或通过其 SDK 连接了真机。
python
import base64
from langchain.tools import BaseTool
from pydantic import BaseModel, Field
# 假设使用 agent-device 的 Python 绑定或 HTTP 接口
import requests
class ScreenshotInput(BaseModel):
quality: int = Field(default=80, description="Image quality from 1 to 100")
device_id: str = Field(default=None, description="Optional specific device ID if multiple connected")
class MobileScreenshotTool(BaseTool):
name: str = "mobile_screenshot"
description: str = (
"Captures the current screen of the connected mobile device (iOS/Android). "
"Returns a base64 encoded PNG image. "
"Use this tool to verify the current UI state, read text from images, or check if an action succeeded."
)
args_schema: type[BaseModel] = ScreenshotInput
def _run(self, quality: int = 80, device_id: str = None) -> str:
try:
# 调用 agent-device 或底层服务的截图接口
# 这里以假设的本地服务接口为例,实际需根据部署调整
url = "http://localhost:8080/screenshot"
params = {"quality": quality}
if device_id:
params["deviceId"] = device_id
response = requests.get(url, params=params)
response.raise_for_status()
# 假设返回的是二进制图片数据
image_bytes = response.content
base64_image = base64.b64encode(image_bytes).decode('utf-8')
return f"data:image/png;base64,{base64_image}"
except Exception as e:
return f"Error capturing screenshot: {str(e)}"
async def _arun(self, quality: int = 80, device_id: str = None) -> str:
return self._run(quality, device_id)
方案 B:基于 Appium + 沙箱(传统稳健方案)
如果你必须使用 Appium(例如在企业内网环境),则需要通过 Sandbox 隔离环境,避免驱动冲突。
python
import os
import base64
from appium import webdriver
from appium.options.android import UiAutomator2Options
from langchain.tools import BaseTool
from pydantic import BaseModel, Field
class AppiumScreenshotTool(BaseTool):
name: str = "appium_screenshot"
description: str = "Takes a screenshot of the currently active Android/iOS device via Appium. Returns base64 string."
args_schema: type[BaseModel] = BaseModel # 无参数或简单参数
def _run(self) -> str:
# 1. 初始化 Driver (实际生产中应复用 Driver 实例,而非每次创建)
# 注意:driver 实例应在工具外部初始化并传入,或通过单例管理
driver = self._get_driver()
try:
# 2. 执行截图
screenshot_base64 = driver.get_screenshot_as_base64()
return f"data:image/png;base64,{screenshot_base64}"
except Exception as e:
return f"Failed to take screenshot: {str(e)}"
finally:
# 不要在这里 quit driver,除非是单次任务
pass
def _get_driver(self):
# 模拟获取已连接的 driver
# 实际项目中建议通过依赖注入传入 driver 对象
options = UiAutomator2Options()
options.platform_name = "Android"
# 连接到本地 Appium Server
driver = webdriver.Remote("http://localhost:4723", options=options)
return driver
四、 如何让 Agent “一句话”调用?
在 System Prompt 中明确告知 Agent 该工具的存在和能力:
System Prompt 示例:
"You have access to a tool named mobile_screenshot. When the user asks to 'see what's on the screen', 'check the current page', or 'take a snapshot', you MUST call this tool. The tool returns a base64 image which you can then analyze using your vision capabilities."
用户指令示例:
“帮我看看现在手机屏幕上显示的是什么应用?”
Agent 执行流程:
思考:用户想知道屏幕内容 -> 需要视觉信息 -> 调用 mobile_screenshot。
行动:mobile_screenshot(quality=80)
观察:收到 Base64 图片字符串。
最终回答:结合视觉模型分析图片,回答“当前屏幕显示的是微信主界面...”
五、 关键避坑指南
Base64 长度限制:真机截图(尤其是高分屏)的 Base64 字符串非常长,可能超过 LLM 的 Context Window 或 API 限制。
优化:在 Tool 内部先进行图片压缩(Resize 到 720p 或更低),或转换为 JPEG 格式再编码。
状态同步:截图是瞬时状态。如果 Agent 需要基于截图做点击操作,必须确保截图后设备状态未发生改变。建议在 Tool 返回中附带时间戳。
隐私与安全:真机截图可能包含敏感信息。在生产环境中,建议在 Tool 层增加脱敏处理或权限确认机制。
错误反馈:如果截图失败(如设备断开),Tool 必须返回清晰的错误信息(如 "Device disconnected"),而不是静默失败,这样 Agent 才能尝试重连或报错。
通过这种封装,开发者无需关心底层的 ADB 命令或 Appium 配置,只需关注业务逻辑,真正实现了“一句话截真机屏”。
<< 上一篇