瀏覽代碼

feat: 引入语义距离分数,优化规则分数计算

主要改动:
1. 新增语义距离评估(第3步)
   - 每个匹配关系新增"距离分数"字段
   - 距离分数:0-1之间,表示B语义和A语义的语义相似度
   - 评分标准:1.0(完全相同), 0.8-0.95(非常接近), 0.5-0.7(明确关联), 0.1-0.4(弱关联), 0.0(完全无关)
   - 距离分数只考虑语义相似度,不考虑其他因素

2. 规则分数计算公式变更:
   - 旧:关系得分直接映射(同义=1.0, 近义=0.9, 上位词=0.6, 下位词=0.4, 无关=0.0)
   - 新:关系得分 = 关系权重 × 距离分数
   - 关系权重:同义=1.0, 近义=0.7, 上位词=0.8, 下位词=0.6, 无关=0.0
   - 规则分数 = Σ(关系得分) / 实质语义总数

3. 更细粒度的评分:
   - 同样是"近义"关系,可以有不同的距离分数(0.7, 0.8, 0.9等)
   - 最终得分 = 0.7 × 距离分数,体现了语义距离的细微差异

4. 输出格式更新:
   - 匹配关系中新增"距离分数"字段
   - 规则分数说明中包含每个匹配关系的详细计算过程

5. calculate_score_by_code 更新:
   - RELATION_SCORES → RELATION_WEIGHTS(语义更清晰)
   - 从匹配关系中提取距离分数
   - 计算:关系得分 = 权重 × 距离分数
   - 验证:缺少距离分数时抛出异常

优势:
- 更细粒度的语义距离评估
- 规则分数计算更灵活(不是固定映射)
- 权重调整:近义降低(0.9→0.7),上位词提高(0.6→0.8)

测试结果:
- 关系="无关", 距离分数=0.0 → 关系得分 = 0.0 × 0.0 = 0.0
- 规则分数 = 0.0, 相关性分数 = 0.2
- 最终分数 = 0.04
- score_by_code = 0.04 ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
yangxiaohui 2 周之前
父節點
當前提交
9cb9e3ff10
共有 1 個文件被更改,包括 56 次插入35 次删除
  1. 56 35
      lib/match_analyzer.py

+ 56 - 35
lib/match_analyzer.py

@@ -204,15 +204,26 @@ MATCH_WITH_DEFINITION_PROMPT = """
    - **下位词**:B在其上下文中的含义 比 A在其上下文中的含义 更具体、更下位(B ⊆ A)
    - **无关**:虽然可比较,但没有明确的语义关系
 
-3. **计算规则分数**
-   - 关系得分:同义=1.0, 近义=0.9, 上位词=0.6, 下位词=0.4, 无关=0.0
-   - 只基于实质语义匹配计算规则分数
+3. **评估语义距离**
+   - 对每对匹配的语义,评估它们之间的语义距离
+   - **距离分数**:0-1之间的浮点数,保留2位小数
+     - **1.0**:语义完全相同
+     - **0.8-0.95**:语义非常接近
+     - **0.5-0.7**:语义有明确关联或层级关系
+     - **0.1-0.4**:语义有弱关联
+     - **0.0**:语义完全无关
+   - 距离分数只考虑B语义和A语义的语义相似度,不考虑其他因素
+
+4. **计算规则分数**
+   - 关系权重:同义=1.0, 近义=0.7, 上位词=0.8, 下位词=0.6, 无关=0.0
    - 计算公式:
      ```
-     规则分数 = Σ(实质语义的关系得分) / 实质语义总数
+     关系得分 = 关系权重 × 距离分数
+     规则分数 = Σ(关系得分) / 实质语义总数
      ```
+   - 例如:关系="近义", 距离分数=0.9 → 关系得分 = 0.7 × 0.9 = 0.63
 
-4. **评估整体相关性**
+5. **评估整体相关性**
    - 在完成上述匹配关系分析后,从宏观角度评估 <B> 和 <A> 的整体相关性
    - 考虑因素:
      - 语义距离:核心概念之间的距离
@@ -228,7 +239,7 @@ MATCH_WITH_DEFINITION_PROMPT = """
    - 给出相关性分数(0-1之间的浮点数,保留2位小数)
    - 给出相关性说明
 
