MaiBot/src/plugins/built_in/relation/relation.py

230 lines
9.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import json
from json_repair import repair_json
from typing import Tuple
from src.common.logger import get_logger
from src.config.config import global_config
from src.person_info.person_info import Person, get_memory_content_from_memory, get_weight_from_memory
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
from src.plugin_system import BaseAction, ActionActivationType
from src.plugin_system.apis import llm_api
logger = get_logger("relation")
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 BuildRelationAction(BaseAction):
"""关系动作 - 构建关系"""
activation_type = ActionActivationType.LLM_JUDGE
parallel_action = True
# 动作基本信息
action_name = "build_relation"
action_description = "了解对于某人的记忆,并添加到你对对方的印象中"
# LLM判断提示词
llm_judge_prompt = """
判定是否需要使用关系动作,添加对于某人的记忆:
1. 对方与你的交互让你对其有新记忆
2. 对方有提到其个人信息,包括喜好,身份,等等
3. 对方希望你记住对方的信息
请回答""""
"""
# 动作参数定义
action_parameters = {"person_name": "需要了解或记忆的人的名称", "impression": "需要了解的对某人的记忆或印象"}
# 动作使用场景
action_require = [
"了解对于某人的记忆,并添加到你对对方的印象中",
"对方与有明确提到有关其自身的事件",
"对方有提到其个人信息,包括喜好,身份,等等",
"对方希望你记住对方的信息",
]
# 关联类型
associated_types = ["text"]
async def execute(self) -> Tuple[bool, str]:
# sourcery skip: assign-if-exp, introduce-default-else, swap-if-else-branches, use-named-expression
"""执行关系动作"""
logger.info(f"{self.log_prefix} 决定添加记忆")
try:
# 1. 获取构建关系的原因
impression = self.action_data.get("impression", "")
logger.info(f"{self.log_prefix} 添加记忆原因: {self.reasoning}")
person_name = self.action_data.get("person_name", "")
# 2. 获取目标用户信息
person = Person(person_name=person_name)
if not person.is_known:
logger.warning(f"{self.log_prefix} 用户 {person_name} 不存在,跳过添加记忆")
return False, f"用户 {person_name} 不存在,跳过添加记忆"
category_list = person.get_all_category()
if not category_list:
category_list_str = "无分类"
else:
category_list_str = "\n".join(category_list)
prompt = await global_prompt_manager.format_prompt(
"relation_category",
category_list=category_list_str,
memory_point=impression,
person_name=person.person_name,
)
if global_config.debug.show_prompt:
logger.info(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")
else:
logger.debug(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")
# 5. 调用LLM
models = llm_api.get_available_models()
chat_model_config = models.get("utils_small") # 使用字典访问方式
if not chat_model_config:
logger.error(f"{self.log_prefix} 未找到'utils_small'模型配置无法调用LLM")
return False, "未找到'utils_small'模型配置"
success, category, _, _ = await llm_api.generate_with_model(
prompt, model_config=chat_model_config, request_type="relation.category"
)
category_data = json.loads(repair_json(category))
category = category_data.get("category", "")
if not category:
logger.warning(f"{self.log_prefix} LLM未给出分类跳过添加记忆")
return False, "LLM未给出分类跳过添加记忆"
# 第二部分:更新记忆
memory_list = person.get_memory_list_by_category(category)
if not memory_list:
logger.info(f"{self.log_prefix} {person.person_name}{category} 的记忆为空,进行创建")
person.memory_points.append(f"{category}:{impression}:1.0")
person.sync_to_database()
return True, f"未找到分类为{category}的记忆点,进行添加"
memory_list_str = ""
memory_list_id = {}
for id, memory in enumerate(memory_list, start=1):
memory_content = get_memory_content_from_memory(memory)
memory_list_str += f"{id}. {memory_content}\n"
memory_list_id[id] = memory
prompt = await global_prompt_manager.format_prompt(
"relation_category_update",
category=category,
memory_list=memory_list_str,
memory_point=impression,
person_name=person.person_name,
)
if global_config.debug.show_prompt:
logger.info(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")
else:
logger.debug(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")
chat_model_config = models.get("utils")
success, update_memory, _, _ = await llm_api.generate_with_model(
prompt, model_config=chat_model_config, request_type="relation.category.update" # type: ignore
)
update_memory_data = json.loads(repair_json(update_memory))
new_memory = update_memory_data.get("new_memory", "")
memory_id = update_memory_data.get("memory_id", "")
integrate_memory = update_memory_data.get("integrate_memory", "")
if new_memory:
# 新记忆
person.memory_points.append(f"{category}:{new_memory}:1.0")
person.sync_to_database()
return True, f"{person.person_name}新增记忆点: {new_memory}"
elif memory_id and integrate_memory:
# 现存或冲突记忆
memory = memory_list_id[memory_id]
memory_content = get_memory_content_from_memory(memory)
del_count = person.del_memory(category, memory_content)
if del_count > 0:
logger.info(f"{self.log_prefix} 删除记忆点: {memory_content}")
memory_weight = get_weight_from_memory(memory)
person.memory_points.append(f"{category}:{integrate_memory}:{memory_weight + 1.0}")
person.sync_to_database()
return True, f"更新{person.person_name}的记忆点: {memory_content} -> {integrate_memory}"
else:
logger.warning(f"{self.log_prefix} 删除记忆点失败: {memory_content}")
return False, f"删除{person.person_name}的记忆点失败: {memory_content}"
return True, "关系动作执行成功"
except Exception as e:
logger.error(f"{self.log_prefix} 关系构建动作执行失败: {e}", exc_info=True)
return False, f"关系动作执行失败: {str(e)}"
# 还缺一个关系的太多遗忘和对应的提取
init_prompt()