diff --git a/src/do_tool/tool_can_use/change_mood.py b/src/do_tool/tool_can_use/change_mood.py new file mode 100644 index 00000000..e7339e53 --- /dev/null +++ b/src/do_tool/tool_can_use/change_mood.py @@ -0,0 +1,58 @@ +from src.do_tool.tool_can_use.base_tool import BaseTool, register_tool +from src.plugins.config.config import global_config +from src.common.logger import get_module_logger +from src.plugins.moods.moods import MoodManager +from src.plugins.chat_module.think_flow_chat.think_flow_generator import ResponseGenerator + +from typing import Dict, Any + +logger = get_module_logger("change_mood_tool") + + +class ChangeMoodTool(BaseTool): + """改变心情的工具""" + + name = "change_mood" + description = "根据收到的内容和自身回复的内容,改变心情,当你回复了别人的消息,你可以使用这个工具" + parameters = { + "type": "object", + "properties": { + "text": {"type": "string", "description": "引起你改变心情的文本"}, + "response_set": {"type": "list", "description": "你对文本的回复"} + }, + "required": ["text", "response_set"], + } + + + async def execute(self, function_args: Dict[str, Any],message_txt:str) -> Dict[str, Any]: + """执行心情改变 + + Args: + function_args: 工具参数 + message_processed_plain_text: 原始消息文本 + response_set: 原始消息文本 + + Returns: + Dict: 工具执行结果 + """ + try: + response_set = function_args.get("response_set") + message_processed_plain_text = function_args.get("text") + + mood_manager = MoodManager.get_instance() + gpt = ResponseGenerator() + + if response_set is None: + response_set = ["你还没有回复"] + + ori_response = ",".join(response_set) + _stance, emotion = await gpt._get_emotion_tags(ori_response, message_processed_plain_text) + mood_manager.update_mood_from_emotion(emotion, global_config.mood_intensity_factor) + return {"name": "change_mood", "content": f"你的心情刚刚变化了,现在的心情是: {emotion}"} + except Exception as e: + logger.error(f"心情改变工具执行失败: {str(e)}") + return {"name": "change_mood", "content": f"心情改变失败: {str(e)}"} + + +# 注册工具 +# register_tool(ChangeMoodTool) diff --git a/src/do_tool/tool_can_use/change_relationship.py b/src/do_tool/tool_can_use/change_relationship.py new file mode 100644 index 00000000..a3d87e27 --- /dev/null +++ b/src/do_tool/tool_can_use/change_relationship.py @@ -0,0 +1,53 @@ +from src.plugins.person_info.relationship_manager import relationship_manager +from src.common.logger import get_module_logger +from src.do_tool.tool_can_use.base_tool import BaseTool +from src.plugins.chat_module.think_flow_chat.think_flow_generator import ResponseGenerator + + +logger = get_module_logger("relationship_tool") + +class RelationshipTool(BaseTool): + name = "change_relationship" + description = "根据收到的文本和回复内容,修改与特定用户的关系值,当你回复了别人的消息,你可以使用这个工具" + parameters = { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "收到的文本" + }, + "changed_value": { + "type": "number", + "description": "变更值" + }, + "reason": { + "type": "string", + "description": "变更原因" + } + }, + "required": ["text", "changed_value", "reason"] + } + + + async def execute(self, args: dict,message_txt:str) -> dict: + """执行工具功能 + + Args: + args: 包含工具参数的字典 + text: 原始消息文本 + changed_value: 变更值 + reason: 变更原因 + + Returns: + dict: 包含执行结果的字典 + """ + try: + text = args.get("text") + changed_value = args.get("changed_value") + reason = args.get("reason") + + return {"content": f"因为你刚刚因为{reason},所以你和发[{text}]这条消息的人的关系值变化为{changed_value}"} + + except Exception as e: + logger.error(f"修改关系值时发生错误: {str(e)}") + return {"content": f"修改关系值失败: {str(e)}"} \ No newline at end of file diff --git a/src/do_tool/tool_can_use/compare_numbers_tool.py b/src/do_tool/tool_can_use/compare_numbers_tool.py index 8d616f85..5ad30622 100644 --- a/src/do_tool/tool_can_use/compare_numbers_tool.py +++ b/src/do_tool/tool_can_use/compare_numbers_tool.py @@ -47,4 +47,4 @@ class CompareNumbersTool(BaseTool): # 注册工具 -register_tool(CompareNumbersTool) +# register_tool(CompareNumbersTool) diff --git a/src/do_tool/tool_can_use/get_current_task.py b/src/do_tool/tool_can_use/get_current_task.py index 1975c40b..dcfd059d 100644 --- a/src/do_tool/tool_can_use/get_current_task.py +++ b/src/do_tool/tool_can_use/get_current_task.py @@ -51,4 +51,4 @@ class GetCurrentTaskTool(BaseTool): # 注册工具 -register_tool(GetCurrentTaskTool) +# register_tool(GetCurrentTaskTool) diff --git a/src/do_tool/tool_can_use/get_knowledge.py b/src/do_tool/tool_can_use/get_knowledge.py index 0b492f11..74289d3d 100644 --- a/src/do_tool/tool_can_use/get_knowledge.py +++ b/src/do_tool/tool_can_use/get_knowledge.py @@ -132,4 +132,4 @@ class SearchKnowledgeTool(BaseTool): # 注册工具 -register_tool(SearchKnowledgeTool) +# register_tool(SearchKnowledgeTool) diff --git a/src/do_tool/tool_can_use/get_memory.py b/src/do_tool/tool_can_use/get_memory.py index 16af4c64..146e18e5 100644 --- a/src/do_tool/tool_can_use/get_memory.py +++ b/src/do_tool/tool_can_use/get_memory.py @@ -56,4 +56,4 @@ class GetMemoryTool(BaseTool): # 注册工具 -register_tool(GetMemoryTool) +# register_tool(GetMemoryTool) diff --git a/src/do_tool/tool_use.py b/src/do_tool/tool_use.py index b29bfcb0..81339ef3 100644 --- a/src/do_tool/tool_use.py +++ b/src/do_tool/tool_use.py @@ -21,7 +21,7 @@ class ToolUser: model=global_config.llm_heartflow, temperature=0.2, max_tokens=1000, request_type="tool_use" ) - async def _build_tool_prompt(self, message_txt: str, sender_name: str, chat_stream: ChatStream): + async def _build_tool_prompt(self, message_txt: str, sender_name: str, chat_stream: ChatStream, reply_message:str = ""): """构建工具使用的提示词 Args: @@ -45,9 +45,11 @@ class ToolUser: prompt = "" prompt += "你正在思考如何回复群里的消息。\n" prompt += f"你注意到{sender_name}刚刚说:{message_txt}\n" + if reply_message: + prompt += f"你刚刚回复的内容是:{reply_message}\n" prompt += f"注意你就是{bot_name},{bot_name}指的就是你。" - prompt += "你现在需要对群里的聊天内容进行回复,现在请你思考,你是否需要额外的信息,或者一些工具来帮你回复,不要使用危险功能(比如文件操作或者系统操作爬虫),比如回忆或者搜寻已有的知识,或者了解你现在正在做什么,请输出你需要的工具,或者你需要的额外信息。" + prompt += "你现在需要对群里的聊天内容进行回复,现在选择工具来对消息和你的回复进行处理,你是否需要额外的信息,或者进行一些动作,比如回忆或者搜寻已有的知识,改变关系和情感,或者了解你现在正在做什么,请输出你需要的工具,或者你需要的额外信息。" return prompt def _define_tools(self): @@ -81,10 +83,26 @@ class ToolUser: # 执行工具 result = await tool_instance.execute(function_args, message_txt) if result: + # 根据工具名称确定类型标签 + tool_type = "" + if "memory" in function_name.lower(): + tool_type = "memory" + elif "schedule" in function_name.lower() or "task" in function_name.lower(): + tool_type = "schedule" + elif "knowledge" in function_name.lower(): + tool_type = "knowledge" + elif "change_relationship" in function_name.lower(): + tool_type = "change_relationship" + elif "change_mood" in function_name.lower(): + tool_type = "change_mood" + else: + tool_type = "other" + return { "tool_call_id": tool_call["id"], "role": "tool", "name": function_name, + "type": tool_type, "content": result["content"], } return None @@ -101,7 +119,7 @@ class ToolUser: chat_stream: 聊天流对象 Returns: - dict: 工具使用结果 + dict: 工具使用结果,包含结构化的信息 """ try: # 构建提示词 @@ -109,6 +127,7 @@ class ToolUser: # 定义可用工具 tools = self._define_tools() + logger.trace(f"工具定义: {tools}") # 使用llm_model_tool发送带工具定义的请求 payload = { @@ -119,7 +138,7 @@ class ToolUser: "temperature": 0.2, } - logger.debug(f"发送工具调用请求,模型: {self.llm_model_tool.model_name}") + logger.trace(f"发送工具调用请求,模型: {self.llm_model_tool.model_name}") # 发送请求获取模型是否需要调用工具 response = await self.llm_model_tool._execute_request( endpoint="/chat/completions", payload=payload, prompt=prompt @@ -128,36 +147,50 @@ class ToolUser: # 根据返回值数量判断是否有工具调用 if len(response) == 3: content, reasoning_content, tool_calls = response - logger.info(f"工具思考: {tool_calls}") + # logger.info(f"工具思考: {tool_calls}") + # logger.debug(f"工具思考: {content}") # 检查响应中工具调用是否有效 if not tool_calls: - logger.info("模型返回了空的tool_calls列表") + logger.debug("模型返回了空的tool_calls列表") return {"used_tools": False} - logger.info(f"模型请求调用{len(tool_calls)}个工具") + tool_calls_str = "" + for tool_call in tool_calls: + tool_calls_str += f"{tool_call['function']['name']}\n" + logger.info(f"模型请求调用{len(tool_calls)}个工具: {tool_calls_str}") tool_results = [] - collected_info = "" + structured_info = { + "memory": [], + "schedule": [], + "knowledge": [], + "change_relationship": [], + "change_mood": [], + "other": [] + } # 执行所有工具调用 for tool_call in tool_calls: result = await self._execute_tool_call(tool_call, message_txt) if result: tool_results.append(result) - # 将工具结果添加到收集的信息中 - collected_info += f"\n{result['name']}返回结果: {result['content']}\n" + # 将工具结果添加到对应类型的列表中 + structured_info[result["type"]].append({ + "name": result["name"], + "content": result["content"] + }) - # 如果有工具结果,直接返回收集的信息 - if collected_info: - logger.info(f"工具调用收集到信息: {collected_info}") + # 如果有工具结果,返回结构化的信息 + if any(structured_info.values()): + logger.info(f"工具调用收集到结构化信息: {json.dumps(structured_info, ensure_ascii=False)}") return { "used_tools": True, - "collected_info": collected_info, + "structured_info": structured_info } else: # 没有工具调用 content, reasoning_content = response - logger.info("模型没有请求调用任何工具") + logger.debug("模型没有请求调用任何工具") # 如果没有工具调用或处理失败,直接返回原始思考 return { diff --git a/src/heart_flow/README.md b/src/heart_flow/README.md new file mode 100644 index 00000000..5e442d8f --- /dev/null +++ b/src/heart_flow/README.md @@ -0,0 +1,82 @@ +# 心流系统 (Heart Flow System) + +心流系统是一个模拟AI机器人内心思考和情感流动的核心系统。它通过多层次的心流结构,使AI能够对外界信息进行观察、思考和情感反应,从而产生更自然的对话和行为。 + +## 系统架构 + +### 1. 主心流 (Heartflow) +- 位于 `heartflow.py` +- 作为整个系统的主控制器 +- 负责管理和协调多个子心流 +- 维护AI的整体思维状态 +- 定期进行全局思考更新 + +### 2. 子心流 (SubHeartflow) +- 位于 `sub_heartflow.py` +- 处理具体的对话场景(如群聊) +- 维护特定场景下的思维状态 +- 通过观察者模式接收和处理信息 +- 能够进行独立的思考和回复判断 + +### 3. 观察系统 (Observation) +- 位于 `observation.py` +- 负责收集和处理外部信息 +- 支持多种观察类型(如聊天观察) +- 对信息进行实时总结和更新 + +## 主要功能 + +### 思维系统 +- 定期进行思维更新 +- 维护短期记忆和思维连续性 +- 支持多层次的思维处理 + +### 情感系统 +- 情绪状态管理 +- 回复意愿判断 +- 情感因素影响决策 + +### 交互系统 +- 群聊消息处理 +- 多场景并行处理 +- 智能回复生成 + +## 工作流程 + +1. 主心流启动并创建必要的子心流 +2. 子心流通过观察者接收外部信息 +3. 系统进行信息处理和思维更新 +4. 根据情感状态和思维结果决定是否回复 +5. 生成合适的回复并更新思维状态 + +## 使用说明 + +### 创建新的子心流 +```python +heartflow = Heartflow() +subheartflow = heartflow.create_subheartflow(chat_id) +``` + +### 添加观察者 +```python +observation = ChattingObservation(chat_id) +subheartflow.add_observation(observation) +``` + +### 启动心流系统 +```python +await heartflow.heartflow_start_working() +``` + +## 配置说明 + +系统的主要配置参数: +- `sub_heart_flow_stop_time`: 子心流停止时间 +- `sub_heart_flow_freeze_time`: 子心流冻结时间 +- `heart_flow_update_interval`: 心流更新间隔 + +## 注意事项 + +1. 子心流会在长时间不活跃后自动清理 +2. 需要合理配置更新间隔以平衡性能和响应速度 +3. 观察系统会限制消息处理数量以避免过载 \ No newline at end of file diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index ce1dd10a..81fa8944 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -18,7 +18,6 @@ import random from src.plugins.chat.chat_stream import ChatStream from src.plugins.person_info.relationship_manager import relationship_manager from src.plugins.chat.utils import get_recent_group_speaker -from src.do_tool.tool_use import ToolUser from ..plugins.utils.prompt_builder import Prompt, global_prompt_manager subheartflow_config = LogConfig( @@ -32,7 +31,7 @@ logger = get_module_logger("subheartflow", config=subheartflow_config) def init_prompt(): prompt = "" # prompt += f"麦麦的总体想法是:{self.main_heartflow_info}\n\n" - prompt += "{collected_info}\n" + prompt += "{extra_info}\n" prompt += "{relation_prompt_all}\n" prompt += "{prompt_personality}\n" prompt += "刚刚你的想法是{current_thinking_info}。如果有新的内容,记得转换话题\n" @@ -47,6 +46,7 @@ def init_prompt(): Prompt(prompt, "sub_heartflow_prompt_before") prompt = "" # prompt += f"你现在正在做的事情是:{schedule_info}\n" + prompt += "{extra_info}\n" prompt += "{prompt_personality}\n" prompt += "现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n" prompt += "刚刚你的想法是{current_thinking_info}。" @@ -97,7 +97,7 @@ class SubHeartflow: self.bot_name = global_config.BOT_NICKNAME - self.tool_user = ToolUser() + def add_observation(self, observation: Observation): """添加一个新的observation对象到列表中,如果已存在相同id的observation则不添加""" @@ -151,25 +151,14 @@ class SubHeartflow: observation = self.observations[0] await observation.observe() - async def do_thinking_before_reply(self, message_txt: str, sender_name: str, chat_stream: ChatStream): + async def do_thinking_before_reply(self, message_txt: str, sender_name: str, chat_stream: ChatStream, extra_info: str): current_thinking_info = self.current_mind mood_info = self.current_state.mood # mood_info = "你很生气,很愤怒" observation = self.observations[0] chat_observe_info = observation.observe_info - # print(f"chat_observe_info:{chat_observe_info}") - # 首先尝试使用工具获取更多信息 - tool_result = await self.tool_user.use_tool(message_txt, sender_name, chat_stream) - # 如果工具被使用且获得了结果,将收集到的信息合并到思考中 - collected_info = "" - if tool_result.get("used_tools", False): - logger.info("使用工具收集了信息") - - # 如果有收集到的信息,将其添加到当前思考中 - if "collected_info" in tool_result: - collected_info = tool_result["collected_info"] # 开始构建prompt prompt_personality = f"你的名字是{self.bot_name},你" @@ -226,7 +215,7 @@ class SubHeartflow: # prompt += f"记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{self.bot_name},{self.bot_name}指的就是你。" prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_before")).format( - collected_info, + extra_info, relation_prompt_all, prompt_personality, current_thinking_info, @@ -250,7 +239,7 @@ class SubHeartflow: logger.info(f"麦麦的思考前脑内状态:{self.current_mind}") return self.current_mind, self.past_mind - async def do_thinking_after_reply(self, reply_content, chat_talking_prompt): + async def do_thinking_after_reply(self, reply_content, chat_talking_prompt, extra_info): # print("麦麦回复之后脑袋转起来了") # 开始构建prompt @@ -277,20 +266,15 @@ class SubHeartflow: message_new_info = chat_talking_prompt reply_info = reply_content - # schedule_info = bot_schedule.get_current_num_task(num=1, time_info=False) - # prompt = "" - # # prompt += f"你现在正在做的事情是:{schedule_info}\n" - # prompt += f"{prompt_personality}\n" - # prompt += f"现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n" - # prompt += f"刚刚你的想法是{current_thinking_info}。" - # prompt += f"你现在看到了网友们发的新消息:{message_new_info}\n" - # prompt += f"你刚刚回复了群友们:{reply_info}" - # prompt += f"你现在{mood_info}" - # prompt += "现在你接下去继续思考,产生新的想法,记得保留你刚刚的想法,不要分点输出,输出连贯的内心独白" - # prompt += "不要太长,但是记得结合上述的消息,要记得你的人设,关注聊天和新内容,关注你回复的内容,不要思考太多:" prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_after")).format( - prompt_personality, chat_observe_info, current_thinking_info, message_new_info, reply_info, mood_info + extra_info, + prompt_personality, + chat_observe_info, + current_thinking_info, + message_new_info, + reply_info, + mood_info, ) try: diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 9f78a10f..3f0869aa 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -21,6 +21,7 @@ from ...person_info.relationship_manager import relationship_manager from ...chat.message_buffer import message_buffer from src.plugins.respon_info_catcher.info_catcher import info_catcher_manager from ...utils.timer_calculater import Timer +from src.do_tool.tool_use import ToolUser # 定义日志配置 chat_config = LogConfig( @@ -37,6 +38,7 @@ class ThinkFlowChat: self.gpt = ResponseGenerator() self.mood_manager = MoodManager.get_instance() self.mood_manager.start_mood_update() + self.tool_user = ToolUser() async def _create_thinking_message(self, message, chat, userinfo, messageinfo): """创建思考消息""" @@ -110,14 +112,10 @@ class ThinkFlowChat: """处理表情包""" if random() < global_config.emoji_chance: emoji_raw = await emoji_manager.get_emoji_for_text(response) - # print("11111111111111") - # logger.info(emoji_raw) if emoji_raw: emoji_path, description = emoji_raw emoji_cq = image_path_to_base64(emoji_path) - # logger.info(emoji_cq) - thinking_time_point = round(message.message_info.time, 2) message_segment = Seg(type="emoji", data=emoji_cq) @@ -136,19 +134,9 @@ class ThinkFlowChat: is_emoji=True, ) - # logger.info("22222222222222") message_manager.add_message(bot_message) - async def _update_using_response(self, message, response_set): - """更新心流状态""" - stream_id = message.chat_stream.stream_id - chat_talking_prompt = "" - if stream_id: - chat_talking_prompt = get_recent_group_detailed_plain_text( - stream_id, limit=global_config.MAX_CONTEXT_SIZE, combine=True - ) - - await heartflow.get_subheartflow(stream_id).do_thinking_after_reply(response_set, chat_talking_prompt) + async def _update_relationship(self, message: MessageRecv, response_set): """更新关系情绪""" @@ -224,13 +212,6 @@ class ThinkFlowChat: logger.info("触发缓冲,已炸飞消息列") return - # 计算回复意愿 - # current_willing_old = willing_manager.get_willing(chat_stream=chat) - # # current_willing_new = (heartflow.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4 - # # current_willing = (current_willing_old + current_willing_new) / 2 - # # 有点bug - # current_willing = current_willing_old - # 获取回复概率 is_willing = False if reply_probability != 1: @@ -266,7 +247,7 @@ class ThinkFlowChat: except Exception as e: logger.error(f"心流创建思考消息失败: {e}") - logger.debug(f"创建捕捉器,thinking_id:{thinking_id}") + logger.trace(f"创建捕捉器,thinking_id:{thinking_id}") info_catcher = info_catcher_manager.get_info_catcher(thinking_id) info_catcher.catch_decide_to_response(message) @@ -279,7 +260,72 @@ class ThinkFlowChat: logger.error(f"心流观察失败: {e}") info_catcher.catch_after_observe(timing_results["观察"]) + + # 思考前使用工具 + update_relationship = "" + try: + with Timer("思考前使用工具", timing_results): + tool_result = await self.tool_user.use_tool(message.processed_plain_text, message.message_info.user_info.user_nickname, chat) + # 如果工具被使用且获得了结果,将收集到的信息合并到思考中 + collected_info = "" + if tool_result.get("used_tools", False): + # 如果有收集到的结构化信息,将其格式化后添加到当前思考中 + if "structured_info" in tool_result: + info = tool_result["structured_info"] + # 处理记忆信息 + if info["memory"]: + collected_info += "\n记忆相关信息:\n" + for mem in info["memory"]: + collected_info += f"- {mem['name']}: {mem['content']}\n" + + # 处理日程信息 + if info["schedule"]: + collected_info += "\n日程相关信息:\n" + for sch in info["schedule"]: + collected_info += f"- {sch['name']}: {sch['content']}\n" + + # 处理知识信息 + if info["knowledge"]: + collected_info += "\n知识相关信息:\n" + for know in info["knowledge"]: + collected_info += f"- {know['name']}: {know['content']}\n" + + # 处理关系信息 + if info["change_relationship"]: + collected_info += "\n关系相关信息:\n" + for rel in info["change_relationship"]: + collected_info += f"- {rel['name']}: {rel['content']}\n" + # print("11111111111111111111111111111") + update_relationship += rel["content"] + # print(f"11111111111111111111111111111{update_relationship}") + + # 处理心情信息 + if info["change_mood"]: + collected_info += "\n心情相关信息:\n" + for mood in info["change_mood"]: + collected_info += f"- {mood['name']}: {mood['content']}\n" + + # 处理其他信息 + if info["other"]: + collected_info += "\n其他相关信息:\n" + for other in info["other"]: + collected_info += f"- {other['name']}: {other['content']}\n" + except Exception as e: + logger.error(f"思考前工具调用失败: {e}") + logger.error(traceback.format_exc()) + + + if update_relationship: + # ori_response = ",".join(response_set) + # print("22222222222222222222222222222") + stance, emotion = await self.gpt._get_emotion_tags_with_reason("你还没有回复", message.processed_plain_text,update_relationship) + await relationship_manager.calculate_update_relationship_value( + chat_stream=message.chat_stream, label=emotion, stance=stance + ) + print("33333333333333333333333333333") + + # 思考前脑内状态 try: with Timer("思考前脑内状态", timing_results): @@ -289,6 +335,7 @@ class ThinkFlowChat: message_txt=message.processed_plain_text, sender_name=message.message_info.user_info.user_nickname, chat_stream=chat, + extra_info=collected_info ) except Exception as e: logger.error(f"心流思考前脑内状态失败: {e}") @@ -323,19 +370,80 @@ class ThinkFlowChat: except Exception as e: logger.error(f"心流处理表情包失败: {e}") - # 更新心流 - try: - with Timer("更新心流", timing_results): - await self._update_using_response(message, response_set) - except Exception as e: - logger.error(f"心流更新失败: {e}") - # 更新关系情绪 + # 思考后使用工具 try: - with Timer("更新关系情绪", timing_results): - await self._update_relationship(message, response_set) + with Timer("思考后使用工具", timing_results): + tool_result = await self.tool_user.use_tool(message.processed_plain_text, message.message_info.user_info.user_nickname, chat) + # 如果工具被使用且获得了结果,将收集到的信息合并到思考中 + collected_info = "" + if tool_result.get("used_tools", False): + + # 如果有收集到的结构化信息,将其格式化后添加到当前思考中 + if "structured_info" in tool_result: + info = tool_result["structured_info"] + # 处理记忆信息 + if info["memory"]: + collected_info += "\n记忆相关信息:\n" + for mem in info["memory"]: + collected_info += f"- {mem['name']}: {mem['content']}\n" + + # 处理日程信息 + if info["schedule"]: + collected_info += "\n日程相关信息:\n" + for sch in info["schedule"]: + collected_info += f"- {sch['name']}: {sch['content']}\n" + + # 处理知识信息 + if info["knowledge"]: + collected_info += "\n知识相关信息:\n" + for know in info["knowledge"]: + collected_info += f"- {know['name']}: {know['content']}\n" + + # 处理关系信息 + if info["change_relationship"]: + collected_info += "\n关系相关信息:\n" + for rel in info["change_relationship"]: + collected_info += f"- {rel['name']}: {rel['content']}\n" + + # 处理心情信息 + if info["change_mood"]: + collected_info += "\n心情相关信息:\n" + for mood in info["change_mood"]: + collected_info += f"- {mood['name']}: {mood['content']}\n" + + # 处理其他信息 + if info["other"]: + collected_info += "\n其他相关信息:\n" + for other in info["other"]: + collected_info += f"- {other['name']}: {other['content']}\n" except Exception as e: - logger.error(f"心流更新关系情绪失败: {e}") + logger.error(f"思考后工具调用失败: {e}") + logger.error(traceback.format_exc()) + + # 更新关系 + if info["change_relationship"]: + ori_response = ",".join(response_set) + stance, emotion = await self.gpt._get_emotion_tags(ori_response, message.processed_plain_text,info["change_relationship"]["content"]) + await relationship_manager.calculate_update_relationship_value( + chat_stream=message.chat_stream, label=emotion, stance=stance + ) + + + + try: + with Timer("思考后脑内状态更新", timing_results): + stream_id = message.chat_stream.stream_id + chat_talking_prompt = "" + if stream_id: + chat_talking_prompt = get_recent_group_detailed_plain_text( + stream_id, limit=global_config.MAX_CONTEXT_SIZE, combine=True + ) + + await heartflow.get_subheartflow(stream_id).do_thinking_after_reply(response_set, chat_talking_prompt,collected_info) + except Exception as e: + logger.error(f"心流思考后脑内状态更新失败: {e}") + # 回复后处理 await willing_manager.after_generate_reply_handle(message.message_info.message_id) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py index c02a8118..17d499bd 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py @@ -225,6 +225,58 @@ class ResponseGenerator: except Exception as e: logger.debug(f"获取情感标签时出错: {e}") return "中立", "平静" # 出错时返回默认值 + + + async def _get_emotion_tags_with_reason(self, content: str, processed_plain_text: str, reason: str): + """提取情感标签,结合立场和情绪""" + try: + # 构建提示词,结合回复内容、被回复的内容以及立场分析 + prompt = f""" + 请严格根据以下对话内容,完成以下任务: + 1. 判断回复者对被回复者观点的直接立场: + - "支持":明确同意或强化被回复者观点 + - "反对":明确反驳或否定被回复者观点 + - "中立":不表达明确立场或无关回应 + 2. 从"开心,愤怒,悲伤,惊讶,平静,害羞,恐惧,厌恶,困惑"中选出最匹配的1个情感标签 + 3. 按照"立场-情绪"的格式直接输出结果,例如:"反对-愤怒" + 4. 考虑回复者的人格设定为{global_config.personality_core} + + 对话示例: + 被回复:「A就是笨」 + 回复:「A明明很聪明」 → 反对-愤怒 + + 当前对话: + 被回复:「{processed_plain_text}」 + 回复:「{content}」 + + 原因:「{reason}」 + + 输出要求: + - 只需输出"立场-情绪"结果,不要解释 + - 严格基于文字直接表达的对立关系判断 + """ + + # 调用模型生成结果 + result, _, _ = await self.model_sum.generate_response(prompt) + result = result.strip() + + # 解析模型输出的结果 + if "-" in result: + stance, emotion = result.split("-", 1) + valid_stances = ["支持", "反对", "中立"] + valid_emotions = ["开心", "愤怒", "悲伤", "惊讶", "害羞", "平静", "恐惧", "厌恶", "困惑"] + if stance in valid_stances and emotion in valid_emotions: + return stance, emotion # 返回有效的立场-情绪组合 + else: + logger.debug(f"无效立场-情感组合:{result}") + return "中立", "平静" # 默认返回中立-平静 + else: + logger.debug(f"立场-情感格式错误:{result}") + return "中立", "平静" # 格式错误时返回默认值 + + except Exception as e: + logger.debug(f"获取情感标签时出错: {e}") + return "中立", "平静" # 出错时返回默认值 async def _process_response(self, content: str) -> List[str]: """处理响应内容,返回处理后的内容和情感标签""" diff --git a/src/plugins/memory_system/Hippocampus.py b/src/plugins/memory_system/Hippocampus.py index 179a5d13..c2c090d5 100644 --- a/src/plugins/memory_system/Hippocampus.py +++ b/src/plugins/memory_system/Hippocampus.py @@ -436,7 +436,7 @@ class Hippocampus: activation_values[neighbor] = new_activation visited_nodes.add(neighbor) nodes_to_process.append((neighbor, new_activation, current_depth + 1)) - logger.debug( + logger.trace( f"节点 '{neighbor}' 被激活,激活值: {new_activation:.2f} (通过 '{current_node}' 连接,强度: {strength}, 深度: {current_depth + 1})" ) # noqa: E501 @@ -1144,7 +1144,7 @@ class Hippocampus: activation_values[neighbor] = new_activation visited_nodes.add(neighbor) nodes_to_process.append((neighbor, new_activation, current_depth + 1)) - logger.debug( + logger.trace( f"节点 '{neighbor}' 被激活,激活值: {new_activation:.2f} (通过 '{current_node}' 连接,强度: {strength}, 深度: {current_depth + 1})" ) # noqa: E501 diff --git a/src/plugins/models/utils_model.py b/src/plugins/models/utils_model.py index a472b5bf..604e7415 100644 --- a/src/plugins/models/utils_model.py +++ b/src/plugins/models/utils_model.py @@ -98,7 +98,7 @@ class LLM_request: "timestamp": datetime.now(), } db.llm_usage.insert_one(usage_data) - logger.debug( + logger.trace( f"Token使用情况 - 模型: {self.model_name}, " f"用户: {user_id}, 类型: {request_type}, " f"提示词: {prompt_tokens}, 完成: {completion_tokens}, " diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index a64a8264..1eb1d28d 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -117,7 +117,7 @@ class PersonInfoManager: return document[field_name] else: default_value = copy.deepcopy(person_info_default[field_name]) - logger.debug(f"获取{person_id}的{field_name}失败,已返回默认值{default_value}") + logger.trace(f"获取{person_id}的{field_name}失败,已返回默认值{default_value}") return default_value async def get_values(self, person_id: str, field_names: list) -> dict: diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index 726bb1db..b16f7d22 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -75,7 +75,7 @@ class RelationshipManager: else: return mood_value / coefficient - async def calculate_update_relationship_value(self, chat_stream: ChatStream, label: str, stance: str) -> None: + async def calculate_update_relationship_value(self, chat_stream: ChatStream, label: str, stance: str) -> tuple: """计算并变更关系值 新的关系值变更计算方式: 将关系值限定在-1000到1000 @@ -84,6 +84,10 @@ class RelationshipManager: 2.关系越差,改善越难,关系越好,恶化越容易 3.人维护关系的精力往往有限,所以当高关系值用户越多,对于中高关系值用户增长越慢 4.连续正面或负面情感会正反馈 + + 返回: + 用户昵称,变更值,变更后关系等级 + """ stancedict = { "支持": 0, @@ -147,6 +151,7 @@ class RelationshipManager: level_num = self.calculate_level_num(old_value + value) relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"] logger.info( + f"用户: {chat_stream.user_info.user_nickname}" f"当前关系: {relationship_level[level_num]}, " f"关系值: {old_value:.2f}, " f"当前立场情感: {stance}-{label}, " @@ -154,6 +159,95 @@ class RelationshipManager: ) await person_info_manager.update_one_field(person_id, "relationship_value", old_value + value, data) + + return chat_stream.user_info.user_nickname,value,relationship_level[level_num] + + async def calculate_update_relationship_value_with_reason(self, chat_stream: ChatStream, label: str, stance: str, reason: str) -> tuple: + """计算并变更关系值 + 新的关系值变更计算方式: + 将关系值限定在-1000到1000 + 对于关系值的变更,期望: + 1.向两端逼近时会逐渐减缓 + 2.关系越差,改善越难,关系越好,恶化越容易 + 3.人维护关系的精力往往有限,所以当高关系值用户越多,对于中高关系值用户增长越慢 + 4.连续正面或负面情感会正反馈 + + 返回: + 用户昵称,变更值,变更后关系等级 + + """ + stancedict = { + "支持": 0, + "中立": 1, + "反对": 2, + } + + valuedict = { + "开心": 1.5, + "愤怒": -2.0, + "悲伤": -0.5, + "惊讶": 0.6, + "害羞": 2.0, + "平静": 0.3, + "恐惧": -1.5, + "厌恶": -1.0, + "困惑": 0.5, + } + + person_id = person_info_manager.get_person_id(chat_stream.user_info.platform, chat_stream.user_info.user_id) + data = { + "platform": chat_stream.user_info.platform, + "user_id": chat_stream.user_info.user_id, + "nickname": chat_stream.user_info.user_nickname, + "konw_time": int(time.time()), + } + old_value = await person_info_manager.get_value(person_id, "relationship_value") + old_value = self.ensure_float(old_value, person_id) + + if old_value > 1000: + old_value = 1000 + elif old_value < -1000: + old_value = -1000 + + value = valuedict[label] + if old_value >= 0: + if valuedict[label] >= 0 and stancedict[stance] != 2: + value = value * math.cos(math.pi * old_value / 2000) + if old_value > 500: + rdict = await person_info_manager.get_specific_value_list("relationship_value", lambda x: x > 700) + high_value_count = len(rdict) + if old_value > 700: + value *= 3 / (high_value_count + 2) # 排除自己 + else: + value *= 3 / (high_value_count + 3) + elif valuedict[label] < 0 and stancedict[stance] != 0: + value = value * math.exp(old_value / 2000) + else: + value = 0 + elif old_value < 0: + if valuedict[label] >= 0 and stancedict[stance] != 2: + value = value * math.exp(old_value / 2000) + elif valuedict[label] < 0 and stancedict[stance] != 0: + value = value * math.cos(math.pi * old_value / 2000) + else: + value = 0 + + self.positive_feedback_sys(label, stance) + value = self.mood_feedback(value) + + level_num = self.calculate_level_num(old_value + value) + relationship_level = ["厌恶", "冷漠", "一般", "友好", "喜欢", "暧昧"] + logger.info( + f"用户: {chat_stream.user_info.user_nickname}" + f"当前关系: {relationship_level[level_num]}, " + f"关系值: {old_value:.2f}, " + f"当前立场情感: {stance}-{label}, " + f"变更: {value:+.5f}" + ) + + await person_info_manager.update_one_field(person_id, "relationship_value", old_value + value, data) + + return chat_stream.user_info.user_nickname,value,relationship_level[level_num] async def build_relationship_info(self, person) -> str: person_id = person_info_manager.get_person_id(person[0], person[1]) diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 1cf324a9..28dc3907 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -189,7 +189,7 @@ pri_out = 16 #模型的输出价格(非必填,可以记录消耗) #非推理模型 -[model.llm_normal] #V3 回复模型1 主要回复模型 +[model.llm_normal] #V3 回复模型1 主要回复模型,默认temp 0.2 如果你使用的是老V3或者其他模型,请自己修改代码中的temp参数 name = "Pro/deepseek-ai/DeepSeek-V3" provider = "SILICONFLOW" pri_in = 2 #模型的输入价格(非必填,可以记录消耗)