TencentQQGYLab AppAgent
腾讯 QQ 实验室出品的 AppAgent
腾讯 QQ 实验室出品的 AppAgent

AppAgent 是一款基于大型语言模型的高级多模式代理,能够掌握和利用任何应用程序执行复杂任务。它通过直观的点击和滑动手势与应用程序交互,模仿类似人类的动作
tencent qq appagent 的设计
本文介绍了一种基于 LLM 的新型多模态代理框架,旨在操作智能手机应用程序。我们的框架使代理能够通过简化的操作空间操作智能手机应用程序,模仿类似人类的交互,例如点击和滑动。这种新颖的方法绕过了对系统后端访问的需求,从而扩大了其在不同应用程序中的适用性。我们代理功能的核心是其创新的学习方法。代理通过自主探索或观察人类演示来学习导航和使用新应用程序。此过程生成一个知识库,代理可以参考该知识库来执行不同应用程序中的复杂任务。为了证明我们代理的实用性,我们对 10 个不同应用程序中的 50 个任务进行了广泛的测试,包括社交媒体、电子邮件、地图、购物和复杂的图像编辑工具。结果证实了我们的代理能够熟练地处理各种高级任务。
app 自动化示例
这是在 x 上搜索 bill gates 的一个 app 自动化操作示例。
在 yelp 上打五星好评的一个示例
App Agent 的两个阶段 探索与部署
在探索阶段,代理与智能手机应用程序交互并从其结果中学习以创建全面的参考文档。在此阶段之后,代理利用此文档中汇编的信息来有效地操作和导航应用程序。
App Agent 分为两个阶段运行,分别称为探索阶段和部署阶段。在第一阶段,App Agent 观察不同应用程序用户界面中的交互。通过充分的观察,App Agent 能够熟练使用应用程序。这些知识被精心汇编成文档。一旦完成此学习阶段,代理就可以采取行动了。在第二阶段,App Agent 能够处理任何受支持应用程序中的高级任务。这种有条不紊的方法使 App Agent 能够高效地完成不同应用程序中的各种复杂任务。
探索阶段

通过观察各类应用程序的图形用户界面,App Agent 学习到了其功能和操作逻辑。这对其深入了解 GUI 元素的知识至关重要,因为它可以与应用程序进行智能交互。
部署阶段

当 App Agent 遇到新的图形用户界面时,它会查阅其知识库中的文档,以了解界面的目的和使用方式。然后,它会制定最合适的方法来完成给定的任务,将正确的操作分步骤地执行。
具体来说,App Agent 可能会进行以下步骤:
1. 访问知识库中的文档以获取界面元素的描述和功能信息。
2. 分析界面的设计模式和布局,以确定界面元素之间的关系和作用。
3. 确定使用界面元素完成任务的最佳策略。
4. 生成一步步地执行正确操作的步骤清单。
5. 根据步骤清单,实现任务的功能。
gmail app 的探索阶段

这是 Gmail App 的探索阶段的例子,通过在探索阶段学习 app 中的界面知识,可以获得足够的上下文信息。
gmail app 的部署阶段

这是 Gmail app 的部署阶段的例子,有了前面的上下文信息,就可以更加准确的处理 app 中的各类操作。
腾讯 AppAgent 部署使用
接下来我们开始安装和使用下这个工具
源代码部署
git clone https://github.com/TencentQQGYLab/AppAgent.git
cd AppAgent
pip install -r requirements.txt
git clone 对应的项目,然后进入项目目录,创建虚拟环境,并安装依赖。
模型配置
# 因为openai的图像识别模型比较贵,所以使用国内免费的qwen模型
# 也可以在本地部署qwen-vl模型
MODEL: Qwen
DASHSCOPE_API_KEY: "sk-你的token" # The dashscope API key that gives you access to Qwen-VL model
QWEN_MODEL: "qwen-vl-max"
配置文件在项目目录下的 config.yaml 中 因为 openai 的图像识别模型比较贵,所以使用国内免费的 qwen 模型 也可以在本地部署 qwen-vl 模型
本地部署视觉识别模型
# 平替模型,不过不稳定
ollama pull llava
ollama pull llama3.2-vision
ollama pull www.modelscope.cn/lmstudio-community/Qwen2-VL-7B-Instruct-GGUF
如果觉得在线模型也不方便,也可以考虑使用本地部署的模型。不过这些本地的小尺寸模型都不稳定。
探索阶段命令
# 配置 config.yaml
$ python learn.py
Welcome to the exploration phase of AppAgent!
The exploration phase aims at generating documentations for UI elements through either autonomous exploration or human demonstration. Both options are task-oriented, which means you need to give a task description. During autonomous exploration, the agent will try to complete the task by interacting with possible elements on the UI within limited rounds. Documentations will be generated during the process of interacting with the correct elements to proceed with the task. Human demonstration relies on the user to show the agent how to complete the given task, and the agent will generate documentations for the elements interacted during the human demo. To start, please enter the main interface of the app on your phone.
Choose from the following modes:
1. autonomous exploration
2. human demonstration
Type 1 or 2.
1
com.google.android.deskclock
在时钟app里添加香港时区
探索生成文档
{
"tap": "The UI element opens the Google app, displaying a search bar and options for Discover, Search, Recent, and More.",
"text": "",
"v_swipe": "",
"h_swipe": "",
"long_press": "",
"locator": "apps/com.google.android.deskclock/auto_docs/com.google.android.apps.nexuslauncher.id_search_container_all_apps_Search_com.google.android.apps.nexuslauncher.id_mic_icon_Voicesearch_2.txt"
}

截图
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy rotation="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1794]">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1794]">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1794]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/decor_content_parent" class="android.view.ViewGroup" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1794]">
<node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1794]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/main" class="android.view.ViewGroup" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1794]">
<node index="0" text="Search for a city" resource-id="com.google.android.deskclock:id/search_empty_view" class="android.widget.TextView" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[383,478][698,850]" />
</node>
</node>
<node index="1" text="" resource-id="com.google.android.deskclock:id/action_bar_container" class="android.widget.FrameLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,63][1080,210]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/action_bar" class="android.view.ViewGroup" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,63][1080,210]">
<node index="0" text="" resource-id="" class="android.widget.ImageButton" package="com.google.android.deskclock" content-desc="Navigate up" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,63][147,210]" />
<node index="1" text="" resource-id="" class="android.support.v7.widget.LinearLayoutCompat" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[240,63][1080,210]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/menu_item_search" class="android.support.v7.widget.LinearLayoutCompat" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[240,73][1080,199]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/search_bar" class="android.widget.LinearLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[240,73][1080,199]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/search_edit_frame" class="android.widget.LinearLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[261,73][1059,199]">
<node index="0" text="" resource-id="com.google.android.deskclock:id/search_plate" class="android.widget.LinearLayout" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[261,73][1059,199]">
<node index="0" text="Search…" resource-id="com.google.android.deskclock:id/search_src_text" class="android.widget.EditText" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="true" scrollable="false" long-clickable="true" password="false" selected="false" bounds="[261,88][954,183]" />
<node index="1" text="" resource-id="com.google.android.deskclock:id/search_close_btn" class="android.widget.ImageView" package="com.google.android.deskclock" content-desc="Clear query" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[954,73][1059,199]" />
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="android:id/navigationBarBackground" class="android.view.View" package="com.google.android.deskclock" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][0,0]" />
</node>
</hierarchy>

部署阶段命令
$ python run.py
com.google.android.deskclock
在时钟app里添加东京时区
接下来就可以使用 run 命令去让 app agent 完成一些 app 的任务了。
代码解读
核心代码
- scripts/config.py 基本的配置,全部是词典
- scripts/and_controller.py 负责 adb 控制
- scripts/model.py 负责大模型的请求响应解析
- scripts/prompts.py 提示词管理
- scripts/document_generation.py 文档生成处理
- scripts/step_recorder.py 探索阶段的人类演示功能
- scripts/self_explorer.py 探索阶段的自动探索功能
- scripts/task_executor.py 部署阶段的任务驱动功能
- learn.py 调用探索阶段的脚本
- run.py 调用 task_executor
- config.yaml 基本的配置,里面有 openai 和 qwen 等视觉模型的基本配置
腾讯 QQ 实验室 app agent 的总结
非常感谢腾讯 QQ 的同学共享的 Idea,这是一个具备创新思想的框架。 不过目前项目不活跃了,仅供参考,不建议使用了。
{.audio .d-block}