来源:2026-09-16 排查图搜与规格匹配失败时,两次都因为缺少记录而无法定位,只能靠手工重放接口和按时长反推。
BatchSpecMatch
if _, err := purchase.NewService(service.DB).BatchSpecMatch(ctx, ...); err != nil { log.Printf("image search spec match failed for syb products %v: %v", ...) }
每条明细的 skipped / pending / failed 原因都在 response.Items 里,这里用 _ 丢掉;err 只在整体出错时非空。
response.Items
_
err
实测后果:2026-09-16 图搜后 23 条明细全部匹配失败(AI 服务 503),日志里一个字都没有。真实原因是手工重放接口才拿到的:{"status":"failed","reason":"AI 匹配服务暂时不可用,请稍后重试"}。后来换 AI 服务商重跑,12 条 failed、7 条 skipped,同样无任何记录。
{"status":"failed","reason":"AI 匹配服务暂时不可用,请稍后重试"}
AgentForegroundService.kt:423 在上报前把错误码换成给采购员看的文案:
AgentForegroundService.kt:423
"IMAGE_SEARCH_ENTRY_NOT_FOUND" -> "打不开拍照搜索入口,请检查 PDD App 版本或手动确认后重试。"
而该错误码在 Agent 内部有两个来源,含义完全不同:
"找不到唯一可点的拍照搜索入口"
"归位到图搜入口并选中参考图失败,请人工检查"
两者在库里长得一模一样。排查任务 156 时只能靠「失败耗时 15 秒 ≈ 50 × 300ms」反推是后者,没有直接证据。
autoConfirmedCount
pendingCount
failedCount
skippedCount
[必须] 两处都不得记录凭据、账号、订单或个人数据;只记录错误码、计数与规格相关的结构化原因。
[必须]
IMAGE_SEARCH_ENTRY_NOT_FOUND
go test ./app/goauto/task/...;Android 单元测试;本地构造一次全失败的匹配并检查日志。
go test ./app/goauto/task/...
错误码语义与可见文案均不变;如 docs/08-agent-api-contract.md 需补充诊断字段,按实际改动同步。
docs/08-agent-api-contract.md
提交 b2b8c0d。
b2b8c0d
服务端 matchSpecsAfterImageSearch:BatchSpecMatch 的返回值此前用 _ 丢弃,改为记录 confirmed/pending/failed/skipped 四个计数,并附前 3 条阻塞原因(batchSpecMatchDigest)。新增的 MatchArchiveSpecs 同样记录计数。
matchSpecsAfterImageSearch
confirmed/pending/failed/skipped
batchSpecMatchDigest
MatchArchiveSpecs
Agent AgentForegroundService:新增 imageSearchFailureMessage(code, internal),在用户文案后括注内部原因,写法与既有的候选点击失败一致。IMAGE_SEARCH_ENTRY_NOT_FOUND 的两个来源(「找不到唯一可点的拍照搜索入口」/「归位到图搜入口并选中参考图失败」)不再被抹平。
AgentForegroundService
imageSearchFailureMessage(code, internal)
[必须] 两处只记录错误码、计数与规格层面的原因,不含凭据、账号、订单和个人数据。采购员可见文案的前半段与现在完全一致。
服务端全部受影响套件通过;Android 全量单测 372 通过、0 失败。
未构造一次全失败的匹配来实地检查日志输出。
待验收。
No dependencies set.
The note is not visible to the blocked user.
问题一:
BatchSpecMatch的逐条结果被丢弃每条明细的 skipped / pending / failed 原因都在
response.Items里,这里用_丢掉;err只在整体出错时非空。实测后果:2026-09-16 图搜后 23 条明细全部匹配失败(AI 服务 503),日志里一个字都没有。真实原因是手工重放接口才拿到的:
{"status":"failed","reason":"AI 匹配服务暂时不可用,请稍后重试"}。后来换 AI 服务商重跑,12 条 failed、7 条 skipped,同样无任何记录。问题二:Agent 的原始失败说明被统一文案覆盖
AgentForegroundService.kt:423在上报前把错误码换成给采购员看的文案:而该错误码在 Agent 内部有两个来源,含义完全不同:
"找不到唯一可点的拍照搜索入口"(立即返回)"归位到图搜入口并选中参考图失败,请人工检查"(预算耗尽)两者在库里长得一模一样。排查任务 156 时只能靠「失败耗时 15 秒 ≈ 50 × 300ms」反推是后者,没有直接证据。
方案
autoConfirmedCount/pendingCount/failedCount/skippedCount记入日志,并带上若干条具体原因,便于定位是 AI 不可用、规格对不上还是已有映射。[必须]两处都不得记录凭据、账号、订单或个人数据;只记录错误码、计数与规格相关的结构化原因。非目标
验收
IMAGE_SEARCH_ENTRY_NOT_FOUND的两个来源在记录中可区分。验证
go test ./app/goauto/task/...;Android 单元测试;本地构造一次全失败的匹配并检查日志。文档影响
错误码语义与可见文案均不变;如
docs/08-agent-api-contract.md需补充诊断字段,按实际改动同步。实施
提交
b2b8c0d。服务端
matchSpecsAfterImageSearch:BatchSpecMatch的返回值此前用_丢弃,改为记录confirmed/pending/failed/skipped四个计数,并附前 3 条阻塞原因(batchSpecMatchDigest)。新增的MatchArchiveSpecs同样记录计数。Agent
AgentForegroundService:新增imageSearchFailureMessage(code, internal),在用户文案后括注内部原因,写法与既有的候选点击失败一致。IMAGE_SEARCH_ENTRY_NOT_FOUND的两个来源(「找不到唯一可点的拍照搜索入口」/「归位到图搜入口并选中参考图失败」)不再被抹平。[必须]两处只记录错误码、计数与规格层面的原因,不含凭据、账号、订单和个人数据。采购员可见文案的前半段与现在完全一致。已验证
服务端全部受影响套件通过;Android 全量单测 372 通过、0 失败。
未验证
未构造一次全失败的匹配来实地检查日志输出。
状态
待验收。