diff --git a/src/config/config.py b/src/config/config.py index 187bb6cde..2ade83f11 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -192,7 +192,6 @@ class BotConfig: reply_trigger_threshold: float = 3.0 # 心流聊天触发阈值,越低越容易触发 probability_decay_factor_per_second: float = 0.2 # 概率衰减因子,越大衰减越快 default_decay_rate_per_second: float = 0.98 # 默认衰减率,越大衰减越慢 - initial_duration: int = 60 # 初始持续时间,越大心流聊天持续的时间越长 # sub_heart_flow_update_interval: int = 60 # 子心流更新频率,间隔 单位秒 # sub_heart_flow_freeze_time: int = 120 # 子心流冻结时间,超过这个时间没有回复,子心流会冻结,间隔 单位秒 @@ -286,11 +285,11 @@ class BotConfig: vlm: Dict[str, str] = field(default_factory=lambda: {}) moderation: Dict[str, str] = field(default_factory=lambda: {}) - # 实验性 llm_observation: Dict[str, str] = field(default_factory=lambda: {}) llm_sub_heartflow: Dict[str, str] = field(default_factory=lambda: {}) llm_heartflow: Dict[str, str] = field(default_factory=lambda: {}) llm_tool_use: Dict[str, str] = field(default_factory=lambda: {}) + llm_plan: Dict[str, str] = field(default_factory=lambda: {}) api_urls: Dict[str, str] = field(default_factory=lambda: {}) @@ -448,7 +447,6 @@ class BotConfig: config.default_decay_rate_per_second = heartflow_config.get( "default_decay_rate_per_second", config.default_decay_rate_per_second ) - config.initial_duration = heartflow_config.get("initial_duration", config.initial_duration) def willing(parent: dict): willing_config = parent["willing"] @@ -489,6 +487,7 @@ class BotConfig: "llm_tool_use", "llm_observation", "llm_sub_heartflow", + "llm_plan", "llm_heartflow", "llm_PFC_action_planner", "llm_PFC_chat", diff --git a/src/heart_flow/background_tasks.py b/src/heart_flow/background_tasks.py index 85fb6c502..21254ce78 100644 --- a/src/heart_flow/background_tasks.py +++ b/src/heart_flow/background_tasks.py @@ -230,8 +230,8 @@ class BackgroundTaskManager: if await self.subheartflow_manager.stop_subheartflow(flow_id, f"定期清理: {reason}"): stopped_count += 1 logger.info(f"[Background Task Cleanup] Cleanup cycle finished. Stopped {stopped_count} inactive flows.") - else: - logger.debug("[Background Task Cleanup] Cleanup cycle finished. No inactive flows found.") + # else: + # logger.debug("[Background Task Cleanup] Cleanup cycle finished. No inactive flows found.") async def _perform_logging_work(self): """执行一轮状态日志记录。""" diff --git a/src/heart_flow/sub_mind.py b/src/heart_flow/sub_mind.py index 111c2cf5c..b213f6f11 100644 --- a/src/heart_flow/sub_mind.py +++ b/src/heart_flow/sub_mind.py @@ -11,6 +11,7 @@ from src.do_tool.tool_use import ToolUser from src.plugins.utils.json_utils import safe_json_dumps, normalize_llm_response, process_llm_tool_calls from src.heart_flow.chat_state_info import ChatStateInfo from src.plugins.chat.chat_stream import chat_manager +from src.plugins.heartFC_chat.heartFC_Cycleinfo import CycleInfo subheartflow_config = LogConfig( console_format=SUB_HEARTFLOW_STYLE_CONFIG["console_format"], @@ -23,12 +24,12 @@ def init_prompt(): prompt = "" prompt += "{extra_info}\n" prompt += "{prompt_personality}\n" - prompt += "刚刚你的内心想法是:{current_thinking_info}\n" + prompt += "{last_loop_prompt}\n" prompt += "-----------------------------------\n" prompt += "现在是{time_now},你正在上网,和qq群里的网友们聊天,以下是正在进行的聊天内容:\n{chat_observe_info}\n" prompt += "\n你现在{mood_info}\n" - prompt += "现在请你生成你的内心想法,要求思考群里正在进行的话题,之前大家聊过的话题,群里成员的关系。" - prompt += "请你思考,要不要对群里的话题进行回复,以及如何对群聊内容进行回复\n" + prompt += "现在请你,阅读群里正在进行的聊天内容,思考群里的正在进行的话题,分析群里成员与你的关系。" + prompt += "请你思考,生成你的内心想法,包括你的思考,要不要对群里的话题进行回复,以及如何对群聊内容进行回复\n" prompt += "回复的要求是:不要总是重复自己提到过的话题,如果你要回复,最好只回复一个人的一个话题\n" prompt += "如果最后一条消息是你自己发的,观察到的内容只有你自己的发言,并且之后没有人回复你,不要回复。" prompt += "如果聊天记录中最新的消息是你自己发送的,并且你还想继续回复,你应该紧紧衔接你发送的消息,进行话题的深入,补充,或追问等等。" @@ -38,6 +39,12 @@ def init_prompt(): prompt += "如果你需要做某件事,来对消息和你的回复进行处理,请使用工具。\n" Prompt(prompt, "sub_heartflow_prompt_before") + + prompt = "" + prompt += "刚刚你的内心想法是:{current_thinking_info}\n" + prompt += "{if_replan_prompt}\n" + + Prompt(prompt, "last_loop") class SubMind: @@ -58,7 +65,7 @@ class SubMind: self.past_mind = [] self.structured_info = {} - async def do_thinking_before_reply(self): + async def do_thinking_before_reply(self, last_cycle: CycleInfo): """ 在回复前进行思考,生成内心想法并收集工具调用结果 @@ -122,6 +129,20 @@ class SubMind: ("继续生成你在这个聊天中的想法,进行深入思考", 0.1), ] + #上一次决策信息 + last_action = last_cycle.action_type + last_reasoning = last_cycle.reasoning + is_replan = last_cycle.replanned + if is_replan: + if_replan_prompt = f"但是你有了上述想法之后,有了新消息,你决定重新思考后,你做了:{last_action}\n因为:{last_reasoning}\n" + else: + if_replan_prompt = f"出于这个想法,你刚才做了:{last_action}\n因为:{last_reasoning}\n" + + last_loop_prompt = (await global_prompt_manager.get_prompt_async("last_loop")).format( + current_thinking_info=current_thinking_info, + if_replan_prompt=if_replan_prompt + ) + # 加权随机选择思考指导 hf_do_next = local_random.choices( [option[0] for option in hf_options], weights=[option[1] for option in hf_options], k=1 @@ -133,11 +154,11 @@ class SubMind: extra_info="", # 可以在这里添加额外信息 prompt_personality=prompt_personality, bot_name=individuality.personality.bot_nickname, - current_thinking_info=current_thinking_info, time_now=time_now, chat_observe_info=chat_observe_info, mood_info=mood_info, hf_do_next=hf_do_next, + last_loop_prompt=last_loop_prompt ) # logger.debug(f"[{self.subheartflow_id}] 心流思考提示词构建完成") diff --git a/src/plugins/heartFC_chat/heartFC_Cycleinfo.py b/src/plugins/heartFC_chat/heartFC_Cycleinfo.py new file mode 100644 index 000000000..030018ddf --- /dev/null +++ b/src/plugins/heartFC_chat/heartFC_Cycleinfo.py @@ -0,0 +1,70 @@ +import time +from typing import List, Optional, Dict, Any + +class CycleInfo: + """循环信息记录类""" + def __init__(self, cycle_id: int): + self.cycle_id = cycle_id + self.start_time = time.time() + self.end_time: Optional[float] = None + self.action_taken = False + self.action_type = "unknown" + self.reasoning = "" + self.timers: Dict[str, float] = {} + self.thinking_id = "" + self.replanned = False + + # 添加响应信息相关字段 + self.response_info: Dict[str, Any] = { + "response_text": [], # 回复的文本列表 + "emoji_info": "", # 表情信息 + "anchor_message_id": "", # 锚点消息ID + "reply_message_ids": [], # 回复消息ID列表 + "sub_mind_thinking": "", # 子思维思考内容 + } + + def to_dict(self) -> Dict[str, Any]: + """将循环信息转换为字典格式""" + return { + "cycle_id": self.cycle_id, + "start_time": self.start_time, + "end_time": self.end_time, + "action_taken": self.action_taken, + "action_type": self.action_type, + "reasoning": self.reasoning, + "timers": self.timers, + "thinking_id": self.thinking_id, + "response_info": self.response_info + } + + def complete_cycle(self): + """完成循环,记录结束时间""" + self.end_time = time.time() + + def set_action_info(self, action_type: str, reasoning: str, action_taken: bool): + """设置动作信息""" + self.action_type = action_type + self.reasoning = reasoning + self.action_taken = action_taken + + def set_thinking_id(self, thinking_id: str): + """设置思考消息ID""" + self.thinking_id = thinking_id + + def set_response_info(self, + response_text: Optional[List[str]] = None, + emoji_info: Optional[str] = None, + anchor_message_id: Optional[str] = None, + reply_message_ids: Optional[List[str]] = None, + sub_mind_thinking: Optional[str] = None): + """设置响应信息""" + if response_text is not None: + self.response_info["response_text"] = response_text + if emoji_info is not None: + self.response_info["emoji_info"] = emoji_info + if anchor_message_id is not None: + self.response_info["anchor_message_id"] = anchor_message_id + if reply_message_ids is not None: + self.response_info["reply_message_ids"] = reply_message_ids + if sub_mind_thinking is not None: + self.response_info["sub_mind_thinking"] = sub_mind_thinking \ No newline at end of file diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index b8338c4b3..c11674fe2 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -1,7 +1,8 @@ import asyncio import time import traceback -from typing import List, Optional, Dict, Any, Set, Deque +import random # <-- 添加导入 +from typing import List, Optional, Dict, Any, Deque from collections import deque from src.plugins.chat.message import MessageRecv, BaseMessageInfo, MessageThinking, MessageSending from src.plugins.chat.message import MessageSet, Seg # Local import needed after move @@ -23,6 +24,7 @@ from src.heart_flow.observation import Observation from src.plugins.heartFC_chat.heartflow_prompt_builder import global_prompt_manager import contextlib from src.plugins.utils.chat_message_builder import num_new_messages_since +from src.plugins.heartFC_chat.heartFC_Cycleinfo import CycleInfo # --- End import --- @@ -139,75 +141,6 @@ class SenderError(HeartFCError): """发送器异常""" pass - -class CycleInfo: - """循环信息记录类""" - def __init__(self, cycle_id: int): - self.cycle_id = cycle_id - self.start_time = time.time() - self.end_time: Optional[float] = None - self.action_taken = False - self.action_type = "unknown" - self.reasoning = "" - self.timers: Dict[str, float] = {} - self.thinking_id = "" - - # 添加响应信息相关字段 - self.response_info: Dict[str, Any] = { - "response_text": [], # 回复的文本列表 - "emoji_info": "", # 表情信息 - "anchor_message_id": "", # 锚点消息ID - "reply_message_ids": [], # 回复消息ID列表 - "sub_mind_thinking": "", # 子思维思考内容 - } - - def to_dict(self) -> Dict[str, Any]: - """将循环信息转换为字典格式""" - return { - "cycle_id": self.cycle_id, - "start_time": self.start_time, - "end_time": self.end_time, - "action_taken": self.action_taken, - "action_type": self.action_type, - "reasoning": self.reasoning, - "timers": self.timers, - "thinking_id": self.thinking_id, - "response_info": self.response_info - } - - def complete_cycle(self): - """完成循环,记录结束时间""" - self.end_time = time.time() - - def set_action_info(self, action_type: str, reasoning: str, action_taken: bool): - """设置动作信息""" - self.action_type = action_type - self.reasoning = reasoning - self.action_taken = action_taken - - def set_thinking_id(self, thinking_id: str): - """设置思考消息ID""" - self.thinking_id = thinking_id - - def set_response_info(self, - response_text: Optional[List[str]] = None, - emoji_info: Optional[str] = None, - anchor_message_id: Optional[str] = None, - reply_message_ids: Optional[List[str]] = None, - sub_mind_thinking: Optional[str] = None): - """设置响应信息""" - if response_text is not None: - self.response_info["response_text"] = response_text - if emoji_info is not None: - self.response_info["emoji_info"] = emoji_info - if anchor_message_id is not None: - self.response_info["anchor_message_id"] = anchor_message_id - if reply_message_ids is not None: - self.response_info["reply_message_ids"] = reply_message_ids - if sub_mind_thinking is not None: - self.response_info["sub_mind_thinking"] = sub_mind_thinking - - class HeartFChatting: """ 管理一个连续的Plan-Replier-Sender循环 @@ -244,8 +177,7 @@ class HeartFChatting: # LLM规划器配置 self.planner_llm = LLMRequest( - model=global_config.llm_normal, - temperature=global_config.llm_normal["temp"], + model=global_config.llm_plan, max_tokens=1000, request_type="action_planning", # 用于动作规划 ) @@ -352,7 +284,7 @@ class HeartFChatting: # 记录规划开始时间点 planner_start_db_time = time.time() - # 执行规划阶段 + # 主循环:思考->决策->执行 action_taken, thinking_id = await self._think_plan_execute_loop( cycle_timers, planner_start_db_time ) @@ -436,29 +368,34 @@ class HeartFChatting: ) -> tuple[bool, str]: """执行规划阶段""" try: - # 获取子思维思考结果 - current_mind = "" - with Timer("思考", cycle_timers): - current_mind = await self._get_submind_thinking() - # 记录子思维思考内容 - if self._current_cycle: - self._current_cycle.set_response_info(sub_mind_thinking=current_mind) + # think:思考 + current_mind = await self._get_submind_thinking(cycle_timers) + # 记录子思维思考内容 + if self._current_cycle: + self._current_cycle.set_response_info(sub_mind_thinking=current_mind) - # 执行规划 + # plan:决策 with Timer("决策", cycle_timers): planner_result = await self._planner(current_mind, cycle_timers) - - # 在获取规划结果后检查新消息 - if await self._check_new_messages(planner_start_db_time): - # 更新循环信息 - logger.info(f"{self.log_prefix} 思考到一半,检测到新消息,重新思考") - self._current_cycle.set_action_info("new_messages", "检测到新消息", False) - return False, "new_messages" - - # 解析规划结果 + action = planner_result.get("action", "error") reasoning = planner_result.get("reasoning", "未提供理由") + self._current_cycle.set_action_info(action, reasoning, False) + + # 在获取规划结果后检查新消息 + if await self._check_new_messages(planner_start_db_time): + if random.random() < 0.3: + logger.info(f"{self.log_prefix} 看到了新消息,麦麦决定重新观察和规划...") + # 重新规划 + with Timer("重新决策", cycle_timers): + self._current_cycle.replanned = True + planner_result = await self._planner(current_mind, cycle_timers, is_re_planned=True) + logger.info(f"{self.log_prefix} 重新规划完成.") + + # 解析规划结果 + action = planner_result.get("action", "error") + reasoning = planner_result.get("reasoning", "未提供理由") # 更新循环信息 self._current_cycle.set_action_info(action, reasoning, True) @@ -467,7 +404,7 @@ class HeartFChatting: logger.error(f"{self.log_prefix} LLM失败: {reasoning}") return False, "" - # 根据动作类型执行对应处理 + # execute:执行 with Timer("执行", cycle_timers): return await self._handle_action(action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time) @@ -699,7 +636,7 @@ class HeartFChatting: logger.info(f"{log_prefix} Sleep interrupted, loop likely cancelling.") raise - async def _get_submind_thinking(self) -> str: + async def _get_submind_thinking(self, cycle_timers: dict) -> str: """ 获取子思维的思考结果 @@ -707,27 +644,38 @@ class HeartFChatting: str: 思考结果,如果思考失败则返回错误信息 """ try: - observation = self.observations[0] - await observation.observe() - current_mind, _past_mind = await self.sub_mind.do_thinking_before_reply() - return current_mind + with Timer("观察", cycle_timers): + observation = self.observations[0] + await observation.observe() + + # 获取上一个循环的信息 + last_cycle = self._cycle_history[-1] if self._cycle_history else None + + with Timer("思考", cycle_timers): + # 获取上一个循环的动作 + # 传递上一个循环的信息给 do_thinking_before_reply + current_mind, _past_mind = await self.sub_mind.do_thinking_before_reply( + last_cycle=last_cycle + ) + return current_mind except Exception as e: logger.error(f"{self.log_prefix}[SubMind] 思考失败: {e}") logger.error(traceback.format_exc()) return "[思考时出错]" - async def _planner(self, current_mind: str, cycle_timers: dict) -> Dict[str, Any]: + async def _planner(self, current_mind: str, cycle_timers: dict, is_re_planned: bool = False) -> Dict[str, Any]: """ 规划器 (Planner): 使用LLM根据上下文决定是否和如何回复。 参数: current_mind: 子思维的当前思考结果 """ - logger.info(f"{self.log_prefix}[Planner] 开始执行规划器") + logger.info(f"{self.log_prefix}[Planner] 开始{'重新' if is_re_planned else ''}执行规划器") # 获取观察信息 observation = self.observations[0] - # await observation.observe() + if is_re_planned: + observation.observe() observed_messages = observation.talking_message observed_messages_str = observation.talking_message_str @@ -740,11 +688,18 @@ class HeartFChatting: try: # 构建提示词 with Timer("构建提示词", cycle_timers): + if is_re_planned: + replan_prompt = await self._build_replan_prompt( + self._current_cycle.action, self._current_cycle.reasoning + ) + prompt = replan_prompt + else: + replan_prompt = "" prompt = await self._build_planner_prompt( - observed_messages_str, current_mind, self.sub_mind.structured_info + observed_messages_str, current_mind, self.sub_mind.structured_info, replan_prompt ) payload = { - "model": self.planner_llm.model_name, + "model": global_config.llm_plan["name"], "messages": [{"role": "user", "content": prompt}], "tools": self.action_manager.get_planner_tool_definition(), "tool_choice": {"type": "function", "function": {"name": "decide_reply_action"}}, @@ -904,9 +859,19 @@ class HeartFChatting: logger.warning(f"{self.log_prefix} 已释放处理锁") logger.info(f"{self.log_prefix} HeartFChatting关闭完成") - + + async def _build_replan_prompt( + self, action: str, reasoning: str + ) -> str: + """构建 Replanner LLM 的提示词""" + prompt = (await global_prompt_manager.get_prompt_async("replan_prompt")).format( + action=action, + reasoning=reasoning, + ) + return prompt + async def _build_planner_prompt( - self, observed_messages_str: str, current_mind: Optional[str], structured_info: Dict[str, Any] + self, observed_messages_str: str, current_mind: Optional[str], structured_info: Dict[str, Any], replan_prompt: str ) -> str: """构建 Planner LLM 的提示词""" @@ -937,6 +902,7 @@ class HeartFChatting: structured_info_block=structured_info_block, chat_content_block=chat_content_block, current_mind_block=current_mind_block, + replan=replan_prompt, ) return prompt diff --git a/src/plugins/heartFC_chat/heartFC_generator.py b/src/plugins/heartFC_chat/heartFC_generator.py index c489e012c..95ee0a754 100644 --- a/src/plugins/heartFC_chat/heartFC_generator.py +++ b/src/plugins/heartFC_chat/heartFC_generator.py @@ -49,12 +49,11 @@ class HeartFCGenerator: arousal_multiplier = MoodManager.get_instance().get_arousal_multiplier() - with Timer() as t_generate_response: - current_model = self.model_normal - current_model.temperature = global_config.llm_normal["temp"] * arousal_multiplier # 激活度越高,温度越高 - model_response = await self._generate_response_with_model( - structured_info, current_mind_info, reason, message, current_model, thinking_id - ) + current_model = self.model_normal + current_model.temperature = global_config.llm_normal["temp"] * arousal_multiplier # 激活度越高,温度越高 + model_response = await self._generate_response_with_model( + structured_info, current_mind_info, reason, message, current_model, thinking_id + ) if model_response: model_processed_response = await self._process_response(model_response) diff --git a/src/plugins/heartFC_chat/heartflow_prompt_builder.py b/src/plugins/heartFC_chat/heartflow_prompt_builder.py index 146a5307f..ec12e2adf 100644 --- a/src/plugins/heartFC_chat/heartflow_prompt_builder.py +++ b/src/plugins/heartFC_chat/heartflow_prompt_builder.py @@ -51,6 +51,7 @@ def init_prompt(): {chat_content_block} 看了以上内容,你产生的内心想法是: {current_mind_block} +{replan} 请结合你的内心想法和观察到的聊天内容,分析情况并使用 'decide_reply_action' 工具来决定你的最终行动。 注意你必须参考以下决策依据来选择工具: 1. 如果聊天内容无聊、与你无关、或者你的内心想法认为不适合回复(例如在讨论你不懂或不感兴趣的话题),选择 'no_reply'。 @@ -64,6 +65,8 @@ def init_prompt(): "planner_prompt", ) + Prompt("你原本打算{action},因为:{reasoning},但是你看到了新的消息,你决定重新决定行动。", "replan_prompt") + Prompt("你正在qq群里聊天,下面是群里在聊的内容:", "chat_target_group1") Prompt("和群里聊天", "chat_target_group2") Prompt("你正在和{sender_name}聊天,这是你们之前聊的内容:", "chat_target_private1") @@ -86,7 +89,7 @@ def init_prompt(): 你的网名叫{bot_name},有人也叫你{bot_other_names},{prompt_personality}。 你正在{chat_target_2},现在请你读读之前的聊天记录,{mood_prompt},然后给出日常且口语化的回复,平淡一些, 尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。{prompt_ger} -请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,尽量不要说你说过的话 +请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,不要浮夸,平淡一些 ,不要重复自己说过的话。 请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。 {moderation_prompt}不要输出多余内容(包括前后缀,冒号和引号,括号(),表情包,at或 @等 )。,只输出回复内容""", "reasoning_prompt_main", diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index d55fca3f0..a85d9f17a 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "1.4.2" +version = "1.5.0" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #如果你想要修改配置文件,请在修改后将version的值进行变更 @@ -81,12 +81,8 @@ model_normal_probability = 0.3 # 麦麦回答时选择一般模型 模型的概 reply_trigger_threshold = 3.0 # 心流聊天触发阈值,越低越容易进入心流聊天 probability_decay_factor_per_second = 0.2 # 概率衰减因子,越大衰减越快,越高越容易退出心流聊天 default_decay_rate_per_second = 0.98 # 默认衰减率,越大衰减越快,越高越难进入心流聊天 -initial_duration = 60 # 初始持续时间,越大心流聊天持续的时间越长 sub_heart_flow_stop_time = 500 # 子心流停止时间,超过这个时间没有回复,子心流会停止,间隔 单位秒 -# sub_heart_flow_update_interval = 60 -# sub_heart_flow_freeze_time = 100 -# heart_flow_update_interval = 600 observation_context_size = 20 # 心流观察到的最长上下文大小,超过这个值的上下文会被压缩 compressed_length = 5 # 不能大于observation_context_size,心流上下文压缩的最短压缩长度,超过心流观察到的上下文长度,会压缩,最短压缩长度为5 @@ -247,6 +243,29 @@ provider = "SILICONFLOW" pri_in = 0.35 pri_out = 0.35 + + +[model.llm_observation] #观察模型,压缩聊天内容,建议用免费的 +# name = "Pro/Qwen/Qwen2.5-7B-Instruct" +name = "Qwen/Qwen2.5-7B-Instruct" +provider = "SILICONFLOW" +pri_in = 0 +pri_out = 0 + +[model.llm_sub_heartflow] #子心流:激情水群时,生成麦麦的内心想法 +name = "Qwen/Qwen2.5-72B-Instruct" +provider = "SILICONFLOW" +pri_in = 4.13 +pri_out = 4.13 +temp = 0.7 #模型的温度,新V3建议0.1-0.3 + + +[model.llm_plan] #决策模型:激情水群时,负责决定麦麦该做什么 +name = "Qwen/Qwen2.5-32B-Instruct" +provider = "SILICONFLOW" +pri_in = 1.26 +pri_out = 1.26 + #嵌入模型 [model.embedding] #嵌入 @@ -255,26 +274,6 @@ provider = "SILICONFLOW" pri_in = 0 pri_out = 0 -[model.llm_observation] #观察模型,建议用免费的:建议使用qwen2.5 7b -# name = "Pro/Qwen/Qwen2.5-7B-Instruct" -name = "Qwen/Qwen2.5-7B-Instruct" -provider = "SILICONFLOW" -pri_in = 0 -pri_out = 0 - -[model.llm_sub_heartflow] #子心流:建议使用V3级别 -name = "Pro/deepseek-ai/DeepSeek-V3" -provider = "SILICONFLOW" -pri_in = 2 -pri_out = 8 -temp = 0.2 #模型的温度,新V3建议0.1-0.3 - -[model.llm_heartflow] #心流:建议使用qwen2.5 32b -# name = "Pro/Qwen/Qwen2.5-7B-Instruct" -name = "Qwen/Qwen2.5-32B-Instruct" -provider = "SILICONFLOW" -pri_in = 1.26 -pri_out = 1.26 #私聊PFC:需要开启PFC功能,默认三个模型均为硅基流动v3,如果需要支持多人同时私聊或频繁调用,建议把其中的一个或两个换成官方v3或其它模型,以免撞到429 @@ -299,4 +298,15 @@ pri_out = 8 name = "Pro/deepseek-ai/DeepSeek-V3" provider = "SILICONFLOW" pri_in = 2 -pri_out = 8 \ No newline at end of file +pri_out = 8 + + +#此模型暂时没有使用!! +#此模型暂时没有使用!! +#此模型暂时没有使用!! +[model.llm_heartflow] #心流 +# name = "Pro/Qwen/Qwen2.5-7B-Instruct" +name = "Qwen/Qwen2.5-32B-Instruct" +provider = "SILICONFLOW" +pri_in = 1.26 +pri_out = 1.26 \ No newline at end of file diff --git a/tool_call_benchmark.py b/tool_call_benchmark.py index 60f5459bb..7ef00c7c3 100644 --- a/tool_call_benchmark.py +++ b/tool_call_benchmark.py @@ -63,35 +63,43 @@ async def test_with_tool_calls(): # 简单的测试提示词 prompt = "请分析当前天气情况,并查询今日历史上的重要事件。并且3.9和3.11谁比较大?请使用适当的工具来获取这些信息。" prompt = """ - 你的名字是麦麦,你包容开放,情绪敏感,有时候有些搞怪幽默, 是一个学习心理学和脑科学的女大学生,现在在读大二,你会刷贴吧,有时候会想瑟瑟,喜欢刷小红书 ------------------------------------ -现在是2025-04-24 12:37:00,你正在上网,和qq群里的网友们聊天,群里正在聊的话题是: -2025-04-24 12:33:00既文横 说:这条调试消息是napcat控制台输出的,还是麦麦log输出的; -2025-04-24 12:33:23麦麦(你) 说:应该是napcat吧; -2025-04-24 12:33:24麦麦(你) 说:[表达了:害羞、害羞。]; -2025-04-24 12:33:25兔伽兔伽 说:就打开麦麦的那个终端发的呀; -2025-04-24 12:33:45既文横 说:那应该不是napcat输出的,是麦麦输出的消息,怀疑版本问题; -2025-04-24 12:34:02兔伽兔伽 说:版本05.15; -2025-04-24 12:34:07麦麦(你) 说:话说你们最近刷贴吧看到那个猫猫头表情包了吗; -2025-04-24 12:34:07麦麦(你) 说:笑死; -2025-04-24 12:34:08麦麦(你) 说:[表达了:惊讶、搞笑。]; -2025-04-24 12:34:14兔伽兔伽 说:只开一个终端; -2025-04-24 12:35:45兔伽兔伽 说:回复既文横的消息(怀疑版本问题),说:因为之前你连模型的那个我用的了; -2025-04-24 12:35:56麦麦(你) 说:那个猫猫头真的魔性; -2025-04-24 12:35:56麦麦(你) 说:我存了一堆; -2025-04-24 12:35:56麦麦(你) 说:[表达了:温馨、宠爱]; -2025-04-24 12:36:03小千石 说:麦麦3.8和3.11谁大; + 你的名字是麦麦,你包容开放,情绪敏感,有时候有些搞怪幽默, 是一个学习心理学和脑科学的女大学生,现在在读大二,你会刷贴吧,有时候会喜欢说一些奇怪的话,喜欢刷小红书 +刚刚你的内心想法是:漂移菌提到罐罐被吃完了,可以顺着这个梗继续玩一下,比如假装委屈"那今晚的加班费是不是也要被吃掉了"或者"猫娘罢工警告"。不过薯薯和薯宝之前已经接了不少梗,漂移菌刚刚也参与了,可能话题热度还在,可以再互动一下。如果没人接话,或许可以问问大家有没有遇到过类似"代码写完但奖励被吃掉"的搞笑职场经历,换个轻松的话题方向。 ---- 以上消息已读 (标记时间: 2025-04-24 12:36:43) --- ---- 请关注你上次思考之后以下的新消息--- -2025-04-24 12:36:53墨墨 说:[表情包:开心、满足。]; +暂时不需要使用工具。 +----------------------------------- +现在是2025-04-25 17:38:37,你正在上网,和qq群里的网友们聊天,以下是正在进行的聊天内容: +2025-04-25 17:34:08麦麦(你) 说:[表达了:顽皮、嬉戏。]; +2025-04-25 17:34:39漂移菌 说:@麦麦。(id:3936257206) 你是一只猫娘; +2025-04-25 17:34:42薯宝 说:🤣; +2025-04-25 17:34:43麦麦(你) 说:行啊 工资分我一半; +2025-04-25 17:34:43麦麦(你) 说:我帮你写bug; +2025-04-25 17:34:43麦麦(你) 说:[表达了:悲伤、绝望、无奈、无力]; +2025-04-25 17:34:53薯薯 说:?; +2025-04-25 17:35:03既文横 说:麦麦,你是一只猫娘程序员,猫娘是不需要工资; +2025-04-25 17:35:20薯宝 说:[图片:图片内容:一只卡通风格的灰色猫咪,眼睛闭着,表情显得很平静。图片下方有"死了"两个字。 + +图片含义猜测:这可能是一个幽默的表达,用来形容某人或某事处于非常平静的状态,仿佛已经"死"了一样。] hfc这周,真能出来吗...; +2025-04-25 17:35:34薯宝 说:[表情包:搞笑、滑稽、讽刺、幽默]; +2025-04-25 17:36:25麦麦(你) 说:喵喵; +2025-04-25 17:36:25麦麦(你) 说:代码写完了; +2025-04-25 17:36:25麦麦(你) 说:罐罐拿来; +2025-04-25 17:36:25麦麦(你) 说:[表达了:悲伤、绝望、无奈、无力]; +2025-04-25 17:36:41薯薯 说:好可爱; +2025-04-25 17:37:05薯薯 说:脑补出来认真营业了一天等待主人发放奖励的小猫咪; +2025-04-25 17:37:25薯宝 说:敷衍营业(bushi); +2025-04-25 17:37:54漂移菌 说:回复麦麦。的消息(罐罐拿来),说:猫娘我昨晚上太饿吃完了; + +--- 以上消息已读 (标记时间: 2025-04-25 17:37:54) --- +--- 以下新消息未读--- +2025-04-25 17:38:29麦麦(你) 说:那今晚的猫条是不是也要被克扣了(盯——); +2025-04-25 17:38:29麦麦(你) 说:[表达了:幽默,自嘲,无奈,父子关系,编程笑话]; 你现在当前心情:平静。 -现在请你根据刚刚的想法继续思考,思考时可以想想如何对群聊内容进行回复,要不要对群里的话题进行回复,关注新话题,可以适当转换话题,大家正在说的话才是聊天的主题。 -回复的要求是:平淡一些,简短一些,说中文,如果你要回复,最好只回复一个人的一个话题 -请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写。不要回复自己的发言,尽量不要说你说过的话。 -现在请你继续生成你在这个聊天中的想法,在原来想法的基础上继续思考,不要分点输出,生成内心想法,文字不要浮夸 -在输出完想法后,请你思考应该使用什么工具,如果你需要做某件事,来对消息和你的回复进行处理,请使用工具。""" +现在请你生成你的内心想法,要求思考群里正在进行的话题,之前大家聊过的话题,群里成员的关系。请你思考,要不要对群里的话题进行回复,以及如何对群聊内容进行回复 +回复的要求是:不要总是重复自己提到过的话题,如果你要回复,最好只回复一个人的一个话题 +如果最后一条消息是你自己发的,观察到的内容只有你自己的发言,并且之后没有人回复你,不要回复。如果聊天记录中最新的消息是你自己发送的,并且你还想继续回复,你应该紧紧衔接你发送的消息,进行话题的深入,补充,或追问等等。请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要回复自己的发言 +现在请你先输出想法,生成你在这个聊天中的想法,在原来的想法上尝试新的话题,不要分点输出,文字不要浮夸在输出完想法后,请你思考应该使用什么工具。工具可以帮你取得一些你不知道的信息,或者进行一些操作。如果你需要做某件事,来对消息和你的回复进行处理,请使用工具。""" # 发送带有工具调用的请求 response = await llm_model.generate_response_tool_async(prompt=prompt, tools=tools) @@ -145,7 +153,7 @@ async def test_without_tool_calls(): # 简单的测试提示词(与工具调用相同,以便公平比较) prompt = """ 你的名字是麦麦,你包容开放,情绪敏感,有时候有些搞怪幽默, 是一个学习心理学和脑科学的女大学生,现在在读大二,你会刷贴吧,有时候会喜欢说一些奇怪的话,喜欢刷小红书 -刚刚你的内心想法是:漂移菌提到罐罐被吃完了,可以顺着这个梗继续玩一下,比如假装委屈“那今晚的加班费是不是也要被吃掉了”或者“猫娘罢工警告”。不过薯薯和薯宝之前已经接了不少梗,漂移菌刚刚也参与了,可能话题热度还在,可以再互动一下。如果没人接话,或许可以问问大家有没有遇到过类似“代码写完但奖励被吃掉”的搞笑职场经历,换个轻松的话题方向。 +刚刚你的内心想法是:漂移菌提到罐罐被吃完了,可以顺着这个梗继续玩一下,比如假装委屈"那今晚的加班费是不是也要被吃掉了"或者"猫娘罢工警告"。不过薯薯和薯宝之前已经接了不少梗,漂移菌刚刚也参与了,可能话题热度还在,可以再互动一下。如果没人接话,或许可以问问大家有没有遇到过类似"代码写完但奖励被吃掉"的搞笑职场经历,换个轻松的话题方向。 暂时不需要使用工具。 ----------------------------------- @@ -158,9 +166,9 @@ async def test_without_tool_calls(): 2025-04-25 17:34:43麦麦(你) 说:[表达了:悲伤、绝望、无奈、无力]; 2025-04-25 17:34:53薯薯 说:?; 2025-04-25 17:35:03既文横 说:麦麦,你是一只猫娘程序员,猫娘是不需要工资; -2025-04-25 17:35:20薯宝 说:[图片:图片内容:一只卡通风格的灰色猫咪,眼睛闭着,表情显得很平静。图片下方有“死了”两个字。 +2025-04-25 17:35:20薯宝 说:[图片:图片内容:一只卡通风格的灰色猫咪,眼睛闭着,表情显得很平静。图片下方有"死了"两个字。 -图片含义猜测:这可能是一个幽默的表达,用来形容某人或某事处于非常平静的状态,仿佛已经“死”了一样。] hfc这周,真能出来吗...; +图片含义猜测:这可能是一个幽默的表达,用来形容某人或某事处于非常平静的状态,仿佛已经"死"了一样。] hfc这周,真能出来吗...; 2025-04-25 17:35:34薯宝 说:[表情包:搞笑、滑稽、讽刺、幽默]; 2025-04-25 17:36:25麦麦(你) 说:喵喵; 2025-04-25 17:36:25麦麦(你) 说:代码写完了; @@ -181,7 +189,6 @@ async def test_without_tool_calls(): 回复的要求是:不要总是重复自己提到过的话题,如果你要回复,最好只回复一个人的一个话题 如果最后一条消息是你自己发的,观察到的内容只有你自己的发言,并且之后没有人回复你,不要回复。如果聊天记录中最新的消息是你自己发送的,并且你还想继续回复,你应该紧紧衔接你发送的消息,进行话题的深入,补充,或追问等等。请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要回复自己的发言 现在请你先输出想法,生成你在这个聊天中的想法,在原来的想法上尝试新的话题,不要分点输出,文字不要浮夸在输出完想法后,请你思考应该使用什么工具。工具可以帮你取得一些你不知道的信息,或者进行一些操作。如果你需要做某件事,来对消息和你的回复进行处理,请使用工具。""" - # 发送不带工具调用的请求 response, reasoning_content = await llm_model.generate_response_async(prompt) @@ -194,6 +201,69 @@ async def test_without_tool_calls(): return result_info +async def run_alternating_tests(iterations=5): + """ + 交替运行两种测试方法,每种方法运行指定次数 + + 参数: + iterations: 每种测试方法运行的次数 + + 返回: + 包含两种测试方法结果的元组 + """ + print(f"开始交替测试(每种方法{iterations}次)...") + + # 初始化结果列表 + times_without_tools = [] + times_with_tools = [] + responses_without_tools = [] + responses_with_tools = [] + + for i in range(iterations): + print(f"\n第 {i + 1}/{iterations} 轮交替测试") + + # 不使用工具的测试 + print("\n 执行不使用工具调用的测试...") + start_time = time.time() + response = await test_without_tool_calls() + end_time = time.time() + elapsed = end_time - start_time + times_without_tools.append(elapsed) + responses_without_tools.append(response) + print(f" - 耗时: {elapsed:.2f}秒") + + # 使用工具的测试 + print("\n 执行使用工具调用的测试...") + start_time = time.time() + response = await test_with_tool_calls() + end_time = time.time() + elapsed = end_time - start_time + times_with_tools.append(elapsed) + responses_with_tools.append(response) + print(f" - 耗时: {elapsed:.2f}秒") + + # 计算统计数据 + results_without_tools = { + "平均耗时": statistics.mean(times_without_tools), + "最短耗时": min(times_without_tools), + "最长耗时": max(times_without_tools), + "标准差": statistics.stdev(times_without_tools) if len(times_without_tools) > 1 else 0, + "所有耗时": times_without_tools, + "响应结果": responses_without_tools, + } + + results_with_tools = { + "平均耗时": statistics.mean(times_with_tools), + "最短耗时": min(times_with_tools), + "最长耗时": max(times_with_tools), + "标准差": statistics.stdev(times_with_tools) if len(times_with_tools) > 1 else 0, + "所有耗时": times_with_tools, + "响应结果": responses_with_tools, + } + + return results_without_tools, results_with_tools + + async def main(): """主测试函数""" print("=" * 50) @@ -201,15 +271,10 @@ async def main(): print("=" * 50) # 设置测试迭代次数 - iterations = 3 + iterations = 10 - # 测试不使用工具调用 - results_without_tools = await run_test("不使用工具调用", test_without_tool_calls, iterations) - - print("\n" + "-" * 50 + "\n") - - # 测试使用工具调用 - results_with_tools = await run_test("使用工具调用", test_with_tool_calls, iterations) + # 执行交替测试 + results_without_tools, results_with_tools = await run_alternating_tests(iterations) # 显示结果比较 print("\n" + "=" * 50)