| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- """
- 短语关系分析模块
- 分析两个短语之间的语义关系
- 提供接口:
- 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> 和 <B> 之间的语义关系。
- ## 输入说明
- - **<A></A>**: 第一个短语(必选)
- - **<B></B>**: 第二个短语(必选)
- - **<A_Context></A_Context>**: A 的补充上下文(可选,帮助理解 A)
- - **<B_Context></B_Context>**: B 的补充上下文(可选,帮助理解 B)
- **重要**:关系分析发生在 <A> 和 <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"<A>\n{phrase_a}\n</A>"
- if context_a:
- a_section += f"\n\n<A_Context>\n{context_a}\n</A_Context>"
- b_section = f"<B>\n{phrase_b}\n</B>"
- if context_b:
- b_section += f"\n\n<B_Context>\n{context_b}\n</B_Context>"
- task_description = f"""## 本次分析任务
- {a_section}
- {b_section}
- 请严格按照系统提示中的要求分析 <A> 和 <B> 之间的语义关系,并输出 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)}"
- }
|