Explorar el Código

阅读优化增加指标

luojunhui hace 6 días
padre
commit
f6d65a2dc1

+ 3 - 2
src/components/RankingSettingsButton.tsx

@@ -26,15 +26,16 @@ interface Props {
   activeModality: ActiveModality
 }
 
-const FORMULA_VIDEO = `综合得分 = c × (α × sim_norm + (1-α) × rov_norm)
+const FORMULA_VIDEO = `综合得分 = α·c·sim_norm + (1-α)·rov_norm  (c 仅作用于相关性分)
   sim_norm = clip((sim - simThreshold) / (1 - simThreshold), 0, 1)
   rov_norm = clip((rov - rovClipLow) / (rovClipHigh - rovClipLow), 0, 1)
   c = boostsByCode[configCode] (选题默认 1, 其他维度默认 0.4) / deconstructBoost (未知维度兜底)
 先按 simThreshold 硬筛 (sim < 阈值剔除), 再按综合分排序.`
 
-const FORMULA_MATERIAL = `综合得分 = α × sim_norm + (1-α) × qualityScore
+const FORMULA_MATERIAL = `综合得分 = α·c·sim_norm + (1-α)·qualityScore  (c 仅作用于相关性分)
   sim_norm = clip((sim - simThreshold) / (1 - simThreshold), 0, 1)
   qualityScore = (wCtr×ctr + wViral×viral + wRoi×roi) / (wCtr+wViral+wRoi)
+  c = boostsByCode[configCode] (默认 1) / deconstructBoost (未知维度兜底)
 先按 simThreshold 硬筛, 再按综合分排序.`
 
 const FORMULA_LEGACY = `${FORMULA_VIDEO}

+ 6 - 5
src/components/RecallResultTable.tsx

@@ -116,7 +116,7 @@ function getWeightedQualityScore(item: RowItem): number | null {
 /**
  * 召回结果表格
  * 列顺序: 标题/封面/召回维度/综合得分/向量相似度/解构/旧AI/指标
- * 综合得分 = c × (α × sim_norm + (1-α) × rov_norm), 参数走 rankingParams (浮层可改)
+ * 综合得分 = α·c·sim_norm + (1-α)·rov_norm (c 仅作用于相关性分), 参数走 rankingParams (浮层可改)
  * sim < simThreshold 的 item 直接剔除
  */
 export default function RecallResultTable({
@@ -1190,10 +1190,11 @@ function CompositeScoreCell({
   const tip =
     modality === 'MATERIAL' ? (
       <div style={{ fontSize: 12, lineHeight: 1.6 }}>
-        <div>sim_norm = {simNorm.toFixed(3)}</div>
-        <div>quality = {weightedQuality != null ? weightedQuality.toFixed(3) : '--'}</div>
+        <div>相关性分 sim_norm = {simNorm.toFixed(3)}</div>
+        <div>质量分 quality = {weightedQuality != null ? weightedQuality.toFixed(3) : '--'}</div>
+        <div>c = {boost.toFixed(2)}</div>
         <div style={{ borderTop: '1px solid rgba(255,255,255,0.3)', marginTop: 4, paddingTop: 4 }}>
-          composite = α·sim_norm + (1-α)·quality = <b>{text}</b>
+          composite = α·sim_norm + (1-α)·quality = <b>{text}</b>
         </div>
       </div>
     ) : (
@@ -1202,7 +1203,7 @@ function CompositeScoreCell({
         <div>质量分 rov_norm = {rovNorm.toFixed(3)}</div>
         <div>c = {boost.toFixed(2)}</div>
         <div style={{ borderTop: '1px solid rgba(255,255,255,0.3)', marginTop: 4, paddingTop: 4 }}>
-          composite = c × (α·sim_norm + (1-α)·rov_norm) = <b>{text}</b>
+          composite = α·c·sim_norm + (1-α)·rov_norm = <b>{text}</b>
         </div>
       </div>
     )

+ 18 - 15
src/utils/scoring.ts

@@ -18,8 +18,9 @@ import type { RecallSignals, VideoMatchEnrichedVO } from '../api/types'
  * 公式 (MATERIAL):
  *   sim_norm = clip((sim - simThreshold) / (1 - simThreshold), 0, 1)
  *   qualityScore = (wCtr × ctr + wViral × viral + wRoi × roi) / qualTotalW
- *   composite = alpha × sim_norm + (1 - alpha) × qualityScore
+ *   composite = alpha × boost × sim_norm + (1 - alpha) × qualityScore
  *   质量缺失时按 materialMissingStrategy 处理:"group"(分组)或 "shrink"(收缩)
+ *   boost 仅作用于相关性分
  */
 export interface RankingParams {
   simThreshold: number
@@ -138,7 +139,7 @@ export function computeCompositeScore(
   // 素材模态:多维质量加权
   if (item.modality === 'MATERIAL') {
     const quality = item.signals?.quality ?? materialQualityFromDetail(item)
-    return rankMaterial(simNorm, lowerBound, passesThreshold, quality, params)
+    return rankMaterial(simNorm, lowerBound, passesThreshold, quality, item, params)
   }
 
   // VIDEO / ARTICLE 模态:ROV 公式
@@ -150,29 +151,35 @@ function rankMaterial(
   lowerBound: number,
   passesThreshold: boolean,
   quality: RecallSignals['quality'] | undefined,
+  item: VideoMatchEnrichedVO,
   params: RankingParams,
 ): ScoreBreakdown {
   const alpha = params.alpha
 
+  // boost 仅作用于相关性分,质量分不加 boost
+  const codeBoost = item.configCode
+    ? (params.boostsByCode?.[item.configCode] ?? getDefaultBoostForCode(item.configCode))
+    : params.deconstructBoost
+
   if (quality == null || !quality.hasData) {
     // group(默认):无质量数据,仅依赖相关性
     if (params.materialMissingStrategy === 'group') {
       return {
-        composite: alpha * simNorm,
+        composite: alpha * codeBoost * simNorm,
         simNorm,
         rovNorm: 0,
-        boost: 1,
+        boost: codeBoost,
         lowerBound,
         passesThreshold,
         qualityMissing: true,
       }
     }
-    // shrink: 无先验均值时退化为 alpha × simNorm
+    // shrink: 无先验均值时退化为 alpha × boost × simNorm
     return {
-      composite: alpha * simNorm,
+      composite: alpha * codeBoost * simNorm,
       simNorm,
       rovNorm: 0,
-      boost: 1,
+      boost: codeBoost,
       lowerBound,
       passesThreshold,
     }
@@ -183,12 +190,12 @@ function rankMaterial(
   const roi = quality.roi ?? 0
   const qualTotalW = params.wCtr + params.wViral + params.wRoi || 1
   const weightedQuality = (params.wCtr * ctr + params.wViral * viral + params.wRoi * roi) / qualTotalW
-  const composite = alpha * simNorm + (1 - alpha) * weightedQuality
+  const composite = alpha * codeBoost * simNorm + (1 - alpha) * weightedQuality
   return {
     composite,
     simNorm,
     rovNorm: 0,
-    boost: 1,
+    boost: codeBoost,
     lowerBound,
     passesThreshold,
     weightedQuality,
@@ -212,12 +219,8 @@ function rankVideoArticle(
   const hasRov = rov != null && Number.isFinite(rov)
 
   if (!hasRov) {
-    if (item.modality === 'VIDEO') {
-      const composite = codeBoost * params.alpha * simNorm
-      return { composite, simNorm, rovNorm: 0, boost: codeBoost, lowerBound, passesThreshold }
-    }
-    const composite = simNorm
-    return { composite, simNorm, rovNorm: 0, boost: 1, lowerBound, passesThreshold }
+    const composite = codeBoost * params.alpha * simNorm
+    return { composite, simNorm, rovNorm: 0, boost: codeBoost, lowerBound, passesThreshold }
   }
 
   const rovDenom = params.rovClipHigh - params.rovClipLow