我怎么给手机 GUI Agent 做记忆层:事实常驻、技能按需,一条写入链

这篇讲什么 :我们给一个操作手机的 AI Agent 做了一个「记忆层」------它每完成一个任务,就把这次的经验记下来,下次开工时塞进提示词里。问题是:这样真的能少走弯路吗?

答案:一半立住了,另一半还没看到正向证据------而且界线很清楚。

  • ✅ 环境事实 ("新建笔记会先弹类型选择框"、"输入框没聚焦时打字静默无效"):任务步数中位数从 41 步降到 21 步,三轮复现方向一致。
  • ⏳ 操作技能 ("新建一条闹钟要点哪几个按钮"):自蒸馏的两种形态真实加载过 ,步数没改善;塞进常驻块反而测得 45 步 (比无知识更差)------ 目前拿不到正向证据,不是已被判死。

一句话基调:一个平面立住了(环境事实 −49%),另一个平面还没看到正向证据(操作技能)。后者不是结论,是待验证。

再定性一句 :我们否定的是「自动蒸馏」这个供给方式 ,不是「技能」这个平面 ------ 技能平面保留,改为人工编写。

全文真机(realme RMX3115 / Android 12)。标注含义:✅ 已实测 / ⏳ 还没看到正向证据 / ⚠️ 方向一致但未达显著 / ❌ 未验证。负结果照实写。


一张表看全局

知识类型 例子 供给方式 现状
环境事实 "新建笔记会先弹类型选择框"、"输入框没聚焦时打字静默无效" 模型自动蒸馏 ✅ 中位 41 → 21 步(p=0.0216)
操作技能 "新建闹钟的完整点击步骤" 自动蒸馏(本版起不再产出)→ 改为人工编写 ⏳ 真实加载过,但还没看到正向证据

下面分四部分展开:立住的那半、待验证的那半(含与开源框架的对照)、知识本身的上限、以及我们怎么设计的。


一、有效的一半:把"环境规律"常驻注入

怎么测的

标准做法是两臂对照(另有技能臂与混合臂,见第二节):

  • A 臂:不给任何知识
  • M 臂:只注入环境事实

执行纪律:两组交错跑(抵消时间漂移)、每轮之前把知识清到该臂基准线(防止上一轮残留污染下一轮)、每轮之后把被测 App 重置。5 轮/组,20 次全部成功。

指标用步数而不是成功率------把步数上限放大到撞不上之后,成功率会饱和到 100%、失去区分度;步数还能反映"知道怎么做"和"执行得干净"之间的差别。

结果

臂 中位步数 均值 对比 A 臂 判定
A 无知识 41 43.0 基线 ---
M 只注入事实 21 20.4 −49% ✅ p=0.0216

怎么读:知道这个 App 的怪癖之后,Agent 少绕了 20 步,差异在统计上显著。

复现与适用条件

换任务重跑三轮,中位步数的改善分别是 −49% / −23% / −19.5% (p=0.0216 / 0.17 / 0.345)。

怎么读:三轮方向一致为正,但后两轮没达到统计显著。我们标成 ⚠️「方向一致」而不是「已证明」------每轮只有 5 次的小样本给不出稳定显著的结论,但方向不会骗人。

收益有前提:换成界面简单的任务,n=10/组,四项指标全部不显著(p=0.36~1.0)。

怎么读:知识能省下的,是"不知道就必然绕远"的那部分路。任务本身简单时没什么可省,收益就低于噪声。


二、还没看到正向证据的一半:操作技能(一次试过、按止损口径放下的尝试)

这一节是本文的探索部分 :操作技能我们不是没想到,而是自动蒸馏这条路目前拿不到正向证据------并且它和公开研究的观测同向。

我们试了什么

让模型在每次任务成功后,除了事实之外再产出一份「操作技能」,产出两种形态,都走同一套校验(引用的控件必须在轨迹里真出现过、文本脱敏、坐标不许偏离实际点按位置):

形态 长什么样 怎么用
文字操作手册 一段引导文字:怎么确认进对界面 → 每一步做什么 → 有哪些坑 → 怎么算成功 模型需要时调用 load_skill 取
步骤序列 从执行轨迹自动提炼的点击步骤(脱敏后落盘) 同上

两者都被模型真实加载过(10 次实验里 10 次调用了取技能的指令)。

结果

形态 中位步数 均值 成功次数
文字操作手册 38 37.6 10/10
步骤序列 41 48.3 9/10(一次撞步数上限)

怎么读 :两种形态都落在"无知识"基线(41 步)附近,没有可确认的改善。被加载 ≠ 有帮助------这是这次探索最反直觉的一条:模型确实去读了技能,但读完并没有少走路。

还有一个副作用更值得记:把技能手册也放进常驻注入块(每步都重发的那段),中位步数变成 45,比无知识还差。

怎么读:常驻上下文是按步计费的"带宽"。往里塞一段平庸内容,代价是把已经生效的内容挤掉。

和开源研究对得上吗?------对得上

来源 他们的结论 与我们的关系
SkillsBench(Agent Skills 规范配套基准) 人写技能 +16.2pp ;自蒸馏 −1.3pp,84 个任务里 16 个负增益 我们的结果与它同向
ASI(arXiv:2504.06821) 程序化技能 + 程序化验证 ,比"文本技能"高 +11.3pp 收益来自"能被验证",不是"写得更好" ⇒ 提示我们缺的可能正是验证器
Memp(arXiv:2508.06433) 抽象脚本泛化强;纯轨迹只在近重复任务上有效 解释了为什么技能段进常驻块反而变差
TencentDB Agent Memory 只做 memory,不做技能层 我们的收敛方向与之一致

我们的负结果和公开报告同向:SkillsBench 上自蒸馏技能 −1.3pp。所以这不是一次失败,是给这个方向补了一个数据点。

这一路的结论

目前它拿不到正向证据。 按我们给这件事预设的止损口径,这一版先不在自动蒸馏技能上继续投入,留给后续任务------但这是资源分配决定,不是终审判决:等价的形态、更好的验证手段、或者换个任务族,都可能翻出正向结果。

有一个值得记下的机制:GUI 场景里没有"技能被执行得对不对"的反馈通道------技能被加载之后,Agent 走对了还是走错了,系统无从判断,也就无法把"对的那一次执行"沉淀下来。而公开研究里收益显著的那类(程序化技能)都自带一个执行验证器。这解释了 ASI 那个 +11.3pp 的前提,也提示我们下一步该补什么。

所以这一版的处置是:

  • 技能平面本身保留(格式、检索、按需加载、知识页管理都保留),供给方式改为人工编写;
  • 自动蒸馏技能从这一版起不再产出,代码路径已移除(蒸馏题目不再要求产出技能、晋升链与轨迹校验链一并撤掉);
  • 不把操作手册的文字并进事实通道------尽管它们本质同类。因为往唯一有效的通道里加内容有实测代价(就是上面那个 45 步),而且会绕过事实侧现有的节流。

一句话:操作技能更像操作缓存而不是知识 ,所以缓存的供给方式应该是人写。这是我们对供给方式的判断,不是"技能层无用"的结论------它留着一个口子:等有了执行验证通道,或换到有复现可能的场景,这条路可以重新拿出来跑。


三、知识本身有多少:约定型知识的实测

事实通道既然唯一有效,那它能装多少真正有迁移价值的知识?这是个必须实测的问题。

先把知识按"是否依赖界面锚点"分两类:

类型 定义 例子 生效条件
锚点型 依赖具体控件 id 或坐标 "点某个控件切到文本输入" 环境提供该锚点时
约定型 不依赖具体控件的行为规律 "软键盘弹出时保存按钮被遮挡"、"新建条目插在列表最前" 任何环境

只有约定型才可能跨 App 复用。两项离线测试(用模型做判定,不跑步数对照):

测试一 · 换提问方式。 同一批真机轨迹,只改蒸馏时给模型的题目:

题目 产出条目 约定型占比 文本锚定 控件 id 锚定 交白卷的轨迹
现状题目("环境事实 / UI 陷阱") 44 43% 1 55% 0 / 11
约定型题目 15 87% 1 0 6 / 13

怎么读 :控件 id 占比 55% → 0。之前"库存九成是控件 id 知识"这件事,很大程度是提问方式逼出来的:要求写"UI 陷阱",模型自然去写具体控件。

测试二 · 补一个漏掉的类别。 读真机产物时发现,唯一一条跨 App 的规律(截图因系统服务未启动而失败 → 改用控件树观察)来自工具与系统层,而题目全在讲界面控件。只补一条类别定义("工具/系统行为规律"),措辞一字不动:

题目 唯一存量(跨轨迹归并后) 交白卷轨迹
约定型(只给界面形态示例) 2 / 1(两次运行) 3/4、3/4
约定型 + 工具/系统类别 4 / 6 / 4(三次运行) 1/4、1/4、1/4

怎么读:三次运行全部高于对照、两个区间不重叠。同一现象的两种抽象层级最能说明问题------

  • 对照:「时间选择器弹出后若处于文本输入模式,键入需先点中小时/分钟框才生效」= 界面形态,换个 App 就不成立;
  • 补类别后:「文本输入工具 在目标输入框未获焦点时静默无效(不报错也不产生内容) ,必须先点击该输入框使其聚焦」= 工具层,跨 App 成立。

补类别后还捞到了此前四批都没出现的经典界面约定:「新建条目插入列表最前(倒序),而非追加在末尾」「单选项弹窗中选中条目本身不关闭弹窗,必须再点底部『确定』才提交」「系统级对话框『确定』在右下、『取消』在左下」。

两个必须承认的限制:

  1. 蒸馏原料原来只给了"这一步观察成功",界面状态被整个丢掉了 ------而约定型知识只存在于界面状态里。补上"动作 + 界面状态摘要"(可见文案 / 可点控件 / 焦点控件,不含 id 与坐标)后,上面那些条目才可能出现。
  2. 4~6 条 / 4 条轨迹仍属稀疏;真正的跨 App 条目集中在工具层,界面层条目多与本批 App 的交互模式相关,跨 App 泛化性未验证。

四、我们怎么设计的

4.1 两个知识平面 + 一层证据

平面 路径 供给方式 消费方式
环境事实 memory/MEMORY.md(分区)· memory_summary.md(注入视图)· fact_meta.json(效用索引) 自动:每次成功任务收尾蒸馏 常驻注入(每步重发,预算内全量)
操作技能 skills/<name>.md 人工编写(UI 支持列表 / 启停 / 删除) 按需加载 :search_skill / load_skill
任务证据 tasks/<tid>/(轨迹 jsonl / run.json) 运行时 蒸馏原料、可选重放

读给模型的内容是引导型文字;substeps 这类动作序列读给机器(做身份与校验),不进 prompt。两个平面共用一套治理:去重、效用分、容量淘汰。

4.2 写入链:一次成功任务之后做什么

arduino 复制代码
轨迹(脱敏:文本内容 → <text>)
  + 每步的界面状态摘要:可见文案 / 可点控件 / 焦点控件(不给 id、不给坐标)
  ↓ 模型提取事实(1 次调用 / 约 3.7s)
{"facts": ["环境规律 1~5 条"]}
  ↓ 语义去重:模型判"重复 / 合并 / 独立"(1 次 / 约 1.5s)
  ↓ 印证与反证:模型勾选被印证 / 被打脸的条目(1 次 / 约 0.9s)
MEMORY.md 追加 + fact_meta.json 更新 + 注入视图重新生成 → 每步重发进 prompt

三个关键设计点:

  • 界面状态摘要不能省(见第三节末)。
  • 允许交白卷:题目里明确写"观察不到规律就交空列表,交白卷是正确答案,凑数写出来的假规律是错误答案"。改成"必须产出 N 条"之后,模型在任何轨迹上都能硬凑出 N 条(含撞步数上限的噪声轨迹),其中约 23% 被判定无证据支撑------被配额逼出来的,不是观察到的。
  • 写入端节流:单次 ≤3 条;同一 App 300 秒内不重复合并(模型调用照常发生,冷却只挡入库,保证下一次任务就能看到本次沉淀)。

