Samien ae7c388a78 优化 Bot 发送回执与确认反馈并提前准备安全令牌 1 mês atrás
..
README.md ae7c388a78 优化 Bot 发送回执与确认反馈并提前准备安全令牌 1 mês atrás
analyze.py 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
instrumentation.patch 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
measurements.json 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
network.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
openmausbot-latency-series-openmausbot-0-short.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
openmausbot-latency-series-openmausbot-160-long.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
openmausbot-latency-series-openmausbot-160-short.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
series-openmausbot-0-short-6.png 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
series-openmausbot-160-long-1.png 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
series-openmausbot-160-short-6.png 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
series-yaoyao-0-short-6.png 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
series-yaoyao-160-long-1.png 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
series-yaoyao-160-short-6.png 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
summary.json 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
versions.json 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
yaoyao-latency-series-yaoyao-0-short.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
yaoyao-latency-series-yaoyao-160-long.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás
yaoyao-latency-series-yaoyao-160-short.jsonl 1c354d5b00 记录夭夭与 OpenMausBot 移动端收发延迟模拟器对比 1 mês atrás

README.md

iOS Bot 模式收发延迟:夭夭与 OpenMausBot 模拟器对比

2026-09-13。结论:OpenMausBot 在有网络延迟时更快结束“发送中”,逐步输出更密集;本机低延迟下连续发送的恢复速度相近。首段文本并非始终 OpenMausBot 更早出现:连续发送时夭夭更早,夭夭首次发送的 CSRF 初始化会改变这一结果。

版本与条件

固定测试开始时(09:27)的最新已提交源码,避开其他任务同时进行的工作区修改:

项目 客户端 服务端 源码
夭夭 iOS 1.3 (200) 0.4.15 iOS 3f500e9;服务端 d4c98d4
OpenMausBot iOS 1.0.0 (9) 0.1.75 a49d2f7d
  • 同一台专用 iPhone 17 Pro 模拟器,iOS 26.5,Xcode 26.6;两边按顺序运行。
  • 两个 App 均从上述源码重新编译、安装并运行,Debug 配置启用 Swift -O,测试不采集代码覆盖率。
  • 使用真实聊天页面、原有发送方法、HTTP/SSE 客户端、消息合并与展示逻辑。临时副本只加入测试连接入口、无障碍发送按钮标识和计时探针;未修改产品源码仓库。
  • 两边均通过新启动的隔离真实服务端。夭夭使用现有 workspace-server 夹具及假 Hermes Gateway;OpenMausBot 使用 launchVerificationServer 及假 Claude CLI。OpenMausBot 手机直连隔离 Harness 的受鉴权接口,未经过桌面 Companion sidecar 转发。没有连接任何真实模型、现有用户会话或真实桌面服务。
  • 假上游在接到 prompt 后等待 250 ms,然后每 20 ms 输出一个片段。短回复 40 个片段;长回复 200 段、正文 8,000 字符。两边正文相同,仅末尾用于区分试次的标记不同。
  • 网络条件:本机 HTTP;另设相同代理,为每个 REST 请求增加 80 ms 上行和 80 ms 下行延迟,为 SSE 数据增加 80 ms 下行延迟。没有模拟限速、丢包、TLS、蜂窝网络或代理缓冲。
  • 4 组短回复(2 App × 2 网络条件),每组 6 次发送。第一轮单独列出,后五轮取中位数;另有两条长回复。正式测试共 26 次发送。之前两次冒烟发送不计入统计。

时间定义

时间从 App 的发送处理开始计算。postAckMs 是提交请求返回,sendReadyMs 是 busy/sendingMessage 恢复,firstViewMs 是 SwiftUI onChange 首次观察到本轮非空回复文本。

“界面文本更新”是原生页面观察到数据的时间,不是物理屏幕像素亮起的时间,也不是帧率。截图和 XCTest 的原生无障碍断言确认回复确实呈现在聊天页面;毫秒值来自 App 内探针,未用 XCTest 轮询耗时冒充精密计时。

连续发送结果

每格是 5 次中位数,单位 ms。

网络 指标 夭夭 OpenMausBot
本机 提交确认 20.38 55.23
本机 发送状态恢复 52.48 55.52
本机 首段进入界面 274.24 373.38
本机 文本更新间隔 101.60 21.45
增加 160 ms 往返 提交确认 173.65 209.38
增加 160 ms 往返 发送状态恢复 675.32 209.68
增加 160 ms 往返 首段进入界面 436.57 541.22
增加 160 ms 往返 文本更新间隔 101.57 22.24

