分析 React Native 中 AI coding agent 的反馈循环问题:JS 层修改可快速验证,但涉 native 改动则需重建 App,严重拖慢迭代速度。
关于移动端 AI 编码智能体,曾经的问题是一个智能体是否真的能驱动你的应用。这个问题现已日益明朗。如今真正决定智能体有多大用处的问题,是它能多快地尝试、观察结果、并再次尝试。在 React Native 中,这个数字很大程度上取决于一次变更能否留在 JavaScript 反馈循环内,还是需要重建原生应用。

我们不断看到同样的场景。一个团队将编码智能体接入其 React Native 仓库,期望得到大家一直在引用的那些数字,智能体也确实写出了合理的代码,但整体表现就是比 Web 团队所获得的体验差一截。简单的解读是:智能体在移动端还不够强。
这种解读遗漏了问题的一大部分,而且这个遗漏代价不菲——因为它让团队放弃了一件他们实际上能够改善的事情。
在过去两年的大部分时间里,确实存在一道真实的差距。智能体可以编写移动端代码,但对接下来发生的事情的感知能力有限。它无法轻易启动模拟器、点击按钮、读取原生崩溃日志,或者注意到键盘遮挡在提交按钮之上。而在 Web 端,这个循环的很大一部分早已很直接:启动一个开发服务器、访问一个 URL、检查页面、读取控制台。移动端智能体的可见性要低得多。
这道差距已经大幅缩小。
在 iOS 端,getsentry/XcodeBuildMCP 让智能体能访问构建、模拟器、日志捕获、调试、截图以及 snapshot_ui——后者暴露屏幕上的视图层级,并附带的可用于交互的元素引用。在 Android 端,基于 ADB 的工具链提供了类似的能力,而 mobile-next/mobile-mcp 则通过无障碍驱动的快照和设备交互同时支持两个平台。
metro-mcp 通过 Chrome DevTools Protocol 连接正在运行的 React Native 应用,以进行运行时、组件和网络检查。Callstack 发布了专门为 AI 智能体编写的 React Native 约定,而 SootSim 等工具也在瞄准更快的 React Native 开发和智能体驱动的反馈循环。
所以智能体现在越来越能够看到你的应用了。更有用的问题是:它能以多快的速度根据所见采取行动。
智能体编程之所以有效,是因为有一个循环:生成、执行、查看、修复、再来。这个循环有多大价值,取决于智能体完成每次迭代的代价有多低。
在 Web 端,许多常见编辑后的应用反馈几乎可以即时到达。在 React Native 中,反馈时间在很大程度上取决于所做变更的种类。
下面的时间范围仅供参考而非基准。确切时间因项目大小、硬件、构建配置、缓存、依赖项和开发环境而异。正是因为这种差异,最后一节才让你去测量你自己的情况。
这可能会在纯 JavaScript 迭代和需要重新编译原生应用的变更之间留下巨大差距。
重要的分界线不在于你的 JavaScript 是否使用了原生功能。React Native 应用无时无刻不在这样做,却并不需要重建。只有当一次编辑改变了原生源代码、原生依赖项、生成的原生代码或构建配置,并且以需要重建或重新安装原生二进制文件的方式发生时,才会走上较慢的路径。
这个区别很重要。
Fast Refresh 可以应用的 JavaScript 变更几乎可以即时可见。需要编译的原生变更则可能需要数十秒甚至数分钟,智能体才能观察到结果。
JavaScript 到原生架构的分界线过去主要是可移植性和性能方面的决策。在智能体辅助的工作流中,它也可能成为迭代速度方面的决策。
智能体完成一项真实任务,靠的是尝试、检查和修正。给它一次机会,它就必须立刻做对。让它有反复检查结果并修正的机会,它就有了恢复的空间。
廉价迭代是推动智能体编程超越自动补全的因素之一。
所以反馈循环成本不是一个 ergonomics 方面的脚注。它影响的是智能体在相同的工程时间内能做多少次实验。
降低一次迭代的成本并不能简单地转化为固定的产出倍数。在某些情况下,更快的反馈可以使一类任务变得可行——而此前在尝试之间需要过多的等待。
相同的智能体。相同的模型。相同的工程师。不同的反馈循环。
根据我们的经验,团队在移动端 AI 工作上往往按照与 Web 端相同的迭代模式来做预算。通常事实并非如此,而部分原因在于架构层面,而非选择更好的模型的问题。
一个明显的反驳是并行运行多个智能体,用吞吐量掩盖延迟。并行确实有帮助,但它不会消除单个反馈周期的底层成本。
随着越来越多的智能体同时请求原生构建、模拟器或测试环境,共享的构建基础设施也可能成为瓶颈。更多的智能体给你更多的并发尝试,但它们不会自动让每次涉及原生的尝试变得更便宜。
一旦原生重建所需时间显著长于 JavaScript 刷新,"我们就加一个小小的原生变更"就成了一项迭代速度决策,而团队可能此前并未将此纳入开发循环的考量。
由此产生几个习惯:
优先选择 JavaScript,并在原生代码真正提供了你需要的东西之前一直保持这样。这个决策仍然应该基于产品需求、平台能力、性能和可维护性,但现在迭代成本也属于这个计算的一部分。
在可行的情况下,将相关的原生变更批量处理,而不是零散地逐步引入。每一次需要重新编译的涉及原生的编辑都会再次付出较慢的反馈循环的代价。
将新的原生 API 或依赖项视为一项计划好的架构决策,而不是在日常 ticket 中悄然混入而不考虑其开发和构建影响。
谨慎地划定原生边界。团队为此已经做了各种版本的努力——为了可维护性和构建速度,将适当的产品逻辑保留在 JavaScript 中,并使用 Expo Prebuild 等工具来生成和管理原生项目,而不是手动编辑每个原生配置。Prebuild 并不会消除当原生依赖项或配置变更时对原生重建的需求,但它可以让这个边界更容易管理。
以上都不是反原生的观点。某些能力确实天生属于原生代码。
更窄的观点是:你改变的原生表面积有多大,以及这些变更有多频繁地需要重新编译,这些会直接且可量化地影响智能体接收反馈的速度。
当开发者只做少量刻意迭代时,这个成本更容易被忽视。智能体让迭代次数变得更加可见。
公平地说,原生构建时间也是一个移动的靶子。预编译框架、配置缓存、编译器缓存以及更好的构建工具持续在降低它。
但让较慢的一侧变得更快,并不能消除 Fast Refresh 与原生重建之间的差异。对于智能体辅助的开发,这两条反馈路径之间的比率值得测量。
快速的循环是必要的,但它本身还不够。智能体仍然需要在屏幕上找到元素,而这部分取决于你的 UI 自我描述得有多好。
暴露可访问性或 UI 层级的工具可以为智能体提供屏幕上元素的结构化引用。但一个元素如果没有有用的文本、角色、标识符或可访问性信息,能为智能体提供的语义上下文就非常有限。
智能体可能正在查看正确的屏幕,但仍然难以确定应该与哪个元素交互。这时它可能会回退到不太可靠的方法,比如截图坐标。
每次识别失败都会浪费额外的检查和交互周期。如果任务已经包含了较慢的原生重建,这些额外的错误会叠加到本已昂贵的循环中。
所以这里有一个思路转换。
testID 和可访问性元数据并非不可互换,可访问性标签仍然应该首先为依赖它们的人设计。但结构良好的标识符、角色、标签和语义 UI 信息共同使用,也会让自动化工具和智能体更容易导航应用程序。
团队为使界面可寻址所做的工作,原来也能使智能体工具受益。
同样出自同一理念的两个低成本成果:
确定性的启动状态。 到达一个 bug 需要六次点击,意味着每个周期都有六次机会让工作流程偏离轨道。一个深链接、测试固件或调试启动器,直接将应用放入已知状态,可以大幅降低这种设置成本。
确定性的启动状态。 到达一个 bug 需要六次点击,意味着每个周期都有六次机会让工作流程偏离轨道。一个深链接、测试固件或调试启动器,直接将应用放入已知状态,可以大幅降低这种设置成本。
类型化的原生边界。 智能体在处理规范良好的 TurboModule 和生成的接口时,有更多结构可以推理。给它一个围绕松散结构化 payloads 手工打造的桥接,智能体和开发者可以依赖的保障都会更少。新架构在这方面还有一个额外好处:其类型化契约使 JavaScript-原生边界更容易检查和推理。
类型化的原生边界。 智能体在处理规范良好的 TurboModule 和生成的接口时,有更多结构可以推理。给它一个围绕松散结构化 payloads 手工打造的桥接,智能体和开发者可以依赖的保障都会更少。新架构在这方面还有一个额外好处:其类型化契约使 JavaScript-原生边界更容易检查和推理。
截图证明了某样东西被渲染了出来。它没有说明应用是否好用。
闭合更多的执行循环并不能取代人。它改变的是人的判断力最重要的所在。
模拟器可以隐藏那些真正损害移动体验的东西:真实负载下的丢帧、设备发热时的热节流、物理设备的性能、触觉反馈、硬件行为,以及不完全符合预期的键盘交互。
在模拟器上通过和在设备上通过是两个不同的结论。
任何诚实的工作流程都会让人留在需要产品判断和真实设备验证的地方。
同样值得诚实评估这个工具链的成本。
XcodeBuildMCP 加上 Android 自动化层加上 metro-mcp,在启用了正确的工作流、配置了会话默认值、模拟器可用、以及为真实设备整理好了代码签名之后,仍然需要设置和维护。
可用不等于零运营成本。
与其他工程工作相比,这项投资可能是 modest 的,但它仍然是运行智能体辅助移动开发环境成本的一部分。
归根结底,这里的论证取决于你可以在一个下午用自己的代码库产出的数字。
在给任何移动 AI 计划投入预算之前先测量它们。
为反馈循环添加仪表。 在一个代表性的屏幕上,让智能体经历一个纯 JavaScript 的变更和一个需要原生重建的变更。测量两者从编辑到可观察结果的延迟,以及智能体检查和响应所需的总端到端时间。
为反馈循环添加仪表。 在一个代表性的屏幕上,让智能体经历一个纯 JavaScript 的变更和一个需要原生重建的变更。测量两者从编辑到可观察结果的延迟,以及智能体检查和响应所需的总端到端时间。
找到你代码库中的悬崖。 将纯 JavaScript 反馈与原生重建反馈进行比较。这个比率是决定智能体在给定周期内能完成多少次有效迭代的因素之一。
找到你代码库中的悬崖。 将纯 JavaScript 反馈与原生重建反馈进行比较。这个比率是决定智能体在给定周期内能完成多少次有效迭代的因素之一。
测试可寻址性。 在具有清晰语义标签和稳定测试标识符的屏幕上,与元素难以被自动化识别的屏幕上进行类似任务比较。统计额外的检查或交互周期。
测试可寻址性。 在具有清晰语义标签和稳定测试标识符的屏幕上,与元素难以被自动化识别的屏幕上进行类似任务比较。统计额外的检查或交互周期。
测试启动确定性。 添加一个直接到达目标状态的深链接或调试路由,然后再次运行工作流。测量重复设置时间消失了多少。
测试启动确定性。 添加一个直接到达目标状态的深链接或调试路由,然后再次运行工作流。测量重复设置时间消失了多少。
智能体是非确定性的,所以每个条件运行多次,并报告一个范围而不是单个数字。
你实际测量出的范围比通用基准更有用,技术受众也会更信任它。
移动开发并没有被排除在你们在 Web 上看到的 AI 辅助开发收益之外。
但这些收益的大小会受到架构选择的高度影响,而这些选择表面上看与 AI 关系不大。
而且你可以在投入更大预算之前先测量它们的影响。
当代码生成变得廉价,反馈和迭代就成为越来越重要的约束。因此,一个有价值的资产是一个智能体能够快速理解、执行、检查和移动通过的代码库。
你不能简单购买这种能力。你需要为它做设计。
将脱颖而出的团队,是那些开始将智能体迭代速度视为系统另一个工程特性、并有意识做出这些架构决策的团队。
getsentry/XcodeBuildMCP --- iOS 构建、模拟器、日志、调试器、截图和 snapshot_ui 工具,供智能体使用
getsentry/XcodeBuildMCP --- iOS 构建、模拟器、日志、调试器、截图和 snapshot_ui 工具,供智能体使用
mobile-next/mobile-mcp --- 通过可访问性快照实现的跨平台(iOS + Android)移动自动化
mobile-next/mobile-mcp --- 通过可访问性快照实现的跨平台(iOS + Android)移动自动化
metro-mcp --- 通过 Chrome DevTools 协议对 React Native 运行时进行检测
metro-mcp --- 通过 Chrome DevTools 协议对 React Native 运行时进行检测
SootSim --- 专为智能体驱动而构建的基于浏览器的 React Native 模拟器
SootSim --- 专为智能体驱动而构建的基于浏览器的 React Native 模拟器
Callstack --- React Native AI 智能体最佳实践
Callstack --- React Native AI 智能体最佳实践
Callstack --- 赋予 AI 智能体双手:移动反馈循环与智能体设备
Callstack --- 赋予 AI 智能体双手:移动反馈循环与智能体设备
React Native --- 构建速度文档 --- 原生构建时间,以及 Fast Refresh 在一两秒内应用编辑
React Native --- 构建速度文档 --- 原生构建时间,以及 Fast Refresh 在一两秒内应用编辑
用于移动开发的 Codex CLI:iOS + XcodeBuildMCP、Android CLI 和 React Native --- 智能体驱动的移动工具链背景
用于移动开发的 Codex CLI:iOS + XcodeBuildMCP、Android CLI 和 React Native --- 智能体驱动的移动工具链背景