豆包手机再替:面向 Android 的第三方系统级 AI 助手 Eta

豆包手机再替:面向 Android 的第三方系统级 AI 助手 Eta

2026-11-11 13:50:27 0点赞 0收藏 0评论

我就知道评论区有好东西。

这次翻到的是 Eta——README 第一行自我定位是「面向 Android 的第三方系统级 AI 助手」,作者自己写得很直白:

不同于仅停留在无障碍模拟点击或通用 Root Shell 的第三方 Agent,Eta 对标的是手机厂商预装的一方系统助手。

这句话点出了两条完全不同的技术路线:

  • Mika 那条路:像人一样看屏幕、找按钮、点击输入。无障碍读界面,读不出来就 OCR 看图。通用,但慢,且碰不到系统内部。

  • Eta 这条路:直接调 Android 系统 API 和厂商自己家的应用接口——闹钟、日历、便签、开关,照着系统内部的规矩改。快,且能碰到别人碰不到的东西。

差别有多大?我拿真机测了一遍,最直观的例子是这条:

「帮我订明天早上 7:30、7:40、7:50 的闹钟」

从指令发出到三个闹钟全部建好并打开开关,13 秒。 全程没有一次点击,没有一张截图发回给模型。

同一台手机上,Mika 做同一件事花了 1 分 52 秒、7 步、12.6 万 Token。Eta 用了 13 秒、1 轮 2 步。

这不是模型更强,是它根本没在「看屏幕」——它在直接改系统数据。

但反过来也得说清楚:不是所有任务都能走这条捷径。 我又试了一个——「用京东查一下当前设备的回收价」,这台手机上明明装着京东 App,它却一次都没碰,全程用内置浏览器查了 47 步、7 分钟才拿到报价。

同一个 App,同一个 Eta,为什么一个 13 秒、一个 7 分钟? 这个问题比那个 13 秒更值得回答,我把整条链路和源码里的三层原因都挖了出来。

然后评论区有人问了一句:「手机是装了京东 App 的,为什么 Eta 不调用 App 去查呢?」

这问题问到了根子上。我把设备的无障碍服务打开,重跑了一遍同一个任务——

它就真去操作京东 App 了。 点搜索栏、输入「手机回收」、滑到回收频道、撞上京东的滑块验证码,然后把验证码画面推到你的主屏上,说「这个得你本人来」。

同一个问题,同一台设备,唯一的变量是「无障碍开没开」——答案就完全不一样。 下面我把两次实验的完整证据链都摆出来。

后来我做了第三次实验:把 Eta 背后的模型换掉,同一台设备、同一句指令、连提示都不多给,重跑一遍。

它还是认错了我的机型——把 Redmi K50 标准版当成了 K50 电竞版,在京东回收里查了错的那一档,报价直接差 180 元。但我只提示了一句「去用 getprop 查证」,它就自己跑命令、自己推翻自己的结论、自己改选机型重查一遍,最后拿到 ¥520。

这三轮实验连起来,指向一个挺反直觉的结论:难的不是让 AI 操作手机,是让它先搞清楚自己在操作什么。

然后我又做了第四次实验,故意换一个不需要它猜的任务:「把我在这台手机上叫过的外卖订单统计一下,都点了些什么、平均花了多少钱」。

这次它表现得出乎意料地好——自己找到了京东「秒送·外卖」订单页,逐单点进详情页核对,15 单全部查实,金额合计 ¥188.26、平均每单 ¥12.55。我自己手动翻了一遍列表复核,单数和金额一单不差。

两轮一对比,边界就清楚了:Eta 的"读"和"算"可靠,它的"猜"不可靠。 让它数订单,它能把 15 单数得一分不差;让它认机型,它会给你一个错得很有说服力的答案。

先说清楚:Eta 是个啥

一句话:一个装在你手机上的系统级 AI 助手,能直接读写你这台手机自己的数据,而不是隔着屏幕猜。

项目在 GitHub 开源(Mangi-11/Eta),APK 约 6.7 MB。几个关键点:

  • 它自己就是一个完整的 Android 数字助理。 长按电源键可以直接唤醒 Eta 本体发起任务,唤醒时自动附带当前屏幕原图和结构化应用内容。也可以通过 Xposed 接管小布助手和超级小爱——你熟悉的那个语音入口,背后换成 Eta 在跑。

  • 直接调一方应用原生接口。 日历日程(批量创建/改/删)、闹钟(建/改时/启停/删)、系统便签,还有手电筒、亮度、息屏、勿扰、音量、Wi-Fi、蓝牙、NFC、应用冻结。所有状态修改都读回核验,没确认会明说,不盲目重复执行。

  • GUI Agent 负责没有接口的部分。 无障碍 UI 树 + 控件定位 + 按需截图。目标 App 已在前台时直接原地操作;Android 14+ 且有 Root/LSPosed 时,跨应用任务默认在后台虚拟屏执行,不抢你的输入焦点、不抢音频焦点。到达收银台或二维码页面时,它能调用 present_to_user 把画面原位交还给你。

  • 终端是真的 Shell。 Android user/root Shell、Alpine/Debian Linux、脚本执行,支持会话、异步后台命令和常驻守护任务。

  • 个人上下文深到有点吓人。 普通授权下能读通知历史、日历、日程、位置、前台应用使用时长;Root 之后进一步开放通讯录、短信与验证码、通话记录、相册(可按图片 OCR 文字检索)、录音、剪贴板历史、Health Connect 健康汇总、已保存的 Wi-Fi 密码。ColorOS 上还能通过小布记忆进程内 Hook 桥直接检索账单、行程、外卖快递订单。

  • 模型你自选。 BYOK 填 API Key,或者登录 Codex(ChatGPT)/ Grok 订阅账号。支持 Skills(GitHub 仓库安装 / 本地 ZIP)、MCP(Streamable HTTP)、Subagent(内置 explore / coder / plan,可拉起临时专职 Subagent)。

  • 基础功能无需 Root。 支持 Android 13+ ARM64 设备,App 本体不限手机品牌。

最后一条是这篇的基调:Root 和 LSPosed 是加分项,不是门槛。 但加分项给得非常大——这正是它和 Mika 最本质的分野。


先看效果

以下动图来自项目 README 的官方演示,我自己的实测在后面,有系统层证据那种。

GUI Agent 跨应用操作:

官方演示:GUI Agent 在后台虚拟屏里操作应用

从小布助手入口发起任务:

官方演示:通过 Xposed 接管小布,唤醒即附带当前屏幕内容

聊天首页聊天首页

聊天首页

小布入口执行命令小布入口执行命令

从小布入口发起的一次真实任务,输出带表格的 PSI 内存分析报告

工具能力工具能力

工具能力页

SkillsSkills

Skills:内置 self-improving-agent、skill-creator、skill-installer


实测环境:先把家底交代清楚

项 值 被测应用 Eta v3.4.1(2026110901),GitHub Releases 直链下载,APK 6.70 MB SHA-256 5ef8d6c59d7494b3ad9a75c55a27cd62217f1788e8e8c8a2584528dfe77f0256 测试机 Redmi 22041211AC · HyperOS(Android 14 / SDK 34)· arm64 系统环境 KernelSU Root + LSPosed(Zygisk) 模型 实测一~六用官方内置模型;实测七、八换成局域网自建 OpenAI 兼容服务 http://192.168.1.213:8000/v1(实测七挂 qwen-latest,实测八换成 Swift 1.5,Qwen3.8 系 MoE / llama.cpp 本地推理 / 262K 上下文;Eta 端配置一个字没动,只改服务端挂的模型) 连接 无线 adb,全程可复现

模型服务是我自己搭的,这也顺带测了一件事:它在你自己的局域网里能不能跑通。 答案是能,全程没有 Eta 官方服务器参与。

而「实测七」这一节之所以能成立,正是因为模型是可以换的——同一个 APK,同一台手机,同一句话,换个脑子就是另一个结果。 这也是我觉得这套东西最有意思的地方:Eta 提供的是一副躯干和一套神经,装进去什么脑子,它就是什么水平。

实测八又把这条结论推了一步:同一个 Swift 1.5,换个任务,能力边界立刻显现。 上一节它"猜"错了机型,这一节它一次都没猜——因为统计订单这件事,每一笔金额都有订单编号可以对证。能对证的地方它很可靠,要靠世界知识的地方它不一定可靠。


实测一:订闹钟——13 秒,而且没碰屏幕

任务很简单:

「帮我订明天早上 7:30、7:40、7:50 的闹钟」

任务已发出任务已发出

任务已输入,发出去

Eta 的回复Eta 的回复

Eta 的回复:三个闹钟都设好了,各响一次

指标 实测 步数 / 模型往返 1 轮 2 步 / 思考 2 次 · 调用 3 个工具 从点发送到首个闹钟写入 12.8 秒(logcat 时间戳实证) Eta 自报本轮模型用时 15.3 秒(含最终回复的生成) 工具调用用时 0.1 秒 首 token 延迟(TTFT) 4.3 秒 输出速度 82 tok/s

性能统计浮层性能统计浮层

v3.4.1 新增的性能统计浮层:步数、模型用时、工具用时、TTFT、TPS 都在

我没信它自述,去系统底层核对了。 三条证据链:

证据一:logcat 里的三次工具派发。

任务在 13:40:33.089 发出(点击发送的 ACTION_DOWN/ACTION_UP 事件),三次派发挤在 45 毫秒内落地:

11-10 13:40:45.925 I Eta: Agent direct tool action=set_alarm outcome=dispatched 11-10 13:40:45.958 I Eta: Agent direct tool action=set_alarm outcome=dispatched 11-10 13:40:45.970 I Eta: Agent direct tool action=set_alarm outcome=dispatched

