一文对 Open‑AutoGLM / AutoGLM Phone Agent 的系统性技术拆解
Open-AutoGLM是一个手机GUI Agent框架,通过"观察-思考-行动"闭环实现自动化操作。系统分为Agent端(电脑/服务器)和视觉模型服务端:Agent端通过ADB/HDC获取手机屏幕截图和当前App信息,构造多模态消息(文字+截图)发送给模型;模型服务(支持云端API或本地vLLM部署)基于OpenAI兼容API返回结构化动作指令(如do/finish);Age
目录
一、整体实现思路:把手机当作一个“可视 GUI 环境”的 Agent 闭环
思考与规划(Thinking / Planning):由模型驱动
动作解析(Action Parsing):把模型输出映射为结构化指令
动作执行(Action Execution):从抽象动作到真实 ADB/HDC 调用
模型服务栈:OpenAI 兼容 API + vLLM/SG‑lang
通信协议:OpenAI Chat Completions(流式)
响应分段:从原始文本中分离 thinking 与 action
六、如果你要“参考 AutoGLM 自己实现一套”:可以怎么抄架构?
小总览:
这个开源项目是怎样实现的?(整体架构与代码逻辑)
底层交互原理是什么?(Agent ⇄ 模型 ⇄ 设备 的闭环机制)
用的是什么技术栈,在这个栈上如何“加上”AI 交互?
与 AI 交互的具体实现细节是什么?(消息格式、模型 API、解析逻辑等)
一、整体实现思路:把手机当作一个“可视 GUI 环境”的 Agent 闭环
AutoGLM 的开源实现叫 Open‑AutoGLM,本质上是一个 “手机 GUI Agent 框架 + 多模态模型服务” 的组合:
-
两大部分架构(README 明确说明)[1]:
-
Agent Code(本仓库)
-
跑在你的电脑/服务器上
-
负责:
-
连接手机(ADB/HDC/WDA)
-
截图 + 识别当前前台 App
-
构造发给模型的多模态消息(文字 + 截图)
-
解析模型返回的
do(...) / finish(...)动作 -
把动作转换成实际的点击、滑动、输入等操作
-
-
-
Vision Model Service(视觉语言模型服务)
-
可以是云端 API(z.ai / Novita / Parasail)
-
也可以是你自己用 vLLM / SG‑lang 在本地部署的服务
-
提供一个 OpenAI 兼容的 Chat Completions HTTP 接口
-
-
核心理念: Agent 只做“观察 + 执行”,不自己做复杂规划;复杂推理/规划全交给多模态大模型。
二、底层交互原理:一个“观察–思考–行动”的循环
用更工程化的语言,AutoGLM 的底层是一个典型的 perception–planning–action loop,每一步都非常清晰。
-
状态感知(Perception):从设备抓取屏幕和上下文
在每个 step 中,Agent 先获取当前手机状态:
device_factory = get_device_factory()screenshot = device_factory.get_screenshot(device_id)current_app = device_factory.get_current_app(device_id)
-
get_screenshot:-
Android:通过 ADB 把
screencap的结果拉过来,转成base64 -
HarmonyOS:通过 HDC 抓图
-
-
get_current_app:-
通过
adb shell dumpsys window等方式解析当前前台 Activity / 包名,抽象成current_app
-
再用 MessageBuilder.build_screen_info(current_app, ...) 组装成一个 JSON 风格的 “屏幕信息摘要字符串”,写进 prompt 里给模型看:
python复制
screen_info = MessageBuilder.build_screen_info(current_app)# 返回 JSON 字符串,例如 {"current_app": "com.tencent.mm"}
-
思考与规划(Thinking / Planning):由模型驱动
整个“该干什么”的决策完全交给模型:
-
构造一个 system 提示(系统角色,用于约束输出格式和行为):
-
中文系统提示(极长):详细定义了可用动作,如
do(action="Launch", app="xxx")、do(action="Tap", element=[x,y])、finish(message="xxx"),以及一堆操作策略规则(比如网络错误重试策略、搜索策略、各种 App 运营规则等)[2]。 -
英文系统提示:结构更简洁,但同样要求输出
<think>...</think><answer>do(...)</answer>格式[3]。
-
-
构造 user message(多模态):
-
第一步:
-
text_content = f"{user_task}\n\n{screen_info}"user_msg = MessageBuilder.create_user_message(text=text_content,image_base64=screenshot.base64_data# 图像用 data:image/png;base64,... 形式) -
后续步骤不再附加用户指令,只上传当前屏幕信息:
-
text_content = f"** Screen Info **\n\n{screen_info}"user_msg = MessageBuilder.create_user_message(text=text_content) -
把所有历史 system + user + assistant 消息(
self._context)送入模型: -
stream = client.chat.completions.create(messages=self._context,model=model_name,stream=True,...) -
模型按照系统提示要求输出:
-
<think>...内部思考...</think><answer>do(action="Tap", element=[x,y])</answer> -
或最终:
-
<answer>finish(message="任务完成")</answer> -
动作解析(Action Parsing):把模型输出映射为结构化指令
模型输出中真正要执行的部分统一是一个 Python 风格的伪代码:
do(action="Launch", app="WeChat")do(action="Tap", element=[523, 312])do(action="Type", text="Hello")finish(message="Done")
在 Agent 中:
from phone_agent.actions.handler import do, finish, parse_actionaction = parse_action(response.action)
parse_action 的逻辑非常关键[4]:
-
对 Type/Type_Name 这种特例,用字符串操作直接提取
text=...。 -
对一般的
do(...)调用:-
使用
ast.parse(response, mode="eval")-
避免直接
eval,安全性高得多
-
-
遍历
ast.Call.keywords,用ast.literal_eval读取参数值: -
python复制
-
action = {"_metadata": "do"}for kw in call.keywords:action[kw.arg] = ast.literal_eval(kw.value)
-
-
对
finish(message=...),生成: -
{"_metadata": "finish", "message": "..."}
所以:模型的“代码输出”本质上是一个 DSL,被安全地解析为结构化 dict。
-
动作执行(Action Execution):从抽象动作到真实 ADB/HDC 调用
ActionHandler.execute(action, screen_width, screen_height) 做了两件事:
-
根据
_metadata判断是否结束:-
_metadata == "finish"→should_finish=True,不再操作设备,只返回消息。 -
否则
_metadata == "do"→ 交给具体 handler 执行。
-
-
按 action 名分发到各个 handler[5]:
-
支持的动作包括:
-
Launch -
Tap -
Type/Type_Name -
Swipe -
Back -
Home -
Double Tap -
Long Press -
Wait -
Take_over -
Note -
Call_API -
Interact
-
-
示例:
Tap的执行大致是: -
def _handle_tap(action, width, height):rel_x, rel_y = action["element"]# 0~1000 相对坐标x = int(rel_x / 1000 * width)y = int(rel_y / 1000 * height)device_factory.tap(x, y, device_id) -
其中
device_factory.tap内部再去组装adb shell input tap x y或 HDC 对应命令。
到这里,一个完整 step 的行为闭环就走完了。
三、用的是什么技术栈?AI 交互是如何“装配”上去的?
-
编程语言 & 运行环境
-
语言:Python 3.10+
-
依赖通过
requirements.txt和pip install -e .安装[1]。 -
框架方面没有重度用到 web 框架,全是命令行/脚本式的结构。
-
设备控制技术栈
表格 还在加载中,请等待加载完成后再尝试复制
ADB/HDC 的实现都是用 Python 包一层 subprocess.run 调用系统 adb/hdc 命令,解析 stdout/stderr,抽象为:
-
get_screenshot(device_id) -
tap(x, y, device_id) -
swipe(start, end, device_id) -
launch_app(app_name, device_id) -
get_current_app(device_id) -
等
-
模型服务栈:OpenAI 兼容 API + vLLM/SG‑lang
核心选型是:不自己发明协议,直接用 OpenAI Chat Completions 协议。
-
使用
openaiPython SDK(from openai import OpenAI)[11]: -
self.client = OpenAI(base_url=config.base_url, api_key=config.api_key) -
默认配置:
-
base_url="http://localhost:8000/v1"model_name="autoglm-phone-9b"max_tokens=3000temperature=0.0top_p=0.85frequency_penalty=0.2 -
本地部署模型(vLLM 示例)[1]:
-
python3 -m vllm.entrypoints.openai.api_server \--served-model-name autoglm-phone-9b-multilingual \--model zai-org/AutoGLM-Phone-9B-Multilingual \--port 8000 \...# 一堆多模态参数# 服务地址即 http://localhost:8000/v1 -
AutoGLM 模型本身的架构:
-
Hugging Face 说明:
AutoGLM-Phone-9B(-Multilingual)的架构 与 GLM‑4.1V‑9B‑Thinking 相同[12],本质是一个多模态 VLM(能看图)。
-
因此 AI 交互并不是绑定某家云服务,而是通过“OpenAI API 兼容协议”这层抽象,你可以用:
-
智谱官方 API (
https://api.z.ai/api/paas/v4) -
Novita AI / Parasail 提供的 OpenAI 兼容端点
-
或者你自己用 vLLM/SG‑lang 跑在本地 GPU 上
四、与 AI 交互的具体实现细节
-
通信协议:OpenAI Chat Completions(流式)
模型客户端 ModelClient 的 request(messages) 做的事是:
stream = client.chat.completions.create(messages=messages,# 标准 OpenAI messages 格式model=config.model_name,max_tokens=config.max_tokens,temperature=config.temperature,top_p=config.top_p,frequency_penalty=config.frequency_penalty,extra_body=config.extra_body,stream=True,)
-
messages的结构示例: -
[{"role": "system", "content": SYSTEM_PROMPT_ZH},{"role": "user","content": [{"type": "image_url", "image_url": {"url": "data:image/png;base64,...."}},{"type": "text", "text": "用户任务 + 屏幕信息 JSON"}]},# 历史 assistant 消息: "<think>...</think><answer>do(...)</answer>"...] -
通过
stream=True实现 令牌级流式输出:-
一边接收 token,一边在控制台打印模型的 “thinking” 部分;
-
一旦检测到
finish(message=或do(action=这样的标记,就认为进入 action 阶段,停止在控制台继续打印 thinking,将剩余内容保留在raw_content中。
-
-
响应分段:从原始文本中分离 thinking 与 action
ModelClient 内部维护:
-
raw_content:把所有 token 串起来 -
buffer:用于查找 action 标记 -
action_markers = ["finish(message=", "do(action="]
流处理过程大概是:
-
每次拿到
chunk.choices[0].delta.content:-
累加到
raw_content -
若尚未进入 action 阶段,则累加到
buffer,并尝试:-
如果某个 marker 出现在
buffer中:-
thinking_part = buffer.split(marker, 1)[0]→ 打印出来 -
标记
in_action_phase=True,记录time_to_thinking_end
-
-
如果
buffer的结尾可能只是 marker 的前缀(例如do(act),则暂不打印,等待更多 token。 -
否则,就把
buffer打印并清空
-
-
-
全部结束后,用
_parse_response(raw_content)分出:-
thinking:完整<think>...</think>部分 -
action:do(...)或finish(...)部分字符串
-
( _parse_response 源码没完全展示,但从使用方式和系统提示内容可推断大致逻辑。)
-
上下文管理:如何维持“有记忆”的多轮操作
PhoneAgent 维护一个 _context: list[dict]:
-
第一步:
-
append system message
-
append user message(任务 + 首屏截图)
-
-
每一步执行完后:
-
将刚刚那轮的
<think>...</think><answer>...</answer>作为 assistant 消息塞回_context: -
self._context.append(MessageBuilder.create_assistant_message(f"<think>{response.thinking}</think><answer>{response.action}</answer>")) -
同时把上一条 user 消息中的图片内容删掉(只保留文字),节省上下文长度:
-
self._context[-1] = MessageBuilder.remove_images_from_message(self._context[-1])
-
下一轮再追加新的 user 消息(当前屏幕信息),如此往复,形成一个 多轮 GUI 操作对话记录。
五、从“底层交互原理”的角度再总结一遍
用一句话概括 AutoGLM 的底层交互原理:
把手机屏幕抽象成“多模态上下文”,把点击/输入抽象成“ DSL 指令”,用 OpenAI 兼容 Chat API 做“视觉—规划—动作生成”,再用 ADB/HDC 把这些 DSL 指令落成真实操作。
更细一点分层看:
-
模型层:
-
AutoGLM‑Phone‑9B(-Multilingual) = 一个 GLM‑4.1V‑9B‑Thinking 架构的 VLM,接受文本 + 图像输入;
-
通过系统 prompt 把输出空间限制为
do(...)/finish(...)风格的动作代码。
-
-
协议层:
-
完全复用 OpenAI Chat Completions 协议(包含多模态 image_url);
-
本地可由 vLLM/SG‑lang 提供服务,云端可由各类兼容 API 提供。
-
-
Agent 层:
-
负责构造 messages、调用模型、解析模型输出、管理对话历史;
-
通过 AST 安全解析将模型输出变为结构化动作。
-
-
设备层:
-
ADB/HDC/WDA 负责真实世界的 GUI 操作;
-
对 Agent 暴露的是逻辑函数:
tap、swipe、launch_app、get_screenshot等。
-
六、如果你要“参考 AutoGLM 自己实现一套”:可以怎么抄架构?
按照 AutoGLM 的思路,你可以最小化复刻一个类似系统,关键步骤是:
-
先选一个多模态模型 + OpenAI 兼容推理框架(如 vLLM)
-
保证支持
image_url输入; -
用类似 AutoGLM 的 system prompt 约束输出为
do(...)/finish(...)。
-
-
实现一个最小的 ModelClient
-
用
openaiSDK 或直接 HTTP 请求; -
支持
messages(system + user + assistant 历史); -
输出一段文本,内部再拆出
thinking和action。
-
-
设计一套简单的 DSL + 解析器
-
比如就支持:
Launch、Tap、Type、Back、Home; -
仿照 AutoGLM 用
ast.parse做安全解析。
-
-
封装设备控制
-
对 Android 包一层 ADB:
tap(x,y),swipe,screencap等; -
用一个
DeviceFactory来屏蔽 ADB/HDC/WDA 差异。
-
-
写一个 Agent Loop
-
输入:自然语言任务;
-
循环: 1)截图 + 当前 App → 拼成 user message 2)调用模型 → 得到
do(...)3)解析动作并执行 4)直到finish(...)或步数上限。
-
这套设计就是 AutoGLM 的核心精髓,Open‑AutoGLM 已经把每一层都拆得很清晰,可以直接按模块借鉴。
References
[1] README_en – Open‑AutoGLM 架构与部署说明. https://github.com/zai-org/Open-AutoGLM/blob/main/README_en.md [2] prompts_zh.py – 中文系统提示与规则. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/config/prompts_zh.py [3] prompts_en.py – 英文系统提示与输出格式约束. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/config/prompts_en.py [4] handler.py – parse_action 实现与动作分发接口. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/actions/handler.py [5] handler.py – ActionHandler 支持的动作类型与执行逻辑. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/actions/handler.py [6] adb/init.py – Android 设备控制函数导出. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/adb/__init__.py [7] adb/connection.py – ADB 连接、列设备与 server 管理实现. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/adb/connection.py [8] hdc/init.py – HarmonyOS 设备控制接口导出. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/hdc/__init__.py [9] hdc/connection.py – HDC 连接、列设备与 server 管理实现. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/hdc/connection.py [10] main.py – CLI 入口与 Agent/ModelConfig 组装逻辑. https://github.com/zai-org/Open-AutoGLM/blob/main/main.py [11] model/client.py – ModelClient 与消息构造、流式响应处理. https://github.com/zai-org/Open-AutoGLM/blob/main/phone_agent/model/client.py [12] AutoGLM-Phone-9B-Multilingual 模型卡 – 模型架构与能力说明. https://huggingface.co/zai-org/AutoGLM-Phone-9B-Multilingual
更多推荐
所有评论(0)