fix(#1743): smart-match 排序随机噪声 + 素材使用次数按成片实际片段计数 #1747

Merged
xiaoxia merged 2 commits from fix/smart-match-noise-usage-count-1743 into develop 2026-09-06 20:17:08 +08:00
Owner

#1743 评论补充发现的智能选素材「每次只选同样几个素材」3 个缺陷中的后端两项(第③项候选池扩大属前端 useSmartMatch.ts,由前端 #1744 处理)。

① smart-match 评分排序零随机(主因)

  • smart_select_assets Step4 排序与多样性分桶注入 0~SCORE_RANDOM_NOISE_MAX(20) 随机噪声(与 from-assets 片段分配同源常量)
  • 同分/近分素材每次选出的组合与顺序不同;分差 >20 的高质量素材排名不受影响
  • 噪声以 asset.id 为 key,同一次调用内排序与分桶轮询一致;r.score 始终为无噪声原始分
  • 支持 rng 注入(测试可复现);smart-match API、正式生成候选截断、模板编辑器三个调用点全部受益(正式生成分配的 _sort_assets_by_smart_score 此前已有噪声,但候选池截断固定 → 池子相同,本次修复后池子本身也随机)

② 使用次数计数口径错误 + 回写核实

  • staging 实证:回写实际生效(0c1bfa83=4/69ea3060=3/668cf0d4=3),但口径错——按请求 task.asset_ids 每个 +1,未被 plan clips 选用的素材(0c1bfa83)也被计数,实际渲染 2 次的素材只计了 3
  • 修复:mark_asset_used_for_generation(asset, times=N) 支持按片段数累加;worker 回写改为统计最终成片 plan(重渲后为重渲版 plan)的 edit_plan_clips asset 引用次数
  • _count_plan_clip_asset_usage / _record_rendered_asset_usage 可测函数;plan 无有效片段兜底 task.asset_ids 单次计数;单素材失败不阻断其他素材
  • 高频排除(get_asset_recent_use_counts)本就基于 used_time_ranges 片段级追踪,口径准确;本次修复后 generation_use_count(unused_bonus 评分维度)同样准确

③ 测试

  • 新增 22 测试:噪声 10(同分排序多样/Top-N 组合变化/大分差稳定/原始分不污染/种子确定/分桶噪声/无 limit 全返回/非 ready 过滤等)+ 回写计数 12(times 累加/空 plan 兜底/未选用素材不计数/单素材失败隔离/缺失素材跳过等)
  • 旧确定性排序断言(test_asset_select_mode、test_smart_match_integration)注入零噪声 rng
  • 顺手修复 test_distribute_assets_uses_smart_score_ordering 预存在 flaky(排序后 shuffle 未被零噪声 patch 覆盖,develop 上 12 次 5 失败)
  • 全量 14234 passed;36 失败均为 develop 基线预存在(34 TTS/voice + generation_cover + auth_bind,沙箱 httpx2/h2 损坏,CI 正常)
#1743 评论补充发现的智能选素材「每次只选同样几个素材」3 个缺陷中的后端两项(第③项候选池扩大属前端 useSmartMatch.ts,由前端 #1744 处理)。 ## ① smart-match 评分排序零随机(主因) - `smart_select_assets` Step4 排序与多样性分桶注入 `0~SCORE_RANDOM_NOISE_MAX(20)` 随机噪声(与 from-assets 片段分配同源常量) - 同分/近分素材每次选出的组合与顺序不同;分差 >20 的高质量素材排名不受影响 - 噪声以 asset.id 为 key,同一次调用内排序与分桶轮询一致;`r.score` 始终为无噪声原始分 - 支持 `rng` 注入(测试可复现);smart-match API、正式生成候选截断、模板编辑器三个调用点全部受益(正式生成分配的 `_sort_assets_by_smart_score` 此前已有噪声,但候选池截断固定 → 池子相同,本次修复后池子本身也随机) ## ② 使用次数计数口径错误 + 回写核实 - staging 实证:回写**实际生效**(0c1bfa83=4/69ea3060=3/668cf0d4=3),但口径错——按请求 `task.asset_ids` 每个 +1,未被 plan clips 选用的素材(0c1bfa83)也被计数,实际渲染 2 次的素材只计了 3 - 修复:`mark_asset_used_for_generation(asset, times=N)` 支持按片段数累加;worker 回写改为统计**最终成片 plan**(重渲后为重渲版 plan)的 `edit_plan_clips` asset 引用次数 - 抽 `_count_plan_clip_asset_usage` / `_record_rendered_asset_usage` 可测函数;plan 无有效片段兜底 task.asset_ids 单次计数;单素材失败不阻断其他素材 - 高频排除(`get_asset_recent_use_counts`)本就基于 used_time_ranges 片段级追踪,口径准确;本次修复后 `generation_use_count`(unused_bonus 评分维度)同样准确 ## ③ 测试 - 新增 22 测试:噪声 10(同分排序多样/Top-N 组合变化/大分差稳定/原始分不污染/种子确定/分桶噪声/无 limit 全返回/非 ready 过滤等)+ 回写计数 12(times 累加/空 plan 兜底/未选用素材不计数/单素材失败隔离/缺失素材跳过等) - 旧确定性排序断言(test_asset_select_mode、test_smart_match_integration)注入零噪声 rng - 顺手修复 test_distribute_assets_uses_smart_score_ordering 预存在 flaky(排序后 shuffle 未被零噪声 patch 覆盖,develop 上 12 次 5 失败) - 全量 14234 passed;36 失败均为 develop 基线预存在(34 TTS/voice + generation_cover + auth_bind,沙箱 httpx2/h2 损坏,CI 正常)
xiaoxia added 1 commit 2026-09-06 19:48:33 +08:00
fix(#1743): smart-match排序注入随机噪声 + 素材使用次数按成片实际片段计数回写
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 34s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m27s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1m25s
AI Code Review / AI Code Review (pull_request) Successful in 1m32s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m38s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 1m59s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m17s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m48s
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
ed09794f4d
1. smart-match 排序零随机修复(主因):
   - smart_select_assets 排序/多样性分桶注入 0~SCORE_RANDOM_NOISE_MAX 随机噪声,
     同分/近分素材每次选出不同组合与顺序;分差>20的高质量素材保持稳定优先级
   - 噪声以 asset.id 为 key 同次调用内一致;r.score 始终为无噪声原始分
   - 支持 rng 注入(测试可复现);smart-match API/正式生成/模板编辑器三调用点全受益
2. 素材使用次数口径修复:
   - mark_asset_used_for_generation 新增 times 参数,按成片实际渲染片段引用次数累加
   - worker 回写从 task.asset_ids(请求列表,含未被plan选用的素材)改为
     统计最终成片 plan 的 edit_plan_clips(同素材多片段复用按片段数累加)
   - 抽 _count_plan_clip_asset_usage/_record_rendered_asset_usage 纯函数(可单测)
   - plan 无有效片段时兜底 task.asset_ids 单次计数;单素材失败不阻断其他
3. 测试:22 新测试(噪声 10 + 回写计数 12);旧确定性排序断言注入零噪声 rng;
   修复 test_distribute_assets 预存在 flaky(shuffle 未被零噪声 patch 覆盖)

🚀 预览环境已部署

项目 详情
PR号 #1747
预览链接 https://pr-1747.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1747 | | 预览链接 | [https://pr-1747.preview.xiaoxiajianji.com](https://pr-1747.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
xiaoxia added 1 commit 2026-09-06 19:59:00 +08:00
test(#1743): 修复 smart-match 随机噪声引发的确定性排序断言
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 14s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 15s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m22s
AI Code Review / AI Code Review (pull_request) Successful in 1m31s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 1m35s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 1m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m54s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m49s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m7s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m31s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 14m41s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 7s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m30s
6cdb70bb61
CI Unit Tests 暴露(沙箱 httpx2 无法 collect test_smart_match*.py 未本地复现):
- test_smart_match_fallback test_limit_backfills: second(quality=40)/third(30)
  质量项仅差 4 分 < 噪声 20,third 可翻到首位 → second 质量提至 90(差 24>20),
  200 seeds 验证零翻转
- test_smart_match test_returns_sorted_by_score_descending / test_image_assets:
  smart_select_assets 直接调用处注入零噪声 rng(_ZeroNoiseRandom),验证纯评分排序
- 验证生产噪声行为:大分差素材排名稳定、同分素材组合随机
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:否
  • 阻塞级问题数量:0 个

📊 审查概览

  • 整体评价:通过
  • 建议级问题数量:1 个

🔴 阻塞级问题(必须修复)

💡 改进建议(不合并)

  1. [apps/worker/worker_app/tasks/generation.py: 449] N+1 查询风险
    • 具体内容:在 _record_rendered_asset_usage 函数中,通过循环遍历 used_counts 并对每个 asset_id 调用 asset_repo.get(aid),在素材数量较多时可能产生 N+1 查询问题。虽然这是在 Worker 异步任务中执行且通常素材数量有限,但建议优化为批量查询(如 session.query(Asset).filter(Asset.id.in_(asset_ids)).all())以提升性能,特别是在高并发或素材库较大的场景下。

良好实践

  1. 逻辑严谨性:素材使用计数逻辑从“请求列表”修正为“实际渲染片段”,有效避免了未被选用的素材被错误计数,逻辑更加准确。
  2. 异常隔离:在 _record_rendered_asset_usage 中对单个素材的更新操作进行了 try-except 包裹,确保单个素材更新失败不会阻断整个任务的统计流程,容错性好。
  3. 可测试性:引入 rng 参数和 _ZeroNoiseRandom 类,使得包含随机噪声的排序逻辑在单元测试中可以完全复现,保证了测试的稳定性和覆盖率。
  4. 降级策略:当 plan 中无有效片段时,自动回退到 task.asset_ids 进行计数,保证了在异常数据情况下统计信息不丢失。

格式检查 逻辑审查 性能⚠️


🤖 由 AI 代码审查机器人自动生成 | 2026-09-06 12:00:31 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:否 - 阻塞级问题数量:0 个 ### 📊 审查概览 - 整体评价:通过 - 建议级问题数量:1 个 ### 🔴 阻塞级问题(必须修复) 无 ### 💡 改进建议(不合并) 1. **[apps/worker/worker_app/tasks/generation.py: 449] N+1 查询风险** - 具体内容:在 `_record_rendered_asset_usage` 函数中,通过循环遍历 `used_counts` 并对每个 asset_id 调用 `asset_repo.get(aid)`,在素材数量较多时可能产生 N+1 查询问题。虽然这是在 Worker 异步任务中执行且通常素材数量有限,但建议优化为批量查询(如 `session.query(Asset).filter(Asset.id.in_(asset_ids)).all()`)以提升性能,特别是在高并发或素材库较大的场景下。 ### ✅ 良好实践 1. **逻辑严谨性**:素材使用计数逻辑从“请求列表”修正为“实际渲染片段”,有效避免了未被选用的素材被错误计数,逻辑更加准确。 2. **异常隔离**:在 `_record_rendered_asset_usage` 中对单个素材的更新操作进行了 try-except 包裹,确保单个素材更新失败不会阻断整个任务的统计流程,容错性好。 3. **可测试性**:引入 `rng` 参数和 `_ZeroNoiseRandom` 类,使得包含随机噪声的排序逻辑在单元测试中可以完全复现,保证了测试的稳定性和覆盖率。 4. **降级策略**:当 `plan` 中无有效片段时,自动回退到 `task.asset_ids` 进行计数,保证了在异常数据情况下统计信息不丢失。 --- **格式检查**:✅ **逻辑审查**:✅ **性能**:⚠️ --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-09-06 12:00:31 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 4c03e05e6c into develop 2026-09-06 20:17:08 +08:00

🗑️ 预览环境已清理

PR #1747 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1747 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.