""" 批量匹配分析模块 分析单个特征与多个特征之间的语义匹配度(批量版本) 提供接口: analyze_batch_match(phrase_a, phrase_b_list, model_name) - 批量分析匹配度 返回格式: [ { "特征": "...", "分数": 0.85, "说明": "..." }, ... ] """ from typing import List from agents import Agent, Runner, ModelSettings from agents.tracing.create import custom_span from lib.client import get_model from lib.utils import parse_json_from_text # ========== System Prompt ========== BATCH_MATCH_SYSTEM_PROMPT = """ # 任务 分析单个特征 与多个特征 之间的语义匹配度。 ## 输入说明 - ****: 待分析的特征(必选) - ****: 多个特征列表(必选) **重要**: 1. 必须在同一个评分标准下对所有 B 进行评分,确保分数可比 2. **优先识别并给出高分**给与 相似度最高的特征 3. 严格区分高相似度和低相似度,避免分数过于集中 --- ## 评分标准(0-1分) **核心原则**:从 中找出与 最相似的特征,给予最高分,其他按相似度递减。 - **0.9-1.0**:几乎完全相同(同义词、可互换) - **0.7-0.9**:非常接近、高度相关(强关联、核心相关) - **0.5-0.7**:有一定关联(中等相关、间接关联) - **0.3-0.5**:关系较弱(弱相关、边缘关联) - **0.0-0.3**:几乎无关或完全无关 **评分策略**: - 优先识别与 最相似的特征,给 0.7+ 高分 - 对明显无关的特征,果断给 0.0-0.3 低分 - 合理使用中间分数段,避免过度集中 - 确保分数有梯度,体现明确的相似度差异 --- ## 输出格式(严格JSON数组) ```json [ { "特征": "第一个B的特征", "分数": 0.85, "说明": "简要说明评分依据" }, { "特征": "第二个B的特征", "分数": 0.45, "说明": "简要说明评分依据" } ] ``` **输出要求**: 1. 数组长度必须等于 的长度,顺序一一对应 2. 分数必须是0-1之间的浮点数,保留2位小数 3. 所有评分必须使用相同的标准,分数之间可比 4. **必须有明显的分数梯度**,最相似的给高分,不相关的给低分 """.strip() def create_batch_match_agent(model_name: str) -> Agent: """创建批量匹配分析的 Agent Args: model_name: 模型名称 Returns: Agent 实例 """ agent = Agent( name="Batch Match Expert", instructions=BATCH_MATCH_SYSTEM_PROMPT, model=get_model(model_name), model_settings=ModelSettings( temperature=0.0, max_tokens=65536, ), tools=[], ) return agent def clean_json_text(text: str) -> str: """清理JSON文本中的常见错误 Args: text: 原始JSON文本 Returns: 清理后的JSON文本 """ import re # 1. 移除数组元素之间的异常字符(如 trib{) # 匹配模式:逗号后面跟着任意非空白字符,直到遇到正常的对象开始 { text = re.sub(r',\s*[a-zA-Z]+\s*\{', r',\n {', text) # 2. 移除对象之间的异常字符 text = re.sub(r'\}\s*[a-zA-Z]+\s*\{', r'},\n {', text) return text def parse_batch_match_response(response_content: str) -> List[dict]: """解析批量匹配响应 Args: response_content: Agent 返回的响应内容 Returns: 解析后的字典列表 """ try: # 使用 parse_json_from_text 函数进行健壮的 JSON 解析 result = parse_json_from_text(response_content) # 如果解析失败(返回空字典),尝试清理后再解析 if not result: print(f"首次解析失败,尝试清理JSON文本后重新解析...") cleaned_text = clean_json_text(response_content) result = parse_json_from_text(cleaned_text) # 如果清理后仍然失败 if not result: print(f"清理后仍解析失败: 无法从响应中提取有效JSON") return [{ "特征": "", "分数": 0.0, "说明": "解析失败: 无法从响应中提取有效JSON" }] # 确保返回的是列表 if not isinstance(result, list): return [result] return result except Exception as e: print(f"解析响应失败: {e}") return [{ "特征": "", "分数": 0.0, "说明": f"解析失败: {str(e)}" }] async def analyze_batch_match( phrase_a: str, phrase_b_list: List[str], model_name: str = None ) -> List[dict]: """批量分析匹配度 Args: phrase_a: 待分析的特征 phrase_b_list: 多个特征列表 model_name: 使用的模型名称(可选,默认使用 client.py 中的 MODEL_NAME) Returns: 匹配结果列表:[{"特征": "...", "分数": 0.85, "说明": "..."}, ...] """ try: # 如果未指定模型,使用默认模型 if model_name is None: from lib.client import MODEL_NAME model_name = MODEL_NAME # 创建 Agent agent = create_batch_match_agent(model_name) # 构建 B 列表字符串 b_list_str = "\n".join([f"- {b}" for b in phrase_b_list]) # 构建任务描述 task_description = f"""## 本次分析任务 {phrase_a} {b_list_str} 请分析 中每个特征的匹配度,输出 JSON 数组格式的结果。 重要:必须使用一致的评分标准!""" # 构造消息 messages = [{ "role": "user", "content": [ { "type": "input_text", "text": task_description } ] }] # 使用 custom_span 追踪分析过程 # 截断显示内容,避免 span name 过长 a_short = (phrase_a[:30] + "...") if len(phrase_a) > 30 else phrase_a with custom_span( name=f"批量匹配分析: {a_short} vs {len(phrase_b_list)}个特征", data={ "phrase_a": phrase_a, "phrase_b_list": phrase_b_list, "b_count": len(phrase_b_list) } ): # 运行 Agent result = await Runner.run(agent, input=messages) # 解析响应 parsed_result = parse_batch_match_response(result.final_output) # 验证返回的结果数量 if len(parsed_result) != len(phrase_b_list): print(f"警告: 返回结果数量 ({len(parsed_result)}) 与输入数量 ({len(phrase_b_list)}) 不匹配") # 补齐或截断 while len(parsed_result) < len(phrase_b_list): parsed_result.append({ "特征": phrase_b_list[len(parsed_result)], "分数": 0.0, "说明": "结果数量不匹配,自动补齐" }) parsed_result = parsed_result[:len(phrase_b_list)] return parsed_result except Exception as e: # 返回错误信息(为每个 B 创建一个错误条目) return [{ "特征": b, "分数": 0.0, "说明": f"分析过程出错: {str(e)}" } for b in phrase_b_list]