Omi 移动端 Feature Vector:基于 Flow-Walker 的 E2E 测试覆盖优先级工程实践指南
Omi 移动端 Feature Vector:基于 Flow-Walker 的 E2E 测试覆盖优先级工程实践指南
导读
本文围绕仓库 app/e2e/feature-vector.md 展开,系统讲解 Omi 团队如何用"特征向量(Feature Vector)"这一可量化的优先级模型,驱动移动端核心流程的端到端(E2E)测试覆盖。你将掌握其双层打分模型(核心使命权重 × 会话频率)、Walker 可自动化评分(0-3)、33 项核心功能的覆盖矩阵、缺口管理方法论,以及如何与仓库内的 YAML 流程文件、Flow-Walker 流水线 和 agent-flutter 驱动工具 协同落地。读完后,你可以直接复刻这套"先排优先级、再分配覆盖、后持续追踪"的 E2E 治理框架到任何移动应用中。
一、Feature Vector 是什么:为 E2E 覆盖排序的量化决策工具
在大型移动应用中,E2E 测试的成本远高于单元测试——每个流程都需要真实设备、真实登录态、真实后端与真实录制,因此不可能也不应该对所有功能一视同仁。Omi 的解法是维护一张"特征向量表"(feature-vector),它本质上是一份经过优先级排序的功能地图,用于指导 flow-walker E2E 覆盖哪些核心 Omi 移动端流程、以什么顺序覆盖、以及每个流程需要多高的自动化程度。
该文档自身即定位为:"Prioritized feature map to guide flow-walker E2E coverage of core Omi mobile app flows"(用于指导 flow-walker E2E 覆盖核心 Omi 移动端流程的优先级功能地图)。它借用了 Omi Issue Triage Guide(问题分诊指南)中的两个评分维度,将产品直觉转化为可计算的优先级数值。
二、评分模型:两个维度量化一个优先级
Feature Vector 的核心是三个可计算的指标,全部定义在 app/e2e/feature-vector.md 的 Scoring Model 一节:
2.1 Combined Priority:组合优先级
Combined Priority = layer_weight × session_frequency
第一维:Core-to-mission(核心使命层权重 layer_weight)
Omi 的产品使命是"AI that sees your screen, listens to your conversations and tells you what to do"(看见你的屏幕、听见你的对话、告诉你该做什么)。据此将功能按对使命的贡献分层赋权:
| 层(Layer) | 权重 | 含义 |
|---|---|---|
| capture(捕获) | 5 | 录音、设备连接等"听见"能力的根基 |
| understand(理解) | 4 | 转写、说话人识别、词汇等"听懂"能力 |
| memory(记忆) | 4 | 记忆库、知识图谱等长期记忆 |
| intelligence(智能) | 3 | AI 聊天、摘要、任务提取等"告诉你要做什么" |
| retrieval-action(检索-行动) | 3 | 搜索、分享、文件夹、应用市场等检索与执行 |
第二维:Session frequency(会话频率)
| 值 | 含义 |
|---|---|
| daily=3 | 用户几乎每天使用 |
| weekly=2 | 每周级使用 |
| setup-only=1 | 仅在初始设置阶段使用 |
示例:会话列表与浏览属于 capture 层(权重 5)× daily 频率(3)= 优先级 15,是整张表中最高的;而日历集成属于 retrieval-action 层(权重 3)× setup-only(1)= 优先级 3,排在最后。
2.2 Walker Score:流程可自动化程度(0-3)
Walker Score 回答的是"这个流程能不能交给 agent 自动跑":
| 分数 | 含义 |
|---|---|
| 3 | 完全可自动化(纯点击、结果确定) |
| 2 | 部分可自动化(需要滚动或条件内容) |
| 1 | 需要先完成人工/物理设置,之后 walker 可验证 |
| 0 | 不可达(SMS 验证、外部 OAuth、真实支付) |
关键演进(2026-03-17):BLE 设备流程原本被评分为 walker=0(不可达)。团队在物理 Pixel 7a + 真实 Omi 设备上验证后,证明它可以通过 ADB + agent-flutter 全流程驱动,因此升级为 walker=1(需要物理设备设置,之后 agent 可驱动完整流程)。这说明 Walker Score 不是静态属性,而是随基础设施能力演进而动态修正的。
三、特征向量总表:33 项功能的三层覆盖矩阵
Feature Vector 将 33 项核心功能划分为三个优先级梯队,每项标注了所属层、优先级、Walker 分数和覆盖状态。以下完整继承原文档的核心要素:
3.1 CORE DAILY:核心每日流程(优先级 9-15,walker 1-3)
| # | 功能 | 层 | 优先级 | Walker | 覆盖状态 |
|---|---|---|---|---|---|
| 1 | 会话列表与浏览 | capture(5) | 15 | 3 | ✅ conversations.yaml(9 步) |
| 2 | 会话详情(转写/摘要/行动项页签) | capture(5) | 15 | 2 | ✅ conversations.yaml |
| 3 | 会话录制(手机麦克风) | capture(5) | 15 | 1 | ✅ phone-capture.yaml(9 步) |
| 4 | 会话录制(Omi 设备) | capture(5) | 15 | 1 | ✅ device-capture.yaml(10 步) |
| 5 | 设备发现与连接(BLE) | capture(5) | 15 | 1 | ✅ device-connect.yaml(10 步) |
| 6 | 设备断开与重连 | capture(5) | 15 | 1 | ✅ device-connect.yaml |
| 7 | 记忆列表与浏览 | memory(4) | 12 | 2 | ✅ memories.yaml(6 步) |
| 8 | 记忆搜索 | memory(4) | 12 | 2 | ✅ memories.yaml |
| 9 | AI 聊天开/关(Ask Omi) | intelligence(3) | 9 | 2 | ✅ ask-omi-chat.yaml(9 步) |
| 10 | 行动项查看 | intelligence(3) | 9 | 2 | ✅ action-items.yaml(7 步) |
| 11 | 每日摘要/评分(首页卡片) | intelligence(3) | 9 | 2 | ✅ daily-summary.yaml(stub) |
| 12 | 全局搜索 | retrieval-action(3) | 9 | 2 | ✅ 已覆盖 |
| 13 | 任务管理(FAB 创建、切换) | retrieval-action(3) | 9 | 2 | ⚠️ 部分覆盖 |
3.2 CORE WEEKLY:核心每周流程(优先级 6-12,walker 1-2)
| # | 功能 | 层 | 优先级 | Walker | 覆盖状态 |
|---|---|---|---|---|---|
| 14 | 记忆审核/批准 | memory(4) | 12 | 1 | ⚠️ 无 UI——后端 API 存在但 Flutter 应用没有审核按钮(user_review 字段在 UI 中未使用) |
| 15 | 记忆分类与筛选 | memory(4) | 8 | 2 | ⚠️ 部分覆盖 |
| 16 | 手动添加/编辑记忆 | memory(4) | 8 | 2 | ✅ add-edit-memory.yaml(7 步) |
| 17 | 记忆图谱可视化 | memory(4) | 8 | 2 | ✅ memory-graph.yaml(stub) |
| 18 | 自定义词汇 | understand(4) | 8 | 2 | ✅ custom-vocabulary.yaml(7 步) |
| 19 | 说话人识别(People) | understand(4) | 8 | 1 | ✅ speaker-identification.yaml(9 步) |
| 20 | 目标追踪 | intelligence(3) | 6 | 2 | ✅ goals-tracking.yaml(7 步) |
| 21 | 会话分享/导出 | retrieval-action(3) | 6 | 2 | ✅ conversation-sharing.yaml(8 步) |
| 22 | 会话文件夹 | retrieval-action(3) | 6 | 2 | ✅ conversation-folders.yaml(10 步) |
| 23 | 应用市场浏览 | retrieval-action(3) | 6 | 2 | ✅ apps-marketplace.yaml(7 步) |
| 24 | 应用详情与安装 | retrieval-action(3) | 6 | 2 | ✅ apps-marketplace.yaml |
| 25 | 离线同步 UI | capture(5) | 10 | 2 | ✅ 已覆盖 |
3.3 SETUP & AUTH:设置与认证流程(优先级 3-5)
| # | 功能 | 层 | 优先级 | Walker | 覆盖状态 |
|---|---|---|---|---|---|
| 26 | 登录(Google Sign-In) | — | 5 | 1 | ✅ login.yaml(5 步) |
| 27 | 退出登录 | — | 5 | 2 | ✅ logout.yaml(5 步) |
| 28 | 首次启动引导(Onboarding) | — | 5 | 1 | ✅ onboarding.yaml(9 步) |
| 29 | 转写设置 | understand(4) | 4 | 2 | ✅ 已覆盖 |
| 30 | 语言选择 | understand(4) | 4 | 2 | ✅ 已覆盖 |
| 31 | 语音画像 | understand(4) | 4 | 1 | ✅ 已覆盖 |
| 32 | 任务集成 | retrieval-action(3) | 3 | 1 | ✅ task-integrations.yaml(stub) |
| 33 | 日历集成 | retrieval-action(3) | 3 | 0 | ⚠️ OAuth 受阻 |
四、覆盖缺口管理:三个未 100% 覆盖项及其根因
Feature Vector 的价值不仅在于"已覆盖",更在于显式登记未覆盖项及其阻塞根因,防止它们被遗忘:
| 排名 | 功能 | 优先级 | 阻塞原因 | 备注 |
|---|---|---|---|---|
| 1 | 记忆审核/批准 | 12 | Flutter 无对应 UI | 后端有 POST /v3/memories/{id}/review 端点与 user_review 字段,但 Flutter 应用没有任何批准/拒绝按钮。无法为不存在的 UI 编写流程。 |
| 2 | 记忆分类与筛选 | 8 | 部分覆盖 | memories.yaml 已覆盖,但筛选开关未充分演练 |
| 3 | 任务管理(FAB 创建) | 9 | 部分覆盖 | 行动项列表已覆盖,但任务创建表单需要文本输入 |
4.1 源码佐证:记忆审核是"后端就绪、前端缺失"的典型
在 backend/routers/memories.py 中可以找到记忆审核端点 POST /v3/memories/{memory_id}/review 的完整实现:它接收 value: bool 作为审核结论,调用 MemoryService.review(),并注释明确指出"Discarding a memory is this surface's thumbs-down. user_review on the memory is a mutable flag with no timestamp, so the ledger row is what gives the verdict a time and lands it in the daily report"(丢弃一条记忆是该接口的"踩",memory 上的 user_review 是无时间戳的可变标志,因此由账本行(ledger row)为判定打上时间并进入日报)。
这段源码精确印证了 feature-vector 的判断:能力已完整存在于服务端(审核、反馈、账本),但移动端 UI 从未暴露入口。这正是"后端 API 存在但 Flutter 应用无审核按钮"的代码级证据——E2E 覆盖矩阵把它标记为缺口,而不是硬写一个跑不通的流程,体现了这套方法的严谨性。
五、已发布 Flow-Walker 报告与覆盖率总结
截至文档更新(2026-03-18),共有 16 份已发布报告(此前为 11 份),全部在物理 Pixel 7a 设备上验证通过:
| 流程 | 步骤 | 结果 |
|---|---|---|
| login | 5/5 | PASS |
| onboarding | 9/9 | PASS |
| logout | 5/5 | PASS |
| ask-omi-chat | 9/9 | PASS |
| conversations | 9/9 | PASS |
| apps-marketplace | 7/7 | PASS |
| memories | 6/6 | PASS |
| action-items | 7/7 | PASS |
| phone-capture | 9/9 | PASS |
| device-connect | 10/10 | PASS |
| device-capture | 10/10 | PASS |
| conversation-folders | 10/10 | PASS |
| conversation-sharing | 8/8 | PASS |
| add-edit-memory | 7/7 | PASS |
| custom-vocabulary | 7/7 | PASS |
| speaker-identification | 9/9 | PASS |
5.1 覆盖率汇总
| 类别 | 总功能 | 已覆盖 | 缺口 |
|---|---|---|---|
| 核心每日(capture、intelligence) | 13 | 12 | 1(任务管理部分覆盖) |
| 核心每周(memory、understand、retrieval) | 12 | 11 | 1(记忆审核——无 UI) |
| 设置与认证 | 8 | 7 | 1(日历 OAuth) |
| 总计 | 33 | 30 | 3 |
覆盖率 30/33 ≈ 91%,且剩余 3 项为"部分覆盖/受阻",而非可立即行动的缺口。
六、版本演进史:Feature Vector 如何随验证结果迭代
Feature Vector 是一份活文档,其三个更新记录完整展示了 E2E 治理的闭环迭代节奏:
6.1 2026-03-17 更新 #1:BLE 流程晋级 + 认证流程入表
- BLE 设备流程从 CORE DAILY 之外升入核心每日梯队:device-connect 与 device-capture 在物理 Pixel 7a + 真实 Omi 设备上被证明可自动化(walker 从 0 升至 1)。
- 新增 3 个流程:phone-capture、device-capture、device-connect(合计 29 个新步骤)。
- 认证流程(login、logout、onboarding)首次入表。
6.2 2026-03-17 更新 #2:补全全部可行动缺口
- 新增 6 个流程,关闭所有可行动缺口:conversation-folders.yaml(10 步)、goals-tracking.yaml(7 步)、add-edit-memory.yaml(7 步)、custom-vocabulary.yaml(7 步)、conversation-sharing.yaml(8 步)、speaker-identification.yaml(9 步)。
- 记忆审核/批准被重新归类:不是"缺口"而是"Flutter UI 功能缺失"(后端存在,应用未暴露)。
- 覆盖率达成 30/33(91%)。
6.3 2026-03-18 更新:5 份新报告 + 一个已知阻塞
- 在物理 Pixel 7a 上新增发布 5 份报告(add-edit-memory、custom-vocabulary、speaker-identification、conversation-folders、conversation-sharing)。
- goals-tracking 流程受阻:尽管偏好已启用,DailyScoreWidget 在 Pixel 7a 上不渲染,导致无目标存在时 "Add Goal" 入口不可用——这是一个真实的 UI 渲染缺陷被 E2E 流程捕获的实例。
- 总报告数从 11 增至 16。
七、与 Flow-Walker 流水线的协同:从特征向量到可执行流程
Feature Vector 是"路线图",而 app/e2e/FLOW-WALKER-SKILL.md 是"施工队"。两者的衔接点在 app/e2e/flows/*.yaml。
7.1 流程 YAML 的 v2 架构
每个流程文件遵循 v2 schema(示例见 conversations.yaml):
version: 2
name: conversations
description: 一句话描述该流程测试什么
app: com.friend.ios.dev
evidence:
video: true
covers: # 该流程演练的源码文件——特征向量与代码的映射点
- app/lib/pages/conversations/conversations_page.dart
- app/lib/providers/conversation_provider.dart
preconditions: # 必须为真的真实用户状态
- auth_ready
steps:
- id: S1
name: 步骤标题
do: "详细操作说明——点什么、验证什么"
verify: true
expect:
- kind: text_visible
values: ["Conversations"]
- kind: interactive_count
min: 4
evidence:
- screenshot: step-S1.webp
note: "实现细节、代码路径、ADB 坐标、边界情况"
每个步骤支持两类断言:text_visible(断言指定文本出现在屏幕上)与 interactive_count(断言至少 N 个可交互控件可见)。preconditions 字段强调用真实用户状态测试(SKILL.md 中有完整的 auth_ready、signed_out、microphone_permission、ble_on、omi_device_connected、phone_number_verified 等前置条件定义表及依赖链)。
7.2 6 阶段流水线
一条流程从 YAML 到公开报告需经过 6 个阶段(详见 FLOW-WALKER-SKILL.md):
# 1. 初始化运行
INIT=$(node $(which flow-walker) record init --flow $FLOW --output-dir app/e2e/runs/ --no-video --json)
# 2. 逐步骤执行 + 流式写入 events.jsonl(必须用真实墙钟时间戳)
stream_event "step_start" "S1"
agent-flutter press 540 1200
adb exec-out screencap -p > /tmp/raw.png && \
cwebp -q 70 -resize 270 600 /tmp/raw.png -o "$RUN_DIR/step-S1.webp"
stream_event "step_end" "S1" ",\"outcome\":\"pass\""
# 3. 结束录制(自动保存 .snapshot.json 供回放)
node $(which flow-walker) record finish --run-id "$RUN_ID" --run-dir "$RUN_DIR" --status pass --flow "$FLOW" --json
# 4. 校验(audit 模式下可能需要手动覆盖 outcome)
node $(which flow-walker) verify "$FLOW" --run-dir "$RUN_DIR" --mode audit --output "$RUN_DIR/run.json" --json
# 5. 生成 HTML 报告
node $(which flow-walker) report "$RUN_DIR" --json
# 6. 推送发布
PUSH=$(node $(which flow-walker) push "$RUN_DIR" --json)
7.3 agent-flutter 驱动与前置条件
驱动层面,SKILL.md 定义了 agent-flutter 命令集(基于 Flutter Marionette 调试协议):snapshot -i --json 查看交互控件与 ref、press @ref/press x y 点击、fill @ref "text" 输入、scroll down/up 滚动、find text "X" press 按文本定位、screenshot PATH 截图。核心规则包括:Flutter 会激进重建 widget 树,ref 极易过期——每次交互前必须重新 snapshot;find type X 比硬编码 ref 更稳定。
前置条件是 feature-vector 中 walker 分数(1=需人工/物理设置)的具体落地。例如 phone-capture.yaml 的 preconditions 声明了 microphone_permission(Android 可通过 adb shell pm grant com.friend.ios.dev android.permission.RECORD_AUDIO 预授权)与 no_omi_device(无 BLE 设备配对时中央麦克风按钮才会出现);device-connect.yaml 则要求 ble_on(模拟器不支持 BLE,必须使用物理设备)与 omi_device_powered(物理 Omi 设备需开机、充电并在 BLE 范围内,LED 闪烁蓝光表示可发现模式)。
八、实践要点与经验沉淀
8.1 评分模型的可操作原则
- 捕获能力权重最高(capture=5):录音、设备连接是"听见你对话"的根基,任何回归都直接伤害核心价值主张。
- walker=0 不意味着放弃:SMS 验证、外部 OAuth、真实支付等无法自动化,要么登记为缺口并等待基础设施演进(如 BLE 从 0 升级到 1),要么依赖人工验证。
- 为不存在的 UI 不写流程:记忆审核的案例证明,E2E 无法为不存在的前端入口编写流程——应记录为"产品缺口"而非"测试缺口"。
8.2 从 YAML 到真实设备的坑位清单
结合各流程文件的 note 字段,可提炼出高频实操经验:
- Action Items 页面禁用系统返回键(action-items.yaml 的 S7):
KEYCODE_BACK会直接退出整个应用(back-exits-app bug),必须用底部导航 Home 页签返回。 - 会话详情进入需注意时间字段(conversations.yaml 的 S3):
startedAt与createdAt不一致的会话会抛 "Bad state: No valid conversation found",应选取两者一致的会话(如 "Mastering Vocal Communication")。 - 设备录音是连续的(device-capture.yaml 的 S8):与手机麦克风的一次性录制不同,Omi 设备按静音间隔自动切分会话(默认静音超时 2 分钟),处理完一段后立即开始下一段。
- BLE 电池读数节流(device-connect.yaml 的 S5):首次读取、变化 ≥5%、15 分钟间隔或穿越 20% 阈值时才会更新。
- 时间戳必须真实(FLOW-WALKER-SKILL.md):伪造/相同时间戳会导致报告显示 "2s" 总时长;schema 中步骤 outcome 误用
status字段会导致报告显示 "undefined"。
8.3 把 feature-vector 复用到你的项目
- 按产品使命定义 5 个左右的功能层并赋权(如 capture=5、understand=4…);
- 用"层权重 × 会话频率"计算每个功能的组合优先级;
- 为每个功能评估 walker 分数(0-3),标记不可达项;
- 按
优先级 × walker_score排序,为高优先可自动化项编写 YAML 流程; - 维护一张覆盖矩阵,显式登记缺口、阻塞根因与责任人;
- 随基础设施与产品演进周期性重评 walker 分数与优先级(参考本文 6.1-6.3 的迭代节奏)。
结语
Feature Vector 是 Omi 团队将"我们该测什么"从主观讨论转化为可计算、可追踪、可迭代的工程资产的关键。它以 91% 的覆盖率(30/33)验证了这套方法论的有效性,并用三个显式缺口(记忆审核无 UI、任务创建需文本输入、日历 OAuth 受阻)展示了成熟团队的取舍智慧——好的 E2E 治理不是消灭所有缺口,而是让每个缺口都有明确根因、优先级和演进路径。对于任何希望建立可持续移动端 E2E 覆盖体系的团队,这份文档与其配套的流程 YAML、流水线脚本和驱动工具链,都是可以直接借鉴的完整样板。