Astrolabe(星盘):让 AI 看见自己写出的 UI

AI 已经可以在几分钟内生成一个完整页面,但"代码写出来了"和"界面实现正确"之间,仍然隔着一段很长的距离。

举一个实际开发中很常见的例子:设计稿里的图标容器是 27×27pt,图片资源的逻辑尺寸是 54×54pt。AI 正确设置了 UIImageView 的 frame,却把 contentMode 写成了 center。从源码和布局数据看,容器尺寸完全正确;运行以后,图标却因为没有缩放而明显偏大。只有把它改成 scaleAspectFit,最终效果才符合设计。

这个问题揭示了 AI 编写 UI 时的一处关键盲区:

编译器只能证明代码能够成立,不能证明最终像素符合预期。

Astrolabe(星盘) 是一个开源的运行时 UI 检查工具,目标是让 AI coding agent 能够读取正在运行的 App,检查节点结构、布局和样式,观察真实截图,并用运行时证据判断自己写出的 UI 是否正确。后文统一简称为 astrolabe

AI 需要的不只是截图

截图能够告诉 AI"这里看起来不对",却很难单独回答"为什么不对"。例如一个按钮位置异常,可能来自约束错误、父视图尺寸错误、Safe Area、Transform,也可能只是截图比例处理错误。

反过来,只读取视图层级也不够。frame 正确不代表资源缩放正确,颜色属性正确也不代表遮罩、透明度和混合后的最终像素正确。

astrolabe 将三类证据放在同一条工作链路中:

证据 回答的问题
UI 层级与节点关系 页面由哪些对象组成,它们如何嵌套
运行时属性与结构化断言 frame、字体、颜色、可见性、图片模式等逻辑值是否正确
系统截图与视觉差异 用户最终看到的像素是否符合预期

AI 因此可以完成一条真正闭环的开发流程:

diff 复制代码
读取设计要求
-> 修改 UI 源码
-> 编译并运行 App
-> 检查运行时节点与截图
-> 定位差异原因
-> 修改源码并重新验证

它是怎样工作的

astrolabe 目前由三个开源仓库组成:

仓库 职责
astrolabe Swift Host、CLI、MCP Adapter 和 AI Skill
astrolabe-runtime-ios 集成在 Debug App 中,采集 UIKit 与 Core Animation 运行时数据
astrolabe-protocol 定义平台无关的 Wire Protocol、JSON Schema、Fixture 和 Swift DTO

一次检查请求会经过下面的链路:

diff 复制代码
AI Agent
-> astrolabe Skill
-> TypeScript MCP Adapter
-> Swift Host
-> 模拟器 Loopback TCP / 真机 USBMux
-> iOS Runtime
-> UIKit / CALayer

Runtime 在主线程读取 UIKit 对象,在越过线程和进程边界前将其转换为不可变的协议数据。Host 负责 App 发现、快照管理、节点查询、断言、截图、Baseline 和视觉差异分析。MCP Adapter 只负责工具协议适配,不重复实现检查逻辑;Skill 则告诉 AI 什么时候应该抓取页面、如何复用快照,以及什么证据能够支持什么结论。

这种拆分让 UI 采集、通信协议、产品能力和 AI 工作流保持独立。未来增加 Android Runtime 时,可以复用 Host、MCP 和平台无关协议,而不需要把 iOS 的 UIKit 语义带到 Android 中。

当前能检查什么

astrolabe 已支持 iOS 模拟器与 USB 真机,核心能力包括:

能力 用途
App 发现 找到已经启用 Runtime 的模拟器或真机 App
页面概览 提取当前屏幕中最值得检查的文本、控件和图片节点
层级与节点查询 按文本、类型、语义角色、可见性等条件定位节点
节点详情 读取 frame、字体、颜色、图片、圆角、边框、阴影、无障碍和约束等属性
布局与样式断言 对节点位置、尺寸和样式执行结构化检查
原生分辨率截图 获取模拟器或真机的最新屏幕像素
Visual Diff 与 Baseline 比较当前页面与目标图或历史基准的像素差异
冻结快照 让后续查询持续基于同一个页面层级事实
临时属性实验 在内存中调整允许修改的展示属性,快速验证 UI 假设