160 ms 条件下,夭夭连续发送恢复范围为 671.25–679.58 ms,OpenMausBot 为 204.28–211.30 ms。两边差距约 466 ms;OpenMausBot 的“发送中”持续时间约为夭夭的三分之一。

从服务端输出的首个非空文本事件到 SwiftUI 观察到它,本机中位数分别为 9.15 / 11.95 ms;加入 80 ms 下行延迟后为 88.95 / 93.22 ms。本轮没有测出夭夭手机侧存在额外的大幅首段接收延迟。

短回复期间,夭夭通常呈现 10 次文本变化,OpenMausBot 约 35–41 次。该差异与服务端 100 ms 合并刷新、以及 OpenMausBot 转发原始 delta 的实现吻合。

首次发送

每组首次发送只有一个样本,不用于估计分布。

网络 指标 夭夭 OpenMausBot
本机 发送恢复 76.48 58.53
增加 160 ms 往返 发送恢复 844.89 214.75
增加 160 ms 往返 首段进入界面 611.76 542.45

请求记录显示夭夭首次提交前多一次 /api/app/bootstrap,用于初始化 cookie 会话的 CSRF 状态。随后提交确认、发送后刷新照常执行。这解释了为什么首次发送时首段顺序会反转。它不是每条消息都有的 160 ms 固定等待。

实际请求链与判断

夭夭连续发送:POST messages 返回后,依次等待 capabilities → agents/conversations(并发)→ conversation detail;直到这些刷新结束才清除 busy。另有独立 read 请求。OpenMausBot 的发送操作在 POST 返回后就清除 sendingMessage,后续依靠 SSE 和独立 read 请求同步。

在 160 ms 条件下,夭夭已经约 174 ms 提交成功,却到约 675 ms 才恢复发送状态。它并没有一直未发送,也没有因此阻止 SSE 在约 437 ms 把首段文字送入界面。

优先值得优化的是发送确认后解除 busy、将无关刷新移出发送等待链,以及流式的合并频率和完整消息重复传输。此次证据不足以把瓶颈归因于手机原生渲染性能,也不能推出真实模型谁生成得更快。

长回复检查

两边各一条长回复,200 段正文,末尾长度分别为 8,034 / 8,039 字符(差别全部来自试次标记)。原生 UI 断言找到最终标记,页面观察到的最终文本长度与生成内容相符,截图显示第 200 段。

  • 夭夭:42 次文本界面更新,中位间隔 103.17 ms。
  • OpenMausBot:150 次文本界面更新,中位间隔 27.90 ms;上游原始文本事件 201 个,部分事件被原生界面合并。
  • 两边都存在较大的单次更新间隔;本轮没有测量帧率,不能将这些数字表述为 FPS 或“绝对无卡顿”。
  • 仅累计文本更新事件,夭夭 495,647 字节,OpenMausBot 91,985 字节。这不是连接总流量:没有将 OpenMausBot 最终完整消息及其他事件纳入该子集,所以不能据此给出总带宽倍数。

验证与局限

xcodebuild test 最终退出码 0,TEST SUCCEEDED,1 个编排测试包含 26 次真实原生 UI 发送和最终标记断言,0 failures。26 次发送的提交、恢复、首段时间均有记录,所有最终文本长度与生成内容相符。

测试运行器自身在少数配置切换处触发了同步 URL 加载诊断:请求的是隔离控制器 /scenario,发生在测量开始前,所在进程是 XCTest runner;它不是产品 App 的网络实现。测试结果仍为通过。计时探针也会产生少量开销,因此不解释几毫秒差异。

此次没有测试真机、Android、真实模型、群聊调度、真实账号登录/配对、后台恢复或附件上传。两套假模型适配器不同,首段总时间包含各自服务端与驱动开销;不能把“夭夭本轮首段更早”外推为真实模型更快。登录钩子只用于连接隔离服务,原有发送与接收方法保持原样。

证据

本机完整结果包:/tmp/yaoyao-mobile-ab-20260913/evidence/comparison.xcresult。构建日志、XCTest 日志和测试后段屏幕录像保留在同目录。该临时目录可能被系统清理;本目录中的 JSON、截图和补丁是随 Git 保留的证据。