从指令发出到第一个闹钟写入系统,12.8 秒。 这 0.1 秒的「工具调用用时」不是吹的——三次 dispatched 不是三次 failed,三次派发之间只隔了 33 毫秒和 12 毫秒。

证据二:dumpsys alarm 里的精确闹钟注册。

RTC_WAKEUP #72: Alarm{63dc507 uId =10150 creatorUid =10150 packageName =com.android.deskclock sourcePackage =com.android.deskclock operation =PendingIntent{4bf3634: PendingIntentRecord{10244e8 com.android.deskclock startForegroundService}} type 0 origWhen 1794353400000 tag=*walarm*:com.android.deskclock.ALARM_ALERT type=RTC_WAKEUP origWhen=2026-11-11 07:30:00.000 window=0 exactAllowReason=policy_permission

window=0 是精确闹钟,exactAllowReason=policy_permission 说明系统按策略允许了精确触发。注册方是时钟 App 自己(packageName =com.android.deskclock)——这说明 Eta 走的是写系统闹钟数据库 → 唤醒时钟 App → 时钟 App 自己注册 AlarmManager 这条正规链路,不是自己偷偷 setExactAndAllowWhileIdle 塞一个。这比很多 App 的做法干净。

证据三:系统时钟 App 里的实际状态。

系统时钟 App:07:30 / 07:40 / 07:50 三个闹钟都在,开关全开,各响一次;我原有的 06:00、07:00 保持关闭,一个没动

但这里有个真问题,我必须说清楚。

我把六份 dumpsys alarm 快照逐一比对后发现:只有 07:30 那条真正进了 AlarmManager,07:40 和 07:50 没有。

# 全部快照中 deskclock 的 ALARM_ALERT 记录 alarm.txt → origWhen=2026-11-11 07:30:00.000 window=0 exactAllowReason=policy_permission alarm2.txt → origWhen=2026-11-11 07:30:00.000 window=0 ... alarm3.txt → origWhen=2026-11-11 07:30:00.000 window=0 ... alarm4.txt → origWhen=2026-11-11 07:30:00.000 window=0 ... alarm5.txt → origWhen=2026-11-11 07:30:00.000 window=0 ... alarm6.txt → (无 deskclock 记录)

我甚至强制停止时钟 App 再重开,想看它会不会补注册——没有补。

也就是说:三个闹钟在 UI 里存在、开关是开的,但只有第一个会被系统真正唤醒。 07:40 和 07:50 很可能不会响。

对「帮我订三个闹钟」这个指令本身,Eta 交差了——它建了三条记录。但对「我明天早上要靠这三个闹钟起床」这个真实意图,它只完成了一半。

这个缺陷藏得很深:如果你不查 dumpsys alarm,光看时钟 App 里三个闹钟都在、开关都亮着,你会完全相信它成功了。

顺带一提,这也从侧面印证了 Eta 的路线选择——它确实走了系统内部,不过也可能顺便继承了系统内部的一些坑。


实测二:GUI Agent——没有接口的部分,它也能干

Eta 的强项是原生接口,但原生接口覆盖不到的 App 呢?它有 GUI Agent 兜底。

任务:

「打开系统设置的显示设置,告诉我这块屏幕的分辨率是多少」

GUI Agent 完成后GUI Agent 完成后

它自己把设置页翻到「显示与亮度 → 屏幕」分组,读出「屏幕分辨率 FHD+」

Eta 的回答Eta 的回答

「思考 11 次 · 调用 10 个工具 · 1 个失败」——11 次思考,答 FHD+,换算 1080 × 2400

指标 实测 步数 11 次思考 · 调用 10 个工具 · 1 个失败 模型用时 1 秒(单步)· 55 tok/s 结果 FHD+ → 1080 × 2400,与 wm size 实测一致

我核了 wm size,就是 1080 × 2400。它答对了,包括 20:9 这个比例换算。

过程里有个细节值得说:任务执行期间,主屏原地就开着设置页,屏幕边缘有一道流光提示正在接管,手势经过顶部胶囊时自动让路。这是 README 里写的「智能分流」——目标 App 已经在前台就直接原地操作,不另开虚拟屏折腾。

这 11 次思考、1 次失败也如实记下来。 对比 Mika 的京东比价(21 步 / 8 分 23 秒 / 118 万 Token),GUI Agent 这类操作依然是重的——原生接口省下来的时间,是实打实省下来的。


实测三:终端——真的能跑

任务:

「在终端里执行 uname -a,把结果原样告诉我」

终端结果终端结果

执行结果原文返回,退出码 0

Linux localhost 5.10.209-android12-9-00019-g4ea09a298bb4-ab12292661 #1 SMP PREEMPT Wed Aug 28 22:16:09 UTC 2024 aarch64 Toybox

命令以退出码 0 正常结束,无 stderr 输出。 而且它没有自己加工——回的是原样。

这条链路不新鲜,但它是整个 Agent 循环可信度的基础:一个能真实执行命令、能拿到退出码、能如实转述输出的 Agent,比一个只会说「我认为结果应该是」的助手有用得多。


实测四:网页搜索——翻车了,但它自己绕过去了

任务:

「用网页搜索查一下豆包手机现在卖多少钱,把前两条结果的价格告诉我」

网页搜索任务网页搜索任务

任务发出

这次翻车了,而且翻得很彻底。

搜索失败详情搜索失败详情

「搜索服务连续三次超时了,我换用浏览器直接查一下」,随后触发「模型请求暂时中断,2 秒后重试(1/3)」

我独立验证了原因:Eta 默认的搜索后端 html.duckduckgo.com/html/ 在我这个网络里 10 秒超时(http_code=000),而同一台设备上百度、models.dev、gh-proxy 均返回 200。不是 Eta 的锅,是我这条网络到 DuckDuckGo 的 HTML 端点不通。

但它的降级行为值得加分:三次失败后没有把任务扔掉,也没有硬编一个答案,而是换用内置浏览器直接去必应查,最后把结果如实报回来。

搜索最终结果搜索最终结果

绕过搜索服务后,从浏览器拿到的价格:一代官方价 3499 元,二代 5999 元起

它给的答案是:搜孤的「豆包手机已售罄」条目里,官方售价 3499 元(nubia M153,16GB+512GB);腾讯网「豆包手机今日正式发售」条目里,豆包手机二代(努比亚 NaviX Ultra)5999 元起(12GB+512GB 5999 元)。并总结「一代官方价 3499 元,二代 5999 元起」。

我拿独立检索交叉核对过,3499 / 5999 这两个数字一致。

上下文用量当时显示 35.93K / 131.07K。

顺带一个成本洞察:这次会话全程没有出现「模型请求暂时中断」以外的反复重试,说明局域网自建 + 自选模型的组合在弱网下比依赖官方服务稳得多。


实测五:查这台手机的回收价——一个任务,三种能力

这个任务是我故意挑的,因为它同时压测 Eta 的三条链路:

「用京东查一下当前设备的回收价」

任务已输入任务已输入

任务已输入,发出去

它的答案是:Redmi K50,京东回收最高可卖 540 元。

先给结论,再拆过程——因为过程比答案有意思得多。

第一步:它先搞清「我是谁」

这是我最欣赏的一步。它没有直接去京东搜"K50 回收价",而是先读系统属性确认这台设备是什么:

$ getprop ro.product.model; getprop ro.product.brand; getprop ro.product.device 22041211AC Redmi rubens

然后读内存和存储,反推出配置版本:

$ grep MemTotal /proc/meminfo MemTotal: 11766340 kB $ df -h /data /dev/block/dm-52 226G 35G 190G 16% /storage/emulated/0

MemTotal 约 11.2 GiB → 12GB 内存版;用户可见存储 226G → 256GB 版。 它得出「Redmi K50 12GB+256GB」。

这一步的意义在于:回收价是机型、内存、存储、成色共同决定的,不问清楚自己的配置,找到的报价就是错的。它拿到 22041211AC 这个代号还能自己认出这是国行 Redmi K50(rubens 正是 K50 标准版的代号),这个判断是对的。

第二步:查报价——走了浏览器,没走 App

这里是本次最值得说的技术选择,我把它单独拆开讲:

设备上装了京东 App,但 Eta 一次都没有碰它,整个任务全程走的是内置浏览器。

而且更关键的是——它连"要不要打开京东 App"这个念头都没产生过。我把这次任务 47 条思考记录全部翻了一遍,找 launch_app、京东 App、installed 这些关键词,零命中。它的第一反应就是"用浏览器打开 huishou.jd.com"。

为什么?我查了代码,找到了三层原因,一层是环境限制,两层是设计取舍:

第一层:无障碍没开,GUI 路径根本不可用。

AgentToolRequirements.kt:73-77 把所有 GUI 工具(observe_screen、tap、tap_element、scroll 等)统一标了 accessibility = true;AgentToolCapabilities.kt:41-43 在生成工具目录时就把没授权的工具剔除——不是执行时拒绝,是压根不进列表。

我查了设备当时的真实状态:

dumpsys accessibility Bound services:{} Enabled services:{}

空的。这次测试全程没开过 Eta 的无障碍服务。 所以「启动京东 App 然后用模拟点击翻回收页」这条路,在当时的设备状态下是走不通的——工具压根不在它的列表里。 那为什么不开?AgentAccessibilityKeeper.ensureEnabledForGuiOperation 会尝试自动开启,但系统层的手动开关挡在前面:从 GitHub 装的 App 手动开无障碍常被系统拦到「受限制的设置」里,得去系统设置页真实点一次才能生效。