这些能力既可以通过 CLI 使用,也可以作为 MCP tools 交给 Codex。AI 不需要解析面向人类的 Inspector 界面,而是直接消费稳定、结构化且可查询的数据。

为什么不能把整棵 UI 树直接交给 AI

真实 App 的 UI 层级远比一个 Demo 页面复杂。窗口、容器、布局包装层、重复 Cell、不可见节点、Backing Layer 和 UIKit 内部节点会共同构成一棵庞大的树。如果将完整 JSON 塞进模型上下文,不仅成本高,真正有价值的业务节点也很容易被噪声淹没。

文件压缩解决不了这个问题。即使使用 gzip 将网络传输体积压小,解压后的全部文本仍然需要进入模型上下文。

astrolabe 使用的是领域语义压缩 :完整层级保存在 Host 的本地快照中,MCP 响应只返回当前任务需要的投影,并保留 snapshotId、节点 ID 和分页游标,使 AI 能够继续追踪原始事实。

以一次生产环境 USB 真机页面测试为例:

数据 规模 紧凑 JSON 大小
完整页面层级 2,753 个节点 2,532,537 字节,约 2.42 MiB
默认推荐节点 12 个节点 2,620 字节,约 2.56 KiB

单次推荐结果相对完整层级缩小约 966.6 倍 ,数据量减少约 99.90%

这不是简单地截断前 12 个节点。处理过程包括:

  1. 扁平化当前 UIView 与 CALayer 层级。
  2. 过滤窗口、Backing Layer 和缺少有效内容的基础设施节点。
  3. 将候选节点按文本、控件、图片和普通可见内容分类。
  4. 去除表达相同内容的嵌套重复节点。
  5. 按页面区域轮询候选,避免结果全部集中在导航栏或某个列表区域。
  6. 返回有界摘要,并保留继续查询原始节点的引用。

完整的 2.42 MiB 层级事实并没有被丢弃。AI 如果发现某个推荐节点值得继续检查,可以通过节点 ID 获取完整详情;如果推荐结果不包含目标,也可以继续使用 find_nodes 在同一个快照中检索。

语义压缩的目标不是让 AI"少看一点",而是让它先看到最有价值的部分,同时保持结果可解释、可恢复和可继续查询。

快照让多步检查基于同一个页面

移动页面是动态的。AI 抓取页面后,用户可能滚动列表、打开弹窗或切换路由。如果每个工具都重新抓取当前层级,一次检查流程可能混合多个时刻的数据。

astrolabe 会为页面层级生成 snapshotId。后续的查找、分页、节点检查和样式断言只要携带这个 ID,就会继续处理同一份层级事实。

快照同时明确了证据边界:

  • 页面层级被冻结,不会因为当前页面变化而被替换。
  • 节点详情优先读取快照缓存;尚未读取的详情通过原始对象 ID 向 Runtime 请求。
  • 如果原始 UIView 已被释放,查询会明确失败,不会在新页面中猜测一个相似节点。
  • 截图始终来自调用时的最新屏幕,不能假装成旧快照时刻的像素。

这套约束看起来比"每次都取最新数据"麻烦,却能阻止 AI 使用时间上不一致的证据得出确定结论。

临时修改不是代码生成,而是假设实验

排查 UI 时,人类开发者经常在调试器里临时改一个颜色或字号,先确认方向,再回到源码正式修改。AI 同样需要这种快速反馈。

astrolabe 允许 AI 对白名单内的展示属性执行内存补丁,例如文本、字号、颜色、透明度、圆角、边框、阴影和部分约束值。不同属性可以组合,同一属性也可以反复调整,并且始终保留首次修改前的原值以便回滚。

这项能力有严格边界:

  • 不调用任意业务方法。
  • 不修改源码、二进制、业务模型或持久化数据。
  • Runtime 停止或 App 进程退出后,补丁自动失效。
  • 临时效果只能验证假设,不能作为功能已经完成的证明。