-5. **计算最终分数**
+6. **计算最终分数**
    - 最终分数 = 0.8 × 规则分数 + 0.2 × 相关性分数
    - 在score说明中说明计算过程,可以提及形式语义的差异作为补充参考
 
@@ -278,8 +289,9 @@ MATCH_WITH_DEFINITION_PROMPT = """
       "A语义": "语义片段1",
       "A语义说明": "从A实质语义分析中复述该片段的说明",
       "是否可比较": true,
-      "关系": "下位词",
-      "说明": "说明两者的关系"
+      "关系": "近义",
+      "说明": "说明两者的关系",
+      "距离分数": 0.85
     },
     {
       "B语义": "语义片段2",
@@ -289,15 +301,16 @@ MATCH_WITH_DEFINITION_PROMPT = """
       "是否可比较": false,
       "不可比较原因": "A是元概念(用于描述其他概念的术语),B是具体概念,抽象层级完全不同",
       "关系": "无关",
-      "说明": "元概念不能与具体概念比较"
+      "说明": "元概念不能与具体概念比较",
+      "距离分数": 0.0
     }
   ],
-  "规则分数": 0.2,
-  "规则分数说明": "B有2个实质语义,第1个是A的下位词(0.4),第2个无关(0.0),规则分数 = (0.4 + 0.0) / 2 = 0.2",
+  "规则分数": 0.3,
+  "规则分数说明": "B有2个实质语义。第1个:关系=近义(权重0.7),距离分数=0.85,关系得分=0.7×0.85=0.595。第2个:关系=无关(权重0.0),距离分数=0.0,关系得分=0.0。规则分数 = (0.595 + 0.0) / 2 = 0.3。",
   "相关性分数": 0.3,
   "相关性说明": "虽然有部分语义重叠,但整体上下文契合度较低,因为B强调具体事物,A强调抽象概念",
-  "score": 0.22,
-  "score说明": "最终分数 = 0.8 × 0.2 + 0.2 × 0.3 = 0.22。形式语义差异:B有'修饰词x',A有'修饰词y',作为补充参考。"
+  "score": 0.3,
+  "score说明": "最终分数 = 0.8 × 0.3 + 0.2 × 0.3 = 0.3。形式语义差异:B有'修饰词x',A有'修饰词y',作为补充参考。"
 }
 ```
 
@@ -309,17 +322,18 @@ MATCH_WITH_DEFINITION_PROMPT = """
 5. **匹配关系**:数组格式,**只包含实质语义的匹配**,字段顺序为:
    - B语义 → B语义说明 → A语义 → A语义说明 → 是否可比较
    - 如果是否可比较=false:添加"不可比较原因"字段
-   - 关系 → 说明
+   - 关系 → 说明 → 距离分数
 6. **B语义说明和A语义说明**:必须从前面的实质语义分析中复述,保持一致
 7. **是否可比较**:布尔值,true或false
 8. **不可比较原因**:字符串,仅在是否可比较=false时提供,说明为什么不可比较
 9. **关系**:必须是以下之一:"同义"、"近义"、"上位词"、"下位词"、"无关"
-10. **规则分数**:0-1之间的浮点数,保留2位小数,基于匹配关系计算
-11. **规则分数说明**:说明规则分数的计算依据
-12. **相关性分数**:0-1之间的浮点数,保留2位小数,整体相关性评估
-13. **相关性说明**:说明相关性分数的判断依据
-14. **score**:0-1之间的浮点数,保留2位小数,= 0.8 × 规则分数 + 0.2 × 相关性分数
-15. **score说明**:说明最终分数的计算过程,可以提及形式语义的差异作为补充
+10. **距离分数**:0-1之间的浮点数,保留2位小数,表示B语义和A语义的语义距离/相似度
+11. **规则分数**:0-1之间的浮点数,保留2位小数,基于匹配关系计算(关系得分 = 关系权重 × 距离分数)
+12. **规则分数说明**:说明规则分数的计算依据,包含每个匹配关系的计算过程
+13. **相关性分数**:0-1之间的浮点数,保留2位小数,整体相关性评估
+14. **相关性说明**:说明相关性分数的判断依据
+15. **score**:0-1之间的浮点数,保留2位小数,= 0.8 × 规则分数 + 0.2 × 相关性分数
+16. **score说明**:说明最终分数的计算过程,可以提及形式语义的差异作为补充
 """.strip()
 
 
@@ -345,8 +359,10 @@ def create_match_agent(model_name: str) -> Agent:
 def calculate_score_by_code(match_result: dict) -> float:
     """根据匹配关系和相关性分数用代码计算最终score
 
-    计算公式:score = 0.8 × 规则分数 + 0.2 × 相关性分数
-    其中规则分数基于匹配关系计算,相关性分数由LLM给出
+    计算公式:
+    - 关系得分 = 关系权重 × 距离分数
+    - 规则分数 = Σ(关系得分) / 实质语义总数
+    - 最终score = 0.8 × 规则分数 + 0.2 × 相关性分数
 
     Args:
         match_result: 匹配结果字典,包含 B语义分析、匹配关系、相关性分数
@@ -357,12 +373,12 @@ def calculate_score_by_code(match_result: dict) -> float:
     Raises:
         ValueError: 当数据不完整时
     """
-    # 关系得分映射
-    RELATION_SCORES = {
+    # 关系权重映射
+    RELATION_WEIGHTS = {
         "同义": 1.0,
-        "近义": 0.9,
-        "上位词": 0.6,
-        "下位词": 0.4,
+        "近义": 0.7,
+        "上位词": 0.8,
+        "下位词": 0.6,
         "无关": 0.0
     }
 
@@ -387,25 +403,30 @@ def calculate_score_by_code(match_result: dict) -> float:
         raise ValueError("B语义分析中实质为空,无法计算score_by_code")
 
     # 计算规则分数:基于实质语义的匹配关系
-    essence_scores = []
+    relation_scores = []  # 存储每个关系的得分
 
     for relation in match_relations:
         b_semantic = relation.get("B语义", "")
         relation_type = relation.get("关系", "无关")
-        score = RELATION_SCORES.get(relation_type, 0.0)
+        distance_score = relation.get("距离分数")
+
+        if distance_score is None:
+            raise ValueError(f"匹配关系中缺少距离分数: {b_semantic}")
 
         # 验证该语义确实属于实质
-        if b_semantic in b_essence:
-            essence_scores.append(score)
-        else:
-            # 如果匹配关系中包含了非实质语义,报错
+        if b_semantic not in b_essence:
             raise ValueError(f"匹配关系中包含非实质语义: {b_semantic}")
 
-    if not essence_scores:
+        # 计算关系得分 = 关系权重 × 距离分数
+        weight = RELATION_WEIGHTS.get(relation_type, 0.0)
+        relation_score = weight * distance_score
+        relation_scores.append(relation_score)
+
+    if not relation_scores:
         raise ValueError("匹配关系中没有实质语义,无法计算score_by_code")
 
     # 计算规则分数(基于匹配关系)
-    rule_score = sum(essence_scores) / len(essence_scores)
+    rule_score = sum(relation_scores) / len(relation_scores)
 
     # 计算最终分数:0.8 × 规则分数 + 0.2 × 相关性分数
     final_score = 0.8 * rule_score + 0.2 * relevance_score