feat:处理器处理时间上限,处理并行模式,planner和思考prompt,循环观察器大优化

feat:增加了处理器处理时间上限,记忆处理并行模式,优化了planner和思考prompt,优化了循环观察器
This commit is contained in:
SengokuCola
2025-05-30 11:04:29 +08:00
parent 8f0a4d9d2c
commit 54724ae21e
21 changed files with 233 additions and 120 deletions

View File

@@ -403,15 +403,15 @@ class ConfigEditor:
# 创建模型名称标签(大字体)
model_name = var.get() if var.get() else providers[0]
section_translations = {
"model.utils": "工具模型",
"model.utils_small": "小型工具模型",
"model.utils": "麦麦组件模型",
"model.utils_small": "小型麦麦组件模型",
"model.memory_summary": "记忆概括模型",
"model.vlm": "图像识别模型",
"model.embedding": "嵌入模型",
"model.normal_chat_1": "普通聊天:主要聊天模型",
"model.normal_chat_2": "普通聊天:次要聊天模型",
"model.focus_working_memory": "专注模式:工作记忆模型",
"model.focus_chat_mind": "专注模式:聊天规划模型",
"model.focus_chat_mind": "专注模式:聊天思考模型",
"model.focus_tool_use": "专注模式:工具调用模型",
"model.focus_planner": "专注模式:决策模型",
"model.focus_expressor": "专注模式:表达器模型",

View File

@@ -302,6 +302,15 @@ description = "思考的时间间隔(秒),可以有效减少消耗"
name = "连续回复能力"
description = "连续回复能力,值越高,麦麦连续回复的概率越高"
[translations.items.parallel_processing]
name = "并行处理"
description = "是否并行处理回忆和处理器阶段,可以节省时间"
[translations.items.processor_max_time]
name = "处理器最大时间"
description = "处理器最大时间,单位秒,如果超过这个时间,处理器会自动停止"
[translations.items.observation_context_size]
name = "观察上下文大小"
description = "观察到的最长上下文大小建议15太短太长都会导致脑袋尖尖"

View File

@@ -19,11 +19,13 @@ def init_prompt() -> None:
learn_style_prompt = """
{chat_str}
请从上面这段群聊中概括除了人名为"SELF"之外的人的语言风格,只考虑文字,不要考虑表情包和图片
不要涉及具体的人名,只考虑语言风格
语言风格包含特殊内容和情感
思考有没有特殊的梗,一并总结成语言风格
总结成如下格式的规律,总结的内容要详细,但具有概括性:
请从上面这段群聊中概括除了人名为"SELF"之外的人的语言风格
1. 只考虑文字,不要考虑表情包和图片
2. 不要涉及具体的人名,只考虑语言风格
3. 语言风格包含特殊内容和情感
4. 思考有没有特殊的梗,一并总结成语言风格
5. 例子仅供参考,请严格根据群聊内容总结!!!
注意:总结成如下格式的规律,总结的内容要详细,但具有概括性:
"xxx"时,可以"xxx", xxx不超过10个字
例如:
@@ -31,7 +33,7 @@ def init_prompt() -> None:
"表示讽刺的赞同,不想讲道理"时,使用"对对对"
"想说明某个观点,但懒得明说",使用"懂的都懂"
注意不要总结你自己的发言
注意不要总结你自己SELF的发言
现在请你概括
"""
Prompt(learn_style_prompt, "learn_style_prompt")
@@ -40,9 +42,10 @@ def init_prompt() -> None:
{chat_str}
请从上面这段群聊中概括除了人名为"SELF"之外的人的语法和句法特点,只考虑纯文字,不要考虑表情包和图片
不要总结【图片】,【动画表情】,[图片][动画表情],不总结 表情符号 at @ 回复 和[回复]
不要涉及具体的人名,只考虑语法和句法特点,
语法和句法特点要包括,句子长短(具体字数),有何种语病,如何拆分句子。
1.不要总结【图片】,【动画表情】,[图片][动画表情],不总结 表情符号 at @ 回复 和[回复]
2.不要涉及具体的人名,只考虑语法和句法特点,
3.语法和句法特点要包括,句子长短(具体字数),有何种语病,如何拆分句子。
4. 例子仅供参考,请严格根据群聊内容总结!!!
总结成如下格式的规律,总结的内容要简洁,不浮夸:
"xxx"时,可以"xxx"
@@ -51,7 +54,7 @@ def init_prompt() -> None:
"不用详细说明的一般表达"时,使用"非常简洁的句子"的句法
"需要单纯简单的确认"时,使用"单字或几个字的肯定(1-2个字)"的句法
注意不要总结你自己的发言
注意不要总结你自己SELF的发言
现在请你概括
"""
Prompt(learn_grammar_prompt, "learn_grammar_prompt")

View File

@@ -44,21 +44,10 @@ PROCESSOR_CLASSES = {
"ToolProcessor": (ToolProcessor, "tool_use_processor"),
"WorkingMemoryProcessor": (WorkingMemoryProcessor, "working_memory_processor"),
"SelfProcessor": (SelfProcessor, "self_identify_processor"),
# "ActionProcessor": (ActionProcessor, "action_processor"), # 这个处理器不需要配置键名,默认启用
}
WAITING_TIME_THRESHOLD = 300 # 等待新消息时间阈值,单位秒
EMOJI_SEND_PRO = 0.3 # 设置一个概率,比如 30% 才真的发
CONSECUTIVE_NO_REPLY_THRESHOLD = 3 # 连续不回复的阈值
logger = get_logger("hfc") # Logger Name Changed
# 设定处理器超时时间(秒)
PROCESSOR_TIMEOUT = 30
async def _handle_cycle_delay(action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str):
"""处理循环延迟"""
@@ -150,7 +139,7 @@ class HeartFChatting:
# 添加循环信息管理相关的属性
self._cycle_counter = 0
self._cycle_history: Deque[CycleDetail] = deque(maxlen=10) # 保留最近10个循环的信息
self._current_cycle: Optional[CycleDetail] = None
self._current_cycle_detail: Optional[CycleDetail] = None
self._shutting_down: bool = False # 关闭标志位
# 存储回调函数
@@ -262,12 +251,12 @@ class HeartFChatting:
try:
exception = task.exception()
if exception:
logger.error(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天(异常): {exception}")
logger.error(f"{self.log_prefix} HeartFChatting: 脱离了聊天(异常): {exception}")
logger.error(traceback.format_exc()) # Log full traceback for exceptions
else:
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天 (外部停止)")
logger.info(f"{self.log_prefix} HeartFChatting: 脱离了聊天 (外部停止)")
except asyncio.CancelledError:
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天(任务取消)")
logger.info(f"{self.log_prefix} HeartFChatting: 脱离了聊天(任务取消)")
finally:
self._loop_active = False
self._loop_task = None
@@ -286,7 +275,8 @@ class HeartFChatting:
# 创建新的循环信息
self._cycle_counter += 1
self._current_cycle = CycleDetail(self._cycle_counter)
self._current_cycle_detail = CycleDetail(self._cycle_counter)
self._current_cycle_detail.prefix = self.log_prefix
# 初始化周期状态
cycle_timers = {}
@@ -295,13 +285,12 @@ class HeartFChatting:
# 执行规划和处理阶段
async with self._get_cycle_context():
thinking_id = "tid" + str(round(time.time(), 2))
self._current_cycle.set_thinking_id(thinking_id)
self._current_cycle_detail.set_thinking_id(thinking_id)
# 主循环:思考->决策->执行
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
logger.debug(f"模板 {self.chat_stream.context.get_template_name()}")
loop_info = await self._observe_process_plan_action_loop(cycle_timers, thinking_id)
print(loop_info["loop_action_info"]["command"])
if loop_info["loop_action_info"]["command"] == "stop_focus_chat":
logger.info(f"{self.log_prefix} 麦麦决定停止专注聊天")
# 如果设置了回调函数,则调用它
@@ -314,10 +303,10 @@ class HeartFChatting:
logger.error(traceback.format_exc())
break
self._current_cycle.set_loop_info(loop_info)
self._current_cycle_detail.set_loop_info(loop_info)
self.hfcloop_observation.add_loop_info(self._current_cycle)
self._current_cycle.timers = cycle_timers
self.hfcloop_observation.add_loop_info(self._current_cycle_detail)
self._current_cycle_detail.timers = cycle_timers
# 防止循环过快消耗资源
await _handle_cycle_delay(
@@ -325,8 +314,8 @@ class HeartFChatting:
)
# 完成当前循环并保存历史
self._current_cycle.complete_cycle()
self._cycle_history.append(self._current_cycle)
self._current_cycle_detail.complete_cycle()
self._cycle_history.append(self._current_cycle_detail)
# 记录循环信息和计时器结果
timer_strings = []
@@ -335,7 +324,7 @@ class HeartFChatting:
timer_strings.append(f"{name}: {formatted_time}")
# 新增:输出每个处理器的耗时
processor_time_costs = self._current_cycle.loop_processor_info.get("processor_time_costs", {})
processor_time_costs = self._current_cycle_detail.loop_processor_info.get("processor_time_costs", {})
processor_time_strings = []
for pname, ptime in processor_time_costs.items():
formatted_ptime = f"{ptime * 1000:.2f}毫秒" if ptime < 1 else f"{ptime:.2f}"
@@ -345,9 +334,9 @@ class HeartFChatting:
)
logger.info(
f"{self.log_prefix}{self._current_cycle.cycle_id}次思考,"
f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.1f}秒, "
f"动作: {self._current_cycle.loop_plan_info['action_result']['action_type']}"
f"{self.log_prefix}{self._current_cycle_detail.cycle_id}次思考,"
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, "
f"动作: {self._current_cycle_detail.loop_plan_info['action_result']['action_type']}"
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
+ processor_time_log
)
@@ -384,7 +373,7 @@ class HeartFChatting:
self._processing_lock.release()
async def _process_processors(
self, observations: List[Observation], running_memorys: List[Dict[str, Any]], cycle_timers: dict
self, observations: List[Observation], running_memorys: List[Dict[str, Any]]
) -> tuple[List[InfoBase], Dict[str, float]]:
# 记录并行任务开始时间
parallel_start_time = time.time()
@@ -400,7 +389,7 @@ class HeartFChatting:
async def run_with_timeout(proc=processor):
return await asyncio.wait_for(
proc.process_info(observations=observations, running_memorys=running_memorys),
timeout=PROCESSOR_TIMEOUT,
timeout=global_config.focus_chat.processor_max_time,
)
task = asyncio.create_task(run_with_timeout())
@@ -429,8 +418,8 @@ class HeartFChatting:
# 记录耗时
processor_time_costs[processor_name] = duration_since_parallel_start
except asyncio.TimeoutError:
logger.info(f"{self.log_prefix} 处理器 {processor_name} 超时(>{PROCESSOR_TIMEOUT}s已跳过")
processor_time_costs[processor_name] = PROCESSOR_TIMEOUT
logger.info(f"{self.log_prefix} 处理器 {processor_name} 超时(>{global_config.focus_chat.processor_max_time}s已跳过")
processor_time_costs[processor_name] = global_config.focus_chat.processor_max_time
except Exception as e:
logger.error(
f"{self.log_prefix} 处理器 {processor_name} 执行失败,耗时 (自并行开始): {duration_since_parallel_start:.2f}秒. 错误: {e}",
@@ -473,28 +462,42 @@ class HeartFChatting:
}
self.all_observations = observations
with Timer("回忆", cycle_timers):
running_memorys = await self.memory_activator.activate_memory(observations)
with Timer("调整动作", cycle_timers):
# 处理特殊的观察
await self.action_modifier.modify_actions(observations=observations, running_memorys=running_memorys)
await self.action_modifier.modify_actions(observations=observations)
await self.action_observation.observe()
observations.append(self.action_observation)
with Timer("执行 信息处理器", cycle_timers):
all_plan_info, processor_time_costs = await self._process_processors(
observations, running_memorys, cycle_timers
)
# 根据配置决定是否并行执行回忆和处理器阶段
# print(global_config.focus_chat.parallel_processing)
if global_config.focus_chat.parallel_processing:
# 并行执行回忆和处理器阶段
with Timer("并行回忆和处理", cycle_timers):
memory_task = asyncio.create_task(self.memory_activator.activate_memory(observations))
processor_task = asyncio.create_task(self._process_processors(observations, []))
# 等待两个任务完成
running_memorys, (all_plan_info, processor_time_costs) = await asyncio.gather(memory_task, processor_task)
else:
# 串行执行
with Timer("回忆", cycle_timers):
running_memorys = await self.memory_activator.activate_memory(observations)
with Timer("执行 信息处理器", cycle_timers):
all_plan_info, processor_time_costs = await self._process_processors(
observations, running_memorys
)
loop_processor_info = {
"all_plan_info": all_plan_info,
"processor_time_costs": processor_time_costs,
}
loop_processor_info = {
"all_plan_info": all_plan_info,
"processor_time_costs": processor_time_costs,
}
with Timer("规划器", cycle_timers):
plan_result = await self.action_planner.plan(all_plan_info, cycle_timers)
plan_result = await self.action_planner.plan(all_plan_info, running_memorys)
loop_plan_info = {
"action_result": plan_result.get("action_result", {}),
@@ -526,6 +529,7 @@ class HeartFChatting:
"action_taken": success,
"reply_text": reply_text,
"command": command,
"taken_time": time.time(),
}
loop_info = {

View File

@@ -24,9 +24,7 @@ logger = get_logger("processor")
def init_prompt():
group_prompt = """
你的名字是{bot_name}
{memory_str}
{extra_info}
{relation_prompt}
{memory_str}{extra_info}{relation_prompt}
{cycle_info_block}
现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容
{chat_observe_info}
@@ -46,15 +44,11 @@ def init_prompt():
private_prompt = """
你的名字是{bot_name}
{memory_str}
{extra_info}
{relation_prompt}
{memory_str}{extra_info}{relation_prompt}
{cycle_info_block}
现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容
{chat_observe_info}
{action_observe_info}
以下是你之前对聊天的观察和规划,你的名字是{bot_name}
{last_mind}
@@ -155,14 +149,14 @@ class MindProcessor(BaseProcessor):
# ---------- 0. 更新和清理 structured_info ----------
if self.structured_info:
updated_info = []
for item in self.structured_info:
item["ttl"] -= 1
if item["ttl"] > 0:
updated_info.append(item)
else:
logger.debug(f"{self.log_prefix} 移除过期的 structured_info 项: {item['id']}")
self.structured_info = updated_info
# updated_info = []
# for item in self.structured_info:
# item["ttl"] -= 1
# if item["ttl"] > 0:
# updated_info.append(item)
# else:
# logger.debug(f"{self.log_prefix} 移除过期的 structured_info 项: {item['id']}")
# self.structured_info = updated_info
self._update_structured_info_str()
logger.debug(
f"{self.log_prefix} 当前完整的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}"

View File

@@ -25,9 +25,7 @@ def init_prompt():
你是一个AI但是你伪装成了一个人类你的人格是{prompt_personality}
{indentify_block}
{relation_prompt}
{memory_str}
{relation_prompt}{memory_str}
现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容
{chat_observe_info}

View File

@@ -23,10 +23,7 @@ def init_prompt():
# 添加工具执行器提示词
tool_executor_prompt = """
你是一个专门执行工具的助手。你的名字是{bot_name}。现在是{time_now}
你当前的额外信息:
{memory_str}
群里正在进行的聊天内容:
{chat_observe_info}
@@ -165,8 +162,9 @@ class ToolProcessor(BaseProcessor):
logger.debug(f"开始执行工具调用{prompt}")
response, _, tool_calls = await self.llm_model.generate_response_tool_async(prompt=prompt, tools=tools)
logger.debug(f"获取到工具原始输出:\n{tool_calls}")
# 处理工具调用和结果收集类似于SubMind中的逻辑
if tool_calls:
logger.debug(f"获取到工具原始输出:\n{tool_calls}")
# 处理工具调用和结果收集类似于SubMind中的逻辑
new_structured_items = []
used_tools = [] # 记录使用了哪些工具

View File

@@ -26,8 +26,8 @@ class NoReplyAction(BaseAction):
action_parameters = {}
action_require = [
"话题无关/无聊/不感兴趣/不懂",
"最后一条消息是你自己发的且无人回应你",
"你发送了太多消息,且无人回复",
"聊天记录中最新一条消息是你自己发的且无人回应你",
"连续发送了太多消息,且无人回复",
]
default = True

View File

@@ -28,11 +28,8 @@ class ActionModifier:
async def modify_actions(
self,
observations: Optional[List[Observation]] = None,
running_memorys: Optional[List[Dict]] = None,
**kwargs: Any,
):
# print(f"observations: {observations}")
# processed_infos = []
# 处理Observation对象
if observations:

View File

@@ -26,9 +26,8 @@ def init_prompt():
"""
你的自我认知是:
{self_info_block}
{extra_info_block}
{memory_str}
你需要基于以下信息决定如何参与对话
这些信息可能会有冲突请你整合这些信息并选择一个最合适的action
{chat_content_block}
@@ -49,7 +48,7 @@ def init_prompt():
请你以下面格式输出你选择的action
{{
"action": "action_name",
"reasoning": "你的决策理由",
"reasoning": "说明你做出该action的原因",
"参数1": "参数1的值",
"参数2": "参数2的值",
"参数3": "参数3的值",
@@ -84,13 +83,13 @@ class ActionPlanner:
self.action_manager = action_manager
async def plan(self, all_plan_info: List[InfoBase], cycle_timers: dict) -> Dict[str, Any]:
async def plan(self, all_plan_info: List[InfoBase], running_memorys: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
参数:
all_plan_info: 所有计划信息
cycle_timers: 计时器字典
running_memorys: 回忆信息
"""
action = "no_reply" # 默认动作
@@ -169,6 +168,7 @@ class ActionPlanner:
current_available_actions=current_available_actions, # <-- Pass determined actions
cycle_info=cycle_info, # <-- Pass cycle info
extra_info=extra_info,
running_memorys=running_memorys,
)
# --- 调用 LLM (普通文本生成) ---
@@ -259,10 +259,22 @@ class ActionPlanner:
current_available_actions: Dict[str, ActionInfo],
cycle_info: Optional[str],
extra_info: list[str],
running_memorys: List[Dict[str, Any]],
) -> str:
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
try:
# --- Determine chat context ---
memory_str = ""
if global_config.focus_chat.parallel_processing:
memory_str = ""
if running_memorys:
memory_str = "以下是当前在聊天中,你回忆起的记忆:\n"
for running_memory in running_memorys:
memory_str += f"{running_memory['topic']}: {running_memory['content']}\n"
chat_context_description = "你现在正在一个群聊中"
chat_target_name = None # Only relevant for private
if not is_group_chat and chat_target_info:
@@ -324,6 +336,7 @@ class ActionPlanner:
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
prompt = planner_prompt_template.format(
self_info_block=self_info_block,
memory_str=memory_str,
# bot_name=global_config.bot.nickname,
prompt_personality=personality_block,
chat_context_description=chat_context_description,

View File

@@ -34,3 +34,13 @@ class ActionObservation:
action_info_block += "\n注意,除了上面动作选项之外,你在群聊里不能做其他任何事情,这是你能力的边界\n"
self.observe_info = action_info_block
def to_dict(self) -> dict:
"""将观察对象转换为可序列化的字典"""
return {
"observe_info": self.observe_info,
"observe_id": self.observe_id,
"last_observe_time": self.last_observe_time,
"all_actions": self.all_actions,
"all_using_actions": self.all_using_actions
}

View File

@@ -66,6 +66,24 @@ class ChattingObservation(Observation):
self.oldest_messages_str = ""
self.compressor_prompt = ""
def to_dict(self) -> dict:
"""将观察对象转换为可序列化的字典"""
return {
"chat_id": self.chat_id,
"platform": self.platform,
"is_group_chat": self.is_group_chat,
"chat_target_info": self.chat_target_info,
"talking_message_str": self.talking_message_str,
"talking_message_str_truncate": self.talking_message_str_truncate,
"name": self.name,
"nick_name": self.nick_name,
"mid_memory_info": self.mid_memory_info,
"person_list": self.person_list,
"oldest_messages_str": self.oldest_messages_str,
"compressor_prompt": self.compressor_prompt,
"last_observe_time": self.last_observe_time
}
async def initialize(self):
self.is_group_chat, self.chat_target_info = await get_chat_type_and_target_info(self.chat_id)
logger.debug(f"初始化observation: self.is_group_chat: {self.is_group_chat}")

View File

@@ -27,40 +27,62 @@ class HFCloopObservation:
recent_active_cycles: List[CycleDetail] = []
for cycle in reversed(self.history_loop):
# 只关心实际执行了动作的循环
action_taken = cycle.loop_action_info["action_taken"]
if action_taken:
recent_active_cycles.append(cycle)
if len(recent_active_cycles) == 5:
break
# action_taken = cycle.loop_action_info["action_taken"]
# if action_taken:
recent_active_cycles.append(cycle)
if len(recent_active_cycles) == 5:
break
cycle_info_block = ""
action_detailed_str = ""
consecutive_text_replies = 0
responses_for_prompt = []
# 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看)
for cycle in recent_active_cycles:
action_type = cycle.loop_plan_info["action_result"]["action_type"]
action_reasoning = cycle.loop_plan_info["action_result"]["reasoning"]
is_taken = cycle.loop_action_info["action_taken"]
action_taken_time = cycle.loop_action_info["taken_time"]
action_taken_time_str = datetime.fromtimestamp(action_taken_time).strftime("%H:%M:%S")
# print(action_type)
# print(action_reasoning)
# print(is_taken)
# print(action_taken_time_str)
# print("--------------------------------")
if action_type == "reply":
consecutive_text_replies += 1
response_text = cycle.loop_plan_info["action_result"]["action_data"].get("text", "[空回复]")
responses_for_prompt.append(response_text)
if is_taken:
action_detailed_str += f"{action_taken_time_str}时,你选择回复(action:{action_type},内容是:'{response_text}')。你选择这个action的原因是:{action_reasoning}\n"
else:
action_detailed_str += f"{action_taken_time_str}时,你选择回复(action:{action_type},内容是:'{response_text}')但是动作失败了。你选择这个action的原因是:{action_reasoning}\n"
elif action_type == "no_reply":
action_detailed_str += f"{action_taken_time_str}时,你选择不回复(action:{action_type}),你选择了沉默,原因是:{action_reasoning}\n"
else:
break
if is_taken:
action_detailed_str += f"{action_taken_time_str}时,你选择执行了(action:{action_type})你选择这个action的原因是:{action_reasoning}\n"
else:
action_detailed_str += f"{action_taken_time_str}时,你选择执行了(action:{action_type})但是动作失败了。你选择这个action的原因是:{action_reasoning}\n"
if action_detailed_str:
cycle_info_block = f"\n你最近做的事:\n{action_detailed_str}\n"
else:
cycle_info_block = "\n"
# 根据连续文本回复的数量构建提示信息
# 注意: responses_for_prompt 列表是从最近到最远排序的
if consecutive_text_replies >= 3: # 如果最近的三个活动都是文本回复
cycle_info_block = f'你已经连续回复了三条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}",第三近: "{responses_for_prompt[2]}")。你回复的有点多了,请注意'
elif consecutive_text_replies == 2: # 如果最近的两个活动是文本回复
cycle_info_block = f'你已经连续回复了两条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}"),请注意'
elif consecutive_text_replies == 1: # 如果最近的一个活动是文本回复
cycle_info_block = f'你刚刚已经回复一条消息(内容: "{responses_for_prompt[0]}"'
# 包装提示块,增加可读性,即使没有连续回复也给个标记
if cycle_info_block:
cycle_info_block = f"\n你最近的回复\n{cycle_info_block}\n"
else:
cycle_info_block = "\n"
# if cycle_info_block:
# cycle_info_block = f"\n你最近的回复\n{cycle_info_block}\n"
# else:
# cycle_info_block = "\n"
# 获取history_loop中最新添加的
if self.history_loop:
@@ -70,10 +92,19 @@ class HFCloopObservation:
if start_time is not None and end_time is not None:
time_diff = int(end_time - start_time)
if time_diff > 60:
cycle_info_block += f"\n距离你上一次阅读消息已经过去了{time_diff / 60}分钟\n"
cycle_info_block += f"距离你上一次阅读消息并思考和规划,已经过去了{int(time_diff / 60)}分钟\n"
else:
cycle_info_block += f"\n距离你上一次阅读消息已经过去了{time_diff}\n"
cycle_info_block += f"距离你上一次阅读消息并思考和规划,已经过去了{time_diff}\n"
else:
cycle_info_block += "\n你还没看过消息\n"
cycle_info_block += "你还没看过消息\n"
self.observe_info = cycle_info_block
def to_dict(self) -> dict:
"""将观察对象转换为可序列化的字典"""
return {
"observe_info": self.observe_info,
"observe_id": self.observe_id,
"last_observe_time": self.last_observe_time,
"history_loop": [cycle.to_dict() for cycle in self.history_loop]
}

View File

@@ -13,5 +13,13 @@ class Observation:
self.observe_id = observe_id
self.last_observe_time = datetime.now().timestamp() # 初始化为当前时间
def to_dict(self) -> dict:
"""将观察对象转换为可序列化的字典"""
return {
"observe_info": self.observe_info,
"observe_id": self.observe_id,
"last_observe_time": self.last_observe_time
}
async def observe(self):
pass

View File

@@ -15,6 +15,16 @@ class StructureObservation:
self.history_loop = []
self.structured_info = []
def to_dict(self) -> dict:
"""将观察对象转换为可序列化的字典"""
return {
"observe_info": self.observe_info,
"observe_id": self.observe_id,
"last_observe_time": self.last_observe_time,
"history_loop": self.history_loop,
"structured_info": self.structured_info
}
def get_observe_info(self):
return self.structured_info

View File

@@ -32,3 +32,13 @@ class WorkingMemoryObservation:
async def observe(self):
pass
def to_dict(self) -> dict:
"""将观察对象转换为可序列化的字典"""
return {
"observe_info": self.observe_info,
"observe_id": self.observe_id,
"last_observe_time": self.last_observe_time,
"working_memory": self.working_memory.to_dict() if hasattr(self.working_memory, 'to_dict') else str(self.working_memory),
"retrieved_working_memory": [item.to_dict() if hasattr(item, 'to_dict') else str(item) for item in self.retrieved_working_memory]
}

View File

@@ -278,10 +278,6 @@ class SubHeartflow:
self.update_last_chat_state_time()
self.history_chat_state.append((current_state, self.chat_state_last_time))
# logger.info(
# f"{log_prefix} 麦麦的聊天状态从 {current_state.value} (持续了 {int(self.chat_state_last_time)} 秒) 变更为 {new_state.value}"
# )
self.chat_state.chat_status = new_state
self.chat_state_last_time = 0
self.chat_state_changed_time = time.time()

View File

@@ -143,9 +143,15 @@ class FocusChatConfig(ConfigBase):
think_interval: float = 1
"""思考间隔(秒)"""
consecutive_replies: float = 1
"""连续回复能力,值越高,麦麦连续回复的概率越高"""
parallel_processing: bool = False
"""是否允许处理器阶段和回忆阶段并行执行"""
processor_max_time: int = 25
"""处理器最大时间,单位秒,如果超过这个时间,处理器会自动停止"""
@dataclass
@@ -160,6 +166,11 @@ class FocusChatProcessorConfig(ConfigBase):
working_memory_processor: bool = True
"""是否启用工作记忆处理器"""
lite_chat_mind_processor: bool = False
"""是否启用轻量级聊天思维处理器可以节省token消耗和时间"""
@dataclass

View File

@@ -14,13 +14,13 @@ def init_prompt() -> None:
personality_expression_prompt = """
{personality}
请从以上人设中总结出这个角色可能的语言风格
请从以上人设中总结出这个角色可能的语言风格,你必须严格根据人设引申,不要输出例子
思考回复的特殊内容和情感
思考有没有特殊的梗,一并总结成语言风格
总结成如下格式的规律,总结的内容要详细,但具有概括性:
"xxx"时,可以"xxx", xxx不超过10个字
例如:
例如(不要输出例子)
"表示十分惊叹"时,使用"我嘞个xxxx"
"表示讽刺的赞同,不想讲道理"时,使用"对对对"
"想说明某个观点,但懒得明说",使用"懂的都懂"

View File

@@ -23,7 +23,7 @@ class MuteAction(PluginAction):
"当有人戳你两次以上时,防止刷屏,禁言他,必须牢记",
"当你想回避某个话题时使用",
]
default = True # 默认动作,是否手动添加到使用集
default = False # 默认动作,是否手动添加到使用集
associated_types = ["command", "text"]
# associated_types = ["text"]

View File

@@ -41,7 +41,7 @@ identity_detail = [
[expression]
# 表达方式
expression_style = "描述麦麦说话的表达风格,表达习惯,例如:(回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。不要有额外的符号,尽量简单简短)"
enable_expression_learning = true # 是否启用表达学习,麦麦会学习人类说话风格
enable_expression_learning = false # 是否启用表达学习,麦麦会学习人类说话风格
learning_interval = 600 # 学习间隔 单位秒
[relationship]
@@ -94,8 +94,11 @@ talk_frequency_down_groups = [] #降低回复频率的群号码
think_interval = 3 # 思考间隔 单位秒,可以有效减少消耗
consecutive_replies = 1 # 连续回复能力,值越高,麦麦连续回复的概率越高
parallel_processing = true # 是否并行处理回忆和处理器阶段,可以节省时间
observation_context_size = 16 # 观察到的最长上下文大小,建议15太短太长都会导致脑袋尖尖
processor_max_time = 25 # 处理器最大时间,单位秒,如果超过这个时间,处理器会自动停止
observation_context_size = 16 # 观察到的最长上下文大小
compressed_length = 8 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度超过心流观察到的上下文长度会压缩最短压缩长度为5
compress_length_limit = 4 #最多压缩份数,超过该数值的压缩上下文会被删除