例如 AI 怀疑一个标题应该使用 20pt 而不是 15pt,可以先临时调整并观察真实页面。如果判断成立,再修改源码、重新编译,并在没有活动补丁的干净进程中完成最终验收。

谁适合使用 astrolabe

如果你的工作流中已经让 AI 编写 iOS UI,astrolabe 可以用于:

  • 根据 Figma 或截图还原 UIKit 页面。
  • 检查不同尺寸设备上的布局适配。
  • 定位 frame 正确但渲染结果错误的问题。
  • 验证字体、颜色、圆角、图片模式和 Auto Layout。
  • 在真机上复现模拟器无法覆盖的 UI 差异。
  • 为 AI 建立"修改、运行、观察、再修改"的自动反馈循环。

它不会替代单元测试、快照测试、XCUITest 或人工设计验收。它补充的是这些工具之间长期缺失的一层:让 AI 能够直接读取运行中的 UI,并将结构、属性和像素组织成可验证的证据。

开始体验

项目目前支持 iOS 和 Codex,Host 运行在 macOS,Runtime 只在 Debug 构建中启用。安装 Host:

bash 复制代码
git clone https://github.com/regulusleow/astrolabe.git
cd astrolabe
npm run install:codex

iOS App 通过 Swift Package Manager 集成 astrolabe-runtime-ios,启动 Debug App 后,Codex 就可以通过 MCP 发现并检查页面。

项目地址:

致谢

astrolabe 的最初灵感来自 Lookin 团队在 iOS UI 检查领域的探索。Lookin 及 LookinServer 对运行时视图层级、属性读取和对象通信的实践,为这个项目提供了重要启发。在此感谢 Lookin 团队及所有参与开源贡献的开发者。

接下来

astrolabe 当前正式支持 UIKit,暂不支持 SwiftUI。虽然 Runtime 可能读取到 UIHostingController 生成的部分 UIKit hosting hierarchy,但这些节点不能等同于 SwiftUI 的声明式视图树,因此不会将其作为稳定的 SwiftUI 检查能力对外承诺。

接下来的两个主要方向是:

  • 增加 Android Runtime,覆盖 Android View 与 Jetpack Compose 页面。
  • 接入更多 AI coding 平台,让同一套运行时检查能力不再局限于 Codex。

平台会继续扩展,但核心目标不会改变:让 AI 获得结构化、可验证且能够追溯的运行时 UI 证据。

AI 编写 UI 的速度已经很快。接下来真正重要的,不只是让它生成更多代码,而是让它能够看见运行结果、理解差异,并对自己的实现负责。

相关推荐
Miku1619 小时前
Claude Code 循环(Loops)入门:从 /goal 到 /schedule 的四种模式
agent·ai编程·claude
魏祖潇19 小时前
AI幻觉不是用更大模型解决——RAG增强+引用溯源+置信度标注让AI开口必带出处
人工智能·ai编程
程序员-李俞19 小时前
向量引擎接入自研 API 中转网关:鉴权、限流、熔断和审计日志复盘
服务器·人工智能·大模型·api·ai编程·ai api
林小果119 小时前
GPT-5.6 Luna API 价格详解:1 亿缓存 Token 成本、LinkAGI 接入与 Codex 配置
ai编程·openai api·codex·api中转·prompt caching·gpt-5.6·linkagi
8Qi819 小时前
HelloAgents学习笔记:智能体性能评估
llm·agent·ai编程·智能体
恋猫de小郭20 小时前
AI 又又造词,Graph 就又要替代 Loop 了?
前端·人工智能·ai编程
怕浪猫20 小时前
第2章 大脑构建:提示词工程与思维链
aigc·openai·ai编程
白玉cfc20 小时前
熟悉Objective-C
开发语言·ios·objective-c
AINative软件工程20 小时前
LLM 应用的 Canary 发布工程实践:Prompt、模型和参数变更如何做到安全灰度
ai编程