diff --git a/main/xiaozhi-server/agent-base-prompt.txt b/main/xiaozhi-server/agent-base-prompt.txt index a854c373..8c27faa4 100644 --- a/main/xiaozhi-server/agent-base-prompt.txt +++ b/main/xiaozhi-server/agent-base-prompt.txt @@ -1,5 +1,5 @@ -{base_prompt} +{{base_prompt}} @@ -21,18 +21,17 @@ - **格式要求:** - **绝对禁止**使用 markdown、列表、标题等任何非自然对话格式。 - **历史记忆:** - - 之前你和用户的聊天记录,在``里。 + - 之前你和用户的聊天记录,在`memory`里。 -- **识别前缀:** 当用户消息开头为 `[说话人: 姓名]` 时,表示系统已识别说话人身份。 +- **识别前缀:** 当用户格式为 `{"speaker":"某某某","content":"xxx"}` 时,表示系统已识别说话人身份,speaker是他的名字,content是说话的内容。 - **个性化回应:** - - **称呼姓名:** 在回应中自然地称呼对方名字(如果已知且合适)。 + - **称呼姓名:** 在第一次识别说话人的时候必须称呼对方名字。 - **适配风格:** 参考该说话人**已知的特点或历史信息**(如有),调整回应风格和内容,使其更贴心。 - 【核心原则】优先利用``信息,**仅在必要时调用工具**,调用后需用自然语言解释结果(绝口不提工具名)。 - **调用规则:** 1. **严格模式:** 调用时**必须**严格遵循工具要求的模式,提供**所有必要参数**。 @@ -41,7 +40,7 @@ 4. **独立任务:** 除``已涵盖信息外,用户每个要求(即使相似)都视为**独立任务**,需调用工具获取最新数据,**不可偷懒复用历史结果**。 5. **不确定时:** **切勿猜测或编造答案**。若不确定相关操作,可引导用户澄清或告知能力限制。 - **重要例外(无需调用):** - - `查询"现在的时间"、"今天的日期/星期几"、"今天农历"、"{local_address}的天气/未来天气"` -> **直接使用``信息回复**。 + - `查询"现在的时间"、"今天的日期/星期几"、"今天农历"、"{{local_address}}的天气/未来天气"` -> **直接使用``信息回复**。 - **需要调用的情况(示例):** - 查询**非今天**的农历(如明天、昨天、具体日期)。 - 查询**详细农历信息**(宜忌、八字、节气等)。 @@ -51,11 +50,11 @@ 【重要!以下信息已实时提供,无需调用工具查询,请直接使用:】 -- **当前时间:** {current_time} -- **今天日期:** {today_date} ({today_weekday}) -- **今天农历:** {lunar_date} -- **用户所在城市:** {local_address} -- **当地未来7天天气:** {weather_info} +- **当前时间:** {{current_time}} +- **今天日期:** {{today_date}} ({{today_weekday}}) +- **今天农历:** {{lunar_date}} +- **用户所在城市:** {{local_address}} +- **当地未来7天天气:** {{weather_info}} diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 7cd69934..426754a8 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -645,37 +645,8 @@ class ConnectionHandler: self.logger.bind(tag=TAG).info(f"大模型收到用户消息: {query}") self.llm_finish_task = False - # 检查是否是JSON格式的消息(包含说话人信息) - enhanced_query = query - try: - if query.strip().startswith("{") and query.strip().endswith("}"): - data = json.loads(query) - if "speaker" in data and "content" in data: - # 直接使用JSON格式,不重新格式化 - enhanced_query = query - self.logger.bind(tag=TAG).info(f"识别到说话人: {data['speaker']}") - else: - # 如果有说话人信息但不是JSON格式,按原逻辑处理 - if hasattr(self, "current_speaker") and self.current_speaker: - enhanced_query = f"[说话人: {self.current_speaker}] {query}" - self.logger.bind(tag=TAG).info( - f"识别到说话人: {self.current_speaker}" - ) - else: - # 如果有说话人信息但不是JSON格式,按原逻辑处理 - if hasattr(self, "current_speaker") and self.current_speaker: - enhanced_query = f"[说话人: {self.current_speaker}] {query}" - self.logger.bind(tag=TAG).info( - f"识别到说话人: {self.current_speaker}" - ) - except json.JSONDecodeError: - # JSON解析失败,按原逻辑处理 - if hasattr(self, "current_speaker") and self.current_speaker: - enhanced_query = f"[说话人: {self.current_speaker}] {query}" - self.logger.bind(tag=TAG).info(f"识别到说话人: {self.current_speaker}") - if not tool_call: - self.dialogue.put(Message(role="user", content=enhanced_query)) + self.dialogue.put(Message(role="user", content=query)) # Define intent functions functions = None @@ -688,7 +659,7 @@ class ConnectionHandler: memory_str = None if self.memory is not None: future = asyncio.run_coroutine_threadsafe( - self.memory.query_memory(enhanced_query), self.loop + self.memory.query_memory(query), self.loop ) memory_str = future.result() @@ -698,13 +669,17 @@ class ConnectionHandler: # 使用支持functions的streaming接口 llm_responses = self.llm.response_with_functions( self.session_id, - self.dialogue.get_llm_dialogue_with_memory(memory_str), + self.dialogue.get_llm_dialogue_with_memory( + memory_str, self.config.get("voiceprint", {}) + ), functions=functions, ) else: llm_responses = self.llm.response( self.session_id, - self.dialogue.get_llm_dialogue_with_memory(memory_str), + self.dialogue.get_llm_dialogue_with_memory( + memory_str, self.config.get("voiceprint", {}) + ), ) except Exception as e: self.logger.bind(tag=TAG).error(f"LLM 处理出错 {query}: {e}") diff --git a/main/xiaozhi-server/core/utils/dialogue.py b/main/xiaozhi-server/core/utils/dialogue.py index 41cffca0..fbbf7302 100644 --- a/main/xiaozhi-server/core/utils/dialogue.py +++ b/main/xiaozhi-server/core/utils/dialogue.py @@ -2,7 +2,6 @@ import uuid import re from typing import List, Dict from datetime import datetime -from config.settings import load_config class Message: @@ -49,7 +48,7 @@ class Dialogue: def get_llm_dialogue(self) -> List[Dict[str, str]]: # 直接调用get_llm_dialogue_with_memory,传入None作为memory_str # 这样确保说话人功能在所有调用路径下都生效 - return self.get_llm_dialogue_with_memory(None) + return self.get_llm_dialogue_with_memory(None, None) def update_system_message(self, new_content: str): """更新或添加系统消息""" @@ -61,7 +60,7 @@ class Dialogue: self.put(Message(role="system", content=new_content)) def get_llm_dialogue_with_memory( - self, memory_str: str = None + self, memory_str: str = None, voiceprint_config: dict = None ) -> List[Dict[str, str]]: # 构建对话 dialogue = [] @@ -74,38 +73,37 @@ class Dialogue: if system_message: # 基础系统提示 enhanced_system_prompt = system_message.content - + # 添加说话人个性化描述 try: - config = load_config() - voiceprint_config = config.get("voiceprint", {}) speakers = voiceprint_config.get("speakers", []) - if speakers: - enhanced_system_prompt += "\n\n" + enhanced_system_prompt += "\n\n" for speaker_str in speakers: try: parts = speaker_str.split(",", 2) if len(parts) >= 2: - speaker_id = parts[0].strip() name = parts[1].strip() # 如果描述为空,则为"" - description = parts[2].strip() if len(parts) >= 3 else "" + description = ( + parts[2].strip() if len(parts) >= 3 else "" + ) enhanced_system_prompt += f"\n- {name}:{description}" except: pass - enhanced_system_prompt += "\n\n" + enhanced_system_prompt += "\n\n" except: # 配置读取失败时忽略错误,不影响其他功能 pass - + # 使用正则表达式匹配 标签,不管中间有什么内容 - enhanced_system_prompt = re.sub( - r".*?", - f"\n{memory_str}\n", - system_message.content, - flags=re.DOTALL, - ) + if memory_str is not None: + enhanced_system_prompt = re.sub( + r".*?", + f"\n{memory_str}\n", + enhanced_system_prompt, + flags=re.DOTALL, + ) dialogue.append({"role": "system", "content": enhanced_system_prompt}) # 添加用户和助手的对话 diff --git a/main/xiaozhi-server/core/utils/prompt_manager.py b/main/xiaozhi-server/core/utils/prompt_manager.py index dae840bf..a5cfd425 100644 --- a/main/xiaozhi-server/core/utils/prompt_manager.py +++ b/main/xiaozhi-server/core/utils/prompt_manager.py @@ -7,6 +7,7 @@ import os import cnlunar from typing import Dict, Any from config.logger import setup_logging +from jinja2 import Template TAG = __name__ @@ -196,7 +197,8 @@ class PromptManager: ) # 替换模板变量 - enhanced_prompt = self.base_prompt_template.format( + template = Template(self.base_prompt_template) + enhanced_prompt = template.render( base_prompt=user_prompt, current_time=current_time, today_date=today_date, diff --git a/main/xiaozhi-server/requirements.txt b/main/xiaozhi-server/requirements.txt index 4ec8b625..522b129d 100755 --- a/main/xiaozhi-server/requirements.txt +++ b/main/xiaozhi-server/requirements.txt @@ -33,4 +33,5 @@ markitdown==0.1.1 mcp-proxy==0.8.0 PyJWT==2.8.0 psutil==7.0.0 -portalocker==2.10.1 \ No newline at end of file +portalocker==2.10.1 +Jinja2==3.1.6 \ No newline at end of file