diff --git a/src/chat/brain_chat/brain_chat.py b/src/chat/brain_chat/brain_chat.py index db037970..d486e865 100644 --- a/src/chat/brain_chat/brain_chat.py +++ b/src/chat/brain_chat/brain_chat.py @@ -238,7 +238,6 @@ class BrainChatting: async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()): asyncio.create_task(self.expression_learner.trigger_learning_for_chat()) - asyncio.create_task(global_memory_chest.build_running_content(chat_id=self.stream_id)) cycle_timers, thinking_id = self.start_cycle() logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考") diff --git a/src/chat/replyer/group_generator.py b/src/chat/replyer/group_generator.py index ec4dd587..617caee9 100644 --- a/src/chat/replyer/group_generator.py +++ b/src/chat/replyer/group_generator.py @@ -278,22 +278,6 @@ class DefaultReplyer: mood_state = await mood_manager.get_mood_by_chat_id(self.chat_stream.stream_id).get_mood() return f"你现在的心情是:{mood_state}" - async def build_memory_block(self) -> str: - """构建记忆块 - """ - # if not global_config.memory.enable_memory: - # return "" - - if global_memory_chest.get_chat_memories_as_string(self.chat_stream.stream_id): - return f"你有以下记忆:\n{global_memory_chest.get_chat_memories_as_string(self.chat_stream.stream_id)}" - else: - return "" - - async def build_question_block(self) -> str: - """构建问题块""" - # 问题跟踪功能已移除,返回空字符串 - return "" - async def build_tool_info(self, chat_history: str, sender: str, target: str, enable_tool: bool = True) -> str: """构建工具信息块 @@ -801,12 +785,11 @@ class DefaultReplyer: show_actions=True, ) - # 并行执行九个构建任务 + # 并行执行七个构建任务 task_results = await asyncio.gather( self._time_and_run_task( self.build_expression_habits(chat_talking_prompt_short, target), "expression_habits" ), - self._time_and_run_task(self.build_memory_block(), "memory_block"), self._time_and_run_task( self.build_tool_info(chat_talking_prompt_short, sender, target, enable_tool=enable_tool), "tool_info" ), @@ -814,7 +797,6 @@ class DefaultReplyer: self._time_and_run_task(self.build_actions_prompt(available_actions, chosen_actions), "actions_info"), self._time_and_run_task(self.build_personality_prompt(), "personality_prompt"), self._time_and_run_task(self.build_mood_state_prompt(), "mood_state_prompt"), - self._time_and_run_task(self.build_question_block(), "question_block"), self._time_and_run_task( build_memory_retrieval_prompt( chat_talking_prompt_short, sender, target, self.chat_stream, self.tool_executor @@ -827,14 +809,11 @@ class DefaultReplyer: task_name_mapping = { "expression_habits": "选取表达方式", "relation_info": "感受关系", - # "memory_block": "回忆", - "memory_block": "记忆", "tool_info": "使用工具", "prompt_info": "获取知识", "actions_info": "动作信息", "personality_prompt": "人格信息", "mood_state_prompt": "情绪状态", - "question_block": "问题", "memory_retrieval": "记忆检索", } @@ -859,13 +838,10 @@ class DefaultReplyer: expression_habits_block: str selected_expressions: List[int] # relation_info: str = results_dict["relation_info"] - # memory_block: str = results_dict["memory_block"] - memory_block: str = results_dict["memory_block"] tool_info: str = results_dict["tool_info"] prompt_info: str = results_dict["prompt_info"] # 直接使用格式化后的结果 actions_info: str = results_dict["actions_info"] personality_prompt: str = results_dict["personality_prompt"] - question_block: str = results_dict["question_block"] memory_retrieval: str = results_dict["memory_retrieval"] keywords_reaction_prompt = await self.build_keywords_reaction_prompt(target) mood_state_prompt: str = results_dict["mood_state_prompt"] @@ -908,10 +884,8 @@ class DefaultReplyer: "replyer_prompt", expression_habits_block=expression_habits_block, tool_info_block=tool_info, - memory_block=memory_block, knowledge_prompt=prompt_info, mood_state=mood_state_prompt, - # memory_block=memory_block, # relation_info_block=relation_info, extra_info_block=extra_info_block, identity=personality_prompt, @@ -923,7 +897,6 @@ class DefaultReplyer: reply_style=global_config.personality.reply_style, keywords_reaction_prompt=keywords_reaction_prompt, moderation_prompt=moderation_prompt_block, - question_block=question_block, memory_retrieval=memory_retrieval, chat_prompt=chat_prompt_block, ), selected_expressions diff --git a/src/chat/replyer/private_generator.py b/src/chat/replyer/private_generator.py index 8a92fd15..58928259 100644 --- a/src/chat/replyer/private_generator.py +++ b/src/chat/replyer/private_generator.py @@ -6,7 +6,6 @@ import re from typing import List, Optional, Dict, Any, Tuple from datetime import datetime -from src.memory_system.Memory_chest import global_memory_chest from src.common.logger import get_logger from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.info_data_model import ActionPlannerInfo @@ -37,10 +36,12 @@ from src.plugin_system.apis import llm_api from src.chat.replyer.prompt.lpmm_prompt import init_lpmm_prompt from src.chat.replyer.prompt.replyer_prompt import init_replyer_prompt from src.chat.replyer.prompt.rewrite_prompt import init_rewrite_prompt +from src.memory_system.memory_retrieval import init_memory_retrieval_prompt, build_memory_retrieval_prompt init_lpmm_prompt() init_replyer_prompt() init_rewrite_prompt() +init_memory_retrieval_prompt() logger = get_logger("replyer") @@ -291,14 +292,6 @@ class PrivateReplyer: return f"你现在的心情是:{mood_state}" - async def build_memory_block(self) -> str: - """构建记忆块 - """ - if global_memory_chest.get_chat_memories_as_string(self.chat_stream.stream_id): - return f"你有以下记忆:\n{global_memory_chest.get_chat_memories_as_string(self.chat_stream.stream_id)}" - else: - return "" - async def build_tool_info(self, chat_history: str, sender: str, target: str, enable_tool: bool = True) -> str: """构建工具信息块 @@ -712,7 +705,7 @@ class PrivateReplyer: show_actions=True, ) - # 并行执行五个构建任务 + # 并行执行八个构建任务 task_results = await asyncio.gather( self._time_and_run_task( self.build_expression_habits(chat_talking_prompt_short, target), "expression_habits" @@ -720,8 +713,6 @@ class PrivateReplyer: self._time_and_run_task( self.build_relation_info(chat_talking_prompt_short, sender), "relation_info" ), - self._time_and_run_task(self.build_memory_block(), "memory_block"), - # self._time_and_run_task(self.build_memory_block(message_list_before_short, target), "memory_block"), self._time_and_run_task( self.build_tool_info(chat_talking_prompt_short, sender, target, enable_tool=enable_tool), "tool_info" ), @@ -729,18 +720,24 @@ class PrivateReplyer: self._time_and_run_task(self.build_actions_prompt(available_actions, chosen_actions), "actions_info"), self._time_and_run_task(self.build_personality_prompt(), "personality_prompt"), self._time_and_run_task(self.build_mood_state_prompt(), "mood_state_prompt"), + self._time_and_run_task( + build_memory_retrieval_prompt( + chat_talking_prompt_short, sender, target, self.chat_stream, self.tool_executor + ), + "memory_retrieval", + ), ) # 任务名称中英文映射 task_name_mapping = { "expression_habits": "选取表达方式", "relation_info": "感受关系", - "memory_block": "回忆", "tool_info": "使用工具", "prompt_info": "获取知识", "actions_info": "动作信息", "personality_prompt": "人格信息", "mood_state_prompt": "情绪状态", + "memory_retrieval": "记忆检索", } # 处理结果 @@ -764,12 +761,12 @@ class PrivateReplyer: expression_habits_block: str selected_expressions: List[int] relation_info: str = results_dict["relation_info"] - memory_block: str = results_dict["memory_block"] tool_info: str = results_dict["tool_info"] prompt_info: str = results_dict["prompt_info"] # 直接使用格式化后的结果 actions_info: str = results_dict["actions_info"] personality_prompt: str = results_dict["personality_prompt"] mood_state_prompt: str = results_dict["mood_state_prompt"] + memory_retrieval: str = results_dict["memory_retrieval"] keywords_reaction_prompt = await self.build_keywords_reaction_prompt(target) if extra_info: @@ -806,7 +803,6 @@ class PrivateReplyer: tool_info_block=tool_info, knowledge_prompt=prompt_info, mood_state=mood_state_prompt, - memory_block=memory_block, relation_info_block=relation_info, extra_info_block=extra_info_block, identity=personality_prompt, @@ -819,6 +815,7 @@ class PrivateReplyer: reply_style=global_config.personality.reply_style, keywords_reaction_prompt=keywords_reaction_prompt, moderation_prompt=moderation_prompt_block, + memory_retrieval=memory_retrieval, chat_prompt=chat_prompt_block, ), selected_expressions else: @@ -828,7 +825,6 @@ class PrivateReplyer: tool_info_block=tool_info, knowledge_prompt=prompt_info, mood_state=mood_state_prompt, - memory_block=memory_block, relation_info_block=relation_info, extra_info_block=extra_info_block, identity=personality_prompt, @@ -840,6 +836,7 @@ class PrivateReplyer: keywords_reaction_prompt=keywords_reaction_prompt, moderation_prompt=moderation_prompt_block, sender_name=sender, + memory_retrieval=memory_retrieval, chat_prompt=chat_prompt_block, ), selected_expressions diff --git a/src/plugins/built_in/memory/_manifest.json b/src/plugins/built_in/memory/_manifest.json deleted file mode 100644 index fd6a2179..00000000 --- a/src/plugins/built_in/memory/_manifest.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "manifest_version": 1, - "name": "Memory Build组件", - "version": "1.0.0", - "description": "可以构建和管理记忆", - "author": { - "name": "Mai", - "url": "https://github.com/MaiM-with-u" - }, - "license": "GPL-v3.0-or-later", - - "host_application": { - "min_version": "0.10.4" - }, - "homepage_url": "https://github.com/MaiM-with-u/maibot", - "repository_url": "https://github.com/MaiM-with-u/maibot", - "keywords": ["memory", "build", "built-in"], - "categories": ["Memory"], - - "default_locale": "zh-CN", - "locales_path": "_locales", - - "plugin_info": { - "is_built_in": true, - "plugin_type": "action_provider", - "components": [ - { - "type": "build_memory", - "name": "build_memory", - "description": "构建记忆" - } - ] - } -} diff --git a/src/plugins/built_in/memory/build_memory.py b/src/plugins/built_in/memory/build_memory.py deleted file mode 100644 index 9422e22f..00000000 --- a/src/plugins/built_in/memory/build_memory.py +++ /dev/null @@ -1,245 +0,0 @@ -import asyncio -from datetime import datetime - -from src.common.logger import get_logger -from src.llm_models.payload_content.tool_option import ToolParamType -from src.memory_system.Memory_chest import global_memory_chest -from src.plugin_system.base.base_tool import BaseTool -from src.plugin_system.apis.message_api import get_messages_by_time_in_chat, build_readable_messages -from src.llm_models.utils_model import LLMRequest -from src.config.config import model_config -from typing import Any - -logger = get_logger("memory") - -def parse_datetime_to_timestamp(value: str) -> float: - """ - 接受多种常见格式并转换为时间戳(秒) - 支持示例: - - 2025-09-29 - - 2025-09-29 00:00:00 - - 2025/09/29 00:00 - - 2025-09-29T00:00:00 - """ - value = value.strip() - fmts = [ - "%Y-%m-%d %H:%M:%S", - "%Y-%m-%d %H:%M", - "%Y/%m/%d %H:%M:%S", - "%Y/%m/%d %H:%M", - "%Y-%m-%d", - "%Y/%m/%d", - "%Y-%m-%dT%H:%M:%S", - "%Y-%m-%dT%H:%M", - ] - last_err = None - for fmt in fmts: - try: - dt = datetime.strptime(value, fmt) - return dt.timestamp() - except Exception as e: - last_err = e - raise ValueError(f"无法解析时间: {value} ({last_err})") - -def parse_time_range(time_range: str) -> tuple[float, float]: - """ - 解析时间范围字符串,返回开始和结束时间戳 - 格式: "YYYY-MM-DD HH:MM:SS - YYYY-MM-DD HH:MM:SS" - """ - if " - " not in time_range: - raise ValueError("时间范围格式错误,应使用 ' - ' 分隔开始和结束时间") - - start_str, end_str = time_range.split(" - ", 1) - start_timestamp = parse_datetime_to_timestamp(start_str.strip()) - end_timestamp = parse_datetime_to_timestamp(end_str.strip()) - - if start_timestamp > end_timestamp: - raise ValueError("开始时间不能晚于结束时间") - - return start_timestamp, end_timestamp -class GetMemoryTool(BaseTool): - """获取用户信息""" - - name = "get_memory" - description = "在记忆中搜索,获取某个问题的答案,可以指定搜索的时间范围或时间点" - parameters = [ - ("question", ToolParamType.STRING, "需要获取答案的问题", True, None), - ("time_point", ToolParamType.STRING, "需要获取记忆的时间点,格式为YYYY-MM-DD HH:MM:SS", False, None), - ("time_range", ToolParamType.STRING, "需要获取记忆的时间范围,格式为YYYY-MM-DD HH:MM:SS - YYYY-MM-DD HH:MM:SS", False, None) - ] - - available_for_llm = True - - async def execute(self, function_args: dict[str, Any]) -> dict[str, Any]: - """执行记忆搜索 - - Args: - function_args: 工具参数 - - Returns: - dict: 工具执行结果 - """ - question: str = function_args.get("question") # type: ignore - time_point: str = function_args.get("time_point") # type: ignore - time_range: str = function_args.get("time_range") # type: ignore - - # 检查是否指定了时间参数 - has_time_params = bool(time_point or time_range) - - if has_time_params and not self.chat_id: - return {"content": f"问题:{question},无法获取聊天记录:缺少chat_id"} - - # 创建并行任务 - tasks = [] - - # 原任务:从记忆仓库获取答案 - memory_task = asyncio.create_task( - global_memory_chest.get_answer_by_question(question=question) - ) - tasks.append(("memory", memory_task)) - - # 新任务:从聊天记录获取答案(如果指定了时间参数) - chat_task = None - if has_time_params: - chat_task = asyncio.create_task( - self._get_answer_from_chat_history(question, time_point, time_range) - ) - tasks.append(("chat", chat_task)) - - # 等待所有任务完成 - results = {} - for task_name, task in tasks: - try: - results[task_name] = await task - except Exception as e: - logger.error(f"任务 {task_name} 执行失败: {e}") - results[task_name] = None - - # 处理结果 - memory_answer = results.get("memory") - chat_answer = results.get("chat") - - # 构建返回内容 - content_parts = [] - - if memory_answer: - content_parts.append(f"对问题'{question}',你回忆的信息是:{memory_answer}") - - if chat_answer: - content_parts.append(f"对问题'{question}',基于聊天记录的回答:{chat_answer}") - elif has_time_params: - if time_point: - content_parts.append(f"在 {time_point} 的时间点,你没有参与聊天") - elif time_range: - content_parts.append(f"在 {time_range} 的时间范围内,你没有参与聊天") - - if content_parts: - retrieval_content = f"问题:{question}" + "\n".join(content_parts) - return {"content": retrieval_content} - else: - return {"content": ""} - - - async def _get_answer_from_chat_history(self, question: str, time_point: str = None, time_range: str = None) -> str: - """从聊天记录中获取问题的答案""" - try: - # 确定时间范围 - print(f"time_point: {time_point}, time_range: {time_range}") - - # 检查time_range的两个时间值是否相同,如果相同则按照time_point处理 - if time_range and not time_point: - try: - start_timestamp, end_timestamp = parse_time_range(time_range) - if start_timestamp == end_timestamp: - # 两个时间值相同,按照time_point处理 - time_point = time_range.split(" - ")[0].strip() - time_range = None - print(f"time_range两个值相同,按照time_point处理: {time_point}") - except Exception as e: - logger.warning(f"解析time_range失败: {e}") - - if time_point: - # 时间点:搜索前后25条记录 - target_timestamp = parse_datetime_to_timestamp(time_point) - # 获取前后各25条记录,总共50条 - messages_before = get_messages_by_time_in_chat( - chat_id=self.chat_id, - start_time=0, - end_time=target_timestamp, - limit=25, - limit_mode="latest" - ) - messages_after = get_messages_by_time_in_chat( - chat_id=self.chat_id, - start_time=target_timestamp, - end_time=float('inf'), - limit=25, - limit_mode="earliest" - ) - messages = messages_before + messages_after - elif time_range: - # 时间范围:搜索范围内最多50条记录 - start_timestamp, end_timestamp = parse_time_range(time_range) - messages = get_messages_by_time_in_chat( - chat_id=self.chat_id, - start_time=start_timestamp, - end_time=end_timestamp, - limit=50, - limit_mode="latest" - ) - else: - return "未指定时间参数" - - if not messages: - return "没有找到相关聊天记录" - - # 将消息转换为可读格式 - chat_content = build_readable_messages(messages, timestamp_mode="relative") - - if not chat_content.strip(): - return "聊天记录为空" - - # 使用LLM分析聊天内容并回答问题 - try: - llm_request = LLMRequest( - model_set=model_config.model_task_config.utils_small, - request_type="chat_history_analysis" - ) - - analysis_prompt = f"""请根据以下聊天记录内容,回答用户的问题。请输出一段平文本,不要有特殊格式。 -聊天记录: -{chat_content} - -用户问题:{question} - -请仔细分析聊天记录,提取与问题相关的信息,并给出准确的答案。如果聊天记录中没有相关信息,无法回答问题,输出"无有效信息"即可,不要输出其他内容。 - -答案:""" - - print(f"analysis_prompt: {analysis_prompt}") - - - response, (reasoning, model_name, tool_calls) = await llm_request.generate_response_async( - prompt=analysis_prompt, - temperature=0.3, - max_tokens=256 - ) - - - print(f"response: {response}") - - if "无有效信息" in response: - return "" - - return response - - except Exception as llm_error: - logger.error(f"LLM分析聊天记录失败: {llm_error}") - # 如果LLM分析失败,返回聊天内容的摘要 - if len(chat_content) > 300: - chat_content = chat_content[:300] + "..." - return chat_content - - except Exception as e: - logger.error(f"从聊天记录获取答案失败: {e}") - return "" diff --git a/src/plugins/built_in/memory/plugin.py b/src/plugins/built_in/memory/plugin.py deleted file mode 100644 index 5d2ba419..00000000 --- a/src/plugins/built_in/memory/plugin.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import List, Tuple, Type - -# 导入新插件系统 -from src.plugin_system import BasePlugin, ComponentInfo, register_plugin -from src.plugin_system.base.config_types import ConfigField - -# 导入依赖的系统组件 -from src.common.logger import get_logger - -from src.plugins.built_in.memory.build_memory import GetMemoryTool - -logger = get_logger("memory_build") - - -@register_plugin -class MemoryBuildPlugin(BasePlugin): - """记忆构建插件 - - 系统内置插件,提供基础的聊天交互功能: - - GetMemory: 获取记忆 - - 注意:插件基本信息优先从_manifest.json文件中读取 - """ - - # 插件基本信息 - plugin_name: str = "memory_build" # 内部标识符 - enable_plugin: bool = True - dependencies: list[str] = [] # 插件依赖列表 - python_dependencies: list[str] = [] # Python包依赖列表 - config_file_name: str = "config.toml" - - # 配置节描述 - config_section_descriptions = { - "plugin": "插件启用配置", - "components": "核心组件启用配置", - } - - # 配置Schema定义 - config_schema: dict = { - "plugin": { - "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), - "config_version": ConfigField(type=str, default="1.1.1", description="配置文件版本"), - }, - } - - def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: - """返回插件包含的组件列表""" - - # --- 根据配置注册组件 --- - components = [] - components.append((GetMemoryTool.get_tool_info(), GetMemoryTool)) - - return components