1
T-272
ila edited this page 2026-08-07 16:37:11 +08:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

同步来源: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:

{
  "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 继续使用原确定性选择,待真机样本达到验收 后另行复用,避免直接扩大不可逆动作前的模型权限。

验收要点

  • 祖先可点、祖先 selected/checked 的颜色/尺码节点能由规则路径正确选择,不调用VLM。
  • 规则唯一成功时模型调用为0;Absent/Ambiguous/click failed/post-click unknown 才触发。
  • 节点 JSON 受限、脱敏、可复现,和截图绑定同一 snapshot hash。
  • 模型只能选择 snapshot 中唯一 node ID;页面变化、旧节点、坐标和多步输出不能点击。
  • 颜色、尺码串行单击,最终同快照未同时确认时不保存为 EXACT_MATCH 候选。
  • disabled、完整分组缺失、安全阻塞和 MANUAL_FIRST 不能被 VLM 改判。
  • 每候选不超过3次调用,相同 snapshot/use case 不重复,网络失败不形成点击循环。
  • API Key、endpoint、完整节点/响应、标题/SKU和截图 Base64不进入日志或outbox。
  • 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。