4.3 语义判断全部交给模型,脚本只做簿记

这是最硬的一条约束:同义判断、矛盾判断、印证判断都不写成"自己拍的规则" 。

这不是反对检索------BM25、向量检索仍是主流且可扩展,向量检索本身也是把语义交给模型。区别在于:阈值是在真机上看着几条样本拍出来的,换一批数据就要重调,而且永远调不到位。

环节 有模型 无模型(降级)
事实去重(新增 vs 存量) 判"重复 / 合并+重写 / 独立" 只做逐字精确去重
事实去重(存量之间) 判"删哪些 / 改写成哪句" 同上
印证 / 反证 勾选被印证 / 被打脸的条目 什么都不做
检索选档 模型选相关项 保持原序,不做相关性判断

降级方向是宁可不判断:两条事实被错并成一条,两边信息都丢了且不容易被发现;留重复交给容量淘汰兜底。

这条约束是被真机数据教出来的------规则路线在同一类错误上失效过多次:阈值式的去重调了三轮仍漏;用"控件名字相同"判技能同一性,结果模型每次命名有出入,同一套路裂成多个档位;"包名或控件出现即印证"的规则命中与真实依赖无关。

4.4 注入与容量

  • 常驻注入块 :事实全文 + 技能目录 top-3(模型选档),总预算 2000 字符,每步重发。
  • 按需加载 :load_skill / search_skill 由模型按需调用,命中即计数(否则命中率不可观测,淘汰没有输入)。
  • 可观测:上报"这次到底注入了哪几条事实"------只有这个能回答"知识到底有没有被送进去"。
对象 上限 治理
事实 单 App / 全局 12(保底 3)/ 40 效用分排序淘汰
技能 全局 20 同上
注入块 / 记忆视图 2000 / 20000 字符 硬上限
轨迹 / 任务 30 条 / 50 run・7 天・100 MB 收尾清理

效用分 = 印证次数×2 − 反证次数×3 + 新鲜度(30 天线性衰减) 。反证来自失败任务:按某条事实说的做却没生效,记一次 fail,累计 3 次直接淘汰------记忆会认错,所以必须有反证通道。

容量的理由是效率不是磁盘:注入块每步重发,字节按步计。实际占几个 G 根本不是问题。

实测治理效果:任务资产 283 run / 16.7 MB → 50 run / 3.6 MB;事实 12 → 9 条(体积 −24%);注入块 2207 → 1420 字符(−36%)。


五、几条设计决策及其代价

决策 依据 代价 / 放弃的东西
知识按"是否依赖锚点"分类,而不是按"事实 / 技能"分类 2×2 实验:抹掉环境里的控件 id(低带宽)后,知识从少 4.2 步 变成多 5.6 步------方向与预期相反 分类不能直接指导产出,得靠题目引导
事实常驻 、技能按需 事实进常驻块 21 步(最好),技能手册进常驻块 45 步(比无知识差) 每步重发的预算必须设硬上限
事实条目短、常驻、写成陈述句 有效的事实里同样有控件 id 知识(如系统确认按钮 id),照样有效 ⇒ 起作用的是载体不是内容 放弃了"沉淀长操作手册"这条路
允许交白卷,不给产出配额 配额会让模型在任何轨迹上硬凑,其中 23% 无证据支撑 沉淀量下降,要靠任务质量而非模型努力
蒸馏题目加入工具/系统行为类别 唯一存量 12 → 46,两区间不重叠,捞到此前从未出现的界面约定 尚未测"这些知识进注入后是否真的更好用"
语义判断全交模型 规则路线反复失效(阈值调三轮仍漏等) 无模型时知识库退化为"不判断"状态,靠容量淘汰兜底
技能平面保留,供给方式改为人工维护 自动蒸馏技能目前拿不到正向证据(本文第二节),与 SkillsBench 自蒸馏 −1.3pp 同向 这一版不再自动产出;留口子------有了执行验证通道或换场景可重跑