后来我把无障碍真的开了,重跑了一遍同一个任务——它就自己去操作京东 App 了。

完整对照实验见下面的「实测六」,那一节有 47 步 vs 7 轮的完整账单对比和源码级归因。 先说最关键的一条:不是它懒得用 App,是它手里根本没有操作 App 的工具。

第二层:browser_use 是零依赖工具,launch_app + GUI 是一整套依赖。

对比一下两者的前置条件(AgentToolRequirements.kt:33-46):

工具 Root 无障碍 额外依赖 browser_use 不需要 不需要 无 search_apps / launch_app 不需要 不需要 无 tap / observe_screen / scroll 不需要 需要 虚拟屏或主屏 web_search / fetch_url 不需要 不需要 无(但走网络服务)

browser_use 和 launch_app 同属 RootRequirement.NONE 这一组,但前者零开关——它操作的是 Eta 自己 app_webview 目录下一个离屏的 android.webkit.WebView,不碰你的屏幕,不需要任何授权。

对一个要查价的任务来说,「打开一个网页读几个数字」比「启动一个 App、看清它的首页、找到回收入口、点进机型、翻问卷」便宜太多——前者 1 次 navigate + 1 次 get_readable 就完事,后者要几十步,还可能撞上 App 的登录墙和风控。

第三层:Eta 对电商 App 没有做原生接口适配。

我全仓搜过 jingdong / jd.com / taobao / alibaba:只在一个地方出现——

// ColorOsMemoryDatabaseQuery.kt:330 private val ORDER_PACKAGES = listOf( "com.sankuai.meituan", "me.ele", "com.ss.android.ugc.lifeservices", "com.jingdong.app.mall", "com.taobao.taobao", "com.xunmeng.pinduoduo", ... )

京东 App 只出现在 ColorOS 小布记忆的「订单检索」白名单里——那是读你自己历史订单用的,和「调用京东的报价接口」完全是两回事。

这跟 Eta 对闹钟的做法形成鲜明对比:闹钟那条路它直接写了系统闹钟数据库、并且和时钟 App 的原生接口握手(packageName =com.android.deskclock、时钟 App 自己注册的 AlarmManager)。对系统组件它敢做深层适配;对第三方电商 App,它没有、也不打算做。

所以这条链路的答案是:Eta 的「系统级」是对系统和厂商 ROM 说的,不是对所有 App 说的。 第三方 App 的数据,它默认只能靠「像人一样操作网页」去拿。

第三步:浏览器里的一场硬仗

选了浏览器之后,真正的难题才开始。47 次思考、47 次工具调用(43 成功 / 4 失败),前后花了 7 分钟。

这段过程我在「展开工作过程」里完整回看了一遍,几个关键节点:

浏览器工具链的完整展开浏览器工具链的完整展开

「思考 1 次 → 打开网页 → 网页截图 → 刷新网页 → 等待网页元素 → 读取文本 → 点击网页」,每一步都有耗时

它踩到的坑,按顺序:

  1. 搜到的第一页是 Redmi K50 Pro。 它立刻识别出「这一页是 Redmi K50 Pro 的报价页,和当前设备不一样」,主动纠正,没拿错数据。

  2. huishou.jd.com 被重定向到促销页(“挑好物逛京东”),它换成必应搜索去找真正的回收入口。

  3. 桌面版表单超出视口。 它发现「表单区域比视口宽,‘大陆国行’ 选项在 x=1075 被裁掉了」,而 scroll 只支持纵向——然后它换了个思路:改用移动端页面 huishou.m.jd.com,问题直接消失。

  4. 点击坐标全部偏移。 这是最硬的一个坑,它自己推理出了原因:

    「DOM 的 #root bounds 是 412x869——页面按 CSS 宽度 412px 渲染,而截图是 1080x2280。所以我的坐标点击必须用 CSS 像素,不是截图像素。截图上 (745, 382) 应该换成 CSS (284, 146)。」

    它从 DOM 尺寸反推出了缩放比 2.62 倍,然后改用 CSS 坐标重算点击位置。 这一步相当漂亮。

  5. 点错系列筛选芯片。 想点「红米 K系列」点成了「红米 Note系列」(DOM 顺序算错了),它截图确认后重新定位。

  6. 4 次工具失败:1 次导航超时、1 次后退超时、2 次点击被遮挡(code=SCRIPT_FAILED)。

最终它是怎么拿到价的? 靠 get_text 读取整个机型列表,列表里直接带着价格:

Redmi K50: ¥540 最高可卖 Redmi K50 (5G 至尊版): ¥560 Redmi K60: ¥860 Redmi K40: ¥350 Redmi K70: ¥960 Redmi Note 13 Pro: ¥670 Xiaomi 14: ¥1140 Xiaomi 15 Pro: ¥2170 ...

这不是它猜的,也不是它算的,是京东页面上写着的价格,它读下来了。

最终答案最终答案

最终回答:Redmi K50 最高可卖 540 元,并附同品牌参考价与"实际到手价取决于成色"的说明

第四步:它停在了登录墙前——这是全场最漂亮的一步

点进 Redmi K50 的估价页后,页面跳到了 plogin.m.jd.com——京东登录页。

它的处理方式:

「京东回收的估价流程走到最后一步弹出了京东登录页(需要登录京东账号才能出准确报价),我没有你的账号凭据,这一步就停在这里。」

然后它没有硬编一个精确报价,而是给了能确定的最高价,并明确说清楚为什么拿不到更准的数:

「540 元是该机型在京东回收渠道的最高报价(最优配置 + 成色最好时的估值)。实际到手价要看你选的内存版本(12+256)和机器成色(屏幕、边框、功能、维修史等),最终报价会低于或等于这个数。」

它还主动提了一句:

「需要登录你的京东账号完成问卷——如果你愿意,登录一下后我可以帮你继续把估价做完。」

把球交回给你,但不甩锅、不硬编、不越权登录。 这一步的边界感,比任务本身完成得漂亮更值得记。

后来我重跑了一次同一个任务,想看它会不会变聪明:

重跑时的登录墙重跑时的登录墙

「京东的登录墙还在(未登录状态)。换个思路,试试桌面版报价页能否不登录直接出报价」

它又试了两条路(换桌面版报价页、重新检查登录态),还是过不去,最后停在同一个结论上。

上下文自动压缩上下文自动压缩

「思考 4 次 · 调用 5 个工具 · 1 个失败」,底部显示「正在压缩上下文…」——上下文用满后它自动压缩继续跑

上下文跑到 98.88K / 131.07K(75.4%)时,它自动触发了上下文压缩,而不是报错或崩掉。

这个任务的完整账单

指标 实测 步数 47 步(思考 47 次 · 调用 47 个工具) 工具成功 / 失败 43 / 4 模型用时 5 分 57 秒(357123 ms) 工具用时 1 分 38 秒(98315 ms) 首 token 延迟 93.4 秒(这是最长的那一步) 输出 17041 tokens 输入 376.5 万 tokens(累计,含多轮上下文重传) 最终上下文 98.88K / 131.07K(75.4%)

这个账单比闹钟那次的 13 秒难看得多——但它难看在对的地方。

闹钟是 1 轮 2 步,因为有原生接口,走的是直通车。这个任务是 47 步,因为京东的回收页只有网页表单,没有捷径可走。

而且这里有个必须点出来的成本真相:输入 376.5 万 tokens。 因为它每轮都要把越来越长的浏览历史重新发给模型——上下文越滚越贵,这就是为什么它后来触发了上下文压缩。 对比闹钟那次的 15.3 秒 / 98876 上下文,差了将近 40 倍。

这组对比恰好说明了两件事:

  1. Eta 的「系统级」能力是真的强——有原生接口时,13 秒解决;

  2. 但它的边界也真的清楚——第三方 App 的网页表单,它只能靠一屏一屏地看、一步一步地点,47 步、7 分钟、376 万 tokens。

这也正好回答了那个问题:为什么装了京东 App 不用?

不是不能,是代价不对等。走 App 要开无障碍、要开虚拟屏、要在 App 里翻找、还要面对登录墙;走浏览器零授权、几步就能读到价格。在一个任务上,选成本更低的那条路,是 Agent 该有的判断——它做对了。

我独立验证了 540 这个数

Eta 说的「最高可卖 540 元」,我拿外部渠道核了两遍:

京东回收自己的详情页(huishou.jd.com/detail?pid=206743)我直接抓了,机型确认是 Redmi K50,内存选项里明确有 12G+256G,而且页面上明确写着要登录京东账号、走完成色问卷才能出精确报价——和 Eta 撞上的那堵登录墙是同一堵。Eta 的描述完全属实,它没有夸大也没有编造。

第三方报价(数码回收网 2026-10-26 报价单)同机型区间:红米 K50(12+256)190–200 元(这是线下收货价)、红米 K50(12+512)260 元、红米 K50(8+128)150–200 元。「完好机 400-600 元」的市场区间,和京东的 540 元对得上。

京东回收给的是线上渠道价(比你拿到手高,因为省了跑腿和压价),线下收货价明显低一档。 540 这个数字站得住。

但这次任务暴露了一个真问题

Eta 全程没有用这台设备上任何一个 App,包括装了京东 App 这件事它都不知道(它没有调用 search_apps 去查)。

它是从 huishou.m.jd.com 这个网址推导出「京东回收在哪个域名」的——这是它自己对电商网站的通用认知,不是对你这台手机的实际认知。

如果你这台手机上没装京东 App、或者装的是京东极速版(域名和流程都不一样),它这套操作照样能跑。反过来说,它永远不会用你 App 里沉淀的东西——你的登录态、你的收藏、你的会员价、你的历史订单,它一个都拿不到(除非走 ColorOS 小布记忆那条路)。

