mirror of https://github.com/Mai-with-u/MaiBot.git
fix:更改一些参数
parent
6e7e9be82a
commit
6b25c0295d
|
|
@ -24,7 +24,7 @@ class MemoryChest:
|
||||||
)
|
)
|
||||||
|
|
||||||
self.memory_build_threshold = 30
|
self.memory_build_threshold = 30
|
||||||
self.memory_size_limit = 800
|
self.memory_size_limit = 1024
|
||||||
|
|
||||||
self.running_content_list = {} # {chat_id: {"content": running_content, "last_update_time": timestamp}}
|
self.running_content_list = {} # {chat_id: {"content": running_content, "last_update_time": timestamp}}
|
||||||
self.fetched_memory_list = [] # [(chat_id, (question, answer, timestamp)), ...]
|
self.fetched_memory_list = [] # [(chat_id, (question, answer, timestamp)), ...]
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class HippocampusToMemoryChestTask(AsyncTask):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
task_name="Hippocampus to Memory Chest Task",
|
task_name="Hippocampus to Memory Chest Task",
|
||||||
wait_before_start=60, # 启动后等待60秒再开始
|
wait_before_start=10, # 启动后等待60秒再开始
|
||||||
run_interval=60 # 每60秒运行一次
|
run_interval=60 # 每60秒运行一次
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -41,13 +41,14 @@ class HippocampusToMemoryChestTask(AsyncTask):
|
||||||
# 获取所有节点
|
# 获取所有节点
|
||||||
all_nodes = list(memory_graph.nodes())
|
all_nodes = list(memory_graph.nodes())
|
||||||
|
|
||||||
if len(all_nodes) < 5:
|
if len(all_nodes) < 10:
|
||||||
|
selected_nodes = all_nodes
|
||||||
logger.info(f"[海马体转换] 当前只有 {len(all_nodes)} 个节点,少于5个,跳过本次转换")
|
logger.info(f"[海马体转换] 当前只有 {len(all_nodes)} 个节点,少于5个,跳过本次转换")
|
||||||
return
|
else:
|
||||||
|
|
||||||
# 随机选择5个节点
|
# 随机选择5个节点
|
||||||
selected_nodes = random.sample(all_nodes, 5)
|
selected_nodes = random.sample(all_nodes, 10)
|
||||||
logger.info(f"[海马体转换] 随机选择了 {len(selected_nodes)} 个节点: {selected_nodes}")
|
logger.info(f"[海马体转换] 随机选择了 {len(selected_nodes)} 个节点: {selected_nodes}")
|
||||||
|
|
||||||
# 拼接节点内容
|
# 拼接节点内容
|
||||||
content_parts = []
|
content_parts = []
|
||||||
|
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
import json
|
|
||||||
import random
|
|
||||||
|
|
||||||
from json_repair import repair_json
|
|
||||||
from typing import List, Tuple
|
|
||||||
|
|
||||||
from src.config.config import global_config, model_config
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.common.data_models.database_data_model import DatabaseMessages
|
|
||||||
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
|
||||||
from src.chat.utils.utils import parse_keywords_string
|
|
||||||
from src.chat.utils.chat_message_builder import build_readable_messages
|
|
||||||
from src.chat.memory_system.Hippocampus import hippocampus_manager
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("memory_activator")
|
|
||||||
|
|
||||||
|
|
||||||
def get_keywords_from_json(json_str) -> List:
|
|
||||||
"""
|
|
||||||
从JSON字符串中提取关键词列表
|
|
||||||
|
|
||||||
Args:
|
|
||||||
json_str: JSON格式的字符串
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[str]: 关键词列表
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 使用repair_json修复JSON格式
|
|
||||||
fixed_json = repair_json(json_str)
|
|
||||||
|
|
||||||
# 如果repair_json返回的是字符串,需要解析为Python对象
|
|
||||||
result = json.loads(fixed_json) if isinstance(fixed_json, str) else fixed_json
|
|
||||||
return result.get("keywords", [])
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"解析关键词JSON失败: {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def init_prompt():
|
|
||||||
# --- Group Chat Prompt ---
|
|
||||||
memory_activator_prompt = """
|
|
||||||
你需要根据以下信息来挑选合适的记忆编号
|
|
||||||
以下是一段聊天记录,请根据这些信息,和下方的记忆,挑选和群聊内容有关的记忆编号
|
|
||||||
|
|
||||||
聊天记录:
|
|
||||||
{obs_info_text}
|
|
||||||
你想要回复的消息:
|
|
||||||
{target_message}
|
|
||||||
|
|
||||||
记忆:
|
|
||||||
{memory_info}
|
|
||||||
|
|
||||||
请输出一个json格式,包含以下字段:
|
|
||||||
{{
|
|
||||||
"memory_ids": "记忆1编号,记忆2编号,记忆3编号,......"
|
|
||||||
}}
|
|
||||||
不要输出其他多余内容,只输出json格式就好
|
|
||||||
"""
|
|
||||||
|
|
||||||
Prompt(memory_activator_prompt, "memory_activator_prompt")
|
|
||||||
|
|
||||||
|
|
||||||
class MemoryActivator:
|
|
||||||
def __init__(self):
|
|
||||||
self.key_words_model = LLMRequest(
|
|
||||||
model_set=model_config.model_task_config.utils_small,
|
|
||||||
request_type="memory.activator",
|
|
||||||
)
|
|
||||||
# 用于记忆选择的 LLM 模型
|
|
||||||
self.memory_selection_model = LLMRequest(
|
|
||||||
model_set=model_config.model_task_config.utils_small,
|
|
||||||
request_type="memory.selection",
|
|
||||||
)
|
|
||||||
|
|
||||||
async def activate_memory_with_chat_history(
|
|
||||||
self, target_message, chat_history: List[DatabaseMessages]
|
|
||||||
) -> List[Tuple[str, str]]:
|
|
||||||
"""
|
|
||||||
激活记忆
|
|
||||||
"""
|
|
||||||
# 如果记忆系统被禁用,直接返回空列表
|
|
||||||
if not global_config.memory.enable_memory:
|
|
||||||
return []
|
|
||||||
|
|
||||||
keywords_list = set()
|
|
||||||
|
|
||||||
for msg in chat_history:
|
|
||||||
keywords = parse_keywords_string(msg.key_words)
|
|
||||||
if keywords:
|
|
||||||
if len(keywords_list) < 30:
|
|
||||||
# 最多容纳30个关键词
|
|
||||||
keywords_list.update(keywords)
|
|
||||||
logger.debug(f"提取关键词: {keywords_list}")
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
if not keywords_list:
|
|
||||||
logger.debug("没有提取到关键词,返回空记忆列表")
|
|
||||||
return []
|
|
||||||
|
|
||||||
# 从海马体获取相关记忆
|
|
||||||
related_memory = await hippocampus_manager.get_memory_from_topic(
|
|
||||||
valid_keywords=list(keywords_list), max_memory_num=5, max_memory_length=3, max_depth=3
|
|
||||||
)
|
|
||||||
|
|
||||||
# logger.info(f"当前记忆关键词: {keywords_list}")
|
|
||||||
logger.debug(f"获取到的记忆: {related_memory}")
|
|
||||||
|
|
||||||
if not related_memory:
|
|
||||||
logger.debug("海马体没有返回相关记忆")
|
|
||||||
return []
|
|
||||||
|
|
||||||
used_ids = set()
|
|
||||||
candidate_memories = []
|
|
||||||
|
|
||||||
# 为每个记忆分配随机ID并过滤相关记忆
|
|
||||||
for memory in related_memory:
|
|
||||||
keyword, content = memory
|
|
||||||
found = any(kw in content for kw in keywords_list)
|
|
||||||
if found:
|
|
||||||
# 随机分配一个不重复的2位数id
|
|
||||||
while True:
|
|
||||||
random_id = "{:02d}".format(random.randint(0, 99))
|
|
||||||
if random_id not in used_ids:
|
|
||||||
used_ids.add(random_id)
|
|
||||||
break
|
|
||||||
candidate_memories.append({"memory_id": random_id, "keyword": keyword, "content": content})
|
|
||||||
|
|
||||||
if not candidate_memories:
|
|
||||||
logger.info("没有找到相关的候选记忆")
|
|
||||||
return []
|
|
||||||
|
|
||||||
# 如果只有少量记忆,直接返回
|
|
||||||
if len(candidate_memories) <= 2:
|
|
||||||
logger.debug(f"候选记忆较少({len(candidate_memories)}个),直接返回")
|
|
||||||
# 转换为 (keyword, content) 格式
|
|
||||||
return [(mem["keyword"], mem["content"]) for mem in candidate_memories]
|
|
||||||
|
|
||||||
return await self._select_memories_with_llm(target_message, chat_history, candidate_memories)
|
|
||||||
|
|
||||||
async def _select_memories_with_llm(
|
|
||||||
self, target_message, chat_history: List[DatabaseMessages], candidate_memories
|
|
||||||
) -> List[Tuple[str, str]]:
|
|
||||||
"""
|
|
||||||
使用 LLM 选择合适的记忆
|
|
||||||
|
|
||||||
Args:
|
|
||||||
target_message: 目标消息
|
|
||||||
chat_history_prompt: 聊天历史
|
|
||||||
candidate_memories: 候选记忆列表,每个记忆包含 memory_id、keyword、content
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[Tuple[str, str]]: 选择的记忆列表,格式为 (keyword, content)
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 构建聊天历史字符串
|
|
||||||
obs_info_text = build_readable_messages(
|
|
||||||
chat_history,
|
|
||||||
replace_bot_name=True,
|
|
||||||
timestamp_mode="relative",
|
|
||||||
read_mark=0.0,
|
|
||||||
show_actions=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 构建记忆信息字符串
|
|
||||||
memory_lines = []
|
|
||||||
for memory in candidate_memories:
|
|
||||||
memory_id = memory["memory_id"]
|
|
||||||
keyword = memory["keyword"]
|
|
||||||
content = memory["content"]
|
|
||||||
|
|
||||||
# 将 content 列表转换为字符串
|
|
||||||
if isinstance(content, list):
|
|
||||||
content_str = " | ".join(str(item) for item in content)
|
|
||||||
else:
|
|
||||||
content_str = str(content)
|
|
||||||
|
|
||||||
memory_lines.append(f"记忆编号 {memory_id}: [关键词: {keyword}] {content_str}")
|
|
||||||
|
|
||||||
memory_info = "\n".join(memory_lines)
|
|
||||||
|
|
||||||
# 获取并格式化 prompt
|
|
||||||
prompt_template = await global_prompt_manager.get_prompt_async("memory_activator_prompt")
|
|
||||||
formatted_prompt = prompt_template.format(
|
|
||||||
obs_info_text=obs_info_text, target_message=target_message, memory_info=memory_info
|
|
||||||
)
|
|
||||||
|
|
||||||
# 调用 LLM
|
|
||||||
response, (reasoning_content, model_name, _) = await self.memory_selection_model.generate_response_async(
|
|
||||||
formatted_prompt, temperature=0.3, max_tokens=150
|
|
||||||
)
|
|
||||||
|
|
||||||
if global_config.debug.show_prompt:
|
|
||||||
logger.info(f"记忆选择 prompt: {formatted_prompt}")
|
|
||||||
logger.info(f"LLM 记忆选择响应: {response}")
|
|
||||||
else:
|
|
||||||
logger.debug(f"记忆选择 prompt: {formatted_prompt}")
|
|
||||||
logger.debug(f"LLM 记忆选择响应: {response}")
|
|
||||||
|
|
||||||
# 解析响应获取选择的记忆编号
|
|
||||||
try:
|
|
||||||
fixed_json = repair_json(response)
|
|
||||||
|
|
||||||
# 解析为 Python 对象
|
|
||||||
result = json.loads(fixed_json) if isinstance(fixed_json, str) else fixed_json
|
|
||||||
|
|
||||||
# 提取 memory_ids 字段并解析逗号分隔的编号
|
|
||||||
if memory_ids_str := result.get("memory_ids", ""):
|
|
||||||
memory_ids = [mid.strip() for mid in str(memory_ids_str).split(",") if mid.strip()]
|
|
||||||
# 过滤掉空字符串和无效编号
|
|
||||||
valid_memory_ids = [mid for mid in memory_ids if mid and len(mid) <= 3]
|
|
||||||
selected_memory_ids = valid_memory_ids
|
|
||||||
else:
|
|
||||||
selected_memory_ids = []
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"解析记忆选择响应失败: {e}", exc_info=True)
|
|
||||||
selected_memory_ids = []
|
|
||||||
|
|
||||||
# 根据编号筛选记忆
|
|
||||||
selected_memories = []
|
|
||||||
memory_id_to_memory = {mem["memory_id"]: mem for mem in candidate_memories}
|
|
||||||
|
|
||||||
selected_memories = [
|
|
||||||
memory_id_to_memory[memory_id] for memory_id in selected_memory_ids if memory_id in memory_id_to_memory
|
|
||||||
]
|
|
||||||
logger.info(f"LLM 选择的记忆编号: {selected_memory_ids}")
|
|
||||||
logger.info(f"最终选择的记忆数量: {len(selected_memories)}")
|
|
||||||
|
|
||||||
# 转换为 (keyword, content) 格式
|
|
||||||
return [(mem["keyword"], mem["content"]) for mem in selected_memories]
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"LLM 选择记忆时出错: {e}", exc_info=True)
|
|
||||||
# 出错时返回前3个候选记忆作为备选,转换为 (keyword, content) 格式
|
|
||||||
return [(mem["keyword"], mem["content"]) for mem in candidate_memories[:3]]
|
|
||||||
|
|
||||||
|
|
||||||
init_prompt()
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
"license": "GPL-v3.0-or-later",
|
"license": "GPL-v3.0-or-later",
|
||||||
|
|
||||||
"host_application": {
|
"host_application": {
|
||||||
"min_version": "0.10.1"
|
"min_version": "0.10.4"
|
||||||
},
|
},
|
||||||
"homepage_url": "https://github.com/MaiM-with-u/maibot",
|
"homepage_url": "https://github.com/MaiM-with-u/maibot",
|
||||||
"repository_url": "https://github.com/MaiM-with-u/maibot",
|
"repository_url": "https://github.com/MaiM-with-u/maibot",
|
||||||
|
|
|
||||||
|
|
@ -12,132 +12,6 @@ from src.plugin_system.base.base_tool import BaseTool
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
logger = get_logger("memory")
|
logger = get_logger("memory")
|
||||||
|
|
||||||
|
|
||||||
def init_prompt():
|
|
||||||
Prompt(
|
|
||||||
"""
|
|
||||||
以下是一些记忆条目的分类:
|
|
||||||
----------------------
|
|
||||||
{category_list}
|
|
||||||
----------------------
|
|
||||||
每一个分类条目类型代表了你对用户:"{person_name}"的印象的一个类别
|
|
||||||
|
|
||||||
现在,你有一条对 {person_name} 的新记忆内容:
|
|
||||||
{memory_point}
|
|
||||||
|
|
||||||
请判断该记忆内容是否属于上述分类,请给出分类的名称。
|
|
||||||
如果不属于上述分类,请输出一个合适的分类名称,对新记忆内容进行概括。要求分类名具有概括性。
|
|
||||||
注意分类数一般不超过5个
|
|
||||||
请严格用json格式输出,不要输出任何其他内容:
|
|
||||||
{{
|
|
||||||
"category": "分类名称"
|
|
||||||
}} """,
|
|
||||||
"relation_category",
|
|
||||||
)
|
|
||||||
|
|
||||||
Prompt(
|
|
||||||
"""
|
|
||||||
以下是有关{category}的现有记忆:
|
|
||||||
----------------------
|
|
||||||
{memory_list}
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
现在,你有一条对 {person_name} 的新记忆内容:
|
|
||||||
{memory_point}
|
|
||||||
|
|
||||||
请判断该新记忆内容是否已经存在于现有记忆中,你可以对现有进行进行以下修改:
|
|
||||||
注意,一般来说记忆内容不超过5个,且记忆文本不应太长
|
|
||||||
|
|
||||||
1.新增:当记忆内容不存在于现有记忆,且不存在矛盾,请用json格式输出:
|
|
||||||
{{
|
|
||||||
"new_memory": "需要新增的记忆内容"
|
|
||||||
}}
|
|
||||||
2.加深印象:如果这个新记忆已经存在于现有记忆中,在内容上与现有记忆类似,请用json格式输出:
|
|
||||||
{{
|
|
||||||
"memory_id": 1, #请输出你认为需要加深印象的,与新记忆内容类似的,已经存在的记忆的序号
|
|
||||||
"integrate_memory": "加深后的记忆内容,合并内容类似的新记忆和旧记忆"
|
|
||||||
}}
|
|
||||||
3.整合:如果这个新记忆与现有记忆产生矛盾,请你结合其他记忆进行整合,用json格式输出:
|
|
||||||
{{
|
|
||||||
"memory_id": 1, #请输出你认为需要整合的,与新记忆存在矛盾的,已经存在的记忆的序号
|
|
||||||
"integrate_memory": "整合后的记忆内容,合并内容矛盾的新记忆和旧记忆"
|
|
||||||
}}
|
|
||||||
|
|
||||||
现在,请你根据情况选出合适的修改方式,并输出json,不要输出其他内容:
|
|
||||||
""",
|
|
||||||
"relation_category_update",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# class BuildMemoryAction(BaseAction):
|
|
||||||
# """关系动作 - 构建关系"""
|
|
||||||
|
|
||||||
# activation_type = ActionActivationType.LLM_JUDGE
|
|
||||||
# parallel_action = True
|
|
||||||
|
|
||||||
# # 动作基本信息
|
|
||||||
# action_name = "build_memory"
|
|
||||||
# action_description = (
|
|
||||||
# "了解对于某个概念或者某件事的记忆,并存储下来,在之后的聊天中,你可以根据这条记忆来获取相关信息"
|
|
||||||
# )
|
|
||||||
|
|
||||||
# # 动作参数定义
|
|
||||||
# action_parameters = {
|
|
||||||
# "concept_name": "需要了解或记忆的概念或事件的名称",
|
|
||||||
# "concept_description": "需要了解或记忆的概念或事件的描述,需要具体且明确",
|
|
||||||
# }
|
|
||||||
|
|
||||||
# # 动作使用场景
|
|
||||||
# action_require = [
|
|
||||||
# "了解对于某个概念或者某件事的记忆,并存储下来,在之后的聊天中,你可以根据这条记忆来获取相关信息",
|
|
||||||
# "有你不了解的概念",
|
|
||||||
# "有人要求你记住某个概念或者事件",
|
|
||||||
# "你对某件事或概念有新的理解,或产生了兴趣",
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# # 关联类型
|
|
||||||
# associated_types = ["text"]
|
|
||||||
|
|
||||||
# async def execute(self) -> Tuple[bool, str]:
|
|
||||||
# """执行关系动作"""
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# # 1. 获取构建关系的原因
|
|
||||||
# concept_description = self.action_data.get("concept_description", "")
|
|
||||||
# logger.info(f"{self.log_prefix} 添加记忆原因: {self.reasoning}")
|
|
||||||
# concept_name = self.action_data.get("concept_name", "")
|
|
||||||
# # 2. 获取目标用户信息
|
|
||||||
|
|
||||||
# # 对 concept_name 进行jieba分词
|
|
||||||
# concept_name_tokens = cut_key_words(concept_name)
|
|
||||||
# # logger.info(f"{self.log_prefix} 对 concept_name 进行分词结果: {concept_name_tokens}")
|
|
||||||
|
|
||||||
# filtered_concept_name_tokens = [
|
|
||||||
# token
|
|
||||||
# for token in concept_name_tokens
|
|
||||||
# if all(keyword not in token for keyword in global_config.memory.memory_ban_words)
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# if not filtered_concept_name_tokens:
|
|
||||||
# logger.warning(f"{self.log_prefix} 过滤后的概念名称列表为空,跳过添加记忆")
|
|
||||||
# return False, "过滤后的概念名称列表为空,跳过添加记忆"
|
|
||||||
|
|
||||||
# similar_topics_dict = (
|
|
||||||
# hippocampus_manager.get_hippocampus().parahippocampal_gyrus.get_similar_topics_from_keywords(
|
|
||||||
# filtered_concept_name_tokens
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
# await hippocampus_manager.get_hippocampus().parahippocampal_gyrus.add_memory_with_similar(
|
|
||||||
# concept_description, similar_topics_dict
|
|
||||||
# )
|
|
||||||
|
|
||||||
# return True, f"成功添加记忆: {concept_name}"
|
|
||||||
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.error(f"{self.log_prefix} 构建记忆时出错: {e}")
|
|
||||||
# return False, f"构建记忆时出错: {e}"
|
|
||||||
|
|
||||||
class GetMemoryTool(BaseTool):
|
class GetMemoryTool(BaseTool):
|
||||||
"""获取用户信息"""
|
"""获取用户信息"""
|
||||||
|
|
||||||
|
|
@ -166,8 +40,6 @@ class GetMemoryTool(BaseTool):
|
||||||
|
|
||||||
return {"content": f"问题:{question},答案:{answer}"}
|
return {"content": f"问题:{question},答案:{answer}"}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GetMemoryAction(BaseAction):
|
class GetMemoryAction(BaseAction):
|
||||||
"""关系动作 - 获取记忆"""
|
"""关系动作 - 获取记忆"""
|
||||||
|
|
||||||
|
|
@ -217,7 +89,3 @@ class GetMemoryAction(BaseAction):
|
||||||
)
|
)
|
||||||
|
|
||||||
return True, f"成功获取记忆: {answer}"
|
return True, f"成功获取记忆: {answer}"
|
||||||
|
|
||||||
|
|
||||||
# 还缺一个关系的太多遗忘和对应的提取
|
|
||||||
init_prompt()
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class MemoryBuildPlugin(BasePlugin):
|
||||||
config_schema: dict = {
|
config_schema: dict = {
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"enabled": ConfigField(type=bool, default=True, description="是否启用插件"),
|
"enabled": ConfigField(type=bool, default=True, description="是否启用插件"),
|
||||||
"config_version": ConfigField(type=str, default="1.1.0", description="配置文件版本"),
|
"config_version": ConfigField(type=str, default="1.1.1", description="配置文件版本"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue