feat(android): evaluate candidates before human confirmation

This commit is contained in:
QiuSW
2026-07-25 21:54:52 +08:00
parent 32d5310000
commit 84f2da3cf7
25 changed files with 2127 additions and 43 deletions
+3 -3
View File
@@ -51,9 +51,9 @@
## 当前阶段与优先路径
当前已完成 Phase 0、T-101 至 T-103:Android 可运行、设备就绪、workflow、私有样本
导入、固定词搜索、最多 5 个候选截图采集和结构化需求提取链路均已验证。下一步是
T-104,用同一需求 schema 评估候选并停在人工确认点,继续禁止订单提交和支付。
当前已完成 Phase 0 和 Phase 1:Android 可运行、设备就绪、workflow、私有样本导入、
动态词搜索、最多 5 个候选截图采集、结构化需求提取、候选评估和人工确认停止点均已
验证。下一步是 T-201,生成并收敛 Go-Gin、SQLite 和迁移骨架。
严格按以下顺序推进:
+7 -4
View File
@@ -8,7 +8,7 @@
| --- | --- |
| 任务来源 | 其他管理后台或本项目管理 Web 采集商品标题、描述、图片、数量和预算。 |
| 第一层样本来源 | 本机目录中的蝦皮订单文本和参考图;二者以蝦皮订单号作为同名文件名。 |
| 执行方式 | 采购人员使用 Android App 操作拼多多;固定词搜索和最多 5 个候选证据采集已可运行,需求提取和匹配判断尚未实现。 |
| 执行方式 | 采购人员使用 Android App 操作拼多多;需求提取、动态词搜索、最多 5 个候选证据采集、匹配建议和人工确认停止点已可运行。 |
| 核心痛点 | 人工把图片和描述转成搜索词、逐条比较商品并记录结果,耗时且不一致。 |
| 验证范围 | 一台设备、一个管理身份、一个采购执行人员、拼多多单平台。 |
| 资金边界 | MVP 不提交订单、不支付,只验证到人工确认位置。 |
@@ -105,9 +105,11 @@ T-004 已固定首版规则:推荐私有目录为被 Git 忽略的 `private-fi
原始输入保留,硬约束与输入一致。T-103 已实现版本化 schema、0.75 置信阈值、
冲突转人工以及 SKU/数量的本地确定性回填;当前样本未提供预算,因此预算保持空。
- F-005/US-004/IX-006:在已验证的拼多多版本上,App 能从任务进入搜索结果并检查
最多 5 个候选;无合理候选时明确结束而不是随意选择。
最多 5 个候选;T-104 已把需求搜索词、当前候选证据和严格评估 schema 绑定,
无合理候选时明确结束而不是随意选择。
- F-006/US-005/IX-007:流程到达人工确认点后停止;MVP 任意路径都不能触发最终
提交订单或支付。
提交订单或支付。T-104 的本地确认只允许标记建议候选可用或拒绝本次候选,
`order_submitted` 固定为 `false`。
- F-007/US-006/IX-008:失败包含稳定错误码、失败步骤、可读说明和必要截图;重新
打开任务后证据仍可查看。
@@ -144,7 +146,8 @@ T-004 已固定首版规则:推荐私有目录为被 Git 忽略的 `private-fi
- OnePlus PKG110、Android 16/API 36、拼多多 8.17.0 的首页、搜索输入、结果页、
候选卡和详情返回已形成可复现基线;不同账号、类目和页面实验的差异仍是风险。
- VLM 需求提取的 provider-neutral 合约和 OpenAI 兼容适配器已实现;真实供应商、
模型、测试凭证、成本上限、数据留存地区和图片隐私规则仍待确认。
模型、测试凭证、成本上限、数据留存地区和图片隐私规则仍待确认。候选评估契约和
本机 mock 集成已实现,但尚无真实模型质量证据。
- 拼多多平台条款、自动化允许范围和账号风控需要业务方确认;项目不实现绕过措施。
- 后续若允许提交订单,必须先明确 SKU、收货地址、运费、优惠、发票、金额审批、
幂等和人工确认规则,并单独更新需求。
+2 -2
View File
@@ -25,10 +25,10 @@
| 图片/截图 | 后端受控本地文件目录,数据库存元数据 | MVP 已定 | 禁止把二进制直接塞入日志;生产再评估对象存储。 |
| 管理鉴权 | 单个种子管理账号 + 服务端会话 Cookie | MVP 已定 | 密码只保存哈希;完整 RBAC 为 V2。 |
| App 鉴权 | 采购员登录态 + 设备绑定令牌 | 目标已定,细节待实现 | 人员身份与设备身份分离;令牌只保存哈希。 |
| VLM 接入 | 应用内统一适配器,优先兼容 OpenAI 风格多模态接口 | 需求提取已实现,供应商待定 | T-103 使用严格 JSON Schema、单次调用预算和 2048 px 图片上限;GUI-Owl/MAI-UI 动作模型不具备需求提取能力。 |
| VLM 接入 | 应用内统一适配器,优先兼容 OpenAI 风格多模态接口 | 需求提取与候选评估已实现,供应商待定 | T-103/T-104 使用严格 JSON Schema、单候选单次调用和 2048 px 图片上限;GUI-Owl/MAI-UI 动作模型不具备需求提取能力。 |
| 通知 | MVP 不使用推送 | 已定 | 点击“获取任务”调用原子 claim API;V2 再评估厂商推送/WebSocket。 |
| 后端测试 | 标准库 `testing` + `httptest` | MVP 已定 | 覆盖状态机、权限、幂等、SQLite 事务和输入校验。 |
| Android 测试 | Gradle `test` + `kotlinx-coroutines-test` 1.7.3 + 真实设备 smoke | 需求提取探针已验证 | 122 次测试覆盖 runner、页面分类、候选、VLM schema、端点策略与隐私;OnePlus PKG110 上完成私有 fixture + 本机 mock 的单次多模态请求 smoke。 |
| Android 测试 | Gradle `test` + `kotlinx-coroutines-test` 1.7.3 + 真实设备 smoke | Phase 1 探针已验证 | 166 次测试覆盖 runner、动态页面分类、受控证据、VLM schema、人工确认策略与隐私;OnePlus PKG110 上完成私有 fixture + 本机 mock 的需求提取和 5 候选评估 smoke。 |
| 部署 | 单机局域网 Go 服务;容器化后置 | MVP 已定 | Android 测试机必须能通过 HTTPS 或受控测试网络访问。 |
## Roubao 上游版本基线
+21 -2
View File
@@ -105,6 +105,14 @@ evidence/ # 截图、步骤日志、脱敏和上传
浏览范围。
- 模型不能返回点击坐标、状态迁移或“允许提交订单”等执行授权。
T-104 按候选 ordinal 串行评估,每个候选最多一次结构化调用、整批最多 5 次;首个
网络失败或无效输出停止后续调用。模型响应只允许
`schema_version/candidate_index/decision/score/matched/missing_or_uncertain/
rejection_reasons/confidence`,其中 `decision` 仅允许 `REVIEW/REJECT/
MANUAL_REQUIRED`。ordinal、证据 SHA-256、建议候选、provider provenance、
`manual_review_required=true` 和 `order_submitted=false` 由本地代码确定。任务没有
预算时,模型声称价格或预算匹配会被视为无效输出。
T-103 的模型响应只允许
`schema_version/search_query/category/attributes/confidence/warnings`。属性来源限定为
`TITLE/IMAGE/BOTH`;额外字段、无效 JSON、重复或越界属性、坐标/动作语义均视为无效
@@ -189,10 +197,10 @@ SearchProbeScreen
登录、验证码、风控、订单或支付边界都终止 workflow。该路径不提供坐标、ADB、
Shizuku shell、OCR 或 VLM 动作降级。
T-102 在搜索结果后追加一个有界候选步骤:
T-102/T-104 在搜索结果后追加一个有界候选步骤:
```text
固定词结果页
精确匹配固定词或当前结构化需求词的结果页
-> 最多 2 次滚动预算
-> 最多 5 个去重商品卡
-> 验证详情页
@@ -206,6 +214,17 @@ T-102 在搜索结果后追加一个有界候选步骤:
受控 evidence 边界读取,不能让 VLM adapter 自行遍历 cache。Android 10/API 29 及
以下不能运行当前截图探针,应在预检时明确不支持,不使用媒体投影或 shell 绕过。
`CandidateEvidenceSource` 只接受当前 workflow 内存中的连续 ordinal 元数据,文件名
固定为 `candidate-01.png` 至 `candidate-05.png`;每张 PNG 最多 8 MiB、全批最多
32 MiB、声明尺寸最长边不超过 10000 px,并复核规范路径、PNG/IHDR、精确字节数、
尺寸和 SHA-256。Android gateway 再解码并把最长边缩至 2048 px。当前需求快照与
搜索词必须同时匹配候选 session,否则拒绝评估;另一个关键词的结果页只允许重新进入
搜索框,不能采集候选。
评估结束后 automation 不再产生动作,UI 进入 `AWAITING_CONFIRMATION`、
`MANUAL_REVIEW` 或 `NO_MATCH`。人员可以把本地建议项标记为可用,或拒绝本次候选;
这只是验证结果,所有状态的 `order_submitted` 均为 `false`。
需求提取是独立探针,不启动拼多多,也不接入 `MobileAgent`。GUI-Owl 和 MAI-UI 输出
动作/坐标,明确不具备 `supportsRequirementExtraction` 能力。真实供应商未确认前,
普通测试只使用 Fake gateway;本机 OpenAI 兼容 mock 仅验证 Android 请求链路和隐私
+8
View File
@@ -65,6 +65,14 @@
- 需求提取标题和 SKU 分别限制为 2048、512 个 UTF-8 字节,超过上限不得截断后发送。
- 图片进入 VLM 前必须校验媒体类型、字节上限、JPEG 魔数、SHA-256 和可解码尺寸,并
按声明长度一次分配精确读取、有界缩放;prompt、Base64 和原始响应不得写普通日志。
- 候选评估按 ordinal 串行执行,每个候选最多调用一次、整批最多 5 次;失败、取消或
无效输出立即停止后续调用,不保留部分结果作为自动建议。
- 候选证据只能通过当前 session 的 metadata allowlist 读取;复核固定文件名、规范
路径、PNG/IHDR、字节数、尺寸和 SHA-256,VLM adapter 不得遍历 cache。
- 候选 session 必须绑定完整需求快照和精确搜索词;旧需求、其他关键词或失败
workflow 的截图不得进入评估。
- 模型不能设置建议 ordinal、人工确认状态或 `order_submitted`;预算缺失时价格或
预算匹配声明无效。
## 6. 后端与 API 规则
+6 -1
View File
@@ -334,6 +334,7 @@ App 空闲或运行时上报设备状态;运行时任务续租使用任务专
```json
{
"schema_version": 1,
"candidate_index": 1,
"decision": "REVIEW",
"score": 0.82,
"matched": ["颜色接近", "价格未超预算"],
@@ -343,7 +344,11 @@ App 空闲或运行时上报设备状态;运行时任务续租使用任务专
}
```
`decision` 只允许 `REVIEW`、`REJECT`、`MANUAL_REQUIRED`。模型没有“提交订单”权限。
`candidate_index` 必须原样回显当前候选 ordinal;`decision` 只允许 `REVIEW`、
`REJECT`、`MANUAL_REQUIRED`。App 按 ordinal 串行评估,每个候选最多调用一次、整批
最多 5 次,并由本地确定性规则产生建议项。模型不能返回页面动作、建议 ordinal、
人工确认状态或订单授权,也没有“提交订单”权限;原任务未提供预算时,任何价格或
预算匹配声明都视为无效输出。
## 执行事件与结果
+15 -7
View File
@@ -5,8 +5,8 @@
## 当前快照
- 日期:2026-07-25
- 阶段:T-103 已完成;准备 T-104 候选评估与人工确认点
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-103 均已纳入 Git 历史
- 阶段:Phase 1 已完成,准备开始 T-201 后端骨架
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104 均已纳入 Git 历史
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码
- Android:固定 `main@c8a6d7f03422eb01744b01f3ee77bf7757741f7e`;MIT 许可证已保留
- 后端:已决定使用 Go 1.23.0 + Gin 1.11.0;Go Blueprint v0.10.11 骨架尚未接入
@@ -14,12 +14,13 @@
Build Tools 34.0.0、Platform Tools/ADB 37.0.0;用户级 SDK 环境变量已设置
- Android Studio:未安装;`winget` 静默安装卡住后已终止,不阻塞命令行构建
- 测试:`lintDebug test assembleDebug` 成功;App 两个变体、task contract 和导入器
共 20 份报告、122 次测试,0 failure、0 error、0 skipped
共 26 份报告、166 次测试,0 failure、0 error、0 skipped
- Workflow:纯 Kotlin runner 已支持步骤 timeout、最多 3 次 retry、安全阻塞、
用户停止和单 runner 并发拒绝;T-102 已接入搜索加有界候选采集五步
- TaskSource:严格 CLI 已生成并验证真实私有 ProbeTask;默认 APK 不含私有 fixture
- VLM:需求提取 schema、0.75 阈值、冲突转人工、单次 OpenAI 兼容调用、安全端点
策略、字段/响应上限和 JPEG 校验/缩放已实现;SKU/数量由本地原值回填,预算保持空
- VLM:需求提取与候选评估均使用严格 schema、0.75 阈值、受控证据源、安全端点和
单次调用边界;候选最多 5 个并按 ordinal 串行评估,本地产生建议并停在人工确认,
SKU/数量由本地原值回填,预算保持空,订单提交状态固定为 false
- 测试设备:OnePlus PKG110,Android 16/API 36;肉包 `1.4.2 (7)`;拼多多
`8.17.0 (81700)`
- 设备就绪:肉包采购无障碍已启用并连接;拼多多首页、搜索输入、固定词结果页、
@@ -45,6 +46,7 @@
| `docs/tasks/T-101.md` | DONE | 固定脱敏词拼多多搜索和结果页真机验证 |
| `docs/tasks/T-102.md` | DONE | 最多 5 个候选详情截图、证据 manifest 和结果页返回 |
| `docs/tasks/T-103.md` | DONE | 私有任务需求 schema、硬约束、隐私边界和 VLM 适配器 |
| `docs/tasks/T-104.md` | DONE | 动态搜索、候选严格评估、本地建议和人工确认点 |
| `deepseek总结.txt` | 已有 | 历史讨论摘要,不是正式需求权威 |
| `android-buyer/` | 已有 | Roubao `main` 固定 commit 的 Android 基线 |
| `android-buyer/task-contract/` | 已有 | Android/CLI 共享 ProbeTask 与 TaskSource |
@@ -54,9 +56,9 @@
## 任务摘要
- 已完成:T-001 至 T-004,以及 T-101 至 T-103。
- 已完成:T-001 至 T-004,以及 T-101 至 T-104。
- 正在进行:无。
- 下一个可领取任务:T-104 接入候选评估并停在人工确认点。
- 下一个可领取任务:T-201 生成并收敛 Go-Gin、SQLite 和迁移骨架。
## 当前可运行内容
@@ -77,6 +79,12 @@ $env:RUN_START_COMMAND = "1"
清空旧结果;设备原 API provider 设置已恢复。该 smoke 只证明集成与隐私边界,不
代表真实 VLM 提取质量;真实凭证调用未执行。
同日完成 T-104 真机 smoke:结构化需求搜索词驱动拼多多搜索并采集 5 份候选证据,
本机 mock 精确收到 5 次按 ordinal 排序的单图 POST;请求未包含订单、店铺、本机
路径或数量字段。严格评估进入“等待人工确认”,人员可标记建议候选可用或拒绝,
`order_submitted` 始终为 false;日志敏感词、Base64、原始响应和 schema/prompt
命中均为 0。该结果不代表真实模型的商品匹配质量。
## 维护规则
发生以下变化时覆盖更新本文:
+109
View File
@@ -0,0 +1,109 @@
---
id: T-104
title: 接入候选评估并停在人工确认点
phase: 1
deps:
- T-102
- T-103
status: DONE
created: 2026-07-25
context_ref: 32d5310
work_branch: main
write_paths:
- android-buyer/app/src/main/java/com/roubao/autopilot/MainActivity.kt
- android-buyer/app/src/main/java/com/roubao/autopilot/accessibility/**
- android-buyer/app/src/main/java/com/roubao/autopilot/pinduoduo/**
- android-buyer/app/src/main/java/com/roubao/autopilot/ui/screens/SearchProbeScreen.kt
- android-buyer/app/src/main/java/com/roubao/autopilot/vlm/**
- android-buyer/app/src/test/java/com/roubao/autopilot/pinduoduo/**
- android-buyer/app/src/test/java/com/roubao/autopilot/vlm/**
- docs/**
- progress.md
---
## 问题 / 背景
T-102 已能有界采集最多 5 份匿名候选截图证据,T-103 已能从私有任务得到严格的结构化
需求,但两者尚未使用同一搜索词连接,候选也没有匹配项、缺失项和拒绝原因。T-104
只完成候选建议和人员确认闭环,不提交订单、不进入支付。
## 方案
1. 需求提取成功后,候选探针使用该提取结果的搜索词;固定脱敏词仍保留给 T-101/T-102
独立回归。
2. 只有搜索词与当前需求一致且 workflow 成功的候选证据可以评估。
3. 受控 evidence source 按内存中的候选元数据读取匿名 PNG,复核数量、文件名、路径、
字节数、PNG 尺寸和 SHA-256;VLM adapter 不自行遍历 cache。
4. 每次用户操作按 ordinal 串行评估,单个候选最多调用一次、全批最多 5 次;任一网络
失败或无效输出都会停止后续付费调用。
5. 本地代码从有效评估中稳定产生建议项;预算缺失、低分、不确定或模型输出无效时保持
人工处理。无论模型输出如何,都不能产生页面动作或订单授权。
6. UI 展示匹配项、缺失项、拒绝原因和建议项,并停在人工确认点;人员只能标记候选
可用或拒绝本次候选,结果始终记录 `order_submitted=false`。
## 验收要点
- [x] 候选搜索使用当前结构化需求的搜索词,旧搜索结果不能冒充当前任务证据。
- [x] 最多 5 份候选 PNG 经受控边界验证后才进入评估 gateway。
- [x] 模型请求不含订单号、店铺名、本机路径、数量或支付信息。
- [x] 严格 schema 输出每个候选的判断、分数、匹配项、缺失项和拒绝原因。
- [x] 缺候选、ordinal 不一致、额外字段、动作语义和证据篡改均安全失败或转人工。
- [x] UI 明确停在人工确认,不包含提交订单或支付动作。
- [x] Fake gateway、证据读取、动态搜索和人工确认状态均有自动化测试。
- [x] `lintDebug test assembleDebug` 通过,默认 APK 不含私有 fixture。
- [x] 无真实模型凭证时只用本机 mock 验证集成,不宣称真实匹配质量。
## 执行记录
### 2026-07-25:任务开始
- 基于 T-103 提交 `32d5310` 开始。
- 当前外部 blocker 仍是真实 VLM 供应商、凭证、费用、数据留存和模型效果;先完成
provider-neutral 契约、Fake 测试和本机 mock 集成。
### 2026-07-25:实现
- 动态搜索使用当前 `RequirementExtraction.searchQuery`,同时绑定完整需求快照、
搜索词、成功 workflow 和本次候选 metadata;任一不一致都拒绝评估。
- `CandidateEvidenceSource` 只按内存 allowlist 读取 `candidate-01.png` 等固定匿名
文件,复核规范路径、8 MiB 单图/32 MiB 总量、PNG/IHDR、尺寸和 SHA-256。
- `CandidateEvaluator` 按 ordinal 串行调用,单候选一次、全批最多 5 次;无效输出、
provider 失败或取消立即停止后续调用,无效批次不保留先前自动建议。
- 严格解析候选 ordinal、判断、分数、匹配项、缺失项、拒绝原因和置信度;拒绝额外
字段、数字字符串、坐标/动作/提交/支付语义,以及无预算时的价格匹配声明。
- 推荐候选由本地按分数、置信度和 ordinal 稳定产生;人工接受必须对应实际存在的
`REVIEW` 建议项,批次和 UI 均固定 `order_submitted=false`。
- UI 展示每个候选的评估理由、警告和人工操作,只提供“标记建议候选可用”和
“拒绝本次候选”,没有提交订单或支付控件。
### 2026-07-25:自动化验证
- 执行
`.\gradlew.bat :app:lintDebug test assembleDebug --no-daemon`,构建与 lint 通过。
- App Debug/Release、task contract 和导入器共 26 份报告、166 次测试,0 failure、
0 error、0 skipped。
- 覆盖动态搜索、其他关键词结果页、受控证据路径/大小/PNG/尺寸/哈希、每候选调用
次数与停止规则、严格 schema、隐私字段、确定性推荐、人工确认和订单未提交状态。
- 不带 `probeFixturesDir` 重建默认 Debug APK,`assets/probe-fixtures/` 条目为 0。
### 2026-07-25:真机 smoke
- 在 OnePlus PKG110、Android 16/API 36、拼多多 8.17.0 上,用私有 fixture 完成
动态搜索和 5/5 候选证据采集。
- 一次性本机 OpenAI 兼容 mock 精确收到 5 次 POST,ordinal 为 1 至 5,每次只有
一张 JPEG data URL;订单、店铺、本机路径和数量字段命中均为 false。
- 严格响应进入“等待人工确认”,5 个候选均可见;点击“标记建议候选可用”后显示
候选已由人员标记可用且订单未提交,页面没有提交或支付按钮。
- 候选流程后的 logcat 中私有 sentinel、Base64、原始 mock 响应及 schema/prompt
命中均为 0;设备 provider 已恢复,ADB reverse 已移除。
### 未验证项
- 未使用真实远程 VLM 凭证,不宣称真实商品匹配质量、成本或供应商可用性。
- 当前证据是整页截图,尚无确定性商品标题和价格采集;第一层预算为空,因此任何
价格或预算匹配都转人工。
### 后续
- T-201 建立 Go-Gin、SQLite 和迁移骨架。
- T-202 生成并确认 P0 Web/App 低保真原型。