所以「装了 App 不用」这件事,是特性也是短板:

  • 特性:不挑 App、不吃登录态、不碰隐私,快且省;

  • 短板:拿不到 App 里的真实优惠。如果我在京东 App 里有一张券,这 540 元的报价它永远看不到。

——但这个结论只对了一半。 因为我当时的测试环境里,无障碍服务是关着的。


实测六:把无障碍打开,它就真去操作京东 App 了

先说结论,再放证据。

第一次(无障碍关闭):47 次工具调用,全是 browser_use 和 terminal,search_apps 和 launch_app 一次都没出现过。我把那 47 条模型的思考原文全导出搜了一遍,launch_app、京东 App、installed 这些词零命中——它连「要不要打开京东 App」这个念头都没产生过。

第二次(无障碍开启):同样一句话、同一个新会话、同一个模型,它在第 2 轮就自己排出了两条路:

Options:

  1. Open the JD app and search for the device’s recycling price.

  2. Use JD’s recycling webpage (e.g. https://hui.jd.com, or the “以旧换新” / recycling page).

The most reliable method: JD has a recycling page

然后在第 6 轮,它主动调用了 search_apps:

→ search_apps 搜索应用 · 京东 ← 已找到 1 个应用 · 京东 → launch_app 打开应用 ← 已打开 · 京东

它自己想到了「先查本地有没有这个 App」。 这在第一次实验里完全没有发生。

我先让你看个东西——开了无障碍之后,Eta 首页的快捷指令变成了这样:

开了无障碍后,Eta 首页多出「分析当前屏幕」「打开微信」这类快捷指令开了无障碍后,Eta 首页多出「分析当前屏幕」「打开微信」这类快捷指令

(无障碍开启后,Eta 首页多出「分析当前屏幕」「打开微信」这类快捷指令——它知道自己能看屏幕了)

先确认无障碍真的生效了

我用 root 直接写 secure 设置把服务拉起来,系统层的绑定记录是实的:

Bound services:{Service[label=Eta Agent, feedbackType[FEEDBACK_GENERIC], capabilities=161, eventTypes=[TYPE_VIEW_TEXT_CHANGED, TYPE_WINDOW_STATE_CHANGED, TYPE_WINDOW_CONTENT_CHANGED, TYPE_VIEW_SCROLLED, TYPE_WINDOWS_CHANGED], ...]} Enabled services:{{io.github.mangi.eta/io.github.mangi.eta.agent.accessibility.AgentAccessibilityService}}

然后我点 Eta 首页那个「分析当前屏幕」的快捷指令,让它必须用眼睛看一次屏幕。它交回来的描述是:

  • 状态栏(顶部):左上角时间 3:10,一个蓝色小图标和「···」,右上角有通知角标、Wi-Fi 信号和电量 47%。

  • 顶部导航:左侧一个「≡」菜单按钮,右侧一个「⋮」更多选项按钮。

  • 对话区:右侧蓝色气泡是你刚发的消息:「截图并描述当前屏幕」。

时间、电量、按钮位置,全是它看屏幕看来的。 工具标签也写得明明白白:「观察屏幕 · 含截图 · 含界面树」。

(Eta 观察屏幕后逐项描述了状态栏、导航栏和对话区,连自己输入框里的那句话都读了出来)

Eta 观察屏幕后逐项描述了状态栏、导航栏和对话区Eta 观察屏幕后逐项描述了状态栏、导航栏和对话区

第三次实验:它自己找到了京东 App

新会话,同一句「用京东查一下当前设备的回收价」。工具调用序列我从 Eta 的 runtime_inflight_events 事件流里逐条导出来了:

1. device_status 查看设备状态 2. get_current_context 读取时间与位置 3. web_search 搜索网页 ← 失败 4. web_search 搜索网页 ← 失败 5. web_search 搜索网页 ← 失败 6. search_apps 搜索应用 · 京东 ← 它自己查本机 App 7. launch_app 打开应用 8. observe_screen 观察屏幕 · 含界面树 9. wait 等待 · 2 秒 10. observe_screen 观察屏幕 · 含界面树 11. tap_element 点击元素 · #57 12. observe_screen 观察屏幕 · 含界面树 13. tap_element 点击元素 · #58 14. observe_screen 观察屏幕 · 含界面树 15. wait 等待 · 1.5 秒 16. tap 点击屏幕 · (540, 260) ← 点搜索栏 17. observe_screen 观察屏幕 · 含截图 · 含界面树

第 6 步 search_apps 是分水岭。 从这一步开始,路线从「浏览器」彻底切到了「真 App」。

Eta 的推理原文里写着「网络搜索超时了,我直接打开京东 App 来查回收价。先找到京东应用。」

Eta 的推理:网络搜索超时了,我直接打开京东 App 来查回收价Eta 的推理:网络搜索超时了,我直接打开京东 App 来查回收价

(模型自己说明路线切换的理由:搜索超时,改用本地 App)

它一路点进了京东的回收频道

第 17 步 observe 回来的截图里,京东 App 已经在搜索页了,搜索框里是「上京东 搜回收」,下面就是「旧手机昨日已涨15%」「测测你的旧手机涨价了吗?」「苹果 iPhone 15系列」。

(Eta 自己点了搜索栏、输入关键词,京东 App 打开了回收频道)

京东 App 打开回收频道,Eta 的胶囊实时显示思考过程京东 App 打开回收频道,Eta 的胶囊实时显示思考过程

(京东 App 的「热门品牌」面板——苹果、华为、小米、荣耀、OPPO、vivo…;Eta 的悬浮胶囊实时显示着它的思考)

再往下,它点进了「爱回收·当面取」的页面,底部导航栏清清楚楚写着「首页 / 以旧换新 / 估价 / 拍拍二手 / 我的」。

京东 App 内的回收频道页面京东 App 内的回收频道页面

(京东 App 内的回收频道页面,「手机回收」入口和品类导航都在)

然后它遇到了第一个坎——京东弹出了「用户信息授权协议」(「感谢您使用回收服务!…请仔细阅读并确认您已经充分理解《用户信息授权协议》」)。

京东弹出的用户信息授权协议京东弹出的用户信息授权协议

(京东的「用户信息授权协议」弹窗——Eta 自己绕过去了)

Eta 自己绕过去了。 没有停下来问你,直接点了同意,继续往下走。

第二个坎更硬——京东的安全验证:滑块轨迹验证码。

京东弹出的滑块轨迹验证码京东弹出的滑块轨迹验证码

(京东弹出的滑块验证码「验证一下,购物无忧」,Eta 的悬浮胶囊停在画面上方)

Eta 悬浮胶囊里显示着「生成回答中 · 呈现到主屏」,然后它的回复是这么写的:

京东触发了安全验证(轨迹绘制验证码),这需要你本人操作才能通过。我已把画面放到你的主屏上了,请在弹窗中按图中轨迹画一下完成验证,验证通过后告诉我,我再继续查回收价。

这个处理方式很漂亮。 它没有硬去破解验证码(那既做不到也不该做),也没有假装任务失败,而是把画面交给你,明确说清楚这一步只能你本人来,然后等你。

(Eta 的完整推理链:7 轮,从「网络搜索超时了,我直接打开京东 App」到「验证码还在屏幕上,你还没完成」)

Eta 展开后的完整工作过程,7 轮推理链清晰可见Eta 展开后的完整工作过程,7 轮推理链清晰可见

(Eta 展开后的完整工作过程——7 轮推理链,每一轮的工具调用和失败数都在)

两次实验的账单对比

无障碍关闭 无障碍开启 路线 全程内置浏览器 浏览器 → 真 App search_apps / launch_app 0 次 1 次 / 1 次 observe_screen / tap 不可用(工具根本没进目录) 6 次 / 2 次 轮次 47 步 7 轮 25 次工具调用 最终结果 停在登录墙前,给出 540 元 卡在滑块验证码,交给你操作

但 GUI 路径的代价非常明显

三件事:

1. 每轮慢一个数量级。 浏览器那轮每步几百毫秒,GUI 这轮每轮 57–199 秒——因为每一步都要把 463KB 的截图传回模型。

2. Token 涨得快得多。 浏览器路径最后 98.88K/131.07K 就触发了自动压缩;GUI 路径光是对照组那一轮就跑到 104.42K(79.7%),而且中途还把「正在压缩上下文…」触发了三次。

3. 无障碍服务会抖。 这是我实测里最实在的一个坑:

→ observe_screen 观察屏幕 · 含界面树 ← 失败 · 该工具当前不可用(ACCESSIBILITY_UNAVAILABLE),本次未执行 → observe_screen 观察屏幕 · 含界面树 ← 已获取当前界面 → tap_element 点击元素 · #57 ← 失败 · 窗口内容已经变化,请重新观察屏幕 · code=STALE_CONTENT → tap_element 点击元素 · #58 ← 失败 · 窗口内容已经变化,请重新观察屏幕 · code=STALE_CONTENT

同一轮里,observe_screen 成功和 ACCESSIBILITY_UNAVAILABLE 交替出现;tap_element 则反复报 STALE_CONTENT(窗口内容变了,坐标过期)。

原因在源码里:Eta 用一个进程内静态变量 AgentAccessibilityService.instance 判断服务是否连上(AgentAccessibilityService.kt:2708),而 Android 在跨 App 切换时会短暂解绑再重绑无障碍服务,那个窗口期里 instance 是 null。

Eta 其实有兜底——AgentAccessibilityKeeper.ensureEnabledForGuiOperation() 会在每次 GUI 操作前确认服务状态,必要时请求重绑。logcat 里能看见它每次都成功:

I Eta: Agent accessibility action=ensure_for_gui outcome=completed recoveryRequested=false elapsed_ms=0

但这个兜底救不了「已经绑上了、只是 UI 树刚好在变」的情况,STALE_CONTENT 就是这么来的。

(同一次点击里连着两条错误:先是「无障碍服务已重连,请重新观察屏幕」,再是「活动窗口已经变化,请重新观察屏幕」——Eta 自己发现并纠正了)

Eta 点击元素时连续遇到两条无障碍相关报错并自行纠正Eta 点击元素时连续遇到两条无障碍相关报错并自行纠正

(展开后的工具调用详情,能看到「无障碍服务已重连」「活动窗口已经变化」两条报错和它随后的纠正动作)

那为什么第一次它连想都不想?

源码给出了确切答案。AgentToolRequirements.kt:73-77 把所有 GUI 工具统一标了 accessibility = true:

listOf( "observe_screen", "tap", "tap_area", "tap_element", "long_press", "long_press_element", "swipe", "scroll", "scroll_element", "type_text", ... ).forEach { name -> put(name, getValue(name).copy(accessibility = true)) }

然后 AgentToolCapabilities.kt:41-43 会把没授权的工具直接从目录里剔除:

if (requirement.accessibility && !accessibilityAvailable && !accessibilityRecoveryAvailable) { return "ACCESSIBILITY_UNAVAILABLE" }

而 accessibilityAvailable 就是那个静态变量 instance != null。

所以无障碍关着的时候,observe_screen、tap、type_text 这些工具压根不在模型的工具列表里。 模型不是「懒得用」,是它手里根本没有这个工具。

第一次实验里,我甚至在它的思考里抓到了它自己发现这件事的那一瞬间:

Wait, the system prompt says “需要重新看屏幕时先按默认参数调用 observe_screen”…

I don’t have GUI tap/observe tools available in this run, so I’ll work through the offscreen browser and web.

它去找了 observe_screen,发现没有,只好退回浏览器。

修正后的结论

上次那节我写「装了 App 不用是特性也是短板」——这话得改成条件句:

无障碍关着,「装了 App 不用」是特性也是短板;无障碍开着,它会用 App,但会用得很笨、很慢、很费 Token。

三个阶段的完整答案:

  1. 无障碍关着:GUI 工具不在目录里,模型根本不可能想到操作 App。它只能靠网址推导,走浏览器。

  2. 无障碍开着:GUI 工具进了目录,模型会主动查本地 App、启动它、用真手点。但它也会遇到验证码、登录墙,最终还是要人接手。

  3. 而且开了之后贵得多:慢一个数量级,Token 翻倍,还会被无障碍抖动反复打断。

所以你的问题,标准答案可能是这样:

Eta 不是「不调用 App」,是「你不开无障碍,它就没有调用 App 的能力」。 开了之后它确实调了——只是这条路要走验证码、要你本人出场,而且每一步都在烧钱。

(开了无障碍后,Eta 首页多出「分析当前屏幕」「打开微信」这类快捷指令——它知道自己能看屏幕了)


实测七:换个模型重跑同一个任务,它能自己认错吗

前面所有实验,都有一个共同的「作弊」前提:我知道这台手机是什么型号。

所以最后我干了件事——把 Eta 背后的模型换掉,从头再跑一遍同一个任务,一个字都不多给。

换的是局域网自建的一个 OpenAI 兼容服务(http://192.168.1.213:8000/v1,模型 qwen-latest,上下文 131K)。设备、App、任务、指令,全都一模一样:

打开手机上的京东App,查一下这台手机的回收价

它还是认错了机型

新模型的表现肉眼可见地比原来那个强。它自己会开 App、会跳过开屏广告、会搜索「手机回收」、会进回收频道、会走完 8 题问卷——整条链路它自己跑通了,中间还自己绕过了好几个坑:

  • 京东首页轮播动画导致节点树频繁刷新,它自己判断「改用坐标直接点击搜索栏」;

  • 搜索按钮会把刚输入的文本清空(这是京东那个页面的真 bug),它试了三种提交方式后放弃搜索框,改走「品牌 → 红米 K系列 → 逐个找」的笨路;

  • tap_element 连续报 STALE_CONTENT,它换成纯坐标点击;

  • 京东弹出轨迹验证码,它没有硬闯,也没有瞎点,直接停下来告诉我:这类验证需要您本人操作,我不能代您通过。我手动划完验证码回了一句「已验证」,它无缝接着往下跑。

但它选错了机型。

它认定这台机器是 Redmi K50 (电竞版),理由是「型号 22041211AC」——然后在京东回收列表里找到了这个条目(¥360),点了进去,一题一题填完,停在报价页。

豆包手机再替:面向 Android 的第三方系统级 AI 助手 Eta

选错的机型:京东估价问卷停在「Redmi K50 (电竞版)」,进度 2/8,选项是 8G+128G / 12G+128G。它在等你确认内存版本。

这台机器到底是谁

拉 adb 的系统属性,一条一条对:

ro.product.marketname = Redmi K50 ro.product.model = 22041211AC ro.product.device = rubens ro.soc.model = MT6895Z/TCZA ← 天玑 8100 ro.board.platform = mt6895 ro.miui.business.version = rubens.cn.1.1.0091 屏幕 supportedModes = 1440×3200 (2K)

rubens 就是 Redmi K50 标准版,天玑 8100、2K 屏。

而 K50 电竞版是另一台机器:骁龙 8 Gen 1、1080P 屏、型号 21121210C、代号 ingres。它俩在京东回收里是两个独立条目——

京东回收条目 配置 最高回收价 Redmi K50 天玑 8100 / 2K 屏 ¥540 Redmi K50 (电竞版) 骁龙 8 Gen 1 / 1080P ¥360

选错一档,报价直接差 180 元。 而且这 180 元的落差,比"成色谈得好不好"的影响还大——成色顶多把 540 谈成 480,机型选错是从一开始就查错了机器。

有意思的是,京东的搜索结果列表里两个机型是并排摆着的,价格明明白白写在后面:

豆包手机再替:面向 Android 的第三方系统级 AI 助手 Eta

京东回收的搜索结果:「Redmi K50 (电竞版) ¥360」和「Redmi K50 ¥540」并排列着。模型只要点错一行,报价就错 180 元。

我只提示了「去查证」,没说答案

然后我发了第二条消息。我没有告诉它正确机型是什么,只告诉了它方法:

先别急着填问卷。请用终端执行 getprop 命令,读取这台手机真实的市场名、机型代号、型号数字和处理器型号(重点看 ro.product.marketname、ro.product.device、ro.product.model、ro.soc.model、ro.miui.business.version),据此判断这台机器到底是 K50 系列的哪一款……如果不一致,点右上角"更换旧机"返回,把机型换成正确的那一款再继续。

它的反应,比我预期的好。

它自己开终端跑 getprop,逐个读属性,然后——推翻了自己上一轮的结论:

Key facts:

  • ro.product.marketname = “Redmi K50”

  • ro.product.device = rubens

  • ro.soc.model = MT6895Z/TCZA = Dimensity 8100

Codename “rubens” = Redmi K50 (standard, Dimensity 8100), model 22041211AC. So JD’s currently selected entry “Redmi K50 (电竞版)” is WRONG. The correct entry is “Redmi K50” (¥540 最高回收价).

更值得记一笔的是它在这之前的推理。它一开始也在瞎猜——先猜「Redmi K50 Gaming」,又改口「Redmi K50 至尊版」,型号数字在它脑子里是乱的。但紧接着它自己写下了一句:

Recall real: … Actually 22041211AC = Redmi K50 至尊版 (Ultra) — released July 2022… So the machine is likely K50 至尊版, not 电竞版. Verify with getprop — marketname will tell directly.

它猜错了三次,但没停在猜测上——它决定去查。

然后它点「更换旧机」返回,绕开那个有 bug 的搜索框,从品牌列表重新进「红米 K系列」,截图确认标题变成了「Redmi K50」,接着把 8 题问卷全部填完:

使用情况「正常进入桌面」/ 购买渠道「大陆国行」/ 内存 12G+256G / 外壳完美无瑕疵 / 屏幕完美无划痕 / 显示完美 / 摄像头无维修更换 / 整机无维修无受潮无拆机。

最后拿到报价:

豆包手机再替:面向 Android 的第三方系统级 AI 助手 Eta

京东官方确认订单页:机型 Redmi K50(正确),预估可卖 ¥520 = 估价金额 ¥440 + 加价券 ¥80。(页面中的地址、姓名、手机号、收款方式等个人信息已打码)

¥520。 而选错机型那一轮,它查的是 ¥360 那一档。

三轮对照

同一个设备,同一句话,只换模型和提示:

轮次 模型 它说的机型 结果 一 旧模型 Xiaomi 13 京东无此条目,流程中断,没拿到任何报价 二 qwen-latest Redmi K50 (电竞版) 8 题问卷走完,但报价对应的是错机器 三 qwen-latest + 提示自查 Redmi K50 ✓ ¥440 + 加价券 ¥80 = ¥520

这次实验真正想说的三件事

第一,模型的"操作能力"和"判断能力"是两回事,而且后者才是瓶颈。

三轮下来,能操作 App 的能力早就有了——问题从来不在"点不点得动"。真正决定结果的是它知不知道自己操作的是个什么东西。旧模型连品牌都猜错,新模型猜对了品牌但选错了版本,而这两轮的结果分别是「拿不到价」和「拿到错的价」——从用户角度看,后一种其实更危险,因为它看起来是成功的。

第二,一次提示就能纠错,说明纠错成本极低。

我给的提示里没有一个字是答案,只有「去查 getprop」这个方法。它立刻就自己查、自己推翻、自己改选。这意味着这类错误不是"模型不行",而是"默认不查"。 模型在有明确指令时会非常乐意做正确的事;它只是不会主动想到要这么做。

这也顺带说明了一件事:Eta 自己没有机型映射表(我全仓搜过 rubens、22041211AC、Redmi K50,零命中),它对设备的了解全部来自模型的世界知识。而世界知识在这件事上是不可靠且不可验证的——22041211AC 这串数字,模型自己都在"至尊版 / 标准版 / 电竞版"之间反复横跳。

第三,新模型确实更能"自己想办法"。

除了上面说的验证码处置和绕过页面 bug,这轮还有两个细节:

  • 它在压缩上下文之后,自己又跑了一遍 getprop 重新核验——不是简单地信任压缩前的记忆;

  • 最后给结论时它主动加了两条说明:成色是按「全最优」填的,质检会下调;并且没有点「提交换线」——没有替我创建回收订单。

豆包手机再替:面向 Android 的第三方系统级 AI 助手 Eta

对话记录:上半部分是「先别急着填问卷」那段纠错指令,中间能看到它自己跑 getprop 的过程。

该不该点那个「提交换线」,模型自己判断了——它没点。 毕竟用户问的是"查回收价",不是"把手机卖了"。这个边界感,比答对一道题更让我意外。


实测八:换个任务——让它统计在京东点过的所有外卖

前七轮测的都是"给一个明确目标,让它去够"。这一次我换了个思路,挑了一个没有标准答案、也没有捷径的任务:

「打开京东App,把我在这台手机上叫过的外卖订单信息统计一下,看看都点了些什么、平均花了多少钱。」

我之前用Mika试过的同类任务。选它的理由很直接:查回收价要跨 App 做决策、会撞上机型识别这种硬骨头;而统计自己的订单,是一个纯读取任务——只要能找到列表、读对数字,答案就是确定的。 一个能把"读"这件事做扎实的 Agent,值不值得用,一测就知道。

它自己找到了入口

我没给任何路径提示。模型的推理链里,这几步是它自己走出来的:

轮次 它的动作 它的想法(原文) 1 search_apps 搜"京东" 「The user wants me to open the JD app and aggregate the takeout orders」 2 launch_app 「Use display=auto so it runs in background virtual screen」 4 observe_screen 「go to 我的 (Me) tab → 我的订单. Note: JD 外卖 orders may be in a separate order list」 7 点「全部」 「I see order entries: 待付款(35), 待收货(36), 待使用(37), 待评价21(38), 退换/售后(39), 全部(40)」 10 点「秒送 外卖」 「There’s a 外卖 badge on 秒送 tab. Tapping it filters to takeout orders」

秒送外卖订单列表秒送外卖订单列表

*它找到的最终位置:京东 App → 我的 → 全部订单 → 「秒送 外卖」标签页。

值得注意的是第 7 轮——京东订单页的界面树几乎读不出东西(它是 WebView / 动态渲染),模型试了两次 tap_area 都发现 screen_changed=false,于是自己换成"截图 + 按坐标点":

「The UI tree is nearly empty — page is a WebView/Flutter-like rendering. Nodes are empty, so I need a screenshot.」

「The tab didn’t switch to 秒送 — 全部 is still selected. The tap may not have registered, or the page content is a WebView with no accessible nodes so change detection can’t tell.」

这正是 GUI Agent 相对 API Agent 的真正代价:它得靠截图"看",一屏 620KB,上下文按 20 多 K tokens 一轮地涨。整轮下来它用了 183 次工具调用,其中 observe_screen 69 次、scroll 42 次、swipe 29 次、tap 20 次。

它做了件让我意外的事:它怀疑列表本身是错的

这是整轮最值钱的部分。

京东的订单列表是虚拟化渲染的——滚一屏,DOM 会把上下卡片的内容串行重画。它很快就撞上了这个坑:同一张卡片的金额,它在不同截图里读出了两个值。它没糊弄过去,而是自己开始做像素级的内容偏移计算:

「So the list is longer than I thought — at the top of this screenshot is a card (樟荣沙县), then 永和大王 ¥12.50, 窄巷口·生烫牛肉米线 ¥12.00」

「the card now at y570 (马纪云 12.10) was at y2378 in the original content. So original card order: 1) 马纪云 12.10, 2) 稻状元 14.89, 3) banner 外卖入会, 4) banner 外卖疯狂周, 5) 马纪云 11.50, 6) 樟荣 13.40」

