Files
xiaji 6a45f84857 perf(llm): 短新闻 enrich 跳过时不再标 'n/a',避免 enrichment_loop 反复扫
问题:
  enrichment_loop 的 in-loop 过滤 (line 616) 把 'n/a' 当成
  "未 enrich" 信号:
    if any(s in ("pending", "failed", "n/a") for s in statuses):
        todo_ids.append(a.id)

  短新闻入表时 format_status='n/a'、image_ai_status='n/a'
  (commit 1 决定),而 enrich_article 在 is_short 跳过这两任务时
  保留 'n/a'。后果:enrichment_loop 永远认为"这两任务未完成",
  每 ~3.5 分钟反复把同一篇短新闻捞进队列 enrich 一次。

  实测(commit 10 修复前 1 小时数据):
  - 9 篇短新闻 × 18 次 enrich = 131 次完全 ok
  - 131 - 9 = 122 次纯浪费(占 95%)
  - 每篇 enrich 内部 Angel + 美团两个 LLM 调用是并行的
  - 浪费配额:Agnes 免费 plan 风险、Angel 月配额、美团限速窗口

修法:
  enrich 跳过某任务时,把对应 status 标 'ok' (语义 = 该任务
  "已完成" = 不需要做),而不是 'n/a' (语义 = 任务存在但跳过)。
  改动 2 处:format 跳过 + image 跳过。
  短新闻 enrich 后,所有 *_status 都是 'ok',enrichment_loop
  看到后不再扫,只跑一次。

注释同步更新:解释 'n/a' vs 'ok' 的语义区别,提醒后续修改者
不要把 'n/a' 写回 status 字段。

存量修复(不写入 commit,运维动作):
  修复前入库存量的短新闻 format/image_ai_status 仍是 'n/a',
  deploy 后第一次循环会把它们 enrich 一遍改成 'ok'。如果你想
  立刻修,跑:
    UPDATE articles
    SET format_status='ok', image_ai_status='ok'
    WHERE is_short_news=true
      AND (format_status='n/a' OR image_ai_status='n/a');

不改:
  - enrichment_loop 的 SQL/loop 过滤条件(不动 'n/a' 状态值,
    仍有合法场景使用:meituan_client 未配置时 commentary_meituan
    会标 'n/a'。但生产环境 meituan key 已配置,该 case 不存在)
  - ingest 路由的 *_status='n/a' 初始化(那是在入库阶段,
    enrichment_loop 不会立即扫到,有 2 秒起步延迟 +
    is_short_news/body_zh_text 过滤)
  - comment_status 等其他 status 字段(短新闻也会跑,设 'ok')

性能影响(预估):
  - 修复前:每篇短新闻每小时 18 次 enrich × 1 路串行 ~18 秒/次
    = 占 enrichment_loop 单 worker 18 * 18s = 5.4 分钟/小时
  - 修复后:每篇短新闻只 enrich 1 次,约 5 秒
  - 节省:短新闻 LLM 调用约减少 95%
  - 副作用:长新闻 enrich 不再被短新闻"挤占"semaphore 资源,
    长新闻 enrich 速度会加快(从当前 ~18s 串行,可能回到 ~5s)
2026-06-14 22:03:06 +08:00
..