Files
cmautobuy/docs/task/255-admin运行时规格规则ai解析.md
T
2026-08-17 17:21:43 +08:00

112 lines
7.1 KiB
Markdown
Raw Blame History

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.
# 255 Admin:实现采购运行时真机规格规则与 AI 解析
- 类型:需求
- 父级大工单:#96
- 所属 MVP / 版本:#253 采购运行时 AI 规格纠偏闭环
- 状态:已完成,待用户验收
- 日期:2026-08-17
- Gitea 工单:http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/255
## 背景与目标
Client 在真实采购时能够读取 PDD App 当前颜色下的真实可购买尺码,但数据库里的规格可能
来自蝦皮回填,和真机文字不同。原有 `MatchSybSpecWithAI` 只读取数据库候选,不能保证
返回真机可点击的规格。
本任务实现 #254 已冻结的一次性规格解析命令:Admin 核对任务和真机候选快照,优先用
确定性规则寻找唯一等价候选,规则无法唯一判断时再调用受控 AI,并把第一次结论幂等、
可审计地返回 Client。解析不得修改任务、PDD 主数据或真实采购安全门禁。
## 最终方案
- 新增 `POST /api/v1/client/tasks/{task_id}/spec-resolution`。Handler 限制请求体为 64 KiB,
读取原始字节用于请求哈希,并把 Service 错误转换为 Client 契约定义的稳定错误码。
- Service 逐项校验 schema、字段长度、1~100 条连续候选、候选原文和 `color/size`,再按
Client 契约的 UTF-8 长度前缀算法重算候选快照哈希和确定性幂等键。
- 在写候选观察前核对任务存在、类型为采购、版本、PDD 商品、领取时的完整动态规格,
并确认当前 Client 曾领取该任务。任务已取消、重派或结束不作为拒绝条件。
- 规则忽略大小写、空白和安全的展示分隔符,处理常见繁简差异,支持
`kg / 公斤 / 千克 / 斤` 单值和正向区间等价。只有一个等价候选时返回 matched;多个
等价或多个重量区间同时重叠时直接 uncertain,不调用模型。加减号和范围符号保留,
避免把 `M+ / M-` 或不同重量范围折叠成同一规格。
- 抽出 SYB 批量 AI 和运行时 AI 共用的候选白名单核心,统一执行运行快照、严格响应结构、
候选编号、冲突/缺失维度和置信度阈值门禁。运行时模型只得到任务目标和请求内短候选,
不能生成规格、真实 PDD 选项键或点击坐标。
- 使用“短事务写 pending 候选观察 → 事务外规则/AI → 短事务完成一次决策并保存幂等响应”。
同一进程内相同幂等身份串行;数据库唯一键和只允许 `pending` 完成一次的条件更新负责
最终收敛。中断留下的 pending 由相同请求接管,不另建记录。
- `pdd_products.skus_json.spec_source=shopee_backfill` 只追加到非敏感决策原因作为诊断,
不主动触发 AI,也不阻断本来可以由规则唯一确定的候选。沿用 v26 表,不新增字段或迁移。
- 最终决策只写 `purchase_spec_resolutions` 和 `idempotency_keys`,另刷新 Client 活动时间;
不更新任务状态、版本、payload、订单总价上限、结果数据或 PDD `skus_json`。
- 不记录完整模型请求/响应、API Key、原始控件树、截图、订单、收货信息、Cookie 或 Token。
模型错误中的当前密钥原文会在进入审计原因前替换为 `[REDACTED]`。
和建单方案相比,最终实现进一步收紧了两个边界:多个重量候选同时重叠时不交给 AI 猜;
`+/-/范围` 符号不作为普通展示符号删除。由于 #254 的 v26 审计模型没有独立诊断来源列,
`shopee_backfill` 使用决策原因留痕,没有为诊断信息增加数据库迁移。
## 改了哪些
- `admin/handler/api/client_api.go`
- 注册一次性规格解析路由,增加请求大小限制和稳定 HTTP 错误映射。
- `admin/handler/api/client_api_test.go`
- 验证超过 64 KiB 的请求在进入数据库前返回 `INVALID_BODY`。
- `admin/main.go`
- 把既有 AI 密钥存储和端点策略注入 Client API。
- `admin/repository/task.go`
- 任务身份查询补充版本和原始 PDD 动态规格,供运行时核对。
- `admin/service/ai_specmatch_client.go`
- 增加 SYB 与运行时共用的模型候选白名单、阈值和冲突门禁核心。
- `admin/service/ai_specmatch.go`
- 原 SYB AI 编排改用共用核心,保留原有人工映射优先和保存前复查流程。
- `admin/service/purchase_spec_resolution.go`
- 实现请求/哈希校验、任务授权、规则、AI、诊断、并发门禁、短事务和幂等响应。
- `admin/service/purchase_spec_resolution_test.go`
- 覆盖规则边界、任务越权、AI 门禁、密钥脱敏、并发重放、主数据不变和诊断来源。
- `docs/admin/01-requirements.md`
- 记录采购运行时真机规格解析的产品和安全边界。
- `docs/admin/02-architecture.md`
- 记录 Client API、共用 AI 核心和两阶段短事务编排。
## 验收结果
| 验收标准 | 结果 |
|---|---|
| 未领取、非采购、版本、商品或任务规格不一致时拒绝且不写解析记录 | 通过 |
| 完全等价、繁简等价和唯一公斤/斤单值及区间由规则匹配,不调用模型 | 通过 |
| 多个等价、多个区间重叠或模型报告信息缺失时不自动选择 | 通过 |
| AI 只能选择当前候选;伪造编号、低置信度、冲突和错误不能返回 matched | 通过 |
| 同一幂等请求重试和并发得到一致响应、一个最终记录和一次有效模型调用 | 通过(隔离 SQLite 与 race 测试) |
| `shopee_backfill` 只记录诊断来源,不触发或拒绝解析 | 通过 |
| 不修改任务状态、payload、价格上限、结果数据和 PDD 主规格 | 通过 |
| 日志、数据库和响应不保存 API Key、原始 XML、订单或个人数据 | 通过 |
| 原 SYB AI 共用白名单核心后保持人工优先和原门禁 | 通过(全量 Go 回归;MySQL 场景见未验证项) |
| Go 1.23.0 格式、build、test 和 vet | 通过 |
| MySQL 8.4 `_test` 服务编排集成测试 | 未验证 |
## 测试
- 执行的命令:
- `$env:GOTOOLCHAIN='go1.23.0'; gofmt -l .`
- `$env:GOTOOLCHAIN='go1.23.0'; go test ./... -count=1`
- `$env:GOTOOLCHAIN='go1.23.0'; go vet ./...`
- `$env:GOTOOLCHAIN='go1.23.0'; go build ./...`
- `$env:GOTOOLCHAIN='go1.23.0'; go test -race ./service -run 'Test(MatchPurchaseSpec|ParsePurchaseSpec|ResolvePurchaseSpec)' -count=1`
- 结果:Go 1.23.0 全量测试、vet、构建和本任务 race 测试通过。运行时服务编排测试默认在
临时隔离 SQLite 数据库执行;设置 `CMAUTOBUY_MYSQL_TEST=1` 时会自动改用项目的隔离
MySQL 8 `_test` 数据库。
- **没验证到的部分**:本机 MySQL 8.4 服务没有当前可用的授权测试账号,因此未执行
`CMAUTOBUY_MYSQL_TEST=1` 的 #255 服务集成用例;没有用生产库替代测试库。依赖工单 #254
已验证 v26 MySQL 8.4 表、约束、唯一键和 Repository。本工单也未做 Client 真机联调,
Client 的采集和续跑属于后续 #256~#258。
## 遗留问题
- 配置可创建临时数据库的本地 MySQL 8 `_test` 账号后,应补跑:
`$env:CMAUTOBUY_MYSQL_TEST='1'; go test ./service -run 'TestResolvePurchaseSpec' -count=1 -v`。
## 相关提交
- `de36cfd` 实现采购运行时规格规则与 AI 解析