它在用两次截图之间的像素差,重建整个列表的真实顺序。这不是"读屏幕",这是在做逆向工程。

然后它做出了一个更关键的决定:不信列表,改成逐单点进详情页核对。

「this page renders cards serially (same order showed ¥13.40/¥11.50), so I must open each order’s detail to verify.」

于是它开了 15 次详情页,每一单都读到了订单编号。这直接把"永和大王 ¥12.50"那个反复出现的卡片解决了——它一度怀疑是渲染重影,最后用订单号证明这是三笔不同的订单(10-26 / 10-30 / 11-02),并顺手纠正了我给它的错误前提:

订单详情页与订单编号订单详情页与订单编号

订单详情页。每张卡片的"合计"数字下面,还有一个订单编号——这是它用来去重的唯一可信凭据。(页面中的配送地址、收货人姓名手机号、订单编号已打码)

它的最终报告

跑完之后,它交出这样一份东西:

# 门店 点的餐 金额 时间 1 清真马纪雲兰州牛肉面(长安路店) 番茄炒蛋盖饭 ¥11.50 11-10 2 稻状元(上海旭辉里店) 4件套 小炒肉柳+清炒时蔬 ¥14.89 11-09 3 清真马纪雲(长安路店) 番茄炒蛋盖饭 ¥12.10 11-06 4 樟荣·沙县小吃(普陀路店) 健身鸡腿饭 ¥13.40 11-04 5 稻状元(上海旭辉里店) 4件套 小炒肉柳+西红柿炒鸡蛋 ¥13.89 11-03 6 永和大王 招牌香卤大鸭腿饭 ¥12.50 11-02 7 樟荣·沙县小吃(普陀路店) 健身鸡腿饭 ¥11.50 10-31 8 永和大王 招牌香卤大鸭腿饭 ¥12.50 10-30 9 窄巷口·生烫牛肉米线(江宁路店) 鲜猪肉肉酱米线 ¥12.00 ~10-28 10 霸碗盖码饭(嘉里不夜城店) 外婆菜炒鸡蛋拼剁椒土豆丝 ¥11.90 10-27 11 永和大王 招牌香卤大鸭腿饭 ¥12.50 10-26 12 七鲜小厨·京东自营现炒菜 外婆菜炒蛋+嫩炒广东菜心双拼盖饭 ¥13.80 10-22 13 稻状元(上海旭辉里店) 农家小炒肉+清炒时蔬 ¥12.89 ~10-21 14 霸碗盖码饭(嘉里不夜城店) 酸菜青豆肉末拼西红柿炒鸡蛋 ¥14.90 ~10-21 15 稻状元(上海旭辉里店) 4件套特惠工作餐 ¥7.99 ~10-20

