docs: import wiki at afc651f75a3a
+200
@@ -0,0 +1,200 @@
|
||||
<!-- docs-wiki-sync:docs/tasks/T-272.md@afc651f75a3abc2676bb13aa8a80f6aa6a25a72e -->
|
||||
> 同步来源:[`docs/tasks/T-272.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-272.md) · commit `afc651f75a3a`
|
||||
|
||||
---
|
||||
id: T-272
|
||||
title: 手机端 VLM 兜底选择并复核颜色尺码
|
||||
phase: 2
|
||||
deps:
|
||||
- T-207
|
||||
- T-246
|
||||
status: DOING
|
||||
created: 2026-08-01
|
||||
context_ref: 8739c39
|
||||
work_branch: null
|
||||
write_paths:
|
||||
- docs/tasks/T-272.md
|
||||
- docs/current-state.md
|
||||
- docs/02-requirements.md
|
||||
- docs/03-tech-stack.md
|
||||
- docs/04-architecture.md
|
||||
- docs/05-coding-rules.md
|
||||
- android-buyer/app/src/main/**
|
||||
- android-buyer/app/src/test/**
|
||||
---
|
||||
|
||||
## 问题 / 背景
|
||||
|
||||
真机任务 `da6be4b5-ed92-4813-b6d9-ae88d4995be6` 在第一轮候选浏览进入商品规格弹层后,
|
||||
有时没有选中任务颜色,有时没有选中任务尺码。人眼能看到对应选项,但现有流程只依赖
|
||||
无障碍节点规则定位和一次点击后复读,无法处理拼多多灰度页面的祖先可点节点、祖先选中
|
||||
状态、规格组新文案或纯视觉选中边框。
|
||||
|
||||
当前代码有两个确定性缺口:
|
||||
|
||||
1. `PinduoduoSpecificationParser.isOption()` 只接受选项节点自身 `clickable`、`selected`
|
||||
或 disabled,没有使用 T-269 已采集的 `selfOrAncestorClickable`。文字子节点不可点而
|
||||
祖先容器可点时,选项在解析阶段就被漏掉,后续点击代码没有机会执行。
|
||||
2. `PinduoduoUiElement.selected` 只反映当前节点自身状态;选中状态落在祖先容器时会把成功
|
||||
点击误判为未选中。候选自动化只复读一次,不能形成节点与视觉证据的交叉确认。
|
||||
|
||||
参考 Obsidian:
|
||||
|
||||
- `ila/项目文档/cmroubao/cmroubao-Android无障碍节点树与VLM混合判断方案.md`
|
||||
- `ila/项目文档/cmroubao/cmroubao-无障碍节点JSON与VLM兜底方案.md`
|
||||
|
||||
本任务实现**规则优先、手机端 VLM 有界兜底、每次只执行一个规格动作、最终同时复核颜色
|
||||
和尺码**。Admin 不代理模型、不保存或下发 provider/API Key;第三轮保底候选不做 SKU
|
||||
硬匹配,因此不启用本兜底。
|
||||
|
||||
## 关联需求与交互
|
||||
|
||||
- 功能:F-005、F-007、F-009
|
||||
- 用户故事:US-004、US-006、US-009
|
||||
- 交互:IX-006、IX-008、IX-010;不新增采购人员操作
|
||||
- 架构:`Android App -> 本机配置的 OpenAI 兼容 VLM Provider`,后端零推理
|
||||
- API/数据库:不新增 Go API 或 migration;通过既有执行事件回传非秘密聚合诊断
|
||||
|
||||
## 行为契约
|
||||
|
||||
### 1. 执行模式和配置来源
|
||||
|
||||
- 自动领取任务时,本机 VLM 配置完整、安全且 provider 支持结构化多模态调用,execution
|
||||
采用 `AI_ASSISTED`;否则采用 `MANUAL_FIRST`,不得因缺少模型阻塞确定性采购。
|
||||
- execution 模式开始后固定。只有 `AI_ASSISTED` 可以调用规格 VLM;`MANUAL_FIRST`、
|
||||
provider 失效或配置中途变化时保持确定性规则并跳过无法确认的候选,不静默冒充 AI。
|
||||
- provider、Base URL、model 和 API Key 只来自 Roubao 的本地设置;任务 payload 和
|
||||
Admin 均不能覆盖。Key 继续使用既有 Keystore-backed 加密存储且不得进入日志/outbox。
|
||||
|
||||
### 2. 原始 SKU 仍是硬约束
|
||||
|
||||
- `SkuHardConstraintExtractor` 从任务原始 SKU 冻结唯一 `COLOR` 和 `SIZE` 目标;模型不得
|
||||
改写目标、数量、预算或商品身份。
|
||||
- VLM 只允许把冻结目标映射到当前截图/节点中实际存在的一个 observed option,例如
|
||||
`BLACK -> 雅黑`;找不到唯一证据返回 `NOT_FOUND/AMBIGUOUS`,不能就近任选。
|
||||
- 明确 disabled 或完整规格组中目标不存在属于 `MISMATCH`,不得调用模型覆盖。
|
||||
|
||||
### 3. 先修确定性节点规则
|
||||
|
||||
- 规格 option 判定接受 `selfOrAncestorClickable`,但组名、交易文案排除、长度和数量上限
|
||||
保持不变。
|
||||
- 采集 `selfOrAncestorSelected`(包含有界祖先的 selected/checked),规格 option 的选中态
|
||||
使用该只读聚合值;遍历层数沿用 `MAX_CLICK_ANCESTORS`,不得无界向上搜索。
|
||||
- 规则给出唯一、enabled 的目标时仍走现有快速路径,不调用 VLM。
|
||||
|
||||
### 4. 脱敏节点 JSON 与同帧截图
|
||||
|
||||
仅在规则返回 `Absent`(可见信息不完整)、`Ambiguous`、唯一选项点击失败,或点击后节点
|
||||
无法确认时构造规格兜底快照:
|
||||
|
||||
- 只允许拼多多前台且页面稳定为 `SPECIFICATION_PANEL`;任一登录、验证码、风控、订单
|
||||
确认或支付边界立即停止,不调用模型覆盖。
|
||||
- 从当前 `AccessibilityNodeInfo` 树生成最多 200 个可见/语义/交互节点的扁平 JSON;字段
|
||||
只含临时 `node_id`、parent、depth/path、裁剪文字、class/resource、可见/启用/点击/
|
||||
选中/滚动状态和屏幕内 bounds。
|
||||
- 删除系统栏、零面积节点、无结构作用的重复容器和敏感文本;单文字最多 160 字符、深度
|
||||
最多 12,不上传原始对象 `toString()`。
|
||||
- 节点 JSON 和 PNG 截图前后各复核一次页面身份,生成包含截图 hash 的 `snapshot_id`;
|
||||
页面变化则丢弃,不调用或不执行旧结果。
|
||||
|
||||
### 5. 定位输出和单步点击
|
||||
|
||||
定位请求按颜色、尺码分别调用,模型只允许返回严格 JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"decision": "TARGET_FOUND",
|
||||
"group": "COLOR",
|
||||
"expected": "BLACK",
|
||||
"observed_option": "雅黑",
|
||||
"target_node_id": "n42",
|
||||
"evidence_node_ids": ["n18", "n42"],
|
||||
"confidence": 0.96,
|
||||
"reason_code": "UNIQUE_SEMANTIC_MATCH"
|
||||
}
|
||||
```
|
||||
|
||||
- `decision` 仅允许 `TARGET_FOUND/ALREADY_SELECTED/NOT_FOUND/AMBIGUOUS/UNSAFE`;
|
||||
confidence 初始阈值为 `0.92`。
|
||||
- `TARGET_FOUND` 必须唯一引用当前 snapshot 中可见、enabled、具有选项语义且自身或祖先
|
||||
可点击的节点;不得返回坐标、多步计划、确认、购买、下单或支付动作。
|
||||
- 网络返回后重新取树,按节点 path + 局部指纹重新定位;目标变化、多个命中或安全条件
|
||||
变化时丢弃。通过后只执行一次 `ACTION_CLICK`,并按现有节奏等待 1 至 3 秒。
|
||||
|
||||
### 6. 点击后与最终组合复核
|
||||
|
||||
- 颜色和尺码严格串行:颜色动作后重新观察,再处理尺码;任何动作不得由模型连续规划。
|
||||
- 规则点击成功但节点未确认时先记为待复核,不盲目重复;VLM 定位点击同理。
|
||||
- 两个步骤结束后必须在同一最终快照上确认颜色和尺码**同时**选中。节点规则已同时确认时
|
||||
不调用模型;否则调用一次只读 VLM,输出仅允许
|
||||
`BOTH_SELECTED/NOT_BOTH_SELECTED/AMBIGUOUS/UNSAFE`,阈值 `0.95`。
|
||||
- VLM 证明以独立 `selection_proof` 保存,包含 group、冻结目标、页面 observed option、
|
||||
method、confidence、snapshot/screenshot hash 和 prompt/schema 版本;不得伪造节点
|
||||
`selected=true`。
|
||||
- 只有确定性双确认,或有效视觉证明同时覆盖颜色和尺码,候选才满足 SKU 硬约束;否则
|
||||
关闭弹层、跳过候选。不得因模型失败终止整轮或重复同一动作。
|
||||
|
||||
### 7. 调用预算、缓存和审计
|
||||
|
||||
- 同一 candidate + group + snapshot + use case 最多调用一次;每候选最多 2 次定位加 1 次
|
||||
最终复核,共 3 次;同一响应不做 HTTP 自动重试或重定向。
|
||||
- 单次调用沿用结构化客户端的有界 timeout;超时、网络错误、schema 错误、低置信度和
|
||||
prompt injection 文案均按不可用处理。
|
||||
- `CandidateSearchDiagnostics` 追加 VLM 调用、接受、拒绝和双规格复核计数,经既有事件
|
||||
outbox 回传 Admin;普通日志只写枚举和计数,不写节点 JSON、截图 Base64、endpoint、
|
||||
Key、任务标题/SKU或供应商原始正文。
|
||||
- 审计证明保存在候选规格证据与本地进度快照中,重启恢复不能把 VLM 证明降级为伪造的
|
||||
确定性选中。
|
||||
|
||||
## 方案
|
||||
|
||||
1. 扩展无障碍元素的有界祖先点击/选中聚合,并为规格节点建立临时 path/fingerprint。
|
||||
2. 增加受限规格快照、canonical hash、严格 JSON 输入输出、prompt 和 provider-neutral
|
||||
`PinduoduoSpecificationVlmGateway`。
|
||||
3. Android adapter 复用 Roubao 现有 `VLMClient` 与本地 provider 设置,校验/缩放规格
|
||||
PNG 后只调用 `predictStructuredOnce()`。
|
||||
4. 把 candidate 规格选择重构为规则快速路径 + 可空 VLM fallback;最终证明显式进入
|
||||
`PinduoduoSpecificationEvidence` 和硬约束策略。
|
||||
5. 追加调用预算和诊断计数,并更新进度存储的向后兼容 JSON。
|
||||
6. 本任务只在候选发现链路启用;订单 dry-run 继续使用原确定性选择,待真机样本达到验收
|
||||
后另行复用,避免直接扩大不可逆动作前的模型权限。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- [x] 祖先可点、祖先 selected/checked 的颜色/尺码节点能由规则路径正确选择,不调用VLM。
|
||||
- [x] 规则唯一成功时模型调用为0;`Absent/Ambiguous/click failed/post-click unknown` 才触发。
|
||||
- [x] 节点 JSON 受限、脱敏、可复现,和截图绑定同一 snapshot hash。
|
||||
- [x] 模型只能选择 snapshot 中唯一 node ID;页面变化、旧节点、坐标和多步输出不能点击。
|
||||
- [x] 颜色、尺码串行单击,最终同快照未同时确认时不保存为 EXACT_MATCH 候选。
|
||||
- [x] disabled、完整分组缺失、安全阻塞和 `MANUAL_FIRST` 不能被 VLM 改判。
|
||||
- [x] 每候选不超过3次调用,相同 snapshot/use case 不重复,网络失败不形成点击循环。
|
||||
- [x] API Key、endpoint、完整节点/响应、标题/SKU和截图 Base64不进入日志或outbox。
|
||||
- [x] Debug/Release 单测、lint 和两种 APK 构建通过。
|
||||
- [ ] 真机复跑 `da6be4b5-ed92-4813-b6d9-ae88d4995be6` 的同类任务,至少固定颜色缺失、
|
||||
尺码缺失各一个样本,Admin 诊断与最终规格截图一致,支付动作次数为0。
|
||||
|
||||
## 边界
|
||||
|
||||
- 不新增 Admin VLM 代理、provider 配置、API Key 字段、Go API 或数据库 migration。
|
||||
- 不允许纯视觉坐标 grounding;无可重新定位节点时跳过候选。
|
||||
- 不改变第三轮 fallback、候选数量、结果滚动、三轮预算、goods_id 或候选去重。
|
||||
- 不把 VLM 规格兜底用于订单确认、提交或支付;不放宽 T-217/T-218 单次提交围栏。
|
||||
- 不关闭 T-265/T-268/T-269/T-270/T-271 的独立真机验收项。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-08-01:根据真机任务颜色/尺码偶发未勾选现象和两份 Obsidian 方案创建任务;确认
|
||||
模型使用 Roubao 本地配置,Admin 不代理推理。状态 `TODO`,尚未修改生产代码。
|
||||
- 2026-08-01:领取任务,状态改为 `DOING`,开始 Android 实现。
|
||||
- 2026-08-01:完成 Android 实现。规格解析器现在使用四层内祖先 clickable 与
|
||||
selected/checked;自动领取按本机安全配置固定 `AI_ASSISTED` 或 `MANUAL_FIRST`。
|
||||
候选发现增加最多 200 节点、深度 12、文字 160 的脱敏快照和裁剪 PNG,截图前后
|
||||
复核结构 hash;定位响应只接受严格 node ID,网络返回后重新按 path + fingerprint
|
||||
定位并单击。颜色、尺码串行处理,最终视觉证明独立保存且绑定实际规格截图 hash。
|
||||
- 2026-08-01:`CandidateSearchDiagnostics` 追加 `specVlmCalls`/`specVlmAccepted`/
|
||||
`specVlmRejected`/`specVlmVerified` 四个非秘密聚合键;进度 JSON 和本地候选 manifest
|
||||
向后兼容保存 proof。Admin、Go API、数据库和第三轮 fallback 未改动。
|
||||
- 2026-08-01:Debug/Release 各 442 项 JVM 单测、`lintDebug`、`assembleDebug`、
|
||||
`assembleRelease` 全部通过。真机颜色缺失/尺码缺失样本和 Admin 诊断、截图一致性仍待
|
||||
人工验收,因此 status 保持 `DOING`。
|
||||
Reference in New Issue
Block a user