enabled: false 连 shadow 都没跑过;combo_health 自愈器决策全对,昨天上午被手动关闭(推测因通知轰炸);canonical 预过滤接口存在但只有 2 家实现,其余 fail-open。同一组合下不同供应商接码率差 2–8 倍,而三层选择逻辑(下单选家 / fallback 排序 / 用户侧推荐)全部按「最便宜/量最大」排序,成功率几乎零权重。建议主线不是重写,而是「接线 + 统一质量分口径」。
apple@TR:7 天 3,966 单、1 单成功(0.0%),但仅 ~11–28 个独立用户——是 API 自动化用户在反复打一个结构性死路(土耳其 Apple Premium 号无 API 供给,8 家聚合器全部虚标库存)。每单打满 fallback 链,贡献了 NO_NUMBERS 空调用 Top 8 的全部位置(约 11,100 次上游无效调用/周)。
combo_health 于 7-31 auto-hide 后,8-1 已止血至 60 单。但 8-2 上午 combo_health.enabled 被手动关闭(commit dcd875f1,22 分钟前刚把 supplier_health 告警从 5min 降到 1h——推测动因是通知轰炸)。已 hide 的 15 个三元组仍然生效(消费端过滤不看开关),但新出现的死路不会再被自动摘除:telegram@SG(0%,132 allocs)、telegram@KR、openai@TW(全 0%)都还裸奔着。
错误分布佐证:失败 attempt 中 NO_NUMBERS 占 76.2%(26,263 次/周)、INVALID_COUNTRY 占 18.3%(6,295 次/周,99.9% 落在 canonical_fallback 路径——明知不支持还派单)。
用户从下单到分配,会经过三次「选谁」的决策,三次全是按最便宜/量最大排序:
| 决策层 | 排序依据 | 代码位置 |
|---|---|---|
| 1. 下单选家(第一枪) | ORDER BY sell_price ASC, source_cost ASC,纯最便宜 | catalog/repository.go:1832(querySellableOffer) |
| 2. fallback 链排序 | ORDER BY priority DESC —— 而 suppliers 表 priority 全 0(除自营池),等于无序;DefaultStrategy 是空实现 passthrough | supplier/repository.go:136、supplier/service.go:479 |
| 3. 用户侧国家推荐 | popularityScore = 量项(log 订单数 ×20/×10,无上限)+ 成功率项(×26,封顶 26 分)。实测便宜死路国 242 分 vs 优质国 159 分,量项占 79%、成功率占 0.5% | catalog/query.go:550-570 |
同组合跨供应商的质量方差证明了这里埋着多少钱(14 天,allocs≥30):
| 组合 | 最好供应商 | 最差供应商 | 量给了谁 |
|---|---|---|---|
| telegram@CA | lubansms 12.9% | durianrcs 6.6% | durianrcs 拿 485 allocs,lubansms 只有 85 |
| telegram@HK | hero-sms 22.0% | grizzly 8.0% | grizzly 拿 251,hero 只有 127 |
| openai@GB | 31.0% | 9.4% | 同模式:价格优先 → 量喂给便宜且差的 |
| telegram@TR | 81.5% | 9.6% | |
| paypal@PL | 66.7% | 11.1% |
粗算 telegram@CA/HK 两个组合:若把量路由到当前最优家,收码量可提升 +70~85%,而这只是 25 个可比组合中的 2 个。
「Smart Quiet」智能路由方案的全部零件都已存在且在运转,唯独最后一根线没接:
| 组件 | 状态 | 证据 |
|---|---|---|
| 打分器(成功率 0.6 / 成本 0.3 / 延迟 0.1 + 贝叶斯先验平滑冷启动) | 代码完成 | supplier/scorer.go:210-284 |
| 数据管道 performance_aggregator(1h/24h/7d 三窗口) | 生产运行中 | supplier_performance_snapshots 表 213 万行,4-19 起持续产出至今 |
| 路由挂载点 applyScorer + 决策日志 | 已接线 | routing.go:447-486 |
| 开关 | enabled=false + shadow_mode=true 双关 | config.production.yaml:653-654;原计划 Day 8 开 shadow、Day 15 放量,现已停滞 3.5 个月 |
两个上线前必须修的暗坑(agent 梳理发现):
routing.go:471 用 zap.DebugLevel gate,而 prod log_level=info —— 即使开了 shadow 也看不到任何决策日志,观测期形同虚设。routing.go:400-408 故意置 0 防污染):scorer 的成本 min-max 归一化会被 0 值扭曲,参与 rank 前要改用 sellable 价或单独处理。架构约束(重要):几乎所有订单下单时就锁定了主家(fixedFirst),scorer 的可重排区间 rankStart..rankEnd 不含主家、有主家时也不含跨家 fallback(routing.go:183/226/423)。即光开 scorer 改变不了「第一枪打给最便宜家」——第一枪由 catalog 的 ORDER BY sell_price ASC 决定。真正的杠杆是两个独立的接线点:①第一枪质量化(catalog 选代表引入质量分),②放开/重排 fallback 链。
| execution_path | attempts(7d) | 取号率 | 收码率 |
|---|---|---|---|
| raw_ref(带精确 refs 直下) | 24,329 | 44.0% | 26.4% |
| canonical_fallback(让供应商自己翻译) | 23,701 | 12.1% | 9.5% |
canonical 路径占了一半 attempts。它的问题分两层:
ListEnabled() 全量盲发,不看目标供应商目录里有没有这个国家。预过滤接口 CanonicalCountrySupport 已存在(interface.go:277-297)但只有 majorphones + isptelecom 实现,其余全部 fail-open(routing.go:939-955)。pickCheapestCombo 在自己目录里也按最低价挑 —— 差上加差。fallback 深度数据佐证空转:37% 订单走了 3+ 家供应商,其中 77.5% 最终仍拿不到号——链条在死路组合上反复空转。
index===0 无条件戴「推荐」徽章(dashboard-recommendations.ts:253)→ 5% 成功率组合获官方背书 → 更多订单 → 排名更高。ORDER BY sell_price ASC(catalog/repository.go:3458-3463)——把刚踩坑的用户推向另一批最便宜(=大概率最差)的国家。DISTINCT ON (country, service, tier) ... ORDER BY sell_price ASC(repository.go:1969)——每个组合只展示最便宜那家的价格与库存;combo_health 即使 hide 掉一家,DISTINCT ON 自动选中下一家最便宜的。safeRate 无样本返 0(query.go:524-529),与真 0% 不可区分——新组合永无出头之日。对比之下后端 scorer 有贝叶斯先验处理同一问题,两套口径没有共享。compareNullableNumbersAsc 参数交换后 null 排最前(dashboard-recommendations.ts:325/338、country-step.tsx:450/464),成功率未知的组合反而排在已知高成功率之前。这个系统不缺算法代码,缺的是「接线」和「口径统一」。当前存在三套互不相通的质量口径:
优雅的终态是一份「组合质量分」:per-(supplier, service, country) 的贝叶斯后验收码率(快照表已有全部原料),三个消费端共享同一数据、只是消费方式不同——路由拿它排序、止血器拿它设阈值、用户侧排序拿它做乘性因子、换国推荐拿它排序。落地不需要新表、不需要新 worker,逐层收缩先验(supplier 全局 → supplier×service → 三元组)解决 11 万长尾组合的冷启动。
| 动作 | 改哪里 | 预期效果 |
|---|---|---|
| 1. 重启 combo_health,通知改日报聚合算法 | 把每决策一条的飞书通知改成「每日汇总一条 + 只有 hide 动作实时推」,然后 combo_health.enabled=true。顺手把 hide_threshold 0.01→0.03~0.05 讨论定档(1% 拦不住 5% 的慢性死路) |
telegram@SG/KR/TW、openai@TW 等新死路自动摘除;防止 apple@TR 型黑洞再次形成。需先确认 8-2 关闭的真实动因 |
| 2. scorer 进 shadow(修两个暗坑后)算法 | ① routing.go:471 shadow 日志 Debug→Info(或独立 sampled logger);② 跨家候选成本 0 值处理;③ enabled=true, shadow_mode=true |
一周 shadow 数据回答「scorer 排序 vs 实际排序」假设收益,为放量提供证据 |
| 3. 跨家 fallback 加供给预过滤工程 | 候选构造时按 sellable_catalog_offers(或 supplier 目录表)过滤「该 supplier 目录里根本没有该国家」的候选;无目录数据的 supplier fail-open。位置:routing.go:313-418 ListEnabled 循环 |
消掉 INVALID_COUNTRY 6,295 次/周 + NO_NUMBERS 的目录性部分;fallback 链名额(max 5 attempts)让给真有货的家 → 取号率直接受益 |
| 4. 处置僵尸供应商工程 | legitsms(收码 2.3%)、1001sms(0%)、majorphones(0%)、virtualsms(5.5%)——合计 2,396 attempts/周只产出 10 条码。降 priority 至负值 / disable / 或等 combo_health 重启后按三元组自然摘除 | fallback 链腾位,减少无效等待 |
| 5. NO_NUMBERS 负缓存工程 | (supplier, service, country) 命中 NO_NUMBERS 后 Redis 短 TTL(2–5min)跳过该候选。挂在 allocateCandidate 前置检查 |
26k 次/周 NO_NUMBERS 中的重复部分不再打上游;apple@TR 型刷单流量的上游放大效应消失 |
| 动作 | 改哪里 | 预期效果 |
|---|---|---|
| 6. 第一枪质量化算法 | catalog 选家(repository.go:1832 和 :1969 DISTINCT ON)从纯 sell_price ASC 改为「质量达标集合内选最便宜」或「质量分×价格综合分」。质量分读 snapshots 贝叶斯后验 |
直接作用于每一单的初始供应商 —— 这是比 scorer 更大的杠杆(scorer 只能重排 fallback 段)。telegram@CA/HK 类组合收码量预估 +70% |
| 7. scorer 放量 + rank 区间放开评估算法 | shadow 数据达标后 shadow_mode=false;评估有主家时是否允许重排跨家 fallback 段(当前 rankEnd=preCrossEnd 锁死) |
fallback 不再按全 0 的 priority 无序轮询 |
| 8. 用户侧排序公式改乘性 + 徽章门槛算法 | ① query.go:559-567 成功率从加性 ×26 改乘性衰减(如 score × rate^k),让 5% 组合分数塌掉;② index===0 推荐徽章加成功率下限;③ 换国推荐 repository.go:3458 按质量排序;④ safeRate 冷启动复用贝叶斯先验;⑤ 修 null 排序 bug |
切断「便宜死路国霸榜→更多订单→继续霸榜」闭环。属定价/路由红线,建议 A/B 验证(见 P2-11) |
| 9. 失败自动重试(产品化用户自救)算法 | expired(有号无码)订单:若该组合还有未试过且质量分达标的供应商,前端一键「换渠道重试」预填充;进阶版后端自动 re-allocate | 用户级成功率 70% 的重试行为系统化;477 人/周「重试永不成功」的用户能更快被引导到可行组合或明确告知无货 |
| 10. 接码率 SLO 告警工程 | supplier 级 / top 组合级 sms_per_alloc 滑窗监控,劣化超阈值飞书告警(走 combo_health 同款日报聚合,别再造轰炸)。当前告警体系只看余额——供给侧交付崩盘完全无感知 | 下一个 otpsell/lubansms 型上线事故从「按周发现」变「按小时发现」 |
| 动作 | 说明 |
|---|---|
| 11. 轻量 A/B 基础设施工程 | orders 加 experiment_variant 列 + user_id hash 分桶 + 按桶切片的指标查询。排序权重、定价规则类改动全部要走 A/B(历史教训:推荐权重与路由改动多次被标记为「需人工+A/B」但基础设施一直缺位) |
| 12. 统一「组合质量分」算法 | 把 scorer / combo_health / popularityScore / 换国推荐收敛到同一个 per-(supplier,service,country) 贝叶斯后验(逐层收缩先验解决长尾冷启动:三元组无样本→回落 supplier×service→再回落 supplier 全局)。combo_health 退化为「质量分 < 硬阈值」的特例,三套代码变一套 |
| 13. 归因补全工程 | errSkipCandidate/预过滤跳过的候选当前不写 attempts(routing.go:572-607)——预过滤上线后会「看不见省了多少」,补一个轻量 skip 计数(metrics 即可,不必落表) |
| 14. Retryable 语义启用工程 | SupplierError.Retryable 字段从未被读(service.go:643 注释承认保留给 P2)——RATE_LIMITED/TIMEOUT 可做同家短退避重试,与跨家 fallback 区分 |