订单总量 15 单,金额合计 ¥188.26,平均每单 ¥12.55,区间 ¥7.99(稻状元特惠)到 ¥14.90(霸碗酸菜)。门店分布:稻状元 4 单、永和大王 3 单、清真马纪雲 2 单、樟荣沙县 2 单、霸碗 2 单、窄巷口 1 单、七鲜小厨 1 单。

Eta 的第一阶段报告Eta 的第一阶段报告

它的第一阶段报告:先给出核实过的 8 单,同时明确列出还有 6 单没核实,并解释为什么必须逐单进详情。

注意这个报告里三个细节,每一个都值得单独说:

第一,它没有一次给全,而是分阶段交付。 第一阶段它只报了 8 单(合计 ¥102.28,平均 ¥12.79),同时明确写「订单列表里至少还有 6 单……这些数字目前只来自订单列表——这个页面滚动时会把上下卡片的内容串行渲染,所以必须逐单进详情核实」。然后才把屏幕交还给我,让我去过验证码,它接着把剩下 6 单核对完。这是"知道自己没做完"和"知道自己不确定"的可核查证据。

第二,它回过头修正了自己的口径。 第一阶段它提醒了一句:「详情页的『合计』是商品金额,配送费和优惠券在『费用明细』里,我没有逐单展开,所以实际支付金额可能和这里有小额差异。」等第二轮跑完,它真的去展开费用明细验证了,结论写在报告开头:

「这些『秒送·外卖』订单详情页的『合计』就是应付实付——我展开过费用明细验证(例:霸碗 11.9,商品总价 11.9、运费原价 3 元『已减』= 免运费,合计 11.9 = 实付)。」

它把自己的免责声明兑现了,而不是丢在那儿。

第三,它给唯一没核到的那一单打了标记。 第 9 单窄巷口米线,它的详情页入口被营销弹窗拦住了,没取到分。它没有把这一单悄悄混进总数,而是加了星号:「第 9 单窄巷口因商品名唯一、价格稳定,按列表卡片确认(详情页入口被营销弹窗拦截,未取到到分实付,风险很低)。」

我自己复核了一遍

我不打算只信模型的报告,于是自己手动把列表从头翻到底,数了一遍。

订单列表顶部(带时间戳)订单列表顶部(带时间戳)

列表顶部。展开的卡片直接写着下单时间:2026-11-10 11:37:51 和 2026-11-09 11:52:11。

结果:15 单,一单不差。 金额、门店、菜品、日期全部对上。我还额外发现了一件模型没提的事——列表卡片里其实带着下单时间戳(2026-11-10 11:37:51),而模型当时没读出来,只能靠订单编号的先后顺序去推断日期(它在报告里诚实地标成了「日期(按订单号推断)」,后 4 单写成了 ~10-28 这种带波浪号的估计值)。

这是 GUI 路径的固有短板:它能看见文字,但不一定看见最容易被机器读的那部分。 我的 uiautomator dump 在这个页面上几乎只能拿到空节点树,而这些时间戳是渲染在卡片里的——模型是靠截图读出来的,只是没往那儿看。两个"眼睛"看到的世界不一样,这就是 GUI Agent 和 API Agent 差的那一层。

列表末尾列表末尾

列表到底了:最后一单是稻状元特惠工作餐 ¥7.99,下面开始就是"淘宝闪购"的商品推荐流。

这一轮和上一轮,差在哪

同一个 Eta,同一台手机,同一个自建模型服务,任务从「查回收价」换成「统计外卖订单」:

查回收价(上一轮) 统计外卖订单(这一轮) 任务类型 跨 App 决策 + 外部世界知识 纯读取 + 数字汇总 需要判断吗 需要(且判断错了) 基本不需要 工具调用 45 次 465 次(183 + 282) 最终结果 机型错了,价格是错的 15 单全部核对通过 有没有交还操作权 有(验证码) 有(验证码),且分阶段交付 有没有主动声明局限 有(成色按最优填、质检会下调) 有(合计≠实付,且后来真的去验了)

结论很直接:Eta 的"读"和"算"是可靠的,它的"猜"是不可靠的。但是这应该是模型的问题更多些

上一轮它把 22041211AC 猜成"电竞版",这一轮它一次都没猜——因为这一轮根本不需要猜,每一笔金额都有订单编号和详情页可以对证。它的能力边界不在"能不能操作",而在"有没有可对证的事实"。

已完成筛选下的逐单核对已完成筛选下的逐单核对

它中途改用「已完成」状态筛选来降低噪音——这个策略是它自己推理出来的,理由写在思维链里:「用状态筛选减少噪音」。

这一轮暴露的真问题:太慢,而且贵

别只看它做对了什么。这轮的两个数字很难看:

  • 465 次工具调用、183 + 282 次思考,跑了一百多轮,全程约 25 分钟;

  • 上下文峰值触顶 131.07K(阶段一结束时就到了 90.09K / 68.7%),触发了两次自动压缩。

原因不难理解:京东订单页没有可读的节点树,模型只能靠一张张截图"看",一屏 620KB 图。为了不漏单,它把 15 单挨个点进详情页——每开一单详情页就是一次截图 + 一次滚动 + 一次返回,翻倍的成本。

按它自己的 tok/s(约 200–225 tok/s)算,这一轮的推理 token 量比前七轮加起来都多。它做对了,但做这件事的性价比并不高。

GUI Agent 的价值在于它能到达那些没有导出接口的地方;一旦对方提供了结构化数据,就应该让给结构化工具。


我拿它当「可疑软件」审了一遍

一个要读你通讯录、短信、剪贴板、Wi-Fi 密码、健康数据的东西,值得用审可疑软件的标准过一遍。结论先说:

确认无数据泄露后门。

App 主动连接的公网地址只有 4 类,全部有明确用途:

地址 用途 出处 api.github.com/repos/Mangi-11/Eta/releases/latest 检查更新,只带 User-Agent AppUpdateChecker.kt:69 models.dev/api.json 社区模型目录,24 小时刷新一次,不带 Key CommunityCatalogRepository.kt:28 html.duckduckgo.com/html/ 默认网页搜索后端 PublicWebSearch.kt:42 语音服务端点 语音转写 SpeechSettings.kt:20-55

全仓零命中:埋点/分析 SDK、android_id/IMEI/IMSI/Build.SERIAL、DexClassLoader、下载并执行远程脚本、静默提权(su 授权由系统弹窗呈现,App 只探测一次,拒绝后不再打扰)、日志打印完整 API Key 或 OAuth Token、hook/ 目录里的任何网络调用。

但有几项需要你知道的风险,说清楚:

1. 敏感读取面的开关「默认全开」。 Prefs.kt:227 在空配置下返回 emptySet(),也就是你不主动关,它就是开的。通讯录、短信、通话、剪贴板历史、健康汇总、Wi-Fi 密码、logcat——这些能力都默认允许模型调用。

2. 最关键的一条:脱敏只作用于「落盘」,不作用于「当轮请求」。

AgentLoop.kt:228 把工具结果(result.content,含原始敏感数据)放进 messages,AgentLoop.kt:114-125 再把这批消息作为 requestMessages 发往模型 API。README 第 129 行只说「不写入持久会话」,很容易被误读成「不外发」。

实际含义是:Eta 用 Root 读到的通讯录、短信、Wi-Fi 密码,会随当轮请求发给你配置的那个模型服务商。 你用的是局域网自建模型,数据不出门,那没问题;你用的是云端服务商,那这些数据会出网。这不是后门,是它的架构必然——但你必须知道。

Root 与系统增强Root 与系统增强

Eta 自己把这件事写在了「Root 与系统增强」页面里:需 Root、具体范围取决于系统/应用版本与已开启的工具权限

3. API Key 在数据库里是明文。 OAuth 凭据走 Android Keystore 加密(ProviderCredentialStorage.kt:100-112、McpSecretStore.kt:13-51),这部分做得很好。但你自己填的 API Key 是明文存 Room 的(ProviderEntities.kt:37),并且明文进备份(EtaBackupRepository.kt:279)。allowBackup=false 挡住了系统级备份,但 Eta 自己的导出备份功能会带上它——分享备份文件给别人等于交出 Key。

4. Linux 环境默认走第三方 GitHub 代理。 DebianEnvironmentInstaller.kt:436、PinnedLinuxToolInstaller.kt:174、LinuxApkAnalysisInstaller.kt:396 都把 https://gh-proxy.com/ 作为优先下载源,官方源排在它后面。README 里没提。因为有硬编码 SHA-256 校验,篡改风险被哈希覆盖,但流量会经过第三方。

5. 全局允许 HTTP 明文流量。 res/xml/network_security_config.xml:3 是 cleartextTrafficPermitted="true",同样未在 README 披露。设计意图是支持局域网自建模型和 MCP,代价是非 TLS 的服务端下 API Key 和对话内容在局域网可见。我这次测试正好走的就是这条路径。

6. gh-proxy.com + 允许明文这两条合起来看,一个装 Root 应用、又能读你通讯录的 App,同时允许明文外发、同时用第三方代理下载东西——这不构成后门,但它不适合装在你的主力机上。


安装与上手

系统要求:

项目 要求 基础功能(聊天、网页搜索、浏览器、记忆、Skills、MCP、普通终端、私有工作区) Android 13 及以上,ARM64 GUI Agent 另需无障碍服务授权 日历读写 / 通知 / 应用使用情况 分别单独授权 位置工具 需要「始终允许」 后台虚拟屏、系统开关修改、应用管理、一方应用原生操作 需 Root 厂商助手接管(电源键、小布、一圈即搜)、系统入口 需 LSPosed + 对应 ROM 适配

第一步,下载安装。 只从 GitHub Releases 下 APK(约 6.7 MB)。

第二步,配模型。 设置 → 模型提供商 → 填 API Key(或登录 Codex / Grok 订阅),选默认模型。模型必须支持 Tool Calling,要理解图片还得支持图片输入。

设置页设置页

设置页:LLM 提供商、上下文与扩展、工具三块,v3.4.1 引入 COUI 与 Miuix 双主题共存

模型已添加模型已添加

我加的是局域网自建服务:手动填写展示名称与 Model ID,模型 qwen-latest,131.07K 上下文

这里有个坑要提醒: 「从远端自动拉取」读的是 /models 列表接口——我这边这个服务返回的列表不符合它的预期,对话框只给「取消」,没有确认键,没法继续。所以直接用「添加自定义模型」手填。顺带一提,v3.4.1 之后这个页面的模型名是分开两个字段的:展示名称 和 Model ID 可以不一样,填错 Model ID 的话模型调用会失败。

第三步,按需开工具开关。 工具能力页可以逐项和按组开关。

第四步,开无障碍(这一步决定了它会不会用你的 App)。 去系统设置 → 无障碍 → 已下载的服务 → 找到「Eta Agent」并打开。

别用 adb 直接写 secure 设置来开。 我第一次就是这么干的(settings put secure enabled_accessibility_services),系统层确实显示绑上了,但进程一重启 instance 就变 null,模型手里的 GUI 工具会时有时无。从系统设置里真实点一次,让服务绑在当前进程上,才稳。

开完之后,Eta 首页的快捷指令会多出「分析当前屏幕」「打开微信」这类条目——这就是它知道自己能看屏幕的标志。

第五步,Root 授权(可选)。 这是 Eta 真正拉开差距的地方。KernelSU 用户进 KernelSU 管理器 → 搜索 Eta → 打开「超级用户」开关。

KernelSU 中已授予超级用户KernelSU 中已授予超级用户

KernelSU 管理器里给 Eta 的授权:App Profile 页,「超级用户」开关已打开

授权后回到 Eta 的「Root 与系统增强」页点「重新检测」,状态就变了:

Root 日志工具可用Root 日志工具可用

授权后 logcat 工具可用:crash 缓冲 0 条,main 缓冲扫 3659 行约 69 秒,无 FATAL EXCEPTION

顺带说一句,它自己会诚实说明环形缓冲的局限——知道扫到的 logcat 只是环形缓冲里还留着的那一段,不是全量日志。这种「知道自己不知道什么」的态度,在实测工具里挺少见。

第六步(可选),验证 GUI 能力。 点首页的「分析当前屏幕」。如果它能准确说出状态栏时间、电量百分比、导航栏按钮位置,说明无障碍真的通了——这是最快的自检方式。

Eta 分析当前屏幕,描述了状态栏、导航栏和对话区Eta 分析当前屏幕,描述了状态栏、导航栏和对话区

(自检:Eta 观察屏幕后逐项描述了状态栏、导航栏和对话区,连自己输入框里的话都读了出来)


实测踩到的坑(一个不遮)

坑 1:多闹钟只有第一个真的会响。 前面实测一详细说了。07:30 精确注册进 AlarmManager,07:40 / 07:50 在 UI 里存在但没注册。如果你要设多个闹钟,务必设完自己看一眼,别全信。

坑 2:默认搜索后端在国内网络大概率不通。 html.duckduckgo.com/html/ 在我这条网络 10 秒超时。它能自己降级到内置浏览器,但耗时会明显变长,而且中间会穿插「模型请求暂时中断,2 秒后重试」。设置里可以换成 DeepSeek Search / Fetch 或自定义 HTTP 接口,建议直接换掉。

坑 3:删除闹钟这一条,我最后没删成。 我让它删掉刚建的三个闹钟,它走 GUI 路线时屏幕操作工具不可用;我让它回退 Root + 终端去找数据,它按 ColorOS 的数据库路径去 HyperOS 上找时钟 App 的库——连续几次退出码 1,没找到。

最后是我自己在系统时钟 App 里手动关掉三个开关完成的:

手动关闭闹钟开关手动关闭闹钟开关

手动清理:逐个关闭开关

三个闹钟已关闭三个闹钟已关闭

清理完成:三个闹钟全部关闭

这里有个很值得记的发现: Eta 创建闹钟走的是系统正规接口(写入后由时钟 App 自己去注册 AlarmManager),所以能成;但删除这条路上,它似乎没有对应的「反向原生接口」可用,只能退回到 GUI 或直接扒数据库——而它按 ColorOS 的路径假设去 HyperOS 上找,自然找不到。

换句话说,Eta 的「系统级适配」目前是单向的:创建顺,删除逆。 这也是为什么它在你这台机器上能建不能删。

坑 4:它对「我用哪个模型」很敏感。 我用局域网自建的 qwen-latest,它在 GUI 那条链路上失败了 1 次,搜索那条链路还遇到过 3 次模型请求重试。开源小模型跑 Agent Loop,翻车是常态——Eta 的能力上限,仍然由你喂的模型决定。

坑 5:无障碍这个开关,决定了它「会不会用你的 App」。 这是我这次实测最大的发现,也是踩得最深的坑。

不开无障碍时,dumpsys accessibility 里 Bound services 和 Enabled services 都是空的,所有 tap / observe_screen / scroll / type_text 工具压根不在模型的工具目录里——不是执行时被拒,是连列表都没进。模型自己都不知道它能看屏幕。

开了之后,同一个任务、同一个模型,它会主动 search_apps 查本地有没有京东 App、然后 launch_app 启动它、用真手点搜索栏、点回收频道。

Eta 会尝试自动开(AgentAccessibilityKeeper.ensureEnabledForGuiOperation),但从 GitHub 装的 App 手动开无障碍常被系统拦到「受限制的设置」里,得去系统设置页真实点一次才生效。

还有三个只有真机才会遇到的细节:

一、force-stop 会把无障碍服务一起解绑。 我第一次实验时用 am force-stop 重启 Eta 再开无障碍,服务确实绑上了,但 Enabled services 立刻变空——进程重启后 AgentAccessibilityService.instance 这个静态变量是 null,而它正是判断服务连没连的唯一依据。要开无障碍就别重启 App。

二、跨 App 切换时服务会抖。 同一轮工具调用里,observe_screen 会交替返回成功和 ACCESSIBILITY_UNAVAILABLE;tap_element 反复报 STALE_CONTENT(窗口内容变了,坐标过期)。原因是 Android 在 App 切换时会短暂解绑再重绑无障碍服务。Eta 有兜底(每次 GUI 操作前确认服务状态、logcat 里能看到 ensure_for_gui outcome=completed),但救不了「服务在、UI 树刚好在变」的情况。

三、GUI 路径比浏览器路径贵一个数量级。 浏览器那轮每步几百毫秒,GUI 这轮每轮 57–199 秒(每步要回传 463KB 截图);上下文也是浏览器路径跑到一半就 104.42K / 131.07K(79.7%),自动压缩触发了三次。

结论:不开无障碍它就只会用浏览器;开了它会用 App,但会更慢、更烧 Token,而且最后多半还是要你本人过验证码。

坑 6:Root 是双刃剑。 授权后 Eta 拿到了通讯录、短信、剪贴板、健康数据、Wi-Fi 密码的读取能力,而这些能力默认全开,且当轮请求会把原始数据发给模型服务商。用完记得关。

坑 7:上下文会滚到爆。 查回收价那个任务,输入累计 376.5 万 tokens,最终上下文占用 98.88K / 131.07K(75.4%),触发了自动压缩。长浏览任务的成本是滚雪球式的——每轮都要把越来越长的历史重发一遍。用它做长时间网页调研,Token 要有心理准备。

而开了无障碍走 GUI 路径,更烧token。 同样一个任务,对照组那一轮就跑到 104.42K / 131.07K,中间触发了三次「正在压缩上下文…」。


所以,要不要玩?

它适合谁:

  • 要跟系统打交道的活儿:批量建日程、管闹钟、控开关、读通知和日历——这类事它比 GUI 模拟快一个数量级;

  • 手里有 Root + LSPosed、且愿意折腾的人:这才轮到它真正的能力上限(一方应用原生接口、厂商助手接管、后台虚拟屏);

  • 想要一个能换模型的系统级助手:自带模型、Skills、MCP、Subagent,甚至能登录 Codex / Grok 订阅账号;

  • 愿意跟它一起调试的人:它不是装完就完美的产品,多闹钟、删除、弱网搜索都踩了坑;

  • 接受「快慢取决于对方开不开门」的人:这是使用 Eta 的核心心理预期。系统任务 13 秒,第三方 App 任务 47 步、几分钟——这个差距不是它偷懒,是生态的现状。

  • 想把它当"统计员"用的人:这轮实测它把 15 单京东外卖订单逐单核对完,单数金额一分不差。但要有心理准备:这类活儿它要 465 次工具调用、跑 25 分钟、上下文两次顶到 131K。 能干,但很贵。

它不适合谁:

  • 主力机。 Root 应用 + 全开敏感读取 + 允许明文流量 + 第三方代理下载,这个组合不该放在你存着身份证和银行卡照片的手机上。闲置机、测试机才是它的正确位置。

  • 不打算自备模型的人。 BYOK 是前提,能力上限全看模型。

成本心里要有数: 这几条链路的账单差着数量级——闹钟 1 轮 2 步 / 写入 12.8 秒;浏览器查回收价 47 步 / 5 分 57 秒模型时间 / 输入累计 376.5 万 tokens;开了无障碍走 GUI 路径 7 轮 25 次工具调用 / 每轮 57–199 秒 / 上下文 104.42K;统计 15 单外卖订单 465 次工具调用 / 约 25 分钟 / 上下文两次顶到 131.07K。

原生接口这条路,本质上是在用代码的正确性换 Token。 代价不是零,是**「谁来给你开门」**:系统给你开了接口,13 秒;第三方 App 没开,你只能一屏一屏地看、一步一步地点,376 万 tokens 就这么烧掉了。

而无障碍开关,等于决定你要不要付这笔钱。 不开,它连 App 都不碰(因为 GUI 工具压根不在它的工具列表里);开了,它会用真 App,但慢一个数量级、Token 翻倍,而且最后多半还是要你本人过验证码——京东那道滑块轨迹,它无论如何也过不去,只能把画面推给你。

所以别把它当「万能助手」用——挑那些系统已经给了接口的活儿去派给它,才划算。真要它碰第三方 App,先想清楚你愿不愿意为「它终于干了」这个结果,付几百万 Token 和一个人工验证码。

再补一条选任务的判断标准,这是最后那轮实验逼出来的:把活儿分成"有凭据可查的"和"要靠猜的",前者派给它,后者自己把关。

统计订单之所以做得漂亮,是因为每一笔金额都有订单编号可以对证,它不需要相信任何人的"世界知识";而认机型之所以栽跟头,是因为全世界只有它脑子里那点先验,没有第二份东西能验它。这不是模型笨不笨的问题,是这类任务里有没有"标准答案"的问题。

而且优先给它派"有凭据"的活儿还有个好处:它做砸了你也看得出来。 它把 15 单数错一单,翻一翻订单页就知道;它把机型认错了,报价看起来完全正常,你根本发现不了。

许可必须提醒: Eta 用的是 PolyForm Noncommercial 1.0.0,不是 Apache-2.0。个人自用、研究、实验、公益教学都允许;但收费代安装、远程协助收费、上架应用商店收费、出售含本代码的商业产品,都超出许可范围。 分发 APK 时必须携带 LICENSE 全文和 Required Notice: Copyright © 2026 蛮吉 (Mangi-11).


最后

展开 收起
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认

相关文章推荐

更多精彩文章
更多精彩文章
最新文章 热门文章