六、边界

  • 结论基于单一任务族(几个 Fossify 系 App)、单一机型、单一模型档位。步数的 run 间方差可达 5~7 倍,是所有对照实验的主要噪声源。

  • 收益指标是步数;单次任务的 token 收益未量化,与公开研究不同口径,不做横向比较。

  • 约定型知识的跨 App 泛化性未验证(4~6 条 / 4 轨迹)。

  • 反证淘汰机制目前只有单测覆盖,未在真实失败任务上验证。

  • 这一层没有标准答案 。公开文献里"自蒸馏知识何时有用"只有一个明确数据点(SkillsBench 自蒸馏 −1.3pp),所以我们的判据只用三条:机制解释、方向一致、负结果重复出现即成立,不追求统计显著性。

  • 两处我们主动停下来的地方(都是资源分配,不是判决):

    1. 操作技能的自动蒸馏 :这一版不再产出(§2)。同向证据已有(SkillsBench −1.3pp),但我们判断继续投入的边际收益低。留口子:一旦有了执行验证手段,或换到有复现可能的场景,可以重跑。
    2. 知识层的进一步收缩 :若把"工具/系统行为"类别搬进生产题目后,事实臂相对无知识臂仍看不到明显改善,就把知识层收缩为事实单平面(注入策略与容量治理保留),停止一切知识形态方向的投入。

七、复现工具

工具 用途
harness/experiments/xhs_probe.py 多臂对照 runner(知识态重置 / App 归位 / 注入块字节 dump)
harness/experiments/_inject_dump.py 用内核自己的代码组装注入块,保证看到的就是 prompt 字节
harness/experiments/_convention_probe.py 知识性质测试(换题目 / 补类别;产出性质与唯一存量统计)
kernel/tests/ · harness/parity/ 内核单测与双仓等价性测试

八、参考与致谢

  • TencentDB Agent Memory(MIT):注入端预算化召回、写入端节流、"低层留证据、高层留结构"。未采纳其"存储端默认永不清理"------那是桌面与服务端的成本结构,手机端每步重发整块必须真删。
  • SkillsBench / Agent Skills 规范:技能以文档 + 渐进披露提供,模型按需加载。其"人写 vs 自蒸馏"的对照数据是本文第二节的关键参照。
  • ASI(arXiv:2504.06821):程序化技能 + 程序化验证的收益量化。
  • Memp(ACL 2026 Findings, arXiv:2508.06433):程序性记忆双粒度。分歧点:其动作是文本指令可逐字照做,GUI 动作含坐标与控件 id 组合、每步界面都在变,逐字照做的前提不成立(未验证)。
  • Agent Workflow Memory(arXiv:2409.07429):从轨迹归纳自然语言 workflow,选择性注入。
  • ExpeL(arXiv:2308.10144):从轨迹抽取"洞察",评估时与成功轨迹一起召回。
  • AppAgent:移动端 Agent 的知识形态是每元素文字文档,恰好等于本文"事实"的形态。
相关推荐
zmsup3 小时前
设计 OpsArk 运维智能体:从一句需求,到一项可验收的任务
产品运营·agent·运维工具·终端运维
hpoenixf3 小时前
一个套壳MCP,为什么长成了研究决策系统
agent
骑着蜗牛撵大象3273 小时前
Agent 打字机是怎么来的:SSE 与 WebSocket 打通实时响应与中间状态
网络·websocket·网络协议·agent·sse·实时通信·流式输出
浮生望4 小时前
LangGraph 实战入门:用状态图写出分支、重试与人工确认
langchain·agent
10年前端老司机4 小时前
原来LangChain社区隐藏着这么多有趣的工具
人工智能·langchain·agent
夫子3964 小时前
【第三部分:第一个 Agent 应用】14. 开发一个完整的企业知识助手:从 RAG 到 Agent
llm·agent
GustorWang4 小时前
我开源了一个 agent harness:同一颗 2B 模型,四个框架得分从 0.017 到 0.821
agent
栈知见4 小时前
03-AgentScope核心概念全景:Agent / Message / Model 与 ReAct
agent
liulilittle4 小时前
短期内不存在通用 AI 工作流魔法
大数据·开发语言·c++·人工智能·llm·agent·tools