Prechádzať zdrojové kódy

外部合作素材 不检查成本

wangyunpeng 12 hodín pred
rodič
commit
7e0593a434

+ 1 - 1
examples/auto_put_ad_mini/DEPLOYMENT.md

@@ -239,7 +239,7 @@ SLS_ERROR_LOGSTORE=error-log
 | `EXTERNAL_RECALL_UV_WINDOW_DAYS` | 外部素材访问 UV 汇总窗口天数 | `90` | 否 |
 | `EXTERNAL_RECALL_UV_WINDOW_DAYS` | 外部素材访问 UV 汇总窗口天数 | `90` | 否 |
 | `EXTERNAL_RECALL_MIN_UV` | 外部合作素材访问UV最低门槛(窗口求和,<此值排除) | `500` | 否 |
 | `EXTERNAL_RECALL_MIN_UV` | 外部合作素材访问UV最低门槛(窗口求和,<此值排除) | `500` | 否 |
 | `EXTERNAL_IMAGE_MODEL` | 外部素材参考图编辑模型 | 复用 `OPENROUTER_IMAGE_MODEL` | 否 |
 | `EXTERNAL_IMAGE_MODEL` | 外部素材参考图编辑模型 | 复用 `OPENROUTER_IMAGE_MODEL` | 否 |
-| `RECALL_MIN_COST_YUAN` | 素材召回历史成本最低门槛(元);历史投放素材与外部合作素材共用;无成本数据(cost is None)的素材严格排除,即使设为 0 | `100` | 否 |
+| `RECALL_MIN_COST_YUAN` | 内部素材召回历史成本最低门槛(元);外部合作素材不走此门槛(见 `EXTERNAL_RECALL_MIN_UV`);无成本数据(cost is None)的素材严格排除,即使设为 0 | `100` | 否 |
 
 
 ### 白名单配置
 ### 白名单配置
 
 

+ 4 - 2
examples/auto_put_ad_mini/config.py

@@ -1027,10 +1027,12 @@ RECALL_PARALLEL_MAX_WORKERS = int(os.getenv("RECALL_PARALLEL_MAX_WORKERS", "4"))
 RECALL_QUERY_LIMIT_PER_VIDEO = int(os.getenv("RECALL_QUERY_LIMIT_PER_VIDEO", "12"))
 RECALL_QUERY_LIMIT_PER_VIDEO = int(os.getenv("RECALL_QUERY_LIMIT_PER_VIDEO", "12"))
 RECALL_MIN_IMPRESSIONS = 0                        # 保留兼容配置;当前不作为硬筛。
 RECALL_MIN_IMPRESSIONS = 0                        # 保留兼容配置;当前不作为硬筛。
 RECALL_MIN_CTR = 0.0                              # 保留兼容配置;当前不作为硬筛。
 RECALL_MIN_CTR = 0.0                              # 保留兼容配置;当前不作为硬筛。
-# --- 素材召回历史成本门槛(2026-08-06 用户确认;2026-08-07 用户调整为 100)---
-# 历史投放素材与外部合作素材共用:历史成本(cost, 元) >= 此值才进入候选池。
+# --- 素材召回历史成本门槛(2026-08-06 用户确认;2026-08-07 调整:外部素材不走此门槛)---
+# 仅历史投放素材(内部)适用:历史成本(cost, 元) >= 此值才进入候选池。
 # 严格语义:无历史成本数据(cost is None,从未投放过)的素材同样排除。
 # 严格语义:无历史成本数据(cost is None,从未投放过)的素材同样排除。
 # 注:设为 0 只关闭金额门槛,cost is None 仍排除(严格语义)。
 # 注:设为 0 只关闭金额门槛,cost is None 仍排除(严格语义)。
+# 外部合作素材召回(recall_external_materials_for_video)传 apply_cost_filter=False
+# 绕过此门槛,以 EXTERNAL_RECALL_MIN_UV 的访问 UV 门槛把关。
 RECALL_MIN_COST_YUAN = int(os.getenv("RECALL_MIN_COST_YUAN", "100"))
 RECALL_MIN_COST_YUAN = int(os.getenv("RECALL_MIN_COST_YUAN", "100"))
 RECALL_SOURCE_LABELS = ["内部素材"]               # 只要内部
 RECALL_SOURCE_LABELS = ["内部素材"]               # 只要内部
 MAX_SAME_LANDING_PER_AD_IN_RUN = int(os.getenv("MAX_SAME_LANDING_PER_AD_IN_RUN", "1"))
 MAX_SAME_LANDING_PER_AD_IN_RUN = int(os.getenv("MAX_SAME_LANDING_PER_AD_IN_RUN", "1"))

+ 3 - 0
examples/auto_put_ad_mini/tools/external_recalled_material.py

@@ -258,12 +258,15 @@ def recall_external_materials_for_video(
     *,
     *,
     element_features: Iterable,
     element_features: Iterable,
 ) -> list[Material]:
 ) -> list[Material]:
+    # 外部合作素材绕过历史成本门槛(apply_cost_filter=False):
+    # 素材多为合作方提供、无本账户历史投放成本,以访问 UV 门槛把关。
     materials = recall_materials_for_video(
     materials = recall_materials_for_video(
         landing,
         landing,
         final_top_n=None,
         final_top_n=None,
         source_labels=[EXTERNAL_RECALL_SOURCE_LABEL],
         source_labels=[EXTERNAL_RECALL_SOURCE_LABEL],
         element_features=element_features,
         element_features=element_features,
         apply_cover_blacklist=False,
         apply_cover_blacklist=False,
+        apply_cost_filter=False,
     )
     )
     ranked = rank_external_materials_by_visit_uv(
     ranked = rank_external_materials_by_visit_uv(
         materials,
         materials,

+ 14 - 6
examples/auto_put_ad_mini/tools/material_recall.py

@@ -369,6 +369,7 @@ def _items_to_materials(
     *,
     *,
     apply_cover_blacklist: bool = True,
     apply_cover_blacklist: bool = True,
     min_cost: Optional[float] = None,
     min_cost: Optional[float] = None,
+    apply_cost_filter: bool = True,
 ) -> tuple:
 ) -> tuple:
     """把召回 items 过滤 + 转 Material。
     """把召回 items 过滤 + 转 Material。
 
 
@@ -376,7 +377,9 @@ def _items_to_materials(
     - modality=MATERIAL(防御性)
     - modality=MATERIAL(防御性)
     - cover URL 不在黑名单
     - cover URL 不在黑名单
     - score >= sim_threshold
     - score >= sim_threshold
-    - min_cost is not None 时:历史成本(cost, 元) >= min_cost(严格,无成本数据也排除)
+    - apply_cost_filter 且 min_cost is not None 时:历史成本(cost, 元) >= min_cost
+      (严格,无成本数据也排除)。外部合作素材召回关闭 apply_cost_filter,
+      仅以访问 UV 门槛把关。
 
 
     CTR / impressions 只作为审批展示和兜底排序参考,不再作为硬筛。
     CTR / impressions 只作为审批展示和兜底排序参考,不再作为硬筛。
     返回 (materials, stats)。
     返回 (materials, stats)。
@@ -409,7 +412,7 @@ def _items_to_materials(
         q = md.get("quality") or {}
         q = md.get("quality") or {}
         raw_cost = q.get("cost")
         raw_cost = q.get("cost")
         cost = _as_float(raw_cost) if raw_cost is not None else None
         cost = _as_float(raw_cost) if raw_cost is not None else None
-        if min_cost is not None and (cost is None or cost < min_cost):
+        if apply_cost_filter and min_cost is not None and (cost is None or cost < min_cost):
             stats["low_cost"] += 1
             stats["low_cost"] += 1
             continue
             continue
         out.append(Material(
         out.append(Material(
@@ -586,6 +589,7 @@ def recall_materials_for_video(
     element_features: Optional[Iterable] = None,
     element_features: Optional[Iterable] = None,
     apply_cover_blacklist: bool = True,
     apply_cover_blacklist: bool = True,
     min_cost: Optional[float] = None,
     min_cost: Optional[float] = None,
+    apply_cost_filter: bool = True,
 ) -> List[Material]:
 ) -> List[Material]:
     """素材召回:用 ODPS 多维特征并行召回并合并排序。
     """素材召回:用 ODPS 多维特征并行召回并合并排序。
 
 
@@ -595,6 +599,7 @@ def recall_materials_for_video(
       3. 汇总、material_id 去重、score>=阈值、按 cost 倒序。
       3. 汇总、material_id 去重、score>=阈值、按 cost 倒序。
 
 
     硬筛:相似度阈值 + 历史成本(cost>=min_cost,min_cost 默认取 config.RECALL_MIN_COST_YUAN)。
     硬筛:相似度阈值 + 历史成本(cost>=min_cost,min_cost 默认取 config.RECALL_MIN_COST_YUAN)。
+    外部合作素材召回传 apply_cost_filter=False 关闭成本门槛,仅以访问 UV 门槛把关。
     曝光/CTR 进入审批表但不拦截。
     曝光/CTR 进入审批表但不拦截。
     """
     """
     from config import (
     from config import (
@@ -608,6 +613,7 @@ def recall_materials_for_video(
 
 
     if min_cost is None:
     if min_cost is None:
         min_cost = RECALL_MIN_COST_YUAN
         min_cost = RECALL_MIN_COST_YUAN
+    cost_marker = "off" if not apply_cost_filter else f"{min_cost:.0f}"
 
 
     if element_features is None:
     if element_features is None:
         element_features = landing.raw.get("element_features") or []
         element_features = landing.raw.get("element_features") or []
@@ -661,13 +667,14 @@ def recall_materials_for_video(
                 RECALL_SIM_THRESHOLD,
                 RECALL_SIM_THRESHOLD,
                 apply_cover_blacklist=apply_cover_blacklist,
                 apply_cover_blacklist=apply_cover_blacklist,
                 min_cost=min_cost,
                 min_cost=min_cost,
+                apply_cost_filter=apply_cost_filter,
             )
             )
             query_materials.append((query, mats))
             query_materials.append((query, mats))
             logger.info(
             logger.info(
-                "[material_recall]   策略=%s q=%r configCode=%s 返回 %d 条,⊘ 黑名单 %d,⊘ score<%.2f %d,⊘ cost<%.0f %d → 保留 %d",
+                "[material_recall]   策略=%s q=%r configCode=%s 返回 %d 条,⊘ 黑名单 %d,⊘ score<%.2f %d,⊘ cost<%s %d → 保留 %d",
                 query.strategy_name, query.query_text[:30], query.config_code,
                 query.strategy_name, query.query_text[:30], query.config_code,
                 len(items), stats["blacklist"], RECALL_SIM_THRESHOLD,
                 len(items), stats["blacklist"], RECALL_SIM_THRESHOLD,
-                stats["low_score"], min_cost, stats["low_cost"],
+                stats["low_score"], cost_marker, stats["low_cost"],
                 len(mats),
                 len(mats),
             )
             )
 
 
@@ -701,6 +708,7 @@ def recall_materials_for_video(
                 RECALL_SIM_THRESHOLD,
                 RECALL_SIM_THRESHOLD,
                 apply_cover_blacklist=apply_cover_blacklist,
                 apply_cover_blacklist=apply_cover_blacklist,
                 min_cost=min_cost,
                 min_cost=min_cost,
+                apply_cost_filter=apply_cost_filter,
             )
             )
             fquery = RecallQuery(
             fquery = RecallQuery(
                 query_text=query.query_text,
                 query_text=query.query_text,
@@ -713,10 +721,10 @@ def recall_materials_for_video(
             )
             )
             fmats = _merge_materials_by_policy([(fquery, fmats)])
             fmats = _merge_materials_by_policy([(fquery, fmats)])
             logger.info(
             logger.info(
-                "[material_recall]     fallback=%s 返回 %d 条,⊘ 黑名单 %d,⊘ score<%.2f %d,⊘ cost<%.0f %d → 保留 %d(cost desc)",
+                "[material_recall]     fallback=%s 返回 %d 条,⊘ 黑名单 %d,⊘ score<%.2f %d,⊘ cost<%s %d → 保留 %d(cost desc)",
                 fallback_cc, len(fallback_items), fstats["blacklist"],
                 fallback_cc, len(fallback_items), fstats["blacklist"],
                 RECALL_SIM_THRESHOLD, fstats["low_score"],
                 RECALL_SIM_THRESHOLD, fstats["low_score"],
-                min_cost, fstats["low_cost"],
+                cost_marker, fstats["low_cost"],
                 len(fmats),
                 len(fmats),
             )
             )
             if fmats:
             if fmats: