feat:修改log,优化关系构建逻辑,节省token,

This commit is contained in:
SengokuCola
2025-07-08 02:04:31 +08:00
parent 723870bcde
commit f17f5cf46c
10 changed files with 303 additions and 322 deletions

View File

@@ -21,66 +21,11 @@ logger = get_logger("relation")
class RelationshipManager:
def __init__(self):
self.positive_feedback_value = 0 # 正反馈系统
self.gain_coefficient = [1.0, 1.0, 1.1, 1.2, 1.4, 1.7, 1.9, 2.0]
self._mood_manager = None
self.relationship_llm = LLMRequest(
model=global_config.model.relation,
request_type="relationship", # 用于动作规划
)
@property
def mood_manager(self):
if self._mood_manager is None:
self._mood_manager = mood_manager
return self._mood_manager
def positive_feedback_sys(self, label: str, stance: str):
"""正反馈系统,通过正反馈系数增益情绪变化,根据情绪再影响关系变更"""
positive_list = [
"开心",
"惊讶",
"害羞",
]
negative_list = [
"愤怒",
"悲伤",
"恐惧",
"厌恶",
]
if label in positive_list:
if 7 > self.positive_feedback_value >= 0:
self.positive_feedback_value += 1
elif self.positive_feedback_value < 0:
self.positive_feedback_value = 0
elif label in negative_list:
if -7 < self.positive_feedback_value <= 0:
self.positive_feedback_value -= 1
elif self.positive_feedback_value > 0:
self.positive_feedback_value = 0
if abs(self.positive_feedback_value) > 1:
logger.debug(f"触发mood变更增益当前增益系数{self.gain_coefficient[abs(self.positive_feedback_value)]}")
def mood_feedback(self, value):
"""情绪反馈"""
mood_manager = self.mood_manager
mood_gain = mood_manager.current_mood.valence**2 * math.copysign(1, value * mood_manager.current_mood.valence)
value += value * mood_gain
logger.debug(f"当前relationship增益系数{mood_gain:.3f}")
return value
def feedback_to_mood(self, mood_value):
"""对情绪的反馈"""
coefficient = self.gain_coefficient[abs(self.positive_feedback_value)]
if mood_value > 0 and self.positive_feedback_value > 0 or mood_value < 0 and self.positive_feedback_value < 0:
return mood_value * coefficient
else:
return mood_value / coefficient
@staticmethod
async def is_known_some_one(platform, user_id):
@@ -168,18 +113,6 @@ class RelationshipManager:
return relation_prompt
async def _update_list_field(self, person_id: str, field_name: str, new_items: list) -> None:
"""更新列表类型的字段,将新项目添加到现有列表中
Args:
person_id: 用户ID
field_name: 字段名称
new_items: 新的项目列表
"""
person_info_manager = get_person_info_manager()
old_items = await person_info_manager.get_value(person_id, field_name) or []
updated_items = list(set(old_items + [item for item in new_items if isinstance(item, str) and item]))
await person_info_manager.update_one_field(person_id, field_name, updated_items)
async def update_person_impression(self, person_id, timestamp, bot_engaged_messages=None):
"""更新用户印象
@@ -194,6 +127,7 @@ class RelationshipManager:
person_info_manager = get_person_info_manager()
person_name = await person_info_manager.get_value(person_id, "person_name")
nickname = await person_info_manager.get_value(person_id, "nickname")
know_times = await person_info_manager.get_value(person_id, "know_times") or 0
alias_str = ", ".join(global_config.bot.alias_names)
# personality_block =get_individuality().get_personality_prompt(x_person=2, level=2)
@@ -239,8 +173,10 @@ class RelationshipManager:
user_count += 1
name_mapping[replace_person_name] = f"用户{current_user}{user_count if user_count > 1 else ''}"
current_user = chr(ord(current_user) + 1)
readable_messages = self.build_focus_readable_messages(messages=user_messages, target_person_id=person_id)
readable_messages = build_readable_messages(
messages=user_messages, replace_bot_name=True, timestamp_mode="normal_no_YMD", truncate=True
)
if not readable_messages:
return
@@ -385,73 +321,121 @@ class RelationshipManager:
# 如果points超过10条按权重随机选择多余的条目移动到forgotten_points
if len(current_points) > 10:
# 获取现有forgotten_points
forgotten_points = await person_info_manager.get_value(person_id, "forgotten_points") or []
if isinstance(forgotten_points, str):
try:
forgotten_points = json.loads(forgotten_points)
except json.JSONDecodeError:
logger.error(f"解析forgotten_points JSON失败: {forgotten_points}")
forgotten_points = []
elif not isinstance(forgotten_points, list):
current_points = await self._update_impression(person_id, current_points, timestamp)
# 更新数据库
await person_info_manager.update_one_field(
person_id, "points", json.dumps(current_points, ensure_ascii=False, indent=None)
)
await person_info_manager.update_one_field(person_id, "know_times", know_times + 1)
know_since = await person_info_manager.get_value(person_id, "know_since") or 0
if know_since == 0:
await person_info_manager.update_one_field(person_id, "know_since", timestamp)
await person_info_manager.update_one_field(person_id, "last_know", timestamp)
logger.debug(f"{person_name} 的印象更新完成")
async def _update_impression(self, person_id, current_points, timestamp):
# 获取现有forgotten_points
person_info_manager = get_person_info_manager()
person_name = await person_info_manager.get_value(person_id, "person_name")
nickname = await person_info_manager.get_value(person_id, "nickname")
know_times = await person_info_manager.get_value(person_id, "know_times") or 0
attitude = await person_info_manager.get_value(person_id, "attitude") or 50
# 根据熟悉度,调整印象和简短印象的最大长度
if know_times > 300:
max_impression_length = 2000
max_short_impression_length = 800
elif know_times > 100:
max_impression_length = 1000
max_short_impression_length = 500
elif know_times > 50:
max_impression_length = 500
max_short_impression_length = 300
elif know_times > 10:
max_impression_length = 200
max_short_impression_length = 100
else:
max_impression_length = 100
max_short_impression_length = 50
# 根据好感度,调整印象和简短印象的最大长度
attitude_multiplier = (abs(100-attitude) / 100) + 1
max_impression_length = max_impression_length * attitude_multiplier
max_short_impression_length = max_short_impression_length * attitude_multiplier
forgotten_points = await person_info_manager.get_value(person_id, "forgotten_points") or []
if isinstance(forgotten_points, str):
try:
forgotten_points = json.loads(forgotten_points)
except json.JSONDecodeError:
logger.error(f"解析forgotten_points JSON失败: {forgotten_points}")
forgotten_points = []
elif not isinstance(forgotten_points, list):
forgotten_points = []
# 计算当前时间
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
# 计算当前时间
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
# 计算每个点的最终权重(原始权重 * 时间权重)
weighted_points = []
for point in current_points:
time_weight = self.calculate_time_weight(point[2], current_time)
final_weight = point[1] * time_weight
weighted_points.append((point, final_weight))
# 计算每个点的最终权重(原始权重 * 时间权重)
weighted_points = []
for point in current_points:
time_weight = self.calculate_time_weight(point[2], current_time)
final_weight = point[1] * time_weight
weighted_points.append((point, final_weight))
# 计算总权重
total_weight = sum(w for _, w in weighted_points)
# 计算总权重
total_weight = sum(w for _, w in weighted_points)
# 按权重随机选择要保留的点
remaining_points = []
points_to_move = []
# 按权重随机选择要保留的点
remaining_points = []
points_to_move = []
# 对每个点进行随机选择
for point, weight in weighted_points:
# 计算保留概率(权重越高越可能保留)
keep_probability = weight / total_weight
# 对每个点进行随机选择
for point, weight in weighted_points:
# 计算保留概率(权重越高越可能保留)
keep_probability = weight / total_weight
if len(remaining_points) < 10:
# 如果还没达到30条直接保留
remaining_points.append(point)
if len(remaining_points) < 10:
# 如果还没达到30条直接保留
remaining_points.append(point)
else:
# 随机决定是否保留
if random.random() < keep_probability:
# 保留这个点,随机移除一个已保留的点
idx_to_remove = random.randrange(len(remaining_points))
points_to_move.append(remaining_points[idx_to_remove])
remaining_points[idx_to_remove] = point
else:
# 随机决定是否保留
if random.random() < keep_probability:
# 保留这个点,随机移除一个已保留的点
idx_to_remove = random.randrange(len(remaining_points))
points_to_move.append(remaining_points[idx_to_remove])
remaining_points[idx_to_remove] = point
else:
# 不保留这个点
points_to_move.append(point)
# 不保留这个点
points_to_move.append(point)
# 更新points和forgotten_points
current_points = remaining_points
forgotten_points.extend(points_to_move)
# 更新points和forgotten_points
current_points = remaining_points
forgotten_points.extend(points_to_move)
# 检查forgotten_points是否达到5
if len(forgotten_points) >= 10:
# 构建压缩总结提示词
alias_str = ", ".join(global_config.bot.alias_names)
# 检查forgotten_points是否达到10
if len(forgotten_points) >= 10:
# 构建压缩总结提示词
alias_str = ", ".join(global_config.bot.alias_names)
# 按时间排序forgotten_points
forgotten_points.sort(key=lambda x: x[2])
# 按时间排序forgotten_points
forgotten_points.sort(key=lambda x: x[2])
# 构建points文本
points_text = "\n".join(
[f"时间:{point[2]}\n权重:{point[1]}\n内容:{point[0]}" for point in forgotten_points]
)
# 构建points文本
points_text = "\n".join(
[f"时间:{point[2]}\n权重:{point[1]}\n内容:{point[0]}" for point in forgotten_points]
)
impression = await person_info_manager.get_value(person_id, "impression") or ""
impression = await person_info_manager.get_value(person_id, "impression") or ""
compress_prompt = f"""
compress_prompt = f"""
你的名字是{global_config.bot.nickname}{global_config.bot.nickname}的别名是{alias_str}
请不要混淆你自己和{global_config.bot.nickname}{person_name}
@@ -466,17 +450,17 @@ class RelationshipManager:
你记得ta最近做的事
{points_text}
请输出一段平文本,以陈诉自白的语气,输出你对{person_name}的了解,不要输出任何其他内容。
请输出一段{max_impression_length}字左右的平文本,以陈诉自白的语气,输出你对{person_name}的了解,不要输出任何其他内容。
"""
# 调用LLM生成压缩总结
compressed_summary, _ = await self.relationship_llm.generate_response_async(prompt=compress_prompt)
# 调用LLM生成压缩总结
compressed_summary, _ = await self.relationship_llm.generate_response_async(prompt=compress_prompt)
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
compressed_summary = f"截至{current_time},你对{person_name}的了解:{compressed_summary}"
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
compressed_summary = f"截至{current_time},你对{person_name}的了解:{compressed_summary}"
await person_info_manager.update_one_field(person_id, "impression", compressed_summary)
await person_info_manager.update_one_field(person_id, "impression", compressed_summary)
compress_short_prompt = f"""
compress_short_prompt = f"""
你的名字是{global_config.bot.nickname}{global_config.bot.nickname}的别名是{alias_str}
请不要混淆你自己和{global_config.bot.nickname}{person_name}
@@ -487,107 +471,77 @@ class RelationshipManager:
1.对{person_name}的直观印象
2.{global_config.bot.nickname}{person_name}的关系
3.{person_name}的关键信息
请输出一段平文本,以陈诉自白的语气,输出你对{person_name}的概括,不要输出任何其他内容。
请输出一段{max_short_impression_length}字左右的平文本,以陈诉自白的语气,输出你对{person_name}的概括,不要输出任何其他内容。
"""
compressed_short_summary, _ = await self.relationship_llm.generate_response_async(
prompt=compress_short_prompt
)
compressed_short_summary, _ = await self.relationship_llm.generate_response_async(
prompt=compress_short_prompt
)
# current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
# compressed_short_summary = f"截至{current_time},你对{person_name}的了解:{compressed_short_summary}"
# current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
# compressed_short_summary = f"截至{current_time},你对{person_name}的了解:{compressed_short_summary}"
await person_info_manager.update_one_field(person_id, "short_impression", compressed_short_summary)
await person_info_manager.update_one_field(person_id, "short_impression", compressed_short_summary)
relation_value_prompt = f"""
relation_value_prompt = f"""
你的名字是{global_config.bot.nickname}
你最近对{person_name}的了解如下:
{points_text}
请根据以上信息,评估你和{person_name}的关系,给出两个维度的值:熟悉度和好感度。
1. 了解度 (familiarity_value): 0-100的整数表示这些信息让你对ta的了解增进程度。
- 0: 没有任何进一步了解
- 25: 有点进一步了解
- 50: 有进一步了解
- 75: 有更多了解
- 100: 有了更多重要的了解
请根据以上信息,评估你和{person_name}的关系,给出你对ta的态度。
2. **好感度 (liking_value)**: 0-100的整数表示这些信息让你对ta的
- 0: 非常厌恶
- 25: 有点反感
- 50: 中立/无感(或者文本中无法明显看出)
- 75: 喜欢这个人
- 100: 非常喜欢/开心对这个人
态度: 0-100的整数表示这些信息让你对ta的态度
- 0: 非常厌恶
- 25: 有点反感
- 50: 中立/无感(或者文本中无法明显看出)
- 75: 喜欢这个人
- 100: 非常喜欢/开心对这个人
请严格按照json格式输出不要有其他多余内容
{{
"familiarity_value": <0-100之间的整数>,
"liking_value": <0-100之间的整数>
"attitude": <0-100之间的整数>,
}}
"""
try:
relation_value_response, _ = await self.relationship_llm.generate_response_async(
prompt=relation_value_prompt
)
relation_value_json = json.loads(repair_json(relation_value_response))
# 从LLM获取新生成的值
new_familiarity_value = int(relation_value_json.get("familiarity_value", 0))
new_liking_value = int(relation_value_json.get("liking_value", 50))
# 获取当前的关系值
old_familiarity_value = await person_info_manager.get_value(person_id, "familiarity_value") or 0
liking_value = await person_info_manager.get_value(person_id, "liking_value") or 50
# 更新熟悉度
if new_familiarity_value > 25:
familiarity_value = old_familiarity_value + (new_familiarity_value - 25) / 75
else:
familiarity_value = old_familiarity_value
# 更新好感度
if new_liking_value > 50:
liking_value += (new_liking_value - 50) / 50
elif new_liking_value < 50:
liking_value -= (50 - new_liking_value) / 50 * 1.5
await person_info_manager.update_one_field(person_id, "familiarity_value", familiarity_value)
await person_info_manager.update_one_field(person_id, "liking_value", liking_value)
logger.info(f"更新了与 {person_name} 的关系值: 熟悉度={familiarity_value}, 好感度={liking_value}")
except (json.JSONDecodeError, ValueError, TypeError) as e:
logger.error(f"解析relation_value JSON失败或值无效: {e}, 响应: {relation_value_response}")
forgotten_points = []
info_list = []
await person_info_manager.update_one_field(
person_id, "info_list", json.dumps(info_list, ensure_ascii=False, indent=None)
try:
relation_value_response, _ = await self.relationship_llm.generate_response_async(
prompt=relation_value_prompt
)
relation_value_json = json.loads(repair_json(relation_value_response))
# 从LLM获取新生成的值
new_attitude = int(relation_value_json.get("attitude", 50))
# 获取当前的关系值
old_attitude = await person_info_manager.get_value(person_id, "attitude") or 50
# 更新熟悉度
if new_attitude > 25:
attitude = old_attitude + (new_attitude - 25) / 75
else:
attitude = old_attitude
# 更新好感度
if new_attitude > 50:
attitude += (new_attitude - 50) / 50
elif new_attitude < 50:
attitude -= (50 - new_attitude) / 50 * 1.5
await person_info_manager.update_one_field(person_id, "attitude", attitude)
logger.info(f"更新了与 {person_name} 的态度: {attitude}")
except (json.JSONDecodeError, ValueError, TypeError) as e:
logger.error(f"解析relation_value JSON失败或值无效: {e}, 响应: {relation_value_response}")
forgotten_points = []
info_list = []
await person_info_manager.update_one_field(
person_id, "forgotten_points", json.dumps(forgotten_points, ensure_ascii=False, indent=None)
person_id, "info_list", json.dumps(info_list, ensure_ascii=False, indent=None)
)
# 更新数据库
await person_info_manager.update_one_field(
person_id, "points", json.dumps(current_points, ensure_ascii=False, indent=None)
person_id, "forgotten_points", json.dumps(forgotten_points, ensure_ascii=False, indent=None)
)
know_times = await person_info_manager.get_value(person_id, "know_times") or 0
await person_info_manager.update_one_field(person_id, "know_times", know_times + 1)
know_since = await person_info_manager.get_value(person_id, "know_since") or 0
if know_since == 0:
await person_info_manager.update_one_field(person_id, "know_since", timestamp)
await person_info_manager.update_one_field(person_id, "last_know", timestamp)
return current_points
logger.info(f"{person_name} 的印象更新完成")
def build_focus_readable_messages(self, messages: list, target_person_id: str = None) -> str:
"""格式化消息,处理所有消息内容"""
if not messages:
return ""
# 直接处理所有消息,不进行过滤
return build_readable_messages(
messages=messages, replace_bot_name=True, timestamp_mode="normal_no_YMD", truncate=True
)
def calculate_time_weight(self, point_time: str, current_time: str) -> float:
"""计算基于时间的权重系数"""