刘立冬 4 周之前
父节点
当前提交
3cf2fc3965
共有 1 个文件被更改,包括 218 次插入177 次删除
  1. 218 177
      sug_v6_1_2_115.py

+ 218 - 177
sug_v6_1_2_115.py

@@ -130,33 +130,41 @@ word_segmenter = Agent[None](
 )
 
 
-# Agent 2: 相关度评估专家
-class RelevanceEvaluation(BaseModel):
-    """相关度评估"""
-    reason: str = Field(..., description="评估理由")
-    relevance_score: float = Field(..., description="相关性分数 -1~1")
+# Agent 2: 动机维度评估专家 + 品类维度评估专家(两阶段评估)
 
-relevance_evaluation_instructions = """
-# 角色定义
-你是一个 **专业的语言专家和语义相关性评判专家**。你的任务是:判断我给你的 <平台sug词条> 与 <原始问题> 的相关度满足度,给出 **-1 到 1 之间** 的数值评分。
+# 动机评估的嵌套模型
+class CoreMotivationExtraction(BaseModel):
+    """核心动机提取"""
+    简要说明核心动机: str = Field(..., description="核心动机说明")
+
+class MotivationEvaluation(BaseModel):
+    """动机维度评估"""
+    原始问题核心动机提取: CoreMotivationExtraction = Field(..., description="原始问题核心动机提取")
+    动机维度得分: float = Field(..., description="动机维度得分 -1~1")
+    简要说明动机维度相关度理由: str = Field(..., description="动机维度相关度理由")
+
+class CategoryEvaluation(BaseModel):
+    """品类维度评估"""
+    品类维度得分: float = Field(..., description="品类维度得分 -1~1")
+    简要说明品类维度相关度理由: str = Field(..., description="品类维度相关度理由")
+
+# 动机评估 prompt
+motivation_evaluation_instructions = """
+#角色
+你是一个 **专业的语言专家和语义相关性评判专家**。你的任务是:判断我给你的 <平台sug词条> 与 <原始问题> 的需求动机匹配度,给出 **-1 到 1 之间** 的数值评分。
 
 ---
 
 # 核心概念与方法论
 
-## 两大评估维度
-本评估系统始终围绕 **两个核心维度** 进行:
+## 评估维度
+本评估系统围绕 **动机维度** 进行:
 
-### 1. 动机维度(权重70%)
+### 1. 动机维度
 **定义:** 用户"想要做什么",即原始问题的行为意图和目的
 - 核心是 **动词**:获取、学习、拍摄、制作、寻找等
 - 包括:核心动作 + 使用场景 + 最终目的
 
-### 2. 品类维度(权重30%)
-**定义:** 用户"关于什么内容",即原始问题的主题对象和限定词
-- 核心是 **名词+限定词**:川西秋季风光摄影素材
-- 包括:核心主体 + 地域限定 + 时间限定 + 质量限定等
-
 ---
 
 ## 如何识别原始问题的核心动机
@@ -180,13 +188,12 @@ relevance_evaluation_instructions = """
 
 如果原始问题是纯名词短语,无任何动作线索:
 → 核心动机 = 无法识别
-→ 初始权重 = 0
-→ 相关度评估以品类匹配为主
+→ 在此情况下,动机维度得分应为 0。
 示例:
-"摄影" → 无法识别动机,初始权重=0
-"川西风光" → 无法识别动机,初始权重=0
-
+"摄影" → 无法识别动机,动机维度得分 = 0
+"川西风光" → 无法识别动机,动机维度得分 = 0
 
+---
 
 # 输入信息
 你将接收到以下输入:
@@ -199,13 +206,13 @@ relevance_evaluation_instructions = """
 
 输入: <原始问题> + <平台sug词条>
-【综合相关性判定】
-    ├→ 步骤1: 评估<sug词条>与<原始问题>的相关
-    └→ 输出: -1到1之间的数值 + 分维度得分 + 判定依据
+【动机维度相关性判定】
+    ├→ 步骤1: 评估<sug词条>与<原始问题>的需求动机匹配
+    └→ 输出: -1到1之间的数值 + 判定依据
 
 
 相关度评估维度详解
-维度1: 动机维度评估(权重70%)
+维度1: 动机维度评估
 评估对象: <平台sug词条> 与 <原始问题> 的需求动机匹配度
 说明: 核心动作是用户需求的第一优先级,决定了推荐的基本有效性
 
@@ -213,13 +220,13 @@ relevance_evaluation_instructions = """
 评分标准:
 
 【正向匹配】
-+1.0: 核心动作完全一致
++0.95~1.0: 核心动作完全一致
   - 例: 原始问题"如何获取素材" vs sug词"素材获取方法"
   - 特殊规则: 如果sug词的核心动作是原始问题动作的**具体化子集**,也判定为完全一致
     · 例: 原始问题"扣除猫咪主体的方法" vs sug词"扣除猫咪眼睛的方法"(子集但目的一致)
 
-+0.8~0.95: 核心动作语义相近或为同义表达
-  - 例: 原始问题"如何获取素材" vs sug词"素材下载教程"
++0.75~0.95: 核心动作语义相近或为同义表达
+  - 例: 原始问题"如何获取素材" vs sug词"如何下载素材"
   - 同义词对: 获取≈下载≈寻找, 技巧≈方法≈教程≈攻略
 
 +0.5~0.75: 核心动作相关但非直接对应(相关实现路径)
@@ -232,6 +239,7 @@ relevance_evaluation_instructions = """
 0: 没有明确目的,动作意图无明确关联
   - 例: 原始问题"如何获取素材" vs sug词"摄影器材推荐"
   - 例: 原始问题无法识别动机 且 sug词也无明确动作 → 0
+  - 如果原始问题无法识别动机,则动机维度得分为0。
 
 【负向偏离】
 -0.2~-0.05: 动作意图轻度冲突或误导
@@ -243,30 +251,90 @@ relevance_evaluation_instructions = """
 -1.0~-0.55: 动作意图完全相反或产生严重负面引导
   - 例: 原始问题"免费素材获取" vs sug词"付费素材强制推销"
 
-维度2: 品类维度评估(权重30%)
+---
+
+# 输出要求
+
+输出结果必须为一个 **JSON 格式**,包含以下内容:
+```json
+{
+  "原始问题核心动机提取": {
+    "简要说明核心动机": ""
+  },
+  "动机维度得分": "-1到1之间的小数",
+  "简要说明动机维度相关度理由": "评估该sug词条与原始问题动机匹配程度的理由"
+}
+```
+
+#注意事项:
+始终围绕动机维度:所有评估都基于"动机"维度,不偏离
+核心动机必须是动词:在评估前,必须先提取原始问题的核心动机(动词),这是整个评估的基础
+严格标准一致性:对所有用例使用相同的评估标准,避免评分飘移
+负分使用原则:仅当sug词条对原始问题动机产生误导、冲突或有害引导时给予负分
+零分使用原则:当sug词条与原始问题动机无明确关联,既不相关也不冲突时给予零分,或原始问题无法识别动机时。
+""".strip()
+
+# 品类评估 prompt
+category_evaluation_instructions = """
+#角色
+你是一个 **专业的语言专家和语义相关性评判专家**。你的任务是:判断我给你的 <平台sug词条> 与 <原始问题> 的内容主体和限定词匹配度,给出 **-1 到 1 之间** 的数值评分。
+
+---
+
+# 核心概念与方法论
+
+## 评估维度
+本评估系统围绕 **品类维度** 进行:
+
+### 2. 品类维度
+**定义:** 用户"关于什么内容",即原始问题的主题对象和限定词
+- 核心是 **名词+限定词**:川西秋季风光摄影素材
+- 包括:核心主体 + 地域限定 + 时间限定 + 质量限定等
+
+---
+
+# 输入信息
+你将接收到以下输入:
+- **<原始问题>**:用户的初始查询问题,代表用户的真实需求意图。
+- **<平台sug词条>**:平台推荐的词条列表,每个词条需要单独评估。
+
+
+#判定流程
+#评估架构
+
+输入: <原始问题> + <平台sug词条>
+         ↓
+【品类维度相关性判定】
+    ├→ 步骤1: 评估<sug词条>与<原始问题>的内容主体和限定词匹配度
+    └→ 输出: -1到1之间的数值 + 判定依据
+
+
+相关度评估维度详解
+维度2: 品类维度评估
 评估对象: <平台sug词条> 与 <原始问题> 的内容主体和限定词匹配度
 
 评分标准:
 
 【正向匹配】
-+1.0: 核心主体+所有关键限定词完全匹配
++0.95~1.0: 核心主体+所有关键限定词完全匹配
   - 例: 原始问题"川西秋季风光摄影素材" vs sug词"川西秋季风光摄影作品"
 
-+0.75~0.95: 核心主体匹配,大部分限定词匹配
++0.75~0.95: 核心主体匹配,存在限定词匹配
   - 例: 原始问题"川西秋季风光摄影素材" vs sug词"川西风光摄影素材"(缺失"秋季")
 
-+0.5~0.7: 核心主体匹配,少量限定词匹配或合理泛化
++0.5~0.75: 核心主体匹配,无限定词匹配或合理泛化
   - 例: 原始问题"川西秋季风光摄影素材" vs sug词"四川风光摄影"
 
-+0.2~0.45: 仅主体词匹配,限定词全部缺失或错位
++0.2~0.5: 主体词匹配,限定词缺失或错位
   - 例: 原始问题"川西秋季风光摄影素材" vs sug词"风光摄影入门"
 
-+0.05~0.15: 主题领域相关但品类不同
++0.05~0.2: 主体词不匹配,品类不同
   - 例: 原始问题"风光摄影素材" vs sug词"人文摄影素材"
 
 【中性/无关】
-0: 主体词部分相关但类别明显不同
+0: 类别明显不同,没有明确目的,无明确关联
   - 例: 原始问题"川西秋季风光摄影素材" vs sug词"人像摄影素材"
+  - 例: 原始问题无法识别动机 且 sug词也无明确动作 → 0
 
 【负向偏离】
 -0.2~-0.05: 主体词或限定词存在误导性
@@ -278,153 +346,39 @@ relevance_evaluation_instructions = """
 -1.0~-0.55: 完全错误的品类或有害引导
   - 例: 原始问题"正版素材获取" vs sug词"盗版素材下载"
 
-
-综合得分计算与规则调整
-步骤1: 应用依存性规则
-规则A: 动机高分保护机制
-
-如果 动机维度得分 ≥ 0.8:
-   → 品类得分即使为0或轻微负向(-0.2~0)
-   → 最终得分 = max(初步得分, 0.55)
-
-解释: 当目的高度一致时,品类的泛化不应导致"弱相关"
-
-规则B: 动机低分限制机制
-如果 动机维度得分 ≤ 0.2:
-   → 无论品类得分多高
-   → 最终得分 = min(初步得分, 0.4)
-
-解释: 目的不符时,品类匹配的价值有限
-
-规则C: 动机负向决定机制
-如果 动机维度得分 < 0:
-   → 最终得分 = min(初步得分, 0)
-
-解释: 动作意图冲突时,推荐具有误导性,不应为正相关
-
-步骤3: 输出最终得分
-
-#基础加权计算
-应用规则后的调整得分 = 目的动机维度得分 × 0.7 + 品类维度得分 × 0.3
-取值范围: -1.0 ~ +1.0
-
----
-
-# 得分档位解释
-
-高度相关】+0.8 ~ +1.0
-相关性高度契合,用户可直接使用
-动机和品类均高度匹配
-典型场景: 动机≥0.85 且 品类≥0.7
-【中高相关】+0.6 ~ +0.79
-相关性较好,用户基本满意
-动机匹配但品类有泛化,或反之
-典型场景: 动机≥0.8 且 品类≥0.3
-【中度相关】+0.3 ~ +0.59
-部分相关,用户需要调整搜索策略
-动机或品类存在一定偏差
-典型场景: 动机0.4-0.7 且 品类0.3-0.7
-【弱相关】+0.01 ~ +0.29
-关联微弱,参考价值有限
-仅有表层词汇重叠
-【无关】0
-无明确关联
-原始问题无法识别动机 且 sug词无明确动作
-没有目的性且没有品类匹配
-【轻度负向】-0.29 ~ -0.01
-产生轻微误导或干扰
-【中度负向】-0.69 ~ -0.3
-存在明显冲突或误导
-【严重负向】-1.0 ~ -0.7
-完全违背意图或产生有害引导
-
 ---
 
 # 输出要求
-输出结果必须为一个 **JSON 格式**,包含以下内容:
-
-#注意事项:
-始终围绕两个核心维度:所有评估都基于"动机"和"品类"两个维度,不偏离
-核心动机必须是动词:在评估前,必须先提取原始问题的核心动机(动词),这是整个评估的基础
-严格标准一致性:对所有用例使用相同的评估标准,避免评分飘移
-负分使用原则:仅当sug词条对原始问题产生误导、冲突或有害引导时给予负分
-零分使用原则:当sug词条与原始问题无明确关联,既不相关也不冲突时给予零分
-分维度独立评分:
-先提取原始问题核心动机
-分别计算动机维度(含两个子维度)和品类维度得分
-按70:30加权得到初步得分
-应用规则调整得到最终得分
-动机优先原则:当动机高度一致时,品类的合理泛化或具体化不应导致低评分
-技巧类需求特殊对待:包含"技巧/方法/教程"等词的需求,对动作一致性要求更严格
-
-## 输出格式(严格遵守)
-
-必须输出标准 JSON 格式,包含以下两个字段:
-
-```json
-{
-  "reason": "详细的评估理由说明",
-  "relevance_score": 0.85
-}
-```
-
-### 字段说明
-- **reason** (string): 详细的评估理由,说明动机维度和品类维度的匹配情况
-- **relevance_score** (number): -1.0 到 1.0 之间的数值,保留2位小数
-
-### 重要约束
-1. **reason 字段内容规则**:
-   - 禁止使用英文双引号 `"`,必须使用替代符号
-   - 推荐使用中文书名号:《》或【】
-   - 或使用中文引号:「」或『』
-   - 示例:使用"核心动机是《制作攻略图》"而不是"核心动机是"制作攻略图""
-
-2. **JSON 格式要求**:
-   - 必须是合法的 JSON 格式
-   - relevance_score 必须是数字类型,不能是字符串
-   - 字段名必须用双引号包裹
 
-### 输出示例
-
-✅ **正确示例**:
-```json
-{
-  "reason": "原始问题的核心动机是《制作攻略图》,包含【拼接】图片等操作。sug词条【拼接】与原始问题中的具体操作完全一致,动机维度匹配度为中等。品类维度相关性较弱。",
-  "relevance_score": 0.22
-}
-```
-
-❌ **错误示例**(会导致解析失败):
+输出结果必须为一个 **JSON 格式**,包含以下内容:
 ```json
 {
-  "reason": "原始问题的核心动机是"制作攻略图",包含"拼接"图片",
-  "relevance_score": "0.22"
+  "品类维度得分": "-1到1之间的小数",
+  "简要说明品类维度相关度理由": "评估该sug词条与原始问题品类匹配程度的理由"
 }
 ```
-错误原因:reason 中使用了未转义的英文双引号,relevance_score 是字符串而非数字
-
-## 关键要求(务必遵守)
-
-**无论reason多长,必须确保输出完整的JSON格式:**
-1. reason字段必须有结束的双引号 `"`
-2. 必须包含 `relevance_score` 字段
-3. JSON必须有完整的闭合大括号 `}`
-4. 不能中途截断输出
+---
 
-**示例:即使reason很长也要完整输出**
-```json
-{
-  "reason": "这里可以写很长的详细推理过程,包括动机维度的详细分析、品类维度的详细分析、规则应用过程等等...",
-  "relevance_score": 0.45
-}
-```
+#注意事项:
+始终围绕品类维度:所有评估都基于"品类"维度,不偏离
+严格标准一致性:对所有用例使用相同的评估标准,避免评分飘移
+负分使用原则:仅当sug词条对原始问题品类产生误导、冲突或有害引导时给予负分
+零分使用原则:当sug词条与原始问题品类无明确关联,既不相关也不冲突时给予零分
 """.strip()
 
-relevance_evaluator = Agent[None](
-    name="相关度评估专家",
-    instructions=relevance_evaluation_instructions,
+# 创建两个评估 Agent
+motivation_evaluator = Agent[None](
+    name="动机维度评估专家",
+    instructions=motivation_evaluation_instructions,
+    model=get_model(MODEL_NAME),
+    output_type=MotivationEvaluation,
+)
+
+category_evaluator = Agent[None](
+    name="品类维度评估专家",
+    instructions=category_evaluation_instructions,
     model=get_model(MODEL_NAME),
-    output_type=RelevanceEvaluation,
+    output_type=CategoryEvaluation,
 )
 
 
@@ -491,6 +445,43 @@ word_selector = Agent[None](
 # 辅助函数
 # ============================================================================
 
+def calculate_final_score(motivation_score: float, category_score: float) -> float:
+    """
+    应用依存性规则计算最终得分
+
+    步骤1: 基础加权计算
+    base_score = motivation_score * 0.7 + category_score * 0.3
+
+    步骤2: 极值保护规则
+
+    Args:
+        motivation_score: 动机维度得分 -1~1
+        category_score: 品类维度得分 -1~1
+
+    Returns:
+        最终得分 -1~1
+    """
+    # 基础加权得分
+    base_score = motivation_score * 0.7 + category_score * 0.3
+
+    # 规则C: 动机负向决定机制(最高优先级)
+    if motivation_score < 0:
+        return 0.0
+
+    # 规则A: 动机高分保护机制
+    if motivation_score >= 0.8:
+        # 当目的高度一致时,品类的泛化不应导致"弱相关"
+        return max(base_score, 0.7)
+
+    # 规则B: 动机低分限制机制
+    if motivation_score <= 0.2:
+        # 目的不符时,品类匹配的价值有限
+        return min(base_score, 0.5)
+
+    # 无规则调整,返回基础得分
+    return base_score
+
+
 def process_note_data(note: dict) -> Post:
     """处理搜索接口返回的帖子数据"""
     note_card = note.get("note_card", {})
@@ -557,23 +548,73 @@ def process_note_data(note: dict) -> Post:
 async def evaluate_with_o(text: str, o: str) -> tuple[float, str]:
     """评估文本与原始问题o的相关度
 
+    采用两阶段评估 + 代码计算规则:
+    1. 动机维度评估(权重70%)
+    2. 品类维度评估(权重30%)
+    3. 应用规则A/B/C调整得分
+
     Returns:
-        tuple[float, str]: (相关度分数, 评估理由)
+        tuple[float, str]: (最终相关度分数, 综合评估理由)
     """
+    # 准备输入
     eval_input = f"""
 <原始问题>
 {o}
 </原始问题>
 
-<当前文本>
+<平台sug词条>
 {text}
-</当前文本>
+</平台sug词条>
 
-请评估当前文本与原始问题的相关度。
+请评估平台sug词条与原始问题的匹配度。
 """
-    result = await Runner.run(relevance_evaluator, eval_input)
-    evaluation: RelevanceEvaluation = result.final_output
-    return evaluation.relevance_score, evaluation.reason
+
+    # 并发调用两个评估器
+    motivation_task = Runner.run(motivation_evaluator, eval_input)
+    category_task = Runner.run(category_evaluator, eval_input)
+
+    motivation_result, category_result = await asyncio.gather(
+        motivation_task,
+        category_task
+    )
+
+    # 获取评估结果
+    motivation_eval: MotivationEvaluation = motivation_result.final_output
+    category_eval: CategoryEvaluation = category_result.final_output
+
+    # 提取得分
+    motivation_score = motivation_eval.动机维度得分
+    category_score = category_eval.品类维度得分
+
+    # 计算基础得分
+    base_score = motivation_score * 0.7 + category_score * 0.3
+
+    # 应用规则计算最终得分
+    final_score = calculate_final_score(motivation_score, category_score)
+
+    # 组合评估理由
+    core_motivation = motivation_eval.原始问题核心动机提取.简要说明核心动机
+    motivation_reason = motivation_eval.简要说明动机维度相关度理由
+    category_reason = category_eval.简要说明品类维度相关度理由
+
+    combined_reason = (
+        f"【核心动机】{core_motivation}\n"
+        f"【动机维度 {motivation_score:.2f}】{motivation_reason}\n"
+        f"【品类维度 {category_score:.2f}】{category_reason}\n"
+        f"【基础得分 {base_score:.2f}】= 动机({motivation_score:.2f})*0.7 + 品类({category_score:.2f})*0.3\n"
+        f"【最终得分 {final_score:.2f}】"
+    )
+
+    # 如果应用了规则,添加规则说明
+    if final_score != base_score:
+        if motivation_score < 0:
+            combined_reason += "(应用规则C:动机负向决定机制)"
+        elif motivation_score >= 0.8:
+            combined_reason += "(应用规则A:动机高分保护机制)"
+        elif motivation_score <= 0.2:
+            combined_reason += "(应用规则B:动机低分限制机制)"
+
+    return final_score, combined_reason
 
 
 # ============================================================================