Mika 的 phone_find 工具深解:Agent 如何在长列表里逐屏滚动、直到找到目标 【免费下载链接】MikaMika — 你手机上的私人 AI 助理替你操作 App、上网、把事办成。An on-device AI agent for Android that operates apps and the web to get things done for you.项目地址https://gitcode.com/gh_mirrors/mika2/Mika点击查看免费下载本篇以 Mika 仓库中phone_find工具的提示词文档phone_find.md为主体完整解读这段发给大模型的工具说明的每一个语义约定并结合 PhoneFind 实现 与 PhoneAutomationEngine 源码讲清 Mika 的端侧 Agent 是如何在 Android 无障碍树accessibility tree上执行滚动—观察—匹配—停止的跨屏查找闭环的。读完后你能掌握phone_find的参数契约direction、text/resourceId/role、maxScrolls、五种停止条件的触发逻辑、匹配结果中ref与父级上下文的含义以及它与phone_query、phone_collect等相邻工具的分工。一、工具提示词原文与逐句解读Mika 的工具提示词统一放在 prompts/tools 目录每个工具一个 Markdown 文件由 Prompts.tool() 读取后注入给模型作为该工具的 description。phone_find的完整提示词只有一句话但每句都是对执行行为的硬约定Scroll the current phone app until text, a resource ID, or a role is found in its accessibility tree. Check each resulting screen, stop if the app changes or content stops moving, and return the current ref and parent context. Use for a target further up or down a long list. maxScrolls is a limit, not a fixed action plan.逐句拆解原文约定对应实现在无障碍树中找 text / resource ID / role匹配基于ScreenSnapshot的UiTreeNode不依赖截图与图像识别每一屏都检查每轮循环先observe(withImage false, recordFrame false)再匹配纯文本读屏不截屏App 切换或内容停止移动就停app_switched与content_unchanged连续 2 屏指纹相同两种停止原因返回当前 ref 与父级上下文结果携带matches[].ref与parents供后续phone_tap等动作直接引用用于长列表中更上/更下的目标明确定位不是读屏工具而是目标不在当前视野时的跨屏搜索maxScrolls是上限而非固定计划循环最多limit次滚动但命中目标或内容稳定会提前退出这段提示词的价值在于它同时约束了模型的调用时机长列表找目标才用和结果解读maxScrolls不是必须滚满避免模型把 30 次滚动当成固定动作清单。二、参数契约方向必传匹配条件三选一工具注册在 PhoneAdvancedTools.kt声明为Risk.Write会真实滚动界面、composite true内部会发起子动作中文标签为滚动查找internal object PhoneFind : PhoneTool { override val def ToolDef(phone_find, Prompts.tool(phone_find), mapOf( text to str(Text or accessibility description to find.), resourceId to str(Full or partial Android resource ID.), role to str(Full or partial role or class.), direction to str(Where the target is: up or down., listOf(up, down)), maxScrolls to int(Maximum scrolls before returning, 1-200 (default 30)., 1, 200), ), listOf(direction)) }生成的 JSON Schema见 prompt surface 测试基线完整参数表如下参数类型必填取值范围 / 默认说明directionstringup/down是枚举目标相对当前位置的方向down表示内容更靠下手指上滑textstring否最大 200 字符要查找的文字或无障碍描述忽略大小写的包含匹配resourceIdstring否最大 200 字符完整或部分 Android 资源 ID包含匹配rolestring否最大 100 字符完整或部分角色/类名包含匹配maxScrollsinteger否1–200默认 30返回前最多滚动次数上限不是计划reasonstring否—调用动机备注不参与执行由 ToolDef.spec() 自动附加实现中有两处参数校验值得注意text、resourceId、role至少要给一个否则抛出ArgError(text, give a target)——direction必填但三个匹配条件全空时工具会在执行入口就拒绝maxScrolls通过a.int(maxScrolls, 1, 200) ?: 30读取越界值会被裁剪到 1–200 区间缺省回落 30。direction的语义与底层滚动工具一致phone_scroll.md 同样定义了 down shows content further down即内容移动方向而非手指方向在 ScrollTools.kt 中directiondown会计算dy -dist手指反向滑动且手机纵向默认滚动优先委托无障碍节点执行、找不到可滚控件时才退化为手势。三、执行循环观察—匹配—滚动—判停PhoneFind.execute 是一个典型的按界面实际内容推进的循环源码注释原话按界面实际内容推进直到找到目标或内容停止变化for (i in 0..limit) { val read ctx.session.observe(withImage false, recordFrame false) if (read.content[ok] ! JsonPrimitive(true)) { reason read_failed; break } val screen ctx.session.lastSnapshot if (screen null) { reason read_failed; break } val currentApp screen.packageName ?: screen.unreadableApp if (screen.protected || !screen.hasWindow || currentApp null) { reason screen_needs_review; break } if (app null) app currentApp else if (app ! currentApp) { reason app_switched; break } result PhoneAutomationEngine.find(screen, query, 100) if ((result[total] as? JsonPrimitive)?.intOrNull ?: 0 0) { reason found; break } val fingerprint screen.windows.hashCode().takeIf { screen.windows.isNotEmpty() } ?: screen.elements.hashCode() unchanged if (fingerprint previous) unchanged 1 else 0 if (unchanged 2) { reason content_unchanged; break } previous fingerprint if (i limit) break val action sub.run(Part.ToolCall(${ctx.callId}.scroll${i 1}, phone_scroll, buildJsonObject { put(direction, direction); put(amount, 3) }.toString())) if (action.content[ok] ! JsonPrimitive(true)) { reason (action.content[error] as? JsonPrimitive)?.contentOrNull ?: scroll_failed break } scrolled }结合提示词中Check each resulting screen, stop if the app changes or content stops moving这句话循环行为可以精确复述为纯文本读屏observe(withImage false, recordFrame false)只取无障碍树不生成截图、不记录帧——查找全程不依赖视觉这与found in its accessibility tree的提示词表述严格对应读屏失败即停ok ! true或快照缺失时以read_failed结束受保护/无窗口屏幕即停protected、hasWindow为 false 或读不到包名时以screen_needs_review结束把判断权交回模型这类屏幕通常要走视觉或人工接管App 切换即停首轮记录当前packageName之后任一轮发生变化即以app_switched结束——对应提示词 stop if the app changes防止滚动把界面带离目标应用后继续盲目翻页内容指纹判停以windows或退化为elements集合的hashCode作为屏幕指纹连续 2 屏指纹相同即以content_unchanged结束——对应 content stops moving等价于已经滚到头了滚动子动作未命中且未判停时通过ctx.sub发起一次phone_scroll子调用固定amount 3Scroll 工具 的默认步长。子调用编号${ctx.callId}.scroll${i1}使每次滚动都作为可追溯的子步骤进入动作记录与单步工具一样享受取消、状态记录与结果上报达到上限滚满limit次仍未命中以scroll_limit结束——这正是提示词 maxScrolls is a limit, not a fixed action plan 的含义30 只是预算命中或内容稳定都会提前退出。循环上限写作for (i in 0..limit)意味着最多做maxScrolls 1次读屏、maxScrolls次滚动先检查当前屏再滚。结果 JSON 的字段返回结构源码由控制字段与最后一次匹配的查询结果合并而成字段含义ok/found是否找到目标reason foundstoppedBecause停止原因found、app_switched、content_unchanged、scroll_limit、read_failed、screen_needs_review、scroll_failed或底层滚动返回的具体错误scrolls实际发生的滚动次数snapshotId/currentApp最后一屏的快照 ID 与应用包名供后续动作引用total/truncated/matches匹配总数、是否截断、匹配明细见下节四、匹配语义PhoneAutomationEngine.find 返回什么每轮匹配都调用 PhoneAutomationEngine.find()它是phone_find、phone_query、phone_run等工具共用的查询引擎源码注释手机界面上的结构化查询和跨屏文本合并工具和后续本地调用共用这套语义。匹配规则与返回字段命中判定三个条件同时满足才算命中null条件视为通配文字比较的是节点标签textdescriptionhintText拼接ignoreCase包含匹配resourceId与role同样是忽略大小写的子串匹配——所以提示词里 resourceId/role 都写作 Full or partialref/actionRef/editRef命中节点自身有ref就用自身的若命中的是纯文本叶子不可点击则沿clickableParent继承最近可点击祖先的ref作为actionRef可编辑场景同理给editRef。这保证模型拿到的 ref 能直接用于phone_tapparents父级上下文沿树向上收集节点标签/资源 ID保留最近 8 层对应提示词 return the current ref and parent context——模型可以据此判断这个确定按钮属于哪个弹窗避免点错同名控件敏感字段隐藏node.secret节点的text不进入标签、不写入name如密码框内容测试 queryKeepsParentRelationshipAndHidesSecret 专门验证查询123456树中一个secret true的 EditText 的值时total为 0降级路径若屏幕没有windows结构树不可用回落到扁平的screen.elements列表做同样的过滤只是此时没有parents截断matches最多返回limitphone_find固定传 100条但total始终是命中总数truncated标明是否被截断。五、在 Agent 体系中的位置调用时机、模型路由与相邻工具能力提示词中的分工约定capabilities/phone.md 是电话手机界面能力层的总提示词对phone_find的指引只有一句但边界清晰Use phone_find to search further up or down a long list. It observes each screen and stops when the target appears or the content stops changing.它与同段其他工具的分工是phone_query在当前单屏的大无障碍树里按 text/resourceId/role 查询实现不滚动limit默认 30phone_find目标在当前屏之外、需要跨屏滚动时用它phone_collect目标不是找一个控件而是把长列表/长聊天的文字采下来它同样逐屏滚动但用 appendPage/prependPage 做重叠行去重合并连续 2 页无新内容no_new_content即停phone_wait/phone_event等待出现/消失等界面条件基于无障碍事件而非轮询。滚动方向在能力提示词中也被反复强调direction指你要看的内容在哪down显示更靠下的内容见 phone.md 第 62-64 行并在没内容移动时先确认方向没滚反再下到底结论。只允许主模型发起在 ModelRouter 中Verb.PhoneFind被列入MAIN_ONLY_VERBS轻量模型给出该调用时不会被执行这一步会改派给主模型。注释给出的理由与其他高判断成本工具一致——放弃、确认、接管、追问、沙箱命令都由主模型决定。phone_find因涉及找没找到、要不要继续的判断而被划入同一档。测试用例如何验证这段提示词PhoneAutomationToolsTest.findScrollsUntilContentContainsTarget 用一个假屏幕前两屏文本为第 0 页/第 1 页第 2 屏后出现目标驱动PhoneFind.execute断言恰好对应提示词的三句话val result PhoneFind.execute(args, dispatcher.ctx).content assertEquals(true, result[found]!!.jsonPrimitive.content) // until ... is found assertEquals(2, result[scrolls]!!.jsonPrimitive.content) // 滚 2 次后在第 3 屏命中 assertEquals(e1, result[matches]!!.jsonArray.single()...) // 返回 current ref另有queryKeepsParentRelationshipAndHidesSecret父级上下文与 secret 隐藏、queryReturnsClickableAncestorForTextOnlyChild纯文本叶子回退到可点击祖先的actionRef两个用例覆盖了第四节描述的匹配语义。提示词与实现的对应关系还由 prompt-surface 测试基线 固化其中第 86 行就是phone_find.md原文第 87 行是生成后的参数 JSON Schema任何一边改动都会被一致性测试捕获。六、实用建议与边界从提示词与实现可以整理出使用phone_find的几条边界均以本仓库源码为准适用场景目标在长列表中、当前屏看不到且能用 text / resourceId / role 之一描述。三个条件可组合例如某个 resourceId 里含 row 的可点击项。maxScrolls的取舍默认 30 次、每次amount3的滚动对中等长度列表通常足够超长列表可调大上限 200但每次滚动都是一轮读屏匹配耗时随次数线性增长。找到或内容稳定都会提前返回不必担心滚过头——但方向给反时会一路滚到列表另一端并返回scroll_limit此时按 phone.md 的指引应先确认方向。返回screen_needs_review的含义屏幕是受保护窗口secure/splash 等或读不出包名此时无障碍树不可用应改用视觉类工具如phone_find_visually见 phone.md 第 10 行或人工接管而不是反复重试phone_find。拿到matches之后用matches[].ref可点击时优先actionRef配合对应snapshotId调phone_tapparents用来消歧同名控件。若同一屏有多个候选且位置敏感改回phone_observe看整屏结构再决定。与phone_collect的选择只要找到并操作一个目标用phone_find要把多屏内容读全用phone_collect——两者共享PhoneAutomationEngine的滚动-判停骨架但输出形态完全不同前者给结构化匹配后者给按视觉顺序合并的纯文本。参考路径工具提示词原文core/src/main/resources/prompts/tools/phone_find.md工具定义与执行循环PhoneAdvancedTools.kt匹配引擎PhoneAutomationEngine.kt单屏查询与多屏采集PhoneAutomationTools.kt滚动实现与方向语义ScrollTools.kt、phone_scroll.md能力层分工指引capabilities/phone.md模型路由主模型专用工具ModelRouter.kt测试与基线PhoneAutomationToolsTest.kt、prompt-surface/tools.txt赞分享【免费下载链接】MikaMika — 你手机上的私人 AI 助理替你操作 App、上网、把事办成。An on-device AI agent for Android that operates apps and the web to get things done for you.项目地址https://gitcode.com/gh_mirrors/mika2/Mika点击查看免费下载相关推荐Mika 的 phone_collect 工具:从一行工具说明到逐屏文本采集的完整实现Mika 的 phone_collect 工具:从一行工具说明到逐屏文本采集的完整实现 本篇以 Mika 面向 Android 的端侧 AI 助理 中的 pho动态工具发现实战MCP Gateway Registry如何帮Agent用自然语言自动找到100工具动态工具发现实战MCP Gateway Registry如何帮Agent用自然语言自动找到100工具 MCP Gateway Registry 是一从转录到剪辑决定列表youtube-agent-skill 的 yt-edit 如何自动找出死空与填充词从转录到剪辑决定列表youtube agent skill 的 yt edit 如何自动找出死空与填充词 youtube agent skill 是一套 MI上一篇如何用Python快速实现蓝牙通信PyBlueZ完整入门指南下一篇GridStudio 与机器学习集成使用 TensorFlow 进行预测分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考