148 lines
8.2 KiB
Markdown
148 lines
8.2 KiB
Markdown
---
|
||
id: T-103
|
||
title: 接入 VLM 需求提取
|
||
phase: 1
|
||
deps:
|
||
- T-004
|
||
- T-101
|
||
status: DONE
|
||
created: 2026-07-25
|
||
context_ref: c25d63c
|
||
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/data/SettingsManager.kt
|
||
- android-buyer/app/src/main/java/com/roubao/autopilot/task/**
|
||
- 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/vlm/**
|
||
- docs/00-ai-start-here.md
|
||
- docs/02-requirements.md
|
||
- docs/03-tech-stack.md
|
||
- docs/04-architecture.md
|
||
- docs/05-coding-rules.md
|
||
- docs/api.md
|
||
- docs/current-state.md
|
||
- docs/tasks/T-103.md
|
||
- progress.md
|
||
---
|
||
|
||
## 问题 / 背景
|
||
|
||
T-004 已把本机私有蝦皮文本和 JPEG 严格导入为 `ProbeTask`,T-101 已证明固定搜索词
|
||
可以进入拼多多结果页,但业务工作流尚不能从标题、SKU、数量和参考图得到受约束的
|
||
搜索需求。T-103 只验证结构化需求提取,不让模型控制页面、不评估候选,也不提交订单。
|
||
|
||
## 关联需求与交互
|
||
|
||
- 功能:F-004 结构化需求提取、F-007 安全失败。
|
||
- 用户故事:US-004、US-006。
|
||
- 交互:Android“探针”页提供独立的需求提取入口,展示脱敏状态、SKU、数量、置信度、
|
||
警告和是否需要人工复核。
|
||
- 架构:`ProbeTask` -> 隐私映射 -> `RequirementExtractor` -> provider-neutral gateway
|
||
-> 严格 schema -> 确定性硬约束复核。
|
||
|
||
## 方案
|
||
|
||
1. 建立与供应商无关的需求提取输入、输出、错误码和 JSON schema。
|
||
2. VLM 请求只保留标题、SKU 和参考图;数量留在本地,订单号、店铺名及本机路径不
|
||
进入 prompt。
|
||
3. SKU、数量和预算只从原始任务产生;模型响应无权覆盖。当前 `ProbeTask` 没有预算,
|
||
输出固定为未知并产生警告。
|
||
4. 严格校验图片大小、媒体类型和 SHA-256;严格解析模型 JSON,拒绝额外字段、坐标、
|
||
动作授权和格式不明输出。
|
||
5. 置信度低于固定探针阈值或输出无效时进入人工复核,不扩大搜索或触发拼多多动作。
|
||
6. 普通测试使用 Fake gateway;真实调用只通过用户已配置且声明支持需求提取的
|
||
OpenAI 兼容供应商进行,每次用户操作最多发出一次模型调用。
|
||
|
||
## 验收要点
|
||
|
||
- [x] 私有样本标题、SKU、数量和 JPEG 可形成不含订单号、店铺名的 VLM 请求。
|
||
- [x] 有效模型响应可解析为版本化 schema。
|
||
- [x] SKU 和数量与原始 `ProbeTask` 完全一致,模型不能改写。
|
||
- [x] 未提供预算时不会由模型猜测,并产生结构化警告。
|
||
- [x] 低置信度、冲突、无效 JSON、额外动作字段和图片校验失败均安全转人工或明确失败。
|
||
- [x] API Key、原图 Base64、订单号、店铺名和模型原始响应不进入普通日志。
|
||
- [x] Fake gateway 测试覆盖成功、隐私、硬约束、低置信度和错误路径。
|
||
- [x] `lintDebug test assembleDebug` 通过,默认 APK 不含私有 fixture。
|
||
- [x] 设备无真实测试凭证;已记录外部 blocker,并用一次性本机 mock 验证真实 Android
|
||
请求链路,不把 mock 结果当成模型效果证据。
|
||
|
||
## 边界
|
||
|
||
- 不让 VLM 输出或执行坐标、点击、状态迁移、下单或支付动作。
|
||
- 不把候选截图交给模型;候选评估属于 T-104。
|
||
- 不引入新的供应商 SDK;沿用现有 OpenAI 兼容客户端。
|
||
- 不提交私有订单、图片、生成 fixture、API Key 或模型原始响应。
|
||
- 不把技术探针的端上密钥路径当作正式架构;正式密钥仍由后端保管。
|
||
|
||
## 执行记录
|
||
|
||
### 2026-07-25:任务开始
|
||
|
||
- 基于 T-102 提交 `c25d63c` 开始。
|
||
- 已确认现有 `VLMClient` 可复用 OpenAI 兼容多模态调用,但业务层缺少 schema、隐私
|
||
映射、确定性复核和低置信度处理。
|
||
- 当前外部 blocker 仍是供应商、模型、测试凭证、成本上限和数据留存未确认;先完成
|
||
provider-neutral 契约、Fake 测试和可配置真实探针,不使用默认付费调用。
|
||
|
||
### 2026-07-25:实现
|
||
|
||
- 新增 `RequirementExtractionInput/Result`、版本化最终 JSON、严格模型响应 parser 和
|
||
`RequirementExtractor`。模型只能返回搜索词、类目、带来源属性、置信度和警告;
|
||
额外字段、动作/坐标语义、格式或边界错误统一转人工。
|
||
- 隐私映射只把标题、SKU 和参考图交给 gateway。订单号、店铺名、相对路径和数量不
|
||
进入 prompt;SKU、数量、空预算和图片 SHA-256 由确定性代码组装。
|
||
- 固定探针阈值为 `0.75`;低于阈值以及图片歧义、标题/图片冲突或 SKU 不清晰均进入
|
||
人工复核,不触发拼多多动作。
|
||
- 新增 `predictStructuredOnce`,每次按钮操作最多调用 provider 一次;禁用连接自动
|
||
重试和 HTTP/HTTPS 重定向,协程取消会取消底层 call,调用上限 75 秒。HTTP 错误不
|
||
读取响应正文,成功响应上限 64 KiB。
|
||
- 远程端点只允许 HTTPS;无 API Key 的本机回环 HTTP 可用于受控 mock。标题和 SKU
|
||
分别限制为 2048、512 个 UTF-8 字节。JPEG 在调用前复核媒体类型、20 MiB 上限、
|
||
魔数、大小和 SHA-256,按声明长度精确读取,解码后最长边限制为 2048 px。
|
||
- `ApiProvider` 增加 `supportsRequirementExtraction`;GUI-Owl 和 MAI-UI 明确禁用。
|
||
加密凭证存储不可用时需求探针 fail closed。
|
||
- “采购验证探针”增加独立 VLM 入口和 IDLE/RUNNING/READY/MANUAL_REVIEW/FAILED/
|
||
STOPPED 状态;展示 schema 摘要,但不展示订单号、店铺名或图片路径。
|
||
|
||
### 2026-07-25:自动化验证
|
||
|
||
- `$env:ANDROID_HOME="$env:LOCALAPPDATA\Android\Sdk";`
|
||
`$env:ANDROID_SDK_ROOT=$env:ANDROID_HOME;`
|
||
`.\gradlew.bat lintDebug test assembleDebug --no-daemon` 成功。
|
||
- App Debug/Release、task contract 和导入器共 20 份报告、122 次测试,0 failure、
|
||
0 error、0 skipped;默认 Debug APK 中 `assets/probe-fixtures/` 条目数为 0。
|
||
- Fake gateway 覆盖有效 schema、订单/店铺/路径/数量不进入 prompt、单次调用、
|
||
原始 SKU/数量保持、空预算、0.75 阈值边界、冲突转人工、无效/动作字段、JPEG
|
||
魔数/哈希失败、输入长度、provider 失败、调用取消和安全端点策略。
|
||
- 静态检查确认需求链路没有记录 prompt、图片字节或原始响应,也没有可执行动作输出。
|
||
|
||
### 2026-07-25:真机集成 smoke
|
||
|
||
- OnePlus PKG110、Android 16/API 36、肉包 `1.4.2 (7)` 上显式注入 T-004 私有
|
||
fixture;设备未配置真实 API Key,直接点击时稳定显示“未配置模型”且不发网络请求。
|
||
- 为验证网络链路,临时选择自定义 provider,通过 `adb reverse` 连接一次性本机
|
||
OpenAI 兼容 mock。App 只发出 1 次 `/v1/chat/completions` POST,包含 1 张 JPEG
|
||
data URL;布尔审计确认 prompt 不含订单/店铺字段和数量键。
|
||
- mock 返回的严格 schema 以 `0.82` 置信度进入 READY;UI 显示类目、属性、原始
|
||
SKU/数量、空预算和 `MAX_BUDGET_NOT_PROVIDED`。截图/XML 和 mock 布尔审计位于
|
||
被忽略的 `.local/`,请求正文和图片未落盘。
|
||
- 最新 APK 再次 smoke 后,将 provider 恢复为无密钥的阿里云配置并重新触发;UI
|
||
显示“未配置模型”,此前 READY 的搜索词和类目不再存在,证明失败路径会清空旧结果。
|
||
- smoke 后已移除 `adb reverse`、停止本机 listener 并恢复设备原 API provider。
|
||
logcat 未写入订单号、店铺名、标题、SKU、prompt、Base64 或原始响应。
|
||
|
||
### 未验证范围
|
||
|
||
- 没有可用的真实 VLM 测试凭证,因此未验证任何供应商的真实提取质量、时延和费用。
|
||
- 真实供应商、模型、成本上限、数据留存地区和图片隐私规则仍是外部 blocker;启用
|
||
前必须由用户显式配置并确认,不得把本机 mock 结果计入 20 条业务试验。
|
||
|
||
## 后续
|
||
|
||
- T-104 读取 T-102 的受控候选证据和本任务的 `RequirementExtraction`,输出匹配项、
|
||
缺失项和拒绝原因,并停在人工确认点。
|
||
- T-104 继续使用 Fake gateway 和本机 mock 验证集成;没有真实凭证时不能宣称候选
|
||
匹配质量已验证。
|