From 6a45f848576080b78b8be297b47aab2683995885 Mon Sep 17 00:00:00 2001 From: xiaji Date: Sun, 14 Jun 2026 22:03:06 +0800 Subject: [PATCH] =?UTF-8?q?perf(llm):=20=E7=9F=AD=E6=96=B0=E9=97=BB=20enri?= =?UTF-8?q?ch=20=E8=B7=B3=E8=BF=87=E6=97=B6=E4=B8=8D=E5=86=8D=E6=A0=87=20'?= =?UTF-8?q?n/a',=E9=81=BF=E5=85=8D=20enrichment=5Floop=20=E5=8F=8D?= =?UTF-8?q?=E5=A4=8D=E6=89=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: 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) --- backend/app/services/llm/enrichment.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/app/services/llm/enrichment.py b/backend/app/services/llm/enrichment.py index 1605efc..17c1842 100644 --- a/backend/app/services/llm/enrichment.py +++ b/backend/app/services/llm/enrichment.py @@ -454,8 +454,12 @@ async def enrich_article(article_id: int) -> dict[str, str]: return {} # === 短新闻(API Push):跳过 format 和 image(短文不需要排版,用户明确不要配图)=== - # 短新闻入表时 format_status / image_ai_status 已置 'n/a',这里再 ensure 一次 - # 防止未来 ingest 路径忘了设 status。 + # 短新闻入表时 format_status / image_ai_status 已置 'n/a'(见 ingest), + # 这里再 ensure 一次防止未来 ingest 路径忘了设。 + # 注意:跳过某任务时要把对应 status 标 'ok'(语义 = 该任务已"完成" = 不需要做), + # 不能再用 'n/a' —— enrichment_loop 过滤集合包含 'n/a'(line 616), + # 否则短新闻会因 format_status='n/a' != 'ok' 永远进队列反复 enrich, + # 浪费 Angel/美团 LLM 配额(commit 10 之前 95% 调用是浪费)。 is_short = bool(art.is_short_news) # === 1) classify(黑名单 gate,优先执行)=== @@ -485,7 +489,8 @@ async def enrich_article(article_id: int) -> dict[str, str]: # === 2) format(短新闻跳过)=== if is_short: - art.format_status = "n/a" + # 短新闻无需排版,标 'ok' 表示该任务"已完成"(语义 = 跳过) + art.format_status = "ok" results["format"] = "skipped" else: try: @@ -498,7 +503,8 @@ async def enrich_article(article_id: int) -> dict[str, str]: # === 3) image(短新闻跳过)=== if is_short: - art.image_ai_status = "n/a" + # 短新闻无需配图,标 'ok' 表示该任务"已完成"(语义 = 跳过) + art.image_ai_status = "ok" results["image"] = "skipped" else: try: