From e766bc625abd1005aedacd97eb66d2c7cd94670d Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Wed, 17 Jun 2026 15:28:00 +0700 Subject: [PATCH] fix: translate all Chinese prompts to English in zep_tools.py - Interview prompt prefix: Chinese -> English - Sub-query decomposition: Chinese -> English - Agent selection: Chinese -> English - Interview questions: Chinese -> English - Interview summary: Chinese -> English - Error messages: Chinese -> English - to_text() labels: Chinese -> English This ensures get_language_instruction() actually controls output language instead of being overridden by Chinese prompt context. --- backend/app/services/zep_tools.py | 294 +++++++++++++++--------------- 1 file changed, 147 insertions(+), 147 deletions(-) diff --git a/backend/app/services/zep_tools.py b/backend/app/services/zep_tools.py index 3bc8a57..dfc73eb 100644 --- a/backend/app/services/zep_tools.py +++ b/backend/app/services/zep_tools.py @@ -44,10 +44,10 @@ class SearchResult: def to_text(self) -> str: """转换为文本格式,供LLM理解""" - text_parts = [f"搜索查询: {self.query}", f"找到 {self.total_count} 条相关信息"] + text_parts = [f"Search query: {self.query}", f"Found {self.total_count} relevant items"] if self.facts: - text_parts.append("\n### 相关事实:") + text_parts.append("\n### Relevant facts:") for i, fact in enumerate(self.facts, 1): text_parts.append(f"{i}. {fact}") @@ -74,8 +74,8 @@ class NodeInfo: def to_text(self) -> str: """转换为文本格式""" - entity_type = next((l for l in self.labels if l not in ["Entity", "Node"]), "未知类型") - return f"实体: {self.name} (类型: {entity_type})\n摘要: {self.summary}" + entity_type = next((l for l in self.labels if l not in ["Entity", "Node"]), "Unknown type") + return f"Entity: {self.name} (Type: {entity_type})\nSummary: {self.summary}" @dataclass @@ -113,14 +113,14 @@ class EdgeInfo: """转换为文本格式""" source = self.source_node_name or self.source_node_uuid[:8] target = self.target_node_name or self.target_node_uuid[:8] - base_text = f"关系: {source} --[{self.name}]--> {target}\n事实: {self.fact}" + base_text = f"Relation: {source} --[{self.name}]--> {target}\nFact: {self.fact}" if include_temporal: - valid_at = self.valid_at or "未知" - invalid_at = self.invalid_at or "至今" - base_text += f"\n时效: {valid_at} - {invalid_at}" + valid_at = self.valid_at or "Unknown" + invalid_at = self.invalid_at or "present" + base_text += f"\nValidity: {valid_at} - {invalid_at}" if self.expired_at: - base_text += f" (已过期: {self.expired_at})" + base_text += f" (Expired: {self.expired_at})" return base_text @@ -147,7 +147,7 @@ class InsightForgeResult: # 各维度检索结果 semantic_facts: List[str] = field(default_factory=list) # 语义搜索结果 - entity_insights: List[Dict[str, Any]] = field(default_factory=list) # 实体洞察 + entity_insights: List[Dict[str, Any]] = field(default_factory=list) # Entity洞察 relationship_chains: List[str] = field(default_factory=list) # 关系链 # 统计信息 @@ -171,40 +171,40 @@ class InsightForgeResult: def to_text(self) -> str: """转换为详细的文本格式,供LLM理解""" text_parts = [ - f"## 未来预测深度分析", - f"分析问题: {self.query}", - f"预测场景: {self.simulation_requirement}", - f"\n### 预测数据统计", - f"- 相关预测事实: {self.total_facts}条", - f"- 涉及实体: {self.total_entities}个", - f"- 关系链: {self.total_relationships}条" + f"## Future Prediction Deep Analysis", + f"Analysis question: {self.query}", + f"Prediction scenario: {self.simulation_requirement}", + f"\n### Prediction Statistics", + f"- Related prediction facts: {self.total_facts} items", + f"- Involved entities: {self.total_entities}", + f"- Relationship chains: {self.total_relationships} items" ] # 子问题 if self.sub_queries: - text_parts.append(f"\n### 分析的子问题") + text_parts.append(f"\n### Analyzed Sub-questions") for i, sq in enumerate(self.sub_queries, 1): text_parts.append(f"{i}. {sq}") # 语义搜索结果 if self.semantic_facts: - text_parts.append(f"\n### 【关键事实】(请在报告中引用这些原文)") + text_parts.append(f"\n### [Key Facts] (Please quote these in the report)") for i, fact in enumerate(self.semantic_facts, 1): text_parts.append(f"{i}. \"{fact}\"") - # 实体洞察 + # Entity洞察 if self.entity_insights: - text_parts.append(f"\n### 【核心实体】") + text_parts.append(f"\n### [Core Entities]") for entity in self.entity_insights: - text_parts.append(f"- **{entity.get('name', '未知')}** ({entity.get('type', '实体')})") + text_parts.append(f"- **{entity.get('name', 'Unknown')}** ({entity.get('type', 'Entity')})") if entity.get('summary'): - text_parts.append(f" 摘要: \"{entity.get('summary')}\"") + text_parts.append(f" Summary: \"{entity.get('summary')}\"") if entity.get('related_facts'): - text_parts.append(f" 相关事实: {len(entity.get('related_facts', []))}条") + text_parts.append(f" Related facts: {len(entity.get('related_facts', []))} items") # 关系链 if self.relationship_chains: - text_parts.append(f"\n### 【关系链】") + text_parts.append(f"\n### [Relationship Chains]") for chain in self.relationship_chains: text_parts.append(f"- {chain}") @@ -250,32 +250,32 @@ class PanoramaResult: def to_text(self) -> str: """转换为文本格式(完整版本,不截断)""" text_parts = [ - f"## 广度搜索结果(未来全景视图)", - f"查询: {self.query}", - f"\n### 统计信息", - f"- 总节点数: {self.total_nodes}", - f"- 总边数: {self.total_edges}", - f"- 当前有效事实: {self.active_count}条", - f"- 历史/过期事实: {self.historical_count}条" + f"## Panorama Search Results (Future Panoramic View)", + f"Query: {self.query}", + f"\n### Statistics", + f"- Total nodes: {self.total_nodes}", + f"- Total edges: {self.total_edges}", + f"- Currently active facts: {self.active_count} items", + f"- Historical/expired facts: {self.historical_count} items" ] # 当前有效的事实(完整输出,不截断) if self.active_facts: - text_parts.append(f"\n### 【当前有效事实】(模拟结果原文)") + text_parts.append(f"\n### [Currently Active Facts] (Simulation results)") for i, fact in enumerate(self.active_facts, 1): text_parts.append(f"{i}. \"{fact}\"") # 历史/过期事实(完整输出,不截断) if self.historical_facts: - text_parts.append(f"\n### 【历史/过期事实】(演变过程记录)") + text_parts.append(f"\n### [Historical/Expired Facts] (Evolution records)") for i, fact in enumerate(self.historical_facts, 1): text_parts.append(f"{i}. \"{fact}\"") - # 关键实体(完整输出,不截断) + # 关键Entity(完整输出,不截断) if self.all_nodes: - text_parts.append(f"\n### 【涉及实体】") + text_parts.append(f"\n### [Involved Entities]") for node in self.all_nodes: - entity_type = next((l for l in node.labels if l not in ["Entity", "Node"]), "实体") + entity_type = next((l for l in node.labels if l not in ["Entity", "Node"]), "Entity") text_parts.append(f"- **{node.name}** ({entity_type})") return "\n".join(text_parts) @@ -304,11 +304,11 @@ class AgentInterview: def to_text(self) -> str: text = f"**{self.agent_name}** ({self.agent_role})\n" # 显示完整的agent_bio,不截断 - text += f"_简介: {self.agent_bio}_\n\n" + text += f"_Bio: {self.agent_bio}_\n\n" text += f"**Q:** {self.question}\n\n" text += f"**A:** {self.response}\n" if self.key_quotes: - text += "\n**关键引言:**\n" + text += "\n**Key quotes:**\n" for quote in self.key_quotes: # 清理各种引号 clean_quote = quote.replace('\u201c', '').replace('\u201d', '').replace('"', '') @@ -375,25 +375,25 @@ class InterviewResult: def to_text(self) -> str: """转换为详细的文本格式,供LLM理解和报告引用""" text_parts = [ - "## 深度采访报告", - f"**采访主题:** {self.interview_topic}", - f"**采访人数:** {self.interviewed_count} / {self.total_agents} 位模拟Agent", - "\n### 采访对象选择理由", - self.selection_reasoning or "(自动选择)", + "## Deep Interview Report", + f"**Interview topic:** {self.interview_topic}", + f"**Interviewed:** {self.interviewed_count} / {self.total_agents} simulation Agents", + "\n### Interviewee Selection Reasoning", + self.selection_reasoning or "(Auto-selected)", "\n---", - "\n### 采访实录", + "\n### Interview Transcripts", ] if self.interviews: for i, interview in enumerate(self.interviews, 1): - text_parts.append(f"\n#### 采访 #{i}: {interview.agent_name}") + text_parts.append(f"\n#### Interview #{i}: {interview.agent_name}") text_parts.append(interview.to_text()) text_parts.append("\n---") else: - text_parts.append("(无采访记录)\n\n---") + text_parts.append("(No interview records)\n\n---") - text_parts.append("\n### 采访摘要与核心观点") - text_parts.append(self.summary or "(无摘要)") + text_parts.append("\n### Interview Summary & Key Perspectives") + text_parts.append(self.summary or "(No summary)") return "\n".join(text_parts) @@ -414,8 +414,8 @@ class ZepToolsService: - get_all_edges - 获取图谱所有边(含时间信息) - get_node_detail - 获取节点详细信息 - get_node_edges - 获取节点相关的边 - - get_entities_by_type - 按类型获取实体 - - get_entity_summary - 获取实体的关系摘要 + - get_entities_by_type - 按类型获取Entity + - get_entity_summary - 获取Entity的关系摘要 """ # 重试配置 @@ -783,14 +783,14 @@ class ZepToolsService: entity_type: str ) -> List[NodeInfo]: """ - 按类型获取实体 + 按类型获取Entity Args: graph_id: 图谱ID - entity_type: 实体类型(如 Student, PublicFigure 等) + entity_type: Entity类型(如 Student, PublicFigure 等) Returns: - 符合类型的实体列表 + 符合类型的Entity列表 """ logger.info(t("console.fetchingEntitiesByType", type=entity_type)) @@ -811,27 +811,27 @@ class ZepToolsService: entity_name: str ) -> Dict[str, Any]: """ - 获取指定实体的关系摘要 + 获取指定Entity的关系摘要 - 搜索与该实体相关的所有信息,并生成摘要 + 搜索与该Entity相关的所有信息,并生成摘要 Args: graph_id: 图谱ID - entity_name: 实体名称 + entity_name: Entity名称 Returns: - 实体摘要信息 + Entity摘要信息 """ logger.info(t("console.fetchingEntitySummary", name=entity_name)) - # 先搜索该实体相关的信息 + # 先搜索该Entity相关的信息 search_result = self.search_graph( graph_id=graph_id, query=entity_name, limit=20 ) - # 尝试在所有节点中找到该实体 + # 尝试在所有节点中找到该Entity all_nodes = self.get_all_nodes(graph_id) entity_node = None for node in all_nodes: @@ -867,7 +867,7 @@ class ZepToolsService: nodes = self.get_all_nodes(graph_id) edges = self.get_all_edges(graph_id) - # 统计实体类型分布 + # 统计Entity类型分布 entity_types = {} for node in nodes: for label in node.labels: @@ -918,10 +918,10 @@ class ZepToolsService: # 获取图谱统计 stats = self.get_graph_statistics(graph_id) - # 获取所有实体节点 + # 获取所有Entity节点 all_nodes = self.get_all_nodes(graph_id) - # 筛选有实际类型的实体(非纯Entity节点) + # 筛选有实际类型的Entity(非纯Entity节点) entities = [] for node in all_nodes: custom_labels = [l for l in node.labels if l not in ["Entity", "Node"]] @@ -956,7 +956,7 @@ class ZepToolsService: 最强大的混合检索函数,自动分解问题并多维度检索: 1. 使用LLM将问题分解为多个子问题 2. 对每个子问题进行语义搜索 - 3. 提取相关实体并获取其详细信息 + 3. 提取相关Entity并获取其详细信息 4. 追踪关系链 5. 整合所有结果,生成深度洞察 @@ -1023,7 +1023,7 @@ class ZepToolsService: result.semantic_facts = all_facts result.total_facts = len(all_facts) - # Step 3: 从边中提取相关实体UUID,只获取这些实体的信息(不获取全部节点) + # Step 3: 从边中提取相关EntityUUID,只获取这些Entity的信息(不获取全部节点) entity_uuids = set() for edge_data in all_edges: if isinstance(edge_data, dict): @@ -1034,11 +1034,11 @@ class ZepToolsService: if target_uuid: entity_uuids.add(target_uuid) - # 获取所有相关实体的详情(不限制数量,完整输出) + # 获取所有相关Entity的详情(不限制数量,完整输出) entity_insights = [] node_map = {} # 用于后续关系链构建 - for uuid in list(entity_uuids): # 处理所有实体,不截断 + for uuid in list(entity_uuids): # 处理所有Entity,不截断 if not uuid: continue try: @@ -1046,9 +1046,9 @@ class ZepToolsService: node = self.get_node_detail(uuid) if node: node_map[uuid] = node - entity_type = next((l for l in node.labels if l not in ["Entity", "Node"]), "实体") + entity_type = next((l for l in node.labels if l not in ["Entity", "Node"]), "Entity") - # 获取该实体相关的所有事实(不截断) + # 获取该Entity相关的所有事实(不截断) related_facts = [ f for f in all_facts if node.name.lower() in f.lower() @@ -1101,23 +1101,23 @@ class ZepToolsService: 将复杂问题分解为多个可以独立检索的子问题 """ - system_prompt = """你是一个专业的问题分析专家。你的任务是将一个复杂问题分解为多个可以在模拟世界中独立观察的子问题。 + system_prompt = """You are a professional question analysis expert. Your task is to decompose a complex question into multiple sub-questions that can be independently observed in the simulation world. -要求: -1. 每个子问题应该足够具体,可以在模拟世界中找到相关的Agent行为或事件 -2. 子问题应该覆盖原问题的不同维度(如:谁、什么、为什么、怎么样、何时、何地) -3. 子问题应该与模拟场景相关 -4. 返回JSON格式:{"sub_queries": ["子问题1", "子问题2", ...]}""" +Requirements: +1. Each sub-question should be specific enough to find relevant Agent behavior or events in the simulation world +2. Sub-questions should cover different dimensions of the original question (who, what, why, how, when, where) +3. Sub-questions should be relevant to the simulation scenario +4. Return in JSON format: {"sub_queries": ["sub-question 1", "sub-question 2", ...]}""" - user_prompt = f"""模拟需求背景: + user_prompt = f"""Simulation requirement background: {simulation_requirement} -{f"报告上下文:{report_context[:500]}" if report_context else ""} +{f"Report context: {report_context[:500]}" if report_context else ""} -请将以下问题分解为{max_queries}个子问题: +Please decompose the following question into {max_queries} sub-questions: {query} -返回JSON格式的子问题列表。""" +Return the sub-questions in JSON format.""" try: response = self.llm.chat_json( @@ -1191,7 +1191,7 @@ class ZepToolsService: if not edge.fact: continue - # 为事实添加实体名称 + # 为事实添加Entity名称 source_name = node_map.get(edge.source_node_uuid, NodeInfo('', '', [], '', {})).name or edge.source_node_uuid[:8] target_name = node_map.get(edge.target_node_uuid, NodeInfo('', '', [], '', {})).name or edge.target_node_uuid[:8] @@ -1200,8 +1200,8 @@ class ZepToolsService: if is_historical: # 历史/过期事实,添加时间标记 - valid_at = edge.valid_at or "未知" - invalid_at = edge.invalid_at or edge.expired_at or "未知" + valid_at = edge.valid_at or "Unknown" + invalid_at = edge.invalid_at or edge.expired_at or "Unknown" fact_with_time = f"[{valid_at} - {invalid_at}] {edge.fact}" historical_facts.append(fact_with_time) else: @@ -1350,15 +1350,15 @@ class ZepToolsService: # 添加优化前缀,约束Agent回复格式 INTERVIEW_PROMPT_PREFIX = ( - "你正在接受一次采访。请结合你的人设、所有的过往记忆与行动," - "以纯文本方式直接回答以下问题。\n" - "回复要求:\n" - "1. 直接用自然语言回答,不要调用任何工具\n" - "2. 不要返回JSON格式或工具调用格式\n" - "3. 不要使用Markdown标题(如#、##、###)\n" - "4. 按问题编号逐一回答,每个回答以「问题X:」开头(X为问题编号)\n" - "5. 每个问题的回答之间用空行分隔\n" - "6. 回答要有实质内容,每个问题至少回答2-3句话\n\n" + "You are being interviewed. Please draw on your persona, all past memories and actions, " + "and answer the following questions directly in plain text.\n" + "Response requirements:\n" + "1. Answer directly in natural language, do not call any tools\n" + "2. Do not return JSON format or tool call format\n" + "3. Do not use Markdown headings (such as #, ##, ###)\n" + "4. Answer each question by number, starting each answer with 'Question X:' (X is the question number)\n" + "5. Separate each answer with a blank line\n" + "6. Provide substantive answers, at least 2-3 sentences per question\n\n" ) optimized_prompt = f"{INTERVIEW_PROMPT_PREFIX}{combined_prompt}" @@ -1387,9 +1387,9 @@ class ZepToolsService: # 检查API调用是否成功 if not api_result.get("success", False): - error_msg = api_result.get("error", "未知错误") + error_msg = api_result.get("error", "Unknown error") logger.warning(t("console.interviewApiReturnedFailure", error=error_msg)) - result.summary = f"采访API调用失败:{error_msg}。请检查OASIS模拟环境状态。" + result.summary = f"Interview API call failed: {error_msg}. Please check OASIS simulation environment status." return result # Step 5: 解析API返回结果,构建AgentInterview对象 @@ -1400,7 +1400,7 @@ class ZepToolsService: for i, agent_idx in enumerate(selected_indices): agent = selected_agents[i] agent_name = agent.get("realname", agent.get("username", f"Agent_{agent_idx}")) - agent_role = agent.get("profession", "未知") + agent_role = agent.get("profession", "Unknown") agent_bio = agent.get("bio", "") # 获取该Agent在两个平台的采访结果 @@ -1462,7 +1462,7 @@ class ZepToolsService: except ValueError as e: # 模拟环境未运行 logger.warning(t("console.interviewApiCallFailed", error=e)) - result.summary = f"采访失败:{str(e)}。模拟环境可能已关闭,请确保OASIS环境正在运行。" + result.summary = f"Interview failed: {str(e)}. Simulation environment may have closed. Please ensure OASIS environment is running." return result except Exception as e: logger.error(t("console.interviewApiCallException", error=e)) @@ -1539,7 +1539,7 @@ class ZepToolsService: "username": row.get("username", ""), "bio": row.get("description", ""), "persona": row.get("user_char", ""), - "profession": "未知" + "profession": "Unknown" }) logger.info(t("console.loadedTwitterProfiles", count=len(profiles))) return profiles @@ -1571,36 +1571,36 @@ class ZepToolsService: summary = { "index": i, "name": profile.get("realname", profile.get("username", f"Agent_{i}")), - "profession": profile.get("profession", "未知"), + "profession": profile.get("profession", "Unknown"), "bio": profile.get("bio", "")[:200], "interested_topics": profile.get("interested_topics", []) } agent_summaries.append(summary) - system_prompt = """你是一个专业的采访策划专家。你的任务是根据采访需求,从模拟Agent列表中选择最适合采访的对象。 + system_prompt = """You are a professional interview planning expert. Your task is to select the most suitable agents to interview from the simulation agent list based on the interview requirements. -选择标准: -1. Agent的身份/职业与采访主题相关 -2. Agent可能持有独特或有价值的观点 -3. 选择多样化的视角(如:支持方、反对方、中立方、专业人士等) -4. 优先选择与事件直接相关的角色 +Selection criteria: +1. Agent's identity/profession is relevant to the interview topic +2. Agent may hold unique or valuable perspectives +3. Select diverse viewpoints (e.g., supporters, opponents, neutral parties, professionals) +4. Prioritize roles directly related to the event -返回JSON格式: +Return in JSON format: { - "selected_indices": [选中Agent的索引列表], - "reasoning": "选择理由说明" + "selected_indices": [list of selected agent indices], + "reasoning": "Explanation of selection reasoning" }""" - user_prompt = f"""采访需求: + user_prompt = f"""Interview requirements: {interview_requirement} -模拟背景: -{simulation_requirement if simulation_requirement else "未提供"} +Simulation background: +{simulation_requirement if simulation_requirement else "Not provided"} -可选择的Agent列表(共{len(agent_summaries)}个): +Available agent list ({len(agent_summaries)} total): {json.dumps(agent_summaries, ensure_ascii=False, indent=2)} -请选择最多{max_agents}个最适合采访的Agent,并说明选择理由。""" +Please select up to {max_agents} agents most suitable for interview and explain your reasoning.""" try: response = self.llm.chat_json( @@ -1612,7 +1612,7 @@ class ZepToolsService: ) selected_indices = response.get("selected_indices", [])[:max_agents] - reasoning = response.get("reasoning", "基于相关性自动选择") + reasoning = response.get("reasoning", "Auto-selected based on relevance") # 获取选中的Agent完整信息 selected_agents = [] @@ -1639,27 +1639,27 @@ class ZepToolsService: ) -> List[str]: """使用LLM生成采访问题""" - agent_roles = [a.get("profession", "未知") for a in selected_agents] + agent_roles = [a.get("profession", "Unknown") for a in selected_agents] - system_prompt = """你是一个专业的记者/采访者。根据采访需求,生成3-5个深度采访问题。 + system_prompt = """You are a professional journalist/interviewer. Based on the interview requirements, generate 3-5 in-depth interview questions. -问题要求: -1. 开放性问题,鼓励详细回答 -2. 针对不同角色可能有不同答案 -3. 涵盖事实、观点、感受等多个维度 -4. 语言自然,像真实采访一样 -5. 每个问题控制在50字以内,简洁明了 -6. 直接提问,不要包含背景说明或前缀 +Question requirements: +1. Open-ended questions that encourage detailed answers +2. Different roles may have different answers +3. Cover multiple dimensions: facts, opinions, feelings +4. Natural language, like a real interview +5. Keep each question under 50 words, concise and clear +6. Ask directly, do not include background explanations or prefixes -返回JSON格式:{"questions": ["问题1", "问题2", ...]}""" +Return in JSON format: {"questions": ["question 1", "question 2", ...]}""" - user_prompt = f"""采访需求:{interview_requirement} + user_prompt = f"""Interview requirements: {interview_requirement} -模拟背景:{simulation_requirement if simulation_requirement else "未提供"} +Simulation background: {simulation_requirement if simulation_requirement else "Not provided"} -采访对象角色:{', '.join(agent_roles)} +Interviewee roles: {', '.join(agent_roles)} -请生成3-5个采访问题。""" +Please generate 3-5 interview questions.""" try: response = self.llm.chat_json( @@ -1670,14 +1670,14 @@ class ZepToolsService: temperature=0.5 ) - return response.get("questions", [f"关于{interview_requirement},您有什么看法?"]) + return response.get("questions", [f"What is your view on {interview_requirement}?"]) except Exception as e: logger.warning(t("console.generateInterviewQuestionsFailed", error=e)) return [ - f"关于{interview_requirement},您的观点是什么?", - "这件事对您或您所代表的群体有什么影响?", - "您认为应该如何解决或改进这个问题?" + f"What is your perspective on {interview_requirement}?", + "How does this affect you or the group you represent?", + "What do you think should be done to address or improve this issue?" ] def _generate_interview_summary( @@ -1688,36 +1688,36 @@ class ZepToolsService: """生成采访摘要""" if not interviews: - return "未完成任何采访" + return "No interviews completed" # 收集所有采访内容 interview_texts = [] for interview in interviews: interview_texts.append(f"【{interview.agent_name}({interview.agent_role})】\n{interview.response[:500]}") - quote_instruction = "引用受访者原话时使用中文引号「」" if get_locale() == 'zh' else 'Use quotation marks "" when quoting interviewees' - system_prompt = f"""你是一个专业的新闻编辑。请根据多位受访者的回答,生成一份采访摘要。 + quote_instruction = 'Use quotation marks "" when quoting interviewees' + system_prompt = f"""You are a professional news editor. Based on multiple interviewees' responses, generate an interview summary. -摘要要求: -1. 提炼各方主要观点 -2. 指出观点的共识和分歧 -3. 突出有价值的引言 -4. 客观中立,不偏袒任何一方 -5. 控制在1000字内 +Summary requirements: +1. Extract key viewpoints from each party +2. Identify consensus and disagreements +3. Highlight valuable quotes +4. Stay objective and neutral, do not favor any party +5. Keep within 1000 words -格式约束(必须遵守): -- 使用纯文本段落,用空行分隔不同部分 -- 不要使用Markdown标题(如#、##、###) -- 不要使用分割线(如---、***) +Format constraints (must follow): +- Use plain text paragraphs, separate sections with blank lines +- Do not use Markdown headings (such as #, ##, ###) +- Do not use dividers (such as ---, ***) - {quote_instruction} -- 可以使用**加粗**标记关键词,但不要使用其他Markdown语法""" +- You may use **bold** to mark key words, but do not use other Markdown syntax""" - user_prompt = f"""采访主题:{interview_requirement} + user_prompt = f"""Interview topic: {interview_requirement} -采访内容: +Interview content: {"".join(interview_texts)} -请生成采访摘要。""" +Please generate an interview summary.""" try: summary = self.llm.chat(