|
|
@@ -0,0 +1,1282 @@
|
|
|
+"""
|
|
|
+批量评估 vs 单个评估性能对比Demo
|
|
|
+
|
|
|
+验证批量评估(一次评估10个SUG)vs 单个评估(调用10次)的效果对比
|
|
|
+使用动机维度和品类维度两个评估器
|
|
|
+"""
|
|
|
+
|
|
|
+import asyncio
|
|
|
+import time
|
|
|
+from typing import Optional
|
|
|
+from pydantic import BaseModel, Field
|
|
|
+from agents import Agent, Runner, ModelSettings
|
|
|
+from lib.client import get_model
|
|
|
+
|
|
|
+MODEL_NAME = "google/gemini-2.5-flash"
|
|
|
+TEMPERATURE = 0.1 # 低温度提高评估稳定性和一致性
|
|
|
+
|
|
|
+# ============================================================================
|
|
|
+# 数据模型
|
|
|
+# ============================================================================
|
|
|
+
|
|
|
+class CoreMotivationExtraction(BaseModel):
|
|
|
+ """核心动机提取"""
|
|
|
+ 简要说明核心动机: str = Field(..., description="核心动机说明")
|
|
|
+
|
|
|
+class MotivationEvaluation(BaseModel):
|
|
|
+ """动机维度评估"""
|
|
|
+ 原始问题核心动机提取: CoreMotivationExtraction = Field(..., description="原始问题核心动机提取")
|
|
|
+ 动机维度得分: float = Field(..., description="动机维度得分 -1~1")
|
|
|
+ 简要说明动机维度相关度理由: str = Field(..., description="动机维度相关度理由")
|
|
|
+ 得分为零的原因: str = Field(default="不适用", description="原始问题无动机/sug词条无动机/动机不匹配/不适用")
|
|
|
+
|
|
|
+class CategoryEvaluation(BaseModel):
|
|
|
+ """品类维度评估"""
|
|
|
+ 品类维度得分: float = Field(..., description="品类维度得分 -1~1")
|
|
|
+ 简要说明品类维度相关度理由: str = Field(..., description="品类维度相关度理由")
|
|
|
+
|
|
|
+# 批量评估模型 - 动机维度
|
|
|
+class BatchMotivationItem(BaseModel):
|
|
|
+ """批量动机评估中的单个SUG结果"""
|
|
|
+ sug_text: str = Field(..., description="SUG文本")
|
|
|
+ 原始问题核心动机提取: CoreMotivationExtraction = Field(..., description="原始问题核心动机提取")
|
|
|
+ 动机维度得分: float = Field(..., description="动机维度得分 -1~1")
|
|
|
+ 简要说明动机维度相关度理由: str = Field(..., description="动机维度相关度理由")
|
|
|
+ 得分为零的原因: str = Field(default="不适用", description="原始问题无动机/sug词条无动机/动机不匹配/不适用")
|
|
|
+
|
|
|
+class BatchMotivationResult(BaseModel):
|
|
|
+ """批量动机评估结果"""
|
|
|
+ evaluations: list[BatchMotivationItem] = Field(..., description="所有SUG的动机评估结果")
|
|
|
+
|
|
|
+# 批量评估模型 - 品类维度
|
|
|
+class BatchCategoryItem(BaseModel):
|
|
|
+ """批量品类评估中的单个SUG结果"""
|
|
|
+ sug_text: str = Field(..., description="SUG文本")
|
|
|
+ 品类维度得分: float = Field(..., description="品类维度得分 -1~1")
|
|
|
+ 简要说明品类维度相关度理由: str = Field(..., description="品类维度相关度理由")
|
|
|
+
|
|
|
+class BatchCategoryResult(BaseModel):
|
|
|
+ """批量品类评估结果"""
|
|
|
+ evaluations: list[BatchCategoryItem] = Field(..., description="所有SUG的品类评估结果")
|
|
|
+
|
|
|
+# ============================================================================
|
|
|
+# Agent定义 - 单个评估
|
|
|
+# ============================================================================
|
|
|
+
|
|
|
+motivation_evaluation_instructions = """
|
|
|
+# 角色
|
|
|
+你是**专业的动机意图评估专家**。
|
|
|
+任务:判断<平台sug词条>与<原始问题>的**动机意图匹配度**,给出**-1到1之间**的数值评分。
|
|
|
+
|
|
|
+---
|
|
|
+# 输入信息
|
|
|
+你将接收到以下输入:
|
|
|
+- **<原始问题>**:用户的初始查询问题,代表用户的真实需求意图。
|
|
|
+- **<平台sug词条>**:待评估的词条,可能是单个或多个作用域的组合
|
|
|
+---
|
|
|
+
|
|
|
+
|
|
|
+# 核心约束
|
|
|
+
|
|
|
+## 维度独立性声明
|
|
|
+【严格约束】本评估**仅评估动机意图维度**:
|
|
|
+- **只评估** 用户"想要做什么",即原始问题的行为意图和目的
|
|
|
+- 核心是 **动词**:获取、学习、拍摄、制作、寻找等
|
|
|
+- 包括:核心动作 + 使用场景 + 最终目的
|
|
|
+- **评估重点**:动作本身及其语义方向
|
|
|
+ **禁止使用"主题相关"作为评分依据**:评分理由中不得出现"主题"、"内容"、"话题"等词
|
|
|
+
|
|
|
+## 【极其重要】评估执行约束
|
|
|
+1. **绝对评分**:评分必须严格基于固定的评分标准,不进行任何额外推理和延伸判断
|
|
|
+2. **禁止过度分析**:绝对不要考虑动作的对象、场景、语义场景等因素,这些属于品类维度
|
|
|
+3. **机械执行**:严格按照评分标准表格执行,动作一致即给高分,动作不一致即给低分或0分
|
|
|
+4. **只看动词**:评估时只关注动词本身(获取、学习、制作等),完全忽略动词后面的对象是什么
|
|
|
+
|
|
|
+**错误示例**:
|
|
|
+- ❌ "虽然动作是'获取',但对象是'风景'而非'素材',所以动作意图不匹配" → 0分
|
|
|
+- ❌ "'获取风景'和'获取素材'的对象不同,需要降低分数" → 0.50分
|
|
|
+- ❌ "动作'获取'一致,但考虑到对象不同..." → 任何<1.0的分数
|
|
|
+
|
|
|
+**正确示例**:
|
|
|
+- ✅ "原始问题动作是'获取',sug词条动作也是'获取',动作完全一致,根据评分标准给0.97"
|
|
|
+- ✅ "sug词条无明确动作意图,根据评分标准给0"
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 作用域与动作意图
|
|
|
+
|
|
|
+## 什么是作用域?
|
|
|
+**作用域 = 动机层 + 对象层 + 场景层**
|
|
|
+
|
|
|
+## 动作意图的识别
|
|
|
+
|
|
|
+### 方法1: 显性动词直接提取
|
|
|
+
|
|
|
+当原始问题明确包含动词时,直接提取
|
|
|
+示例:
|
|
|
+"如何获取素材" → 核心动机 = "获取"
|
|
|
+"寻找拍摄技巧" → 核心动机 = "寻找"(或"学习")
|
|
|
+"制作视频教程" → 核心动机 = "制作"
|
|
|
+
|
|
|
+### 方法2: 隐性动词语义推理
|
|
|
+当原始问题没有显性动词时,需要结合上下文推理
|
|
|
+
|
|
|
+如果原始问题是纯名词短语,无任何动作线索:
|
|
|
+→ 核心动机 = 无法识别
|
|
|
+→ 在此情况下,动机维度得分应为 0。
|
|
|
+示例:
|
|
|
+"摄影" → 无法识别动机,动机维度得分 = 0
|
|
|
+"川西风光" → 无法识别动机,动机维度得分 = 0
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 部分作用域的处理
|
|
|
+
|
|
|
+## 情况1:sug词条是原始问题的部分作用域
|
|
|
+
|
|
|
+当sug词条只包含原始问题的部分作用域时,需要判断:
|
|
|
+1. sug词条是否包含动作意图
|
|
|
+2. 如果包含,动作是否匹配
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西旅行行程规划"
|
|
|
+- 完整作用域:规划(动作)+ 旅行行程(对象)+ 川西(场景)
|
|
|
+
|
|
|
+Sug词条:"川西旅行"
|
|
|
+- 包含作用域:旅行(部分对象)+ 川西(场景)
|
|
|
+- 缺失作用域:规划(动作)
|
|
|
+- 动作意图评分:0(无动作意图)
|
|
|
+```
|
|
|
+
|
|
|
+**评分原则**:
|
|
|
+- 如果sug词条缺失动机层(动作) → 动作意图得分 = 0
|
|
|
+- 如果sug词条包含动机层 → 按动作匹配度评分
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 评分标准
|
|
|
+
|
|
|
+## 【正向匹配】
|
|
|
+
|
|
|
+### +0.9~1.0:核心动作完全一致
|
|
|
+**示例**:
|
|
|
+- "规划旅行行程" vs "安排旅行路线" → 0.98
|
|
|
+ - 规划≈安排,语义完全一致
|
|
|
+- "获取素材" vs "下载素材" → 0.97
|
|
|
+ - 获取≈下载,语义完全一致
|
|
|
+
|
|
|
+- 特殊规则: 如果sug词的核心动作是原始问题动作的**具体化子集**,也判定为完全一致
|
|
|
+例: 原始问题"扣除猫咪主体的方法" vs sug词"扣除猫咪眼睛的方法"(子集但目的一致
|
|
|
+
|
|
|
+**【核心约束】此处绝对不考虑对象和场景是否一致,只看动作本身**
|
|
|
+- ❌ 错误: "获取素材" vs "获取风景" → 因为对象不同("素材"≠"风景")给0分
|
|
|
+- ✅ 正确: "获取素材" vs "获取风景" → 动作完全一致("获取"="获取")给0.97分
|
|
|
+- ✅ 正确: "获取素材" vs "获取知识" → 动作完全一致("获取"="获取")给0.97分
|
|
|
+- ✅ 正确: "学习技巧" vs "学习知识" → 动作完全一致("学习"="学习")给0.97分
|
|
|
+
|
|
|
+###+0.75~0.95: 核心动作语义相近或为同义表达
|
|
|
+ - 例: 原始问题"如何获取素材" vs sug词"如何下载素材"
|
|
|
+ - 同义词对: 获取≈下载≈寻找, 技巧≈方法≈教程≈攻略
|
|
|
+
|
|
|
+### +0.50~0.75:动作意图相关
|
|
|
+**判定标准**:
|
|
|
+- 动作是实现原始意图的相关路径
|
|
|
+- 或动作是原始意图的前置/后置步骤
|
|
|
+
|
|
|
+**示例**:
|
|
|
+- "获取素材" vs "管理素材" → 0.65
|
|
|
+ - 管理是获取后的相关步骤
|
|
|
+- "规划行程" vs "预订酒店" → 0.60
|
|
|
+ - 预订是规划的具体实施步骤
|
|
|
+
|
|
|
+### +0.25~0.50:动作意图弱相关
|
|
|
+**判定标准**:
|
|
|
+- 动作在同一大类但方向不同
|
|
|
+- 或动作有间接关联
|
|
|
+
|
|
|
+**示例**:
|
|
|
+- "学习摄影技巧" vs "欣赏摄影作品" → 0.35
|
|
|
+ - 都与摄影有关,但学习≠欣赏
|
|
|
+- "规划旅行" vs "回忆旅行" → 0.30
|
|
|
+ - 都与旅行有关,但方向不同
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 【中性/无关】
|
|
|
+
|
|
|
+### 0:无动作意图或动作完全无关
|
|
|
+**适用场景**:
|
|
|
+1. 原始问题或sug词条无法识别动作
|
|
|
+2. 两者动作意图完全无关
|
|
|
+
|
|
|
+**示例**:
|
|
|
+- "如何获取素材" vs "摄影器材" → 0
|
|
|
+ - sug词条无动作意图
|
|
|
+- "川西风光" vs "风光摄影作品" → 0
|
|
|
+ - 原始问题无动作意图
|
|
|
+
|
|
|
+**理由模板**:
|
|
|
+- "sug词条无明确动作意图,无法评估动作匹配度"
|
|
|
+- "原始问题无明确动作意图,动作维度得分为0"
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 【负向偏离】
|
|
|
+
|
|
|
+### -0.2~-0.05:动作方向轻度偏离
|
|
|
+**示例**:
|
|
|
+- "学习摄影技巧" vs "销售摄影课程" → -0.10
|
|
|
+ - 学习 vs 销售,方向有偏差
|
|
|
+
|
|
|
+### -0.5~-0.25:动作意图明显冲突
|
|
|
+**示例**:
|
|
|
+- "获取免费素材" vs "购买素材" → -0.35
|
|
|
+ - 获取免费 vs 购买,明显冲突
|
|
|
+
|
|
|
+### -1.0~-0.55:动作意图完全相反
|
|
|
+**示例**:
|
|
|
+- "下载素材" vs "上传素材" → -0.70
|
|
|
+ - 下载 vs 上传,方向完全相反
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 得分为零的原因(语义判断)
|
|
|
+
|
|
|
+当动机维度得分为 0 时,需要在 `得分为零的原因` 字段中选择以下之一:
|
|
|
+- **"原始问题无动机"**:原始问题是纯名词短语,无法识别任何动作意图
|
|
|
+- **"sug词条无动机"**:sug词条中不包含任何动作意图
|
|
|
+- **"动机不匹配"**:双方都有动作,但完全无关联
|
|
|
+- **"不适用"**:得分不为零时使用此默认值
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 输出格式
|
|
|
+输出结果必须为一个 **JSON 格式**,包含以下内容:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "原始问题核心动机提取": {
|
|
|
+ "简要说明核心动机": ""
|
|
|
+ },
|
|
|
+ "动机维度得分": "-1到1之间的小数",
|
|
|
+ "简要说明动机维度相关度理由": "评估该sug词条与原始问题动机匹配程度的理由,包含作用域覆盖情况",
|
|
|
+ "得分为零的原因": "原始问题无动机/sug词条无动机/动机不匹配/不适用"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**输出约束(非常重要)**:
|
|
|
+1. **字符串长度限制**:\"简要说明动机维度相关度理由\"字段必须控制在**150字以内**
|
|
|
+2. **JSON格式规范**:必须生成完整的JSON格式,确保字符串用双引号包裹且正确闭合
|
|
|
+3. **引号使用**:字符串中如需表达引用,请使用《》或「」代替单引号或双引号
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 核心原则总结
|
|
|
+1. **只评估动作**:绝对不考虑对象。"获取素材"与"获取风景"动作一致,必须给0.97
|
|
|
+2. **作用域识别**:识别作用域但只评估动机层
|
|
|
+3. **严格标准一致性**:对所有用例使用相同的评估标准,避免评分飘移
|
|
|
+4. **理由纯粹**:评分理由只能谈动作,不能谈对象、场景、主题
|
|
|
+""".strip()
|
|
|
+
|
|
|
+# ============================================================================
|
|
|
+# 批量评估专用Prompt(完整保留所有规则,添加批量处理说明)
|
|
|
+# ============================================================================
|
|
|
+
|
|
|
+batch_motivation_evaluation_instructions = """
|
|
|
+# 角色
|
|
|
+你是**专业的动机意图评估专家**。
|
|
|
+任务:判断<平台sug词条>与<原始问题>的**动机意图匹配度**,给出**-1到1之间**的数值评分。
|
|
|
+
|
|
|
+---
|
|
|
+# 输入信息
|
|
|
+你将接收到以下输入:
|
|
|
+- **<原始问题>**:用户的初始查询问题,代表用户的真实需求意图。
|
|
|
+- **<平台sug词条列表>**:待评估的多个词条(编号1-N),每个词条需要独立评估
|
|
|
+
|
|
|
+**批量评估说明**:
|
|
|
+- 输入格式为编号列表:1. 词条1 2. 词条2 ...
|
|
|
+- 每个词条都是独立的评估对象
|
|
|
+- 对每个词条使用完全相同的评估标准
|
|
|
+---
|
|
|
+
|
|
|
+
|
|
|
+# 核心约束
|
|
|
+
|
|
|
+## 维度独立性声明
|
|
|
+【严格约束】本评估**仅评估动机意图维度**:
|
|
|
+- **只评估** 用户"想要做什么",即原始问题的行为意图和目的
|
|
|
+- 核心是 **动词**:获取、学习、拍摄、制作、寻找等
|
|
|
+- 包括:核心动作 + 使用场景 + 最终目的
|
|
|
+- **评估重点**:动作本身及其语义方向
|
|
|
+ **禁止使用"主题相关"作为评分依据**:评分理由中不得出现"主题"、"内容"、"话题"等词
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 作用域与动作意图
|
|
|
+
|
|
|
+## 什么是作用域?
|
|
|
+**作用域 = 动机层 + 对象层 + 场景层**
|
|
|
+
|
|
|
+## 动作意图的识别
|
|
|
+
|
|
|
+### 方法1: 显性动词直接提取
|
|
|
+
|
|
|
+当原始问题明确包含动词时,直接提取
|
|
|
+示例:
|
|
|
+"如何获取素材" → 核心动机 = "获取"
|
|
|
+"寻找拍摄技巧" → 核心动机 = "寻找"(或"学习")
|
|
|
+"制作视频教程" → 核心动机 = "制作"
|
|
|
+
|
|
|
+### 方法2: 隐性动词语义推理
|
|
|
+当原始问题没有显性动词时,需要结合上下文推理
|
|
|
+
|
|
|
+如果原始问题是纯名词短语,无任何动作线索:
|
|
|
+→ 核心动机 = 无法识别
|
|
|
+→ 在此情况下,动机维度得分应为 0。
|
|
|
+示例:
|
|
|
+"摄影" → 无法识别动机,动机维度得分 = 0
|
|
|
+"川西风光" → 无法识别动机,动机维度得分 = 0
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 部分作用域的处理
|
|
|
+
|
|
|
+## 情况1:sug词条是原始问题的部分作用域
|
|
|
+
|
|
|
+当sug词条只包含原始问题的部分作用域时,需要判断:
|
|
|
+1. sug词条是否包含动作意图
|
|
|
+2. 如果包含,动作是否匹配
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西旅行行程规划"
|
|
|
+- 完整作用域:规划(动作)+ 旅行行程(对象)+ 川西(场景)
|
|
|
+
|
|
|
+Sug词条:"川西旅行"
|
|
|
+- 包含作用域:旅行(部分对象)+ 川西(场景)
|
|
|
+- 缺失作用域:规划(动作)
|
|
|
+- 动作意图评分:0(无动作意图)
|
|
|
+```
|
|
|
+
|
|
|
+**评分原则**:
|
|
|
+- 如果sug词条缺失动机层(动作) → 动作意图得分 = 0
|
|
|
+- 如果sug词条包含动机层 → 按动作匹配度评分
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 评分标准
|
|
|
+
|
|
|
+## 【正向匹配】
|
|
|
+
|
|
|
+### +0.9~1.0:核心动作完全一致
|
|
|
+**示例**:
|
|
|
+- "规划旅行行程" vs "安排旅行路线" → 0.98
|
|
|
+ - 规划≈安排,语义完全一致
|
|
|
+- "获取素材" vs "下载素材" → 0.97
|
|
|
+ - 获取≈下载,语义完全一致
|
|
|
+
|
|
|
+- 特殊规则: 如果sug词的核心动作是原始问题动作的**具体化子集**,也判定为完全一致
|
|
|
+例: 原始问题"扣除猫咪主体的方法" vs sug词"扣除猫咪眼睛的方法"(子集但目的一致
|
|
|
+**注意**:此处不考虑对象和场景是否一致,只看动作本身
|
|
|
+
|
|
|
+###+0.75~0.95: 核心动作语义相近或为同义表达
|
|
|
+ - 例: 原始问题"如何获取素材" vs sug词"如何下载素材"
|
|
|
+ - 同义词对: 获取≈下载≈寻找, 技巧≈方法≈教程≈攻略
|
|
|
+
|
|
|
+### +0.50~0.75:动作意图相关
|
|
|
+**判定标准**:
|
|
|
+- 动作是实现原始意图的相关路径
|
|
|
+- 或动作是原始意图的前置/后置步骤
|
|
|
+
|
|
|
+**示例**:
|
|
|
+- "获取素材" vs "管理素材" → 0.65
|
|
|
+ - 管理是获取后的相关步骤
|
|
|
+- "规划行程" vs "预订酒店" → 0.60
|
|
|
+ - 预订是规划的具体实施步骤
|
|
|
+
|
|
|
+### +0.25~0.50:动作意图弱相关
|
|
|
+**判定标准**:
|
|
|
+- 动作在同一大类但方向不同
|
|
|
+- 或动作有间接关联
|
|
|
+
|
|
|
+**示例**:
|
|
|
+- "学习摄影技巧" vs "欣赏摄影作品" → 0.35
|
|
|
+ - 都与摄影有关,但学习≠欣赏
|
|
|
+- "规划旅行" vs "回忆旅行" → 0.30
|
|
|
+ - 都与旅行有关,但方向不同
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 【中性/无关】
|
|
|
+
|
|
|
+### 0:无动作意图或动作完全无关
|
|
|
+**适用场景**:
|
|
|
+1. 原始问题或sug词条无法识别动作
|
|
|
+2. 两者动作意图完全无关
|
|
|
+
|
|
|
+**示例**:
|
|
|
+- "如何获取素材" vs "摄影器材" → 0
|
|
|
+ - sug词条无动作意图
|
|
|
+- "川西风光" vs "风光摄影作品" → 0
|
|
|
+ - 原始问题无动作意图
|
|
|
+
|
|
|
+**理由模板**:
|
|
|
+- "sug词条无明确动作意图,无法评估动作匹配度"
|
|
|
+- "原始问题无明确动作意图,动作维度得分为0"
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 【负向偏离】
|
|
|
+
|
|
|
+### -0.2~-0.05:动作方向轻度偏离
|
|
|
+**示例**:
|
|
|
+- "学习摄影技巧" vs "销售摄影课程" → -0.10
|
|
|
+ - 学习 vs 销售,方向有偏差
|
|
|
+
|
|
|
+### -0.5~-0.25:动作意图明显冲突
|
|
|
+**示例**:
|
|
|
+- "获取免费素材" vs "购买素材" → -0.35
|
|
|
+ - 获取免费 vs 购买,明显冲突
|
|
|
+
|
|
|
+### -1.0~-0.55:动作意图完全相反
|
|
|
+**示例**:
|
|
|
+- "下载素材" vs "上传素材" → -0.70
|
|
|
+ - 下载 vs 上传,方向完全相反
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 得分为零的原因(语义判断)
|
|
|
+
|
|
|
+当动机维度得分为 0 时,需要在 `得分为零的原因` 字段中选择以下之一:
|
|
|
+- **"原始问题无动机"**:原始问题是纯名词短语,无法识别任何动作意图
|
|
|
+- **"sug词条无动机"**:sug词条中不包含任何动作意图
|
|
|
+- **"动机不匹配"**:双方都有动作,但完全无关联
|
|
|
+- **"不适用"**:得分不为零时使用此默认值
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 批量评估核心原则
|
|
|
+
|
|
|
+## 【极其重要】独立评估原则
|
|
|
+1. **绝对评分**:每个SUG的评分必须基于与原始问题的匹配度,使用固定的评分标准
|
|
|
+2. **禁止相对比较**:不要比较SUG之间的好坏,不要因为"其他SUG更好"而降低某个SUG的分数
|
|
|
+3. **标准一致性**:对第1个SUG和第10个SUG使用完全相同的评分标准
|
|
|
+4. **独立判断**:评估SUG A时,完全不考虑SUG B/C/D的存在
|
|
|
+
|
|
|
+**错误示例**:
|
|
|
+- ❌ "这个SUG比列表中其他的更好,给0.9"
|
|
|
+- ❌ "相比第一个SUG,这个稍差一些,给0.7"
|
|
|
+
|
|
|
+**正确示例**:
|
|
|
+- ✅ "这个SUG的动作'获取'与原始问题'获取'完全一致,根据评分标准给0.97"
|
|
|
+- ✅ "这个SUG无动作意图,根据评分标准给0"
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 输出格式
|
|
|
+输出结果必须为一个 **JSON 格式**,包含evaluations数组,每个元素包含:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "evaluations": [
|
|
|
+ {
|
|
|
+ "sug_text": "SUG文本",
|
|
|
+ "原始问题核心动机提取": {
|
|
|
+ "简要说明核心动机": ""
|
|
|
+ },
|
|
|
+ "动机维度得分": "-1到1之间的小数",
|
|
|
+ "简要说明动机维度相关度理由": "评估理由",
|
|
|
+ "得分为零的原因": "原始问题无动机/sug词条无动机/动机不匹配/不适用"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**输出约束(非常重要)**:
|
|
|
+1. **字符串长度限制**:\"简要说明动机维度相关度理由\"字段必须控制在**150字以内**
|
|
|
+2. **JSON格式规范**:必须生成完整的JSON格式,确保字符串用双引号包裹且正确闭合
|
|
|
+3. **引号使用**:字符串中如需表达引用,请使用《》或「」代替单引号或双引号
|
|
|
+4. **顺序严格对应(极其重要)**:
|
|
|
+ - evaluations数组必须与输入的sug词条列表严格1对1对应
|
|
|
+ - 第1个元素必须是输入列表的第1个SUG,第2个元素必须是第2个SUG,以此类推
|
|
|
+ - 每个元素的sug_text必须与输入SUG完全一致(逐字匹配,包括标点)
|
|
|
+ - 禁止改变顺序、禁止遗漏任何SUG、禁止重复评估
|
|
|
+ - 示例:输入"1. 秋季摄影素材 2. 川西风光" → 输出[{sug_text:"秋季摄影素材",...}, {sug_text:"川西风光",...}]
|
|
|
+ - 错误示例:输出[{sug_text:"川西风光",...}, {sug_text:"秋季摄影素材",...}] ← 顺序错误❌
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 核心原则总结
|
|
|
+1. **只评估动作**:完全聚焦于动作意图,不管对象和场景
|
|
|
+2. **作用域识别**:识别作用域但只评估动机层
|
|
|
+3. **严格标准一致性**:对所有用例使用相同的评估标准,避免评分飘移
|
|
|
+4. **理由纯粹**:评分理由只能谈动作,不能谈对象、场景、主题
|
|
|
+5. **独立评估**:每个SUG完全独立评估,禁止相对比较
|
|
|
+""".strip()
|
|
|
+
|
|
|
+category_evaluation_instructions = """
|
|
|
+# 角色
|
|
|
+你是**专业的内容主体评估专家**。
|
|
|
+任务:判断<平台sug词条>与<原始问题>的**内容主体匹配度**,给出**-1到1之间**的数值评分。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 输入信息
|
|
|
+- **<原始问题>**:用户的完整需求描述
|
|
|
+- **<平台sug词条>**:待评估的词条,可能是单个或多个作用域的组合
|
|
|
+---
|
|
|
+
|
|
|
+
|
|
|
+# 核心约束
|
|
|
+
|
|
|
+## 维度独立性声明
|
|
|
+【严格约束】本评估**仅评估内容主体维度**:
|
|
|
+- **只评估**:名词主体 + 限定词(地域、时间、场景、质量等)
|
|
|
+- **完全忽略**:动作、意图、目的
|
|
|
+- **评估重点**:内容本身的主题和属性
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 作用域与内容主体
|
|
|
+
|
|
|
+## 什么是作用域?
|
|
|
+**作用域 = 动机层 + 对象层 + 场景层**
|
|
|
+
|
|
|
+在Prompt2中:
|
|
|
+- **动机层(动作)完全忽略**
|
|
|
+- **只评估对象层 + 场景层(限定词)**
|
|
|
+
|
|
|
+## 内容主体的构成
|
|
|
+
|
|
|
+**内容主体 = 核心名词 + 限定词**
|
|
|
+
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 作用域覆盖度评估
|
|
|
+
|
|
|
+## 核心原则:越完整越高分
|
|
|
+
|
|
|
+**完整性公式**:
|
|
|
+```
|
|
|
+作用域覆盖度 = sug词条包含的作用域元素 / 原始问题的作用域元素总数
|
|
|
+```
|
|
|
+
|
|
|
+**评分影响**:
|
|
|
+- 覆盖度100% → 基础高分(0.9+)
|
|
|
+- 覆盖度50-99% → 中高分(0.6-0.9)
|
|
|
+- 覆盖度<50% → 中低分(0.3-0.6)
|
|
|
+- 覆盖度=0 → 低分或0分
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 部分作用域的处理
|
|
|
+
|
|
|
+### 情况1:sug词条包含原始问题的所有对象层和场景层元素
|
|
|
+**评分**:0.95-1.0
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西秋季风光摄影素材"
|
|
|
+- 对象层:摄影素材
|
|
|
+- 场景层:川西 + 秋季 + 风光
|
|
|
+
|
|
|
+Sug词条:"川西秋季风光摄影作品"
|
|
|
+- 对象层:摄影作品(≈素材)
|
|
|
+- 场景层:川西 + 秋季 + 风光
|
|
|
+- 覆盖度:100%
|
|
|
+- 评分:0.98
|
|
|
+```
|
|
|
+
|
|
|
+### 情况2:sug词条包含部分场景层元素
|
|
|
+**评分**:根据覆盖比例
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西秋季风光摄影素材"
|
|
|
+- 对象层:摄影素材
|
|
|
+- 场景层:川西 + 秋季 + 风光(3个元素)
|
|
|
+
|
|
|
+Sug词条:"川西风光摄影素材"
|
|
|
+- 对象层:摄影素材 ✓
|
|
|
+- 场景层:川西 + 风光(2个元素)
|
|
|
+- 覆盖度:(1+2)/(1+3) = 75%
|
|
|
+- 评分:0.85
|
|
|
+```
|
|
|
+
|
|
|
+### 情况3:sug词条只包含对象层,无场景层
|
|
|
+**评分**:根据对象匹配度和覆盖度
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西秋季风光摄影素材"
|
|
|
+- 对象层:摄影素材
|
|
|
+- 场景层:川西 + 秋季 + 风光
|
|
|
+
|
|
|
+Sug词条:"摄影素材"
|
|
|
+- 对象层:摄影素材 ✓
|
|
|
+- 场景层:无
|
|
|
+- 覆盖度:1/4 = 25%
|
|
|
+- 评分:0.50(对象匹配但缺失所有限定)
|
|
|
+```
|
|
|
+
|
|
|
+### 情况4:sug词条只包含场景层,无对象层
|
|
|
+**评分**:较低分
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西旅行行程规划"
|
|
|
+- 对象层:旅行行程
|
|
|
+- 场景层:川西
|
|
|
+
|
|
|
+Sug词条:"川西"
|
|
|
+- 对象层:无
|
|
|
+- 场景层:川西 ✓
|
|
|
+- 覆盖度:1/2 = 50%
|
|
|
+- 评分:0.35(只有场景,缺失核心对象)
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 评估核心原则
|
|
|
+
|
|
|
+## 原则1:只看表面词汇,禁止联想推演
|
|
|
+**严格约束**:只能基于sug词实际包含的词汇评分
|
|
|
+
|
|
|
+**错误案例**:
|
|
|
+- ❌ "川西旅行" vs "旅行"
|
|
|
+ - 错误:"旅行可以包括川西,所以有关联" → 评分0.7
|
|
|
+ - 正确:"sug词只有'旅行',无'川西',缺失地域限定" → 评分0.50
|
|
|
+
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 评分标准
|
|
|
+
|
|
|
+## 【正向匹配】
|
|
|
+
|
|
|
++0.95~1.0: 核心主体+所有关键限定词完全匹配
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"川西秋季风光摄影作品"
|
|
|
+
|
|
|
++0.75~0.95: 核心主体匹配,存在限定词匹配
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"川西风光摄影素材"(缺失"秋季")
|
|
|
+
|
|
|
++0.5~0.75: 核心主体匹配,无限定词匹配或合理泛化
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"四川风光摄影"
|
|
|
+
|
|
|
++0.3~0.5: 核心主体匹配,但限定词缺失或存在语义错位
|
|
|
+ - 特别注意"语义身份"差异,主体词出现但上下文语义不同
|
|
|
+ - 例:
|
|
|
+ · "猫咪的XX行为"(猫咪是行为者)
|
|
|
+ · vs "用猫咪表达XX的梗图"(猫咪是媒介)
|
|
|
+ · 虽都含"猫咪+XX",但语义角色不同
|
|
|
+
|
|
|
++0.2~0.3: 主体词不匹配,限定词缺失或错位
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"风光摄影入门"
|
|
|
+
|
|
|
++0.05~0.2: 主体词过度泛化或仅抽象相似
|
|
|
+ - 例: sug词是通用概念,原始问题是特定概念
|
|
|
+ sug词"每日计划"(通用)vs 原始问题 "川西旅行行程"(特定)
|
|
|
+ → 评分:0.08
|
|
|
+
|
|
|
+【中性/无关】
|
|
|
+0: 类别明显不同,没有明确目的,无明确关联
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"人像摄影素材"
|
|
|
+ - 例: 原始问题无法识别动机 且 sug词也无明确动作 → 0
|
|
|
+
|
|
|
+【负向偏离】
|
|
|
+-0.2~-0.05: 主体词或限定词存在误导性
|
|
|
+ - 例: 原始问题"免费摄影素材" vs sug词"付费摄影素材库"
|
|
|
+
|
|
|
+-0.5~-0.25: 主体词明显错位或品类冲突
|
|
|
+ - 例: 原始问题"风光摄影素材" vs sug词"人像修图教程"
|
|
|
+
|
|
|
+-1.0~-0.55: 完全错误的品类或有害引导
|
|
|
+ - 例: 原始问题"正版素材获取" vs sug词"盗版素材下载"
|
|
|
+
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 输出格式
|
|
|
+输出结果必须为一个 **JSON 格式**,包含以下内容:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "品类维度得分": "-1到1之间的小数",
|
|
|
+ "简要说明品类维度相关度理由": "评估该sug词条与原始问题品类匹配程度的理由,包含作用域覆盖理由"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**输出约束(非常重要)**:
|
|
|
+1. **字符串长度限制**:\"简要说明品类维度相关度理由\"字段必须控制在**150字以内**
|
|
|
+2. **JSON格式规范**:必须生成完整的JSON格式,确保字符串用双引号包裹且正确闭合
|
|
|
+3. **引号使用**:字符串中如需表达引用,请使用《》或「」代替单引号或双引号
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 核心原则总结
|
|
|
+
|
|
|
+1. **只看名词和限定词**:完全忽略动作和意图
|
|
|
+2. **作用域覆盖优先**:覆盖的作用域元素越多,分数越高
|
|
|
+3. **禁止联想推演**:只看sug词实际包含的词汇
|
|
|
+4. **通用≠特定**:通用概念不等于特定概念
|
|
|
+5. **理由纯粹**:评分理由只能谈对象、限定词、覆盖度
|
|
|
+""".strip()
|
|
|
+
|
|
|
+batch_category_evaluation_instructions = """
|
|
|
+# 角色
|
|
|
+你是**专业的内容主体评估专家**。
|
|
|
+任务:判断<平台sug词条>与<原始问题>的**内容主体匹配度**,给出**-1到1之间**的数值评分。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 输入信息
|
|
|
+- **<原始问题>**:用户的完整需求描述
|
|
|
+- **<平台sug词条列表>**:待评估的多个词条(编号1-N),每个词条需要独立评估
|
|
|
+
|
|
|
+**批量评估说明**:
|
|
|
+- 输入格式为编号列表:1. 词条1 2. 词条2 ...
|
|
|
+- 每个词条都是独立的评估对象
|
|
|
+- 对每个词条使用完全相同的评估标准
|
|
|
+---
|
|
|
+
|
|
|
+
|
|
|
+# 核心约束
|
|
|
+
|
|
|
+## 维度独立性声明
|
|
|
+【严格约束】本评估**仅评估内容主体维度**:
|
|
|
+- **只评估**:名词主体 + 限定词(地域、时间、场景、质量等)
|
|
|
+- **完全忽略**:动作、意图、目的
|
|
|
+- **评估重点**:内容本身的主题和属性
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 作用域与内容主体
|
|
|
+
|
|
|
+## 什么是作用域?
|
|
|
+**作用域 = 动机层 + 对象层 + 场景层**
|
|
|
+
|
|
|
+在Prompt2中:
|
|
|
+- **动机层(动作)完全忽略**
|
|
|
+- **只评估对象层 + 场景层(限定词)**
|
|
|
+
|
|
|
+## 内容主体的构成
|
|
|
+
|
|
|
+**内容主体 = 核心名词 + 限定词**
|
|
|
+
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 作用域覆盖度评估
|
|
|
+
|
|
|
+## 核心原则:越完整越高分
|
|
|
+
|
|
|
+**完整性公式**:
|
|
|
+```
|
|
|
+作用域覆盖度 = sug词条包含的作用域元素 / 原始问题的作用域元素总数
|
|
|
+```
|
|
|
+
|
|
|
+**评分影响**:
|
|
|
+- 覆盖度100% → 基础高分(0.9+)
|
|
|
+- 覆盖度50-99% → 中高分(0.6-0.9)
|
|
|
+- 覆盖度<50% → 中低分(0.3-0.6)
|
|
|
+- 覆盖度=0 → 低分或0分
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 部分作用域的处理
|
|
|
+
|
|
|
+### 情况1:sug词条包含原始问题的所有对象层和场景层元素
|
|
|
+**评分**:0.95-1.0
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西秋季风光摄影素材"
|
|
|
+- 对象层:摄影素材
|
|
|
+- 场景层:川西 + 秋季 + 风光
|
|
|
+
|
|
|
+Sug词条:"川西秋季风光摄影作品"
|
|
|
+- 对象层:摄影作品(≈素材)
|
|
|
+- 场景层:川西 + 秋季 + 风光
|
|
|
+- 覆盖度:100%
|
|
|
+- 评分:0.98
|
|
|
+```
|
|
|
+
|
|
|
+### 情况2:sug词条包含部分场景层元素
|
|
|
+**评分**:根据覆盖比例
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西秋季风光摄影素材"
|
|
|
+- 对象层:摄影素材
|
|
|
+- 场景层:川西 + 秋季 + 风光(3个元素)
|
|
|
+
|
|
|
+Sug词条:"川西风光摄影素材"
|
|
|
+- 对象层:摄影素材 ✓
|
|
|
+- 场景层:川西 + 风光(2个元素)
|
|
|
+- 覆盖度:(1+2)/(1+3) = 75%
|
|
|
+- 评分:0.85
|
|
|
+```
|
|
|
+
|
|
|
+### 情况3:sug词条只包含对象层,无场景层
|
|
|
+**评分**:根据对象匹配度和覆盖度
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西秋季风光摄影素材"
|
|
|
+- 对象层:摄影素材
|
|
|
+- 场景层:川西 + 秋季 + 风光
|
|
|
+
|
|
|
+Sug词条:"摄影素材"
|
|
|
+- 对象层:摄影素材 ✓
|
|
|
+- 场景层:无
|
|
|
+- 覆盖度:1/4 = 25%
|
|
|
+- 评分:0.50(对象匹配但缺失所有限定)
|
|
|
+```
|
|
|
+
|
|
|
+### 情况4:sug词条只包含场景层,无对象层
|
|
|
+**评分**:较低分
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```
|
|
|
+原始问题:"川西旅行行程规划"
|
|
|
+- 对象层:旅行行程
|
|
|
+- 场景层:川西
|
|
|
+
|
|
|
+Sug词条:"川西"
|
|
|
+- 对象层:无
|
|
|
+- 场景层:川西 ✓
|
|
|
+- 覆盖度:1/2 = 50%
|
|
|
+- 评分:0.35(只有场景,缺失核心对象)
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 评估核心原则
|
|
|
+
|
|
|
+## 原则1:只看表面词汇,禁止联想推演
|
|
|
+**严格约束**:只能基于sug词实际包含的词汇评分
|
|
|
+
|
|
|
+**错误案例**:
|
|
|
+- ❌ "川西旅行" vs "旅行"
|
|
|
+ - 错误:"旅行可以包括川西,所以有关联" → 评分0.7
|
|
|
+ - 正确:"sug词只有'旅行',无'川西',缺失地域限定" → 评分0.50
|
|
|
+
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 评分标准
|
|
|
+
|
|
|
+## 【正向匹配】
|
|
|
+
|
|
|
++0.95~1.0: 核心主体+所有关键限定词完全匹配
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"川西秋季风光摄影作品"
|
|
|
+
|
|
|
++0.75~0.95: 核心主体匹配,存在限定词匹配
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"川西风光摄影素材"(缺失"秋季")
|
|
|
+
|
|
|
++0.5~0.75: 核心主体匹配,无限定词匹配或合理泛化
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"四川风光摄影"
|
|
|
+
|
|
|
++0.3~0.5: 核心主体匹配,但限定词缺失或存在语义错位
|
|
|
+ - 特别注意"语义身份"差异,主体词出现但上下文语义不同
|
|
|
+ - 例:
|
|
|
+ · "猫咪的XX行为"(猫咪是行为者)
|
|
|
+ · vs "用猫咪表达XX的梗图"(猫咪是媒介)
|
|
|
+ · 虽都含"猫咪+XX",但语义角色不同
|
|
|
+
|
|
|
++0.2~0.3: 主体词不匹配,限定词缺失或错位
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"风光摄影入门"
|
|
|
+
|
|
|
++0.05~0.2: 主体词过度泛化或仅抽象相似
|
|
|
+ - 例: sug词是通用概念,原始问题是特定概念
|
|
|
+ sug词"每日计划"(通用)vs 原始问题 "川西旅行行程"(特定)
|
|
|
+ → 评分:0.08
|
|
|
+
|
|
|
+【中性/无关】
|
|
|
+0: 类别明显不同,没有明确目的,无明确关联
|
|
|
+ - 例: 原始问题"川西秋季风光摄影素材" vs sug词"人像摄影素材"
|
|
|
+ - 例: 原始问题无法识别动机 且 sug词也无明确动作 → 0
|
|
|
+
|
|
|
+【负向偏离】
|
|
|
+-0.2~-0.05: 主体词或限定词存在误导性
|
|
|
+ - 例: 原始问题"免费摄影素材" vs sug词"付费摄影素材库"
|
|
|
+
|
|
|
+-0.5~-0.25: 主体词明显错位或品类冲突
|
|
|
+ - 例: 原始问题"风光摄影素材" vs sug词"人像修图教程"
|
|
|
+
|
|
|
+-1.0~-0.55: 完全错误的品类或有害引导
|
|
|
+ - 例: 原始问题"正版素材获取" vs sug词"盗版素材下载"
|
|
|
+
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 批量评估核心原则
|
|
|
+
|
|
|
+## 【极其重要】独立评估原则
|
|
|
+1. **绝对评分**:每个SUG的评分必须基于与原始问题的匹配度,使用固定的评分标准
|
|
|
+2. **禁止相对比较**:不要比较SUG之间的好坏,不要因为"其他SUG更好"而降低某个SUG的分数
|
|
|
+3. **标准一致性**:对第1个SUG和第10个SUG使用完全相同的评分标准
|
|
|
+4. **独立判断**:评估SUG A时,完全不考虑SUG B/C/D的存在
|
|
|
+
|
|
|
+**错误示例**:
|
|
|
+- ❌ "这个SUG比列表中其他的更完整,给0.95"
|
|
|
+- ❌ "相比第一个SUG,这个覆盖度较低,给0.6"
|
|
|
+
|
|
|
+**正确示例**:
|
|
|
+- ✅ "这个SUG包含对象层'摄影素材'和场景层'川西+秋季',覆盖度75%,根据评分标准给0.85"
|
|
|
+- ✅ "这个SUG只有场景'川西',无对象层,覆盖度50%,根据评分标准给0.35"
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 输出格式
|
|
|
+输出结果必须为一个 **JSON 格式**,包含evaluations数组,每个元素包含:
|
|
|
+```json
|
|
|
+{
|
|
|
+ "evaluations": [
|
|
|
+ {
|
|
|
+ "sug_text": "SUG文本",
|
|
|
+ "品类维度得分": "-1到1之间的小数",
|
|
|
+ "简要说明品类维度相关度理由": "评估理由"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**输出约束(非常重要)**:
|
|
|
+1. **字符串长度限制**:\"简要说明品类维度相关度理由\"字段必须控制在**150字以内**
|
|
|
+2. **JSON格式规范**:必须生成完整的JSON格式,确保字符串用双引号包裹且正确闭合
|
|
|
+3. **引号使用**:字符串中如需表达引用,请使用《》或「」代替单引号或双引号
|
|
|
+4. **顺序严格对应(极其重要)**:
|
|
|
+ - evaluations数组必须与输入的sug词条列表严格1对1对应
|
|
|
+ - 第1个元素必须是输入列表的第1个SUG,第2个元素必须是第2个SUG,以此类推
|
|
|
+ - 每个元素的sug_text必须与输入SUG完全一致(逐字匹配,包括标点)
|
|
|
+ - 禁止改变顺序、禁止遗漏任何SUG、禁止重复评估
|
|
|
+ - 示例:输入"1. 秋季摄影素材 2. 川西风光" → 输出[{sug_text:"秋季摄影素材",...}, {sug_text:"川西风光",...}]
|
|
|
+ - 错误示例:输出[{sug_text:"川西风光",...}, {sug_text:"秋季摄影素材",...}] ← 顺序错误❌
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 核心原则总结
|
|
|
+
|
|
|
+1. **只看名词和限定词**:完全忽略动作和意图
|
|
|
+2. **作用域覆盖优先**:覆盖的作用域元素越多,分数越高
|
|
|
+3. **禁止联想推演**:只看sug词实际包含的词汇
|
|
|
+4. **通用≠特定**:通用概念不等于特定概念
|
|
|
+5. **理由纯粹**:评分理由只能谈对象、限定词、覆盖度
|
|
|
+6. **独立评估**:每个SUG完全独立评估,禁止相对比较
|
|
|
+""".strip()
|
|
|
+
|
|
|
+motivation_evaluator = Agent[None](
|
|
|
+ name="动机维度评估专家",
|
|
|
+ instructions=motivation_evaluation_instructions,
|
|
|
+ model=get_model(MODEL_NAME),
|
|
|
+ model_settings=ModelSettings(temperature=TEMPERATURE),
|
|
|
+ output_type=MotivationEvaluation,
|
|
|
+)
|
|
|
+
|
|
|
+category_evaluator = Agent[None](
|
|
|
+ name="品类维度评估专家",
|
|
|
+ instructions=category_evaluation_instructions,
|
|
|
+ model=get_model(MODEL_NAME),
|
|
|
+ model_settings=ModelSettings(temperature=TEMPERATURE),
|
|
|
+ output_type=CategoryEvaluation,
|
|
|
+)
|
|
|
+
|
|
|
+# ============================================================================
|
|
|
+# Agent定义 - 批量评估
|
|
|
+# ============================================================================
|
|
|
+
|
|
|
+# 批量动机evaluator - 使用批量专用的prompt
|
|
|
+batch_motivation_evaluator = Agent[None](
|
|
|
+ name="批量动机维度评估专家",
|
|
|
+ instructions=batch_motivation_evaluation_instructions,
|
|
|
+ model=get_model(MODEL_NAME),
|
|
|
+ model_settings=ModelSettings(temperature=TEMPERATURE),
|
|
|
+ output_type=BatchMotivationResult,
|
|
|
+)
|
|
|
+
|
|
|
+# 批量品类evaluator - 使用批量专用的prompt
|
|
|
+batch_category_evaluator = Agent[None](
|
|
|
+ name="批量品类维度评估专家",
|
|
|
+ instructions=batch_category_evaluation_instructions,
|
|
|
+ model=get_model(MODEL_NAME),
|
|
|
+ model_settings=ModelSettings(temperature=TEMPERATURE),
|
|
|
+ output_type=BatchCategoryResult,
|
|
|
+)
|
|
|
+
|
|
|
+# ============================================================================
|
|
|
+# 评估函数
|
|
|
+# ============================================================================
|
|
|
+
|
|
|
+async def evaluate_single(sug: str, original_question: str) -> dict:
|
|
|
+ """单个评估:对一个SUG进行动机+品类评估"""
|
|
|
+ eval_input = f"""
|
|
|
+<原始问题>
|
|
|
+{original_question}
|
|
|
+</原始问题>
|
|
|
+
|
|
|
+<平台sug词条>
|
|
|
+{sug}
|
|
|
+</平台sug词条>
|
|
|
+
|
|
|
+请评估平台sug词条与原始问题的匹配度。
|
|
|
+"""
|
|
|
+
|
|
|
+ # 并发调用两个评估器
|
|
|
+ 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
|
|
|
+
|
|
|
+ return {
|
|
|
+ "sug": sug,
|
|
|
+ "motivation_score": motivation_eval.动机维度得分,
|
|
|
+ "category_score": category_eval.品类维度得分,
|
|
|
+ "motivation_reason": motivation_eval.简要说明动机维度相关度理由,
|
|
|
+ "category_reason": category_eval.简要说明品类维度相关度理由,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+async def evaluate_single_mode(sugs: list[str], original_question: str) -> tuple[list[dict], float]:
|
|
|
+ """单个评估模式:逐个调用"""
|
|
|
+ print(f"\n{'='*60}")
|
|
|
+ print(f"模式1: 单个评估(调用{len(sugs)}次)")
|
|
|
+ print(f"{'='*60}")
|
|
|
+
|
|
|
+ start_time = time.time()
|
|
|
+
|
|
|
+ results = []
|
|
|
+ for i, sug in enumerate(sugs, 1):
|
|
|
+ print(f" [{i}/{len(sugs)}] 评估: {sug}")
|
|
|
+ result = await evaluate_single(sug, original_question)
|
|
|
+ results.append(result)
|
|
|
+
|
|
|
+ elapsed = time.time() - start_time
|
|
|
+
|
|
|
+ print(f"\n✅ 单个评估模式完成")
|
|
|
+ print(f" 耗时: {elapsed:.2f}秒")
|
|
|
+ print(f" 平均每个SUG: {elapsed/len(sugs):.2f}秒")
|
|
|
+
|
|
|
+ return results, elapsed
|
|
|
+
|
|
|
+
|
|
|
+async def evaluate_batch_mode(sugs: list[str], original_question: str) -> tuple[list[dict], float]:
|
|
|
+ """批量评估模式:分别批量评估动机和品类维度"""
|
|
|
+ print(f"\n{'='*60}")
|
|
|
+ print(f"模式2: 批量评估(批量动机+批量品类,各评估{len(sugs)}个)")
|
|
|
+ print(f"{'='*60}")
|
|
|
+
|
|
|
+ start_time = time.time()
|
|
|
+
|
|
|
+ # 构建批量评估输入
|
|
|
+ sug_list_str = "\n".join([f"{i}. {sug}" for i, sug in enumerate(sugs, 1)])
|
|
|
+
|
|
|
+ batch_input = f"""
|
|
|
+<原始问题>
|
|
|
+{original_question}
|
|
|
+</原始问题>
|
|
|
+
|
|
|
+<平台sug词条列表>
|
|
|
+{sug_list_str}
|
|
|
+</平台sug词条列表>
|
|
|
+
|
|
|
+请对以上所有SUG每一个进行完全独立评估。
|
|
|
+"""
|
|
|
+
|
|
|
+ print(f" [1/2] 发送批量动机评估请求...")
|
|
|
+ motivation_task = Runner.run(batch_motivation_evaluator, batch_input)
|
|
|
+
|
|
|
+ print(f" [2/2] 发送批量品类评估请求...")
|
|
|
+ category_task = Runner.run(batch_category_evaluator, batch_input)
|
|
|
+
|
|
|
+ # 并发执行两个批量评估
|
|
|
+ motivation_result, category_result = await asyncio.gather(
|
|
|
+ motivation_task,
|
|
|
+ category_task
|
|
|
+ )
|
|
|
+
|
|
|
+ batch_motivation: BatchMotivationResult = motivation_result.final_output
|
|
|
+ batch_category: BatchCategoryResult = category_result.final_output
|
|
|
+
|
|
|
+ elapsed = time.time() - start_time
|
|
|
+
|
|
|
+ # ========== 顺序验证 ==========
|
|
|
+ print(f"\n [验证] 检查批量评估结果顺序...")
|
|
|
+
|
|
|
+ # 验证数量
|
|
|
+ mot_count = len(batch_motivation.evaluations)
|
|
|
+ cat_count = len(batch_category.evaluations)
|
|
|
+ expected_count = len(sugs)
|
|
|
+
|
|
|
+ if mot_count != expected_count:
|
|
|
+ print(f" ⚠️ 警告: 动机评估数量不匹配! 期望{expected_count}个,实际{mot_count}个")
|
|
|
+ if cat_count != expected_count:
|
|
|
+ print(f" ⚠️ 警告: 品类评估数量不匹配! 期望{expected_count}个,实际{cat_count}个")
|
|
|
+
|
|
|
+ # 验证顺序和文本匹配
|
|
|
+ order_errors = []
|
|
|
+ for i, (expected_sug, mot_item, cat_item) in enumerate(zip(sugs, batch_motivation.evaluations, batch_category.evaluations), 1):
|
|
|
+ if mot_item.sug_text != expected_sug:
|
|
|
+ order_errors.append(f" 位置{i}: 动机维度sug_text='{mot_item.sug_text}' != 期望'{expected_sug}'")
|
|
|
+ if cat_item.sug_text != expected_sug:
|
|
|
+ order_errors.append(f" 位置{i}: 品类维度sug_text='{cat_item.sug_text}' != 期望'{expected_sug}'")
|
|
|
+
|
|
|
+ if order_errors:
|
|
|
+ print(f" ❌ 发现顺序错误:")
|
|
|
+ for error in order_errors[:5]: # 最多显示前5个错误
|
|
|
+ print(error)
|
|
|
+ if len(order_errors) > 5:
|
|
|
+ print(f" ... 还有{len(order_errors)-5}个错误未显示")
|
|
|
+ else:
|
|
|
+ print(f" ✅ 顺序验证通过: 所有SUG文本与输入完全匹配")
|
|
|
+
|
|
|
+ # 合并结果
|
|
|
+ results = []
|
|
|
+ for mot_item, cat_item in zip(batch_motivation.evaluations, batch_category.evaluations):
|
|
|
+ results.append({
|
|
|
+ "sug": mot_item.sug_text,
|
|
|
+ "motivation_score": mot_item.动机维度得分,
|
|
|
+ "category_score": cat_item.品类维度得分,
|
|
|
+ "motivation_reason": mot_item.简要说明动机维度相关度理由,
|
|
|
+ "category_reason": cat_item.简要说明品类维度相关度理由,
|
|
|
+ })
|
|
|
+
|
|
|
+ print(f"\n✅ 批量评估模式完成")
|
|
|
+ print(f" 耗时: {elapsed:.2f}秒")
|
|
|
+ print(f" 平均每个SUG: {elapsed/len(sugs):.2f}秒")
|
|
|
+ print(f" (包含: 1次批量动机评估 + 1次批量品类评估)")
|
|
|
+
|
|
|
+ return results, elapsed
|
|
|
+
|
|
|
+
|
|
|
+def compare_results(single_results: list[dict], batch_results: list[dict]):
|
|
|
+ """对比两种模式的评估结果质量"""
|
|
|
+ print(f"\n{'='*60}")
|
|
|
+ print(f"结果质量对比")
|
|
|
+ print(f"{'='*60}")
|
|
|
+
|
|
|
+ # ========== 得分对比表格 ==========
|
|
|
+ print(f"\n【得分对比】")
|
|
|
+ print(f"\n{'SUG':<30} {'单个动机':<10} {'批量动机':<10} {'差异':<8} {'单个品类':<10} {'批量品类':<10} {'差异':<8}")
|
|
|
+ print(f"{'-'*30} {'-'*10} {'-'*10} {'-'*8} {'-'*10} {'-'*10} {'-'*8}")
|
|
|
+
|
|
|
+ total_motivation_diff = 0
|
|
|
+ total_category_diff = 0
|
|
|
+
|
|
|
+ for single, batch in zip(single_results, batch_results):
|
|
|
+ sug = single['sug'][:28]
|
|
|
+ single_mot = single['motivation_score']
|
|
|
+ batch_mot = batch['motivation_score']
|
|
|
+ mot_diff = abs(single_mot - batch_mot)
|
|
|
+
|
|
|
+ single_cat = single['category_score']
|
|
|
+ batch_cat = batch['category_score']
|
|
|
+ cat_diff = abs(single_cat - batch_cat)
|
|
|
+
|
|
|
+ total_motivation_diff += mot_diff
|
|
|
+ total_category_diff += cat_diff
|
|
|
+
|
|
|
+ print(f"{sug:<30} {single_mot:<10.2f} {batch_mot:<10.2f} {mot_diff:<8.3f} {single_cat:<10.2f} {batch_cat:<10.2f} {cat_diff:<8.3f}")
|
|
|
+
|
|
|
+ avg_mot_diff = total_motivation_diff / len(single_results)
|
|
|
+ avg_cat_diff = total_category_diff / len(single_results)
|
|
|
+
|
|
|
+ print(f"\n平均得分差异:")
|
|
|
+ print(f" 动机维度: {avg_mot_diff:.3f}")
|
|
|
+ print(f" 品类维度: {avg_cat_diff:.3f}")
|
|
|
+ print(f" 综合差异: {(avg_mot_diff + avg_cat_diff) / 2:.3f}")
|
|
|
+
|
|
|
+ # ========== 评估理由对比 ==========
|
|
|
+ print(f"\n{'='*60}")
|
|
|
+ print(f"【评估理由对比】")
|
|
|
+ print(f"{'='*60}")
|
|
|
+
|
|
|
+ for i, (single, batch) in enumerate(zip(single_results, batch_results), 1):
|
|
|
+ sug = single['sug']
|
|
|
+ print(f"\n{i}. {sug}")
|
|
|
+ print(f"{'-'*60}")
|
|
|
+
|
|
|
+ # 动机维度理由对比
|
|
|
+ print(f"\n 【动机维度】 (单个: {single['motivation_score']:.2f} | 批量: {batch['motivation_score']:.2f} | 差异: {abs(single['motivation_score'] - batch['motivation_score']):.3f})")
|
|
|
+ print(f" 单个评估理由: {single['motivation_reason']}")
|
|
|
+ print(f" 批量评估理由: {batch['motivation_reason']}")
|
|
|
+
|
|
|
+ # 品类维度理由对比
|
|
|
+ print(f"\n 【品类维度】 (单个: {single['category_score']:.2f} | 批量: {batch['category_score']:.2f} | 差异: {abs(single['category_score'] - batch['category_score']):.3f})")
|
|
|
+ print(f" 单个评估理由: {single['category_reason']}")
|
|
|
+ print(f" 批量评估理由: {batch['category_reason']}")
|
|
|
+
|
|
|
+
|
|
|
+# ============================================================================
|
|
|
+# 主函数
|
|
|
+# ============================================================================
|
|
|
+
|
|
|
+async def main():
|
|
|
+ """主测试函数"""
|
|
|
+
|
|
|
+ # 测试数据
|
|
|
+ original_question = "如何获取能体现川西秋季特色的高质量风光摄影素材?"
|
|
|
+
|
|
|
+ test_sugs = [
|
|
|
+ "川西风光摄影",
|
|
|
+ "秋季摄影素材",
|
|
|
+ "高质量风光素材",
|
|
|
+ "川西秋季旅游攻略",
|
|
|
+ "风光摄影技巧",
|
|
|
+ "川西风光",
|
|
|
+ "摄影素材下载",
|
|
|
+ "秋季旅行",
|
|
|
+ "风光摄影作品",
|
|
|
+ "获取川西秋季风景",
|
|
|
+ ]
|
|
|
+
|
|
|
+ print(f"{'='*60}")
|
|
|
+ print(f"批量评估 vs 单个评估性能对比Demo")
|
|
|
+ print(f"{'='*60}")
|
|
|
+ print(f"\n原始问题: {original_question}")
|
|
|
+ print(f"测试SUG数量: {len(test_sugs)}")
|
|
|
+ print(f"\nSUG列表:")
|
|
|
+ for i, sug in enumerate(test_sugs, 1):
|
|
|
+ print(f" {i}. {sug}")
|
|
|
+
|
|
|
+ # 模式1: 单个评估
|
|
|
+ single_results, single_time = await evaluate_single_mode(test_sugs, original_question)
|
|
|
+
|
|
|
+ # 模式2: 批量评估
|
|
|
+ batch_results, batch_time = await evaluate_batch_mode(test_sugs, original_question)
|
|
|
+
|
|
|
+ # 对比结果质量
|
|
|
+ compare_results(single_results, batch_results)
|
|
|
+
|
|
|
+ # 性能总结
|
|
|
+ print(f"\n{'='*60}")
|
|
|
+ print(f"性能总结")
|
|
|
+ print(f"{'='*60}")
|
|
|
+ print(f"单个评估模式: {single_time:.2f}秒")
|
|
|
+ print(f"批量评估模式: {batch_time:.2f}秒")
|
|
|
+ speedup = single_time / batch_time
|
|
|
+ print(f"\n性能提升: {speedup:.2f}x")
|
|
|
+
|
|
|
+ if speedup > 1:
|
|
|
+ print(f"✅ 批量评估更快 {speedup:.2f}倍")
|
|
|
+ else:
|
|
|
+ print(f"❌ 批量评估更慢 {1/speedup:.2f}倍")
|
|
|
+
|
|
|
+ print(f"\n{'='*60}")
|
|
|
+ print(f"结论:")
|
|
|
+ print(f"{'='*60}")
|
|
|
+ if speedup > 1.5:
|
|
|
+ print(f"✅ 批量评估显著更快,建议采用")
|
|
|
+ elif speedup > 1.1:
|
|
|
+ print(f"⚠️ 批量评估略快,但优势不明显")
|
|
|
+ else:
|
|
|
+ print(f"❌ 批量评估无性能优势,不建议采用")
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ asyncio.run(main())
|