""" 短语关系分析模块 分析两个短语之间的语义关系 提供接口: analyze_relation(phrase_a, phrase_b, model_name, context_a="", context_b="") - 分析两个短语的关系 支持可选的 Context 参数: - context_a: phrase_a 的补充上下文(帮助理解 phrase_a) - context_b: phrase_b 的补充上下文(帮助理解 phrase_b) - Context 默认为空,不提供时不会出现在 prompt 中 返回格式: { "relation": "same", # 7种关系之一 "score": 0.95, # 0-1,语义接近程度 "explanation": "说明" # 关系判断的依据 } """ import json from agents import Agent, Runner, ModelSettings from agents.tracing.create import custom_span from lib.client import get_model # ========== System Prompt ========== RELATION_SYSTEM_PROMPT = """ # 任务 分析两个短语 之间的语义关系。 ## 输入说明 - ****: 第一个短语(必选) - ****: 第二个短语(必选) - ****: A 的补充上下文(可选,帮助理解 A) - ****: B 的补充上下文(可选,帮助理解 B) **重要**:关系分析发生在 之间,Context 仅作为补充理解的辅助信息。 --- ## 关系类型(7种) ### 1. same(同义) - **定义**:意思完全相同或非常接近,可以互相替换 - **例子**: - "医生" 和 "大夫" → same - "计算机" 和 "电脑" → same - "快乐" 和 "高兴" → same ### 2. coordinate(同级) - **定义**:有共同的上位概念,属于并列关系,通常无交集 - **例子**: - "轿车" 和 "SUV" → coordinate(都是汽车) - "苹果" 和 "香蕉" → coordinate(都是水果) - "数学" 和 "物理" → coordinate(都是学科) ### 3. contains(包含) - **定义**:A 的概念范围包含 B,B 是 A 的子类或特例 - **例子**: - "水果" contains "苹果" - "汽车" contains "轿车" - "动物" contains "狗" ### 4. contained_by(被包含) - **定义**:A 被 B 包含,A 是 B 的子类或特例 - **例子**: - "苹果" contained_by "水果" - "轿车" contained_by "汽车" - "狗" contained_by "动物" ### 5. overlap(部分重叠) - **定义**:两个概念有交集,但互不包含 - **例子**: - "红苹果" 和 "大苹果" → overlap(有又红又大的苹果) - "亚洲国家" 和 "发展中国家" → overlap(如中国、印度等) - "学生" 和 "运动员" → overlap(有学生运动员) ### 6. related(相关) - **定义**:有语义联系,但不属于上述任何层级关系 - **例子**: - "医生" 和 "医院" → related(工作场所关系) - "阅读" 和 "书籍" → related(动作-对象关系) - "钥匙" 和 "锁" → related(工具-用途关系) - "老师" 和 "学生" → related(角色关系) ### 7. unrelated(无关) - **定义**:无明显语义关系 - **例子**: - "医生" 和 "石头" → unrelated - "苹果" 和 "数学" → unrelated --- ## 评分标准(score: 0-1) **score 表示两个短语的语义接近程度:** - **0.9-1.0**:几乎完全相同(完全同义) - **0.8-0.9**:非常接近(高度同义、直接包含关系) - **0.7-0.8**:比较接近(近义、明确的同级或包含) - **0.6-0.7**:有一定接近度(同级但层级稍远、间接包含) - **0.5-0.6**:中等程度的关系(中等交集、中度相关) - **0.4-0.5**:关系较弱(小交集、弱相关) - **0.3-0.4**:关系很弱(勉强算同级、很弱的相关) - **0.0-0.3**:几乎无关或完全无关 **不同关系类型的 score 范围参考:** - same: 通常 0.7-1.0(完全同义接近1.0,近义0.7-0.8) - contains/contained_by: 通常 0.5-0.9(直接包含0.8+,跨层级0.5-0.7) - coordinate: 通常 0.3-0.8(同级且上位概念近0.7+,同级但距离远0.3-0.5) - overlap: 通常 0.2-0.8(交集大0.6+,交集小0.2-0.4) - related: 通常 0.1-0.7(强相关0.5+,弱相关0.1-0.3) - unrelated: 通常 0.0-0.2 --- ## 判断逻辑(按优先级) 1. **A 和 B 意思相同或非常接近?** → same 2. **A 包含 B 或 B 包含 A?** → contains 或 contained_by 3. **A 和 B 有共同上位概念且无交集?** → coordinate 4. **A 和 B 有交集但互不包含?** → overlap 5. **A 和 B 有语义联系但不属于上述?** → related 6. **A 和 B 完全无关?** → unrelated --- ## 输出格式(严格JSON) ```json { "relation": "same", "score": 0.95, "explanation": "简要说明为什么是这个关系,以及 score 的依据" } ``` **输出要求**: 1. 必须严格按照上述JSON格式输出 2. 所有字段都必须填写 3. **relation字段**:必须是以下7个值之一:same, coordinate, contains, contained_by, overlap, related, unrelated 4. **score字段**:必须是0-1之间的浮点数,保留2位小数 5. **explanation字段**:必须简洁说明关系类型和评分依据(1-2句话) """.strip() def create_relation_agent(model_name: str) -> Agent: """创建关系分析的 Agent Args: model_name: 模型名称 Returns: Agent 实例 """ agent = Agent( name="Phrase Relation Expert", instructions=RELATION_SYSTEM_PROMPT, model=get_model(model_name), model_settings=ModelSettings( temperature=0.0, max_tokens=65536, ), tools=[], ) return agent def parse_relation_response(response_content: str) -> dict: """解析关系分析响应 Args: response_content: Agent 返回的响应内容 Returns: 解析后的字典 """ try: # 如果响应包含在 markdown 代码块中,提取 JSON 部分 if "```json" in response_content: json_start = response_content.index("```json") + 7 json_end = response_content.index("```", json_start) json_text = response_content[json_start:json_end].strip() elif "```" in response_content: json_start = response_content.index("```") + 3 json_end = response_content.index("```", json_start) json_text = response_content[json_start:json_end].strip() else: json_text = response_content.strip() return json.loads(json_text) except Exception as e: print(f"解析响应失败: {e}") return { "relation": "unrelated", "score": 0.0, "explanation": f"解析失败: {str(e)}" } async def analyze_relation( phrase_a: str, phrase_b: str, model_name: str = None, context_a: str = "", context_b: str = "" ) -> dict: """分析两个短语之间的关系 Args: phrase_a: 第一个短语 phrase_b: 第二个短语 model_name: 使用的模型名称(可选,默认使用 client.py 中的 MODEL_NAME) context_a: phrase_a 的补充上下文(可选,默认为空) context_b: phrase_b 的补充上下文(可选,默认为空) Returns: 关系分析结果字典:{"relation": "same", "score": 0.95, "explanation": "..."} """ try: # 如果未指定模型,使用默认模型 if model_name is None: from lib.client import MODEL_NAME model_name = MODEL_NAME # 创建 Agent agent = create_relation_agent(model_name) # 构建任务描述 a_section = f"\n{phrase_a}\n" if context_a: a_section += f"\n\n\n{context_a}\n" b_section = f"\n{phrase_b}\n" if context_b: b_section += f"\n\n\n{context_b}\n" task_description = f"""## 本次分析任务 {a_section} {b_section} 请严格按照系统提示中的要求分析 之间的语义关系,并输出 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 b_short = (phrase_b[:30] + "...") if len(phrase_b) > 30 else phrase_b with custom_span( name=f"关系分析: {a_short} <-> {b_short}", data={ "phrase_a": phrase_a, "phrase_b": phrase_b, "context_a": context_a if context_a else None, "context_b": context_b if context_b else None, } ): # 运行 Agent result = await Runner.run(agent, input=messages) # 解析响应 parsed_result = parse_relation_response(result.final_output) return parsed_result except Exception as e: return { "relation": "unrelated", "score": 0.0, "explanation": f"分析过程出错: {str(e)}" }