2026-07-28 11:25:32 +08:00
|
|
|
|
---
|
|
|
|
|
|
id: T-208
|
|
|
|
|
|
title: 候选决策数据与结构化人工理由闭环
|
|
|
|
|
|
phase: 2
|
|
|
|
|
|
deps:
|
|
|
|
|
|
- T-207
|
|
|
|
|
|
- T-213
|
2026-07-28 11:57:25 +08:00
|
|
|
|
status: DONE
|
2026-07-28 11:25:32 +08:00
|
|
|
|
created: 2026-07-28
|
|
|
|
|
|
context_ref: 4c3b962
|
|
|
|
|
|
work_branch: null
|
|
|
|
|
|
write_paths:
|
|
|
|
|
|
- docs/tasks/T-208.md
|
|
|
|
|
|
- docs/00-ai-start-here.md
|
|
|
|
|
|
- docs/02-requirements.md
|
|
|
|
|
|
- docs/04-architecture.md
|
|
|
|
|
|
- docs/05-coding-rules.md
|
|
|
|
|
|
- docs/06-tasks.md
|
|
|
|
|
|
- docs/08-interaction-checklist.md
|
|
|
|
|
|
- docs/api.md
|
|
|
|
|
|
- docs/current-state.md
|
|
|
|
|
|
- backend-api/migrations/**
|
|
|
|
|
|
- backend-api/internal/domain/**
|
|
|
|
|
|
- backend-api/internal/usecase/**
|
|
|
|
|
|
- backend-api/internal/repository/sqlite/**
|
|
|
|
|
|
- backend-api/internal/transport/httpapi/**
|
|
|
|
|
|
- backend-api/internal/transport/webui/**
|
|
|
|
|
|
- android-buyer/app/build.gradle.kts
|
|
|
|
|
|
- android-buyer/app/src/main/java/com/roubao/autopilot/MainActivity.kt
|
|
|
|
|
|
- android-buyer/app/src/main/java/com/roubao/autopilot/procurement/**
|
|
|
|
|
|
- android-buyer/app/src/main/java/com/roubao/autopilot/ui/screens/SearchProbeScreen.kt
|
|
|
|
|
|
- android-buyer/app/src/test/java/com/roubao/autopilot/procurement/**
|
|
|
|
|
|
- android-buyer/app/src/test/java/com/roubao/autopilot/ui/**
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 问题 / 背景
|
|
|
|
|
|
|
|
|
|
|
|
T-207 已能回传候选批次、模型评估、本地推荐和一段 `operator_reason`,但后端仍把候选
|
|
|
|
|
|
主体保存在不可查询 JSON 中,人工说明也不是可用于离线评估的标签。AI 模式还会在
|
|
|
|
|
|
回传前过滤模型拒绝项,导致无法还原同一次图片搜索实际曝光的候选集合,也无法区分
|
|
|
|
|
|
召回、模型、推荐策略和人工判断各自的问题。
|
|
|
|
|
|
|
|
|
|
|
|
本任务在 20 条真实采购试验前建立可信的数据闭环。它不建设训练管线、外部抓取或
|
|
|
|
|
|
报表,也不改变候选阶段 `order_submitted=false` 的安全边界。
|
|
|
|
|
|
|
|
|
|
|
|
## 关联需求与交互
|
|
|
|
|
|
|
|
|
|
|
|
- 功能:F-008。
|
|
|
|
|
|
- 用户故事:US-008。
|
|
|
|
|
|
- 交互:IX-009。
|
|
|
|
|
|
- 依赖:沿用 T-207 的 execution、受控 evidence、加密 outbox 和结果终态;沿用
|
|
|
|
|
|
T-213 的规格选择摘要与组合价格证据。
|
|
|
|
|
|
|
|
|
|
|
|
## 冻结合约
|
|
|
|
|
|
|
|
|
|
|
|
### 候选数据层
|
|
|
|
|
|
|
|
|
|
|
|
1. 每个 execution 第一版只允许一个候选 search run。`execution_id` 同时作为 run
|
|
|
|
|
|
identity,保存任务内容 hash、精确搜索审计值、App/Android/拼多多版本、开始/接收
|
|
|
|
|
|
时间和采集完整性。
|
|
|
|
|
|
2. `POST /api/v1/tasks/{task_id}/candidates` 继续作为 App 的批量入口,但候选数组改为
|
|
|
|
|
|
实际检查的原始连续 ordinal `0..5` 项,不再只上传模型通过项。每项 observation
|
|
|
|
|
|
保存可见标题、规格、价格、受限外链和已鉴权 evidence;后端绝不请求外链。
|
|
|
|
|
|
3. AI 模式逐 observation 保存 model evaluation。确定性 recommendation 可指向任一
|
|
|
|
|
|
原始 ordinal,但目标必须满足本地颜色/尺码硬约束和当前阈值;不得通过重排改写
|
|
|
|
|
|
observation ordinal。MANUAL_FIRST 没有 model run/evaluation/recommendation。
|
|
|
|
|
|
4. 后端在保存候选批次的同一事务内写入
|
|
|
|
|
|
`candidate_search_runs`、`candidate_observations`、`model_runs`、
|
|
|
|
|
|
`candidate_evaluations` 和 `candidate_recommendations`;旧 JSON 只作为兼容审计
|
|
|
|
|
|
副本,不能继续作为新查询的唯一来源。
|
|
|
|
|
|
|
|
|
|
|
|
### 人工 review API
|
|
|
|
|
|
|
|
|
|
|
|
新增设备鉴权、claim-scoped、幂等的
|
|
|
|
|
|
`POST /api/v1/tasks/{task_id}/human-reviews`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"execution_id": "uuid",
|
|
|
|
|
|
"claim_generation": 1,
|
|
|
|
|
|
"task_content_sha256": "64-char-lowercase-hex",
|
|
|
|
|
|
"reason_schema_version": 1,
|
|
|
|
|
|
"outcome": "CANDIDATE_ACCEPTED",
|
|
|
|
|
|
"selected_candidate_ordinal": 2,
|
|
|
|
|
|
"primary_reason_code": "SELECTED_BEST_MATCH",
|
|
|
|
|
|
"note": "",
|
|
|
|
|
|
"supersedes_review_id": null,
|
|
|
|
|
|
"items": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"candidate_ordinal": 1,
|
|
|
|
|
|
"label": "REJECT",
|
|
|
|
|
|
"primary_reason_code": "NOT_BEST_MATCH",
|
|
|
|
|
|
"reason_codes": ["NOT_BEST_MATCH"],
|
|
|
|
|
|
"note": ""
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"candidate_ordinal": 2,
|
|
|
|
|
|
"label": "ACCEPT",
|
|
|
|
|
|
"primary_reason_code": "SKU_MATCH",
|
|
|
|
|
|
"reason_codes": ["SKU_MATCH", "IMAGE_MATCH"],
|
|
|
|
|
|
"note": ""
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- review 主理由:`SELECTED_BEST_MATCH`、`NO_ACCEPTABLE_CANDIDATE`、
|
|
|
|
|
|
`INSUFFICIENT_EVIDENCE`、`OTHER`。
|
|
|
|
|
|
- ACCEPT 理由:`SKU_MATCH`、`IMAGE_MATCH`、`PRICE_ACCEPTABLE`、
|
|
|
|
|
|
`EVIDENCE_SUFFICIENT`、`OTHER`。
|
|
|
|
|
|
- REJECT 理由:`SKU_MISMATCH`、`IMAGE_MISMATCH`、`PRICE_TOO_HIGH`、
|
|
|
|
|
|
`OUT_OF_STOCK`、`EVIDENCE_INSUFFICIENT`、`NOT_BEST_MATCH`、`OTHER`。
|
|
|
|
|
|
- `OTHER` 的对应备注必须为 4-200 个字符;其他备注可空,非空时同样最多 200 个字符。
|
|
|
|
|
|
- 无预算任务拒绝 `PRICE_ACCEPTABLE` 和 `PRICE_TOO_HIGH`。
|
|
|
|
|
|
- 非空候选批次的 review 必须按 ordinal 恰好覆盖每个 observation。接受时恰好一个
|
|
|
|
|
|
ACCEPT 且等于 `selected_candidate_ordinal`,其余全部 REJECT;拒绝、无匹配或转
|
|
|
|
|
|
人工时全部为 REJECT。零候选只允许 `NO_MATCH/MANUAL_REQUIRED` 和空 items。
|
|
|
|
|
|
- 修订必须引用同一 execution 当前最新 review;服务端追加新版本并建立
|
|
|
|
|
|
`supersedes_review_id`,不得更新或删除旧版本。
|
|
|
|
|
|
|
|
|
|
|
|
### App 与管理端
|
|
|
|
|
|
|
|
|
|
|
|
1. App 人工确认不再使用自由文本作为唯一输入。人员必须显式选择候选、接受主理由和
|
|
|
|
|
|
其余候选拒绝主理由,或选择全部拒绝理由;模型理由只读且不会预选人工理由。
|
|
|
|
|
|
2. 第一版 UI 允许人员明确把同一拒绝理由批量应用到所有未选候选,但提交 payload
|
|
|
|
|
|
仍展开成逐 observation item。
|
|
|
|
|
|
3. App 先把 HUMAN_REVIEW 放入加密 outbox,再加入兼容的 COMPLETE;网络失败保留
|
|
|
|
|
|
同一 idempotency key 和草稿顺序。
|
|
|
|
|
|
4. Admin 任务详情按 observation、model prediction、deterministic recommendation、
|
|
|
|
|
|
human review 四个独立区块显示,修订历史按版本可见;受控截图继续走鉴权接口。
|
|
|
|
|
|
|
|
|
|
|
|
## 验收要点
|
|
|
|
|
|
|
2026-07-28 11:57:25 +08:00
|
|
|
|
- [x] migration `up/down/up` 可重复;有 review 数据时破坏性 down 明确失败。
|
|
|
|
|
|
- [x] 最多 5 个原始曝光 observation 按原 ordinal 可查询,模型拒绝项不会丢失。
|
|
|
|
|
|
- [x] observation、model evaluation、recommendation 和 human label 分表且引用一致。
|
|
|
|
|
|
- [x] human review API 校验理由 allowlist、标签兼容、预算适用性、全候选覆盖、唯一
|
2026-07-28 11:25:32 +08:00
|
|
|
|
接受项、幂等重放和追加式 supersedes。
|
2026-07-28 11:57:25 +08:00
|
|
|
|
- [x] App 支持选择推荐项、改选、全部拒绝和零候选;每种路径都产生结构化逐候选理由。
|
|
|
|
|
|
- [x] 模型理由不会预填人工理由,旧 `operator_reason` 只保留兼容审计含义。
|
|
|
|
|
|
- [x] Admin/API 能读取当前 review 和历史版本,外链不会触发任何服务端网络请求。
|
|
|
|
|
|
- [x] Android/Go 单元测试、race、migration、Debug/Release 构建和根验证通过。
|
2026-07-28 11:25:32 +08:00
|
|
|
|
|
|
|
|
|
|
## 边界
|
|
|
|
|
|
|
|
|
|
|
|
- 不实现模型训练、指标报表、数据导出、自动标注或跨任务聚合分析。
|
|
|
|
|
|
- 不抓取商品页、图片 URL 或平台全量结果,不宣称为全平台 Top 5。
|
|
|
|
|
|
- 不在本任务创建订单、加入购物车或支付;Admin 下单授权属于后续独立任务。
|
|
|
|
|
|
- 不把 VLM Key、Authorization、完整 endpoint、供应商原始响应或模型理由写成人工
|
|
|
|
|
|
标签。
|
|
|
|
|
|
|
|
|
|
|
|
## 执行记录
|
|
|
|
|
|
|
|
|
|
|
|
- 2026-07-28:T-213 真机验收提交 `4c3b962` 后领取。审计确认现有
|
|
|
|
|
|
`execution_candidate_batches`/`execution_outcomes` 只能提供 JSON 审计副本和自由
|
|
|
|
|
|
文本说明,AI 模式还会过滤拒绝候选;因此冻结以上归一化数据层和结构化 review
|
|
|
|
|
|
合约后再开始实现。
|
2026-07-28 11:57:25 +08:00
|
|
|
|
- 2026-07-28:新增 v6 migration 和规范化仓储,在候选批次同一事务内保存 search
|
|
|
|
|
|
run、全部原始 observation、逐项模型评估和引用原 ordinal 的 recommendation;
|
|
|
|
|
|
兼容 JSON 保留,但不再是唯一查询来源。空库 migration `up/down/up` 通过,存在
|
|
|
|
|
|
review 时 down guard 经 HTTP 集成测试确认失败且不破坏数据。
|
|
|
|
|
|
- 2026-07-28:新增设备鉴权、claim-scoped、幂等的
|
|
|
|
|
|
`POST /api/v1/tasks/{id}/human-reviews`,验证完整覆盖、唯一接受项、reason allowlist、
|
|
|
|
|
|
无预算价格理由、OTHER 备注、重放和 supersedes;集成测试确认同一 execution 的
|
|
|
|
|
|
version 1/2 均可从 Admin/API 读取。
|
|
|
|
|
|
- 2026-07-28:Android 改为上传全部实际曝光候选并保持原 ordinal;推荐只引用合格
|
|
|
|
|
|
observation。候选确认页使用候选和理由单选控件,未选项的批量拒绝理由显式展开为
|
|
|
|
|
|
逐候选 item;加密 outbox 严格按 CANDIDATES、HUMAN_REVIEW、COMPLETE 顺序重放。
|
|
|
|
|
|
App 升级为 `1.4.11 (16)`。
|
|
|
|
|
|
- 2026-07-28:`.\init.ps1`、Android Debug/Release 单元测试与构建、
|
|
|
|
|
|
`go test -race ./...`、Go vet/format/build 全部通过。Android App Debug 和 Release
|
|
|
|
|
|
各 26 个 suite/153 个测试、0 失败;共享模块另有 12 个测试。Debug APK 已通过
|
|
|
|
|
|
SDK ADB 覆盖安装并启动于 PKG110,设备报告 `1.4.11 (16)`,肉包采购无障碍仍
|
|
|
|
|
|
已启用。安装后截图确认任务首屏无重叠或裁切。
|