From dab7e91fed2bda28115ac314f69f1786e3897970 Mon Sep 17 00:00:00 2001 From: Windpicker-owo <3431391539@qq.com> Date: Sun, 14 Dec 2025 23:30:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(kokoro=5Fflow=5Fchatter):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=B4=BB=E5=8A=A8=E6=B5=81=E6=A0=BC=E5=BC=8F=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8F=8A=E4=B8=8A=E4=B8=8B=E6=96=87=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=88=86=E7=A6=BB?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=A4=B1=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/official_configs.py | 26 +++ .../built_in/kokoro_flow_chatter/chatter.py | 9 + .../built_in/kokoro_flow_chatter/config.py | 11 ++ .../kokoro_flow_chatter/proactive_thinker.py | 22 ++- .../kokoro_flow_chatter/prompt/builder.py | 180 +++++++++++++++++- .../kokoro_flow_chatter/prompt/prompts.py | 19 +- template/bot_config_template.toml | 16 +- 7 files changed, 262 insertions(+), 21 deletions(-) diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 862ff3d13..cddaf4d3e 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -995,6 +995,27 @@ class KokoroFlowChatterWaitingConfig(ValidatedConfigBase): ) +class KokoroFlowChatterPromptConfig(ValidatedConfigBase): + """Kokoro Flow Chatter 提示词/上下文构建配置""" + + activity_stream_format: Literal["narrative", "table", "both"] = Field( + default="narrative", + description='活动流格式: "narrative"(线性叙事) / "table"(结构化表格) / "both"(两者都输出)', + ) + max_activity_entries: int = Field( + default=30, + ge=0, + le=200, + description="活动流最多保留条数(越大越完整,但token越高)", + ) + max_entry_length: int = Field( + default=500, + ge=0, + le=5000, + description="活动流单条最大字符数(用于裁剪,避免单条过长拖垮上下文)", + ) + + class KokoroFlowChatterConfig(ValidatedConfigBase): """ Kokoro Flow Chatter 配置类 - 私聊专用心流对话系统 @@ -1031,6 +1052,11 @@ class KokoroFlowChatterConfig(ValidatedConfigBase): description="自定义KFC决策行为指导提示词(unified影响整体,split仅影响planner)", ) + prompt: KokoroFlowChatterPromptConfig = Field( + default_factory=KokoroFlowChatterPromptConfig, + description="提示词/上下文构建配置(活动流格式、裁剪等)", + ) + waiting: KokoroFlowChatterWaitingConfig = Field( default_factory=KokoroFlowChatterWaitingConfig, description="等待策略配置(默认等待时间、倍率等)", diff --git a/src/plugins/built_in/kokoro_flow_chatter/chatter.py b/src/plugins/built_in/kokoro_flow_chatter/chatter.py index b14d5a3a7..17fe2ffcf 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/chatter.py +++ b/src/plugins/built_in/kokoro_flow_chatter/chatter.py @@ -223,6 +223,9 @@ class KokoroFlowChatter(BaseChatter): exec_results.append(result) if result.get("success") and action.type in ("kfc_reply", "respond"): has_reply = True + reply_text = (result.get("reply_text") or "").strip() + if reply_text: + action.params["content"] = reply_text # 11. 记录 Bot 规划到 mental_log session.add_bot_planning( @@ -336,6 +339,12 @@ class KokoroFlowChatter(BaseChatter): # 为 kfc_reply 动作注入回复生成所需的上下文 for action in plan_response.actions: if action.type == "kfc_reply": + # 分离模式下 Planner 不应直接生成回复内容;即使模型输出了 content,也应忽略 + if "content" in action.params and action.params.get("content"): + logger.warning( + "[KFC] Split模式下Planner输出了kfc_reply.content,已忽略(由Replyer生成)" + ) + action.params.pop("content", None) action.params["user_id"] = user_id action.params["user_name"] = user_name action.params["thought"] = plan_response.thought diff --git a/src/plugins/built_in/kokoro_flow_chatter/config.py b/src/plugins/built_in/kokoro_flow_chatter/config.py index b46a2a31d..a139976cd 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/config.py +++ b/src/plugins/built_in/kokoro_flow_chatter/config.py @@ -90,6 +90,12 @@ class PromptConfig: # 每条记录最大字符数 max_entry_length: int = 500 + # 活动流格式:narrative(线性叙事)/ table(结构化表格)/ both(两者都给) + # - narrative: 更自然,但信息密度较低,长时更容易丢细节 + # - table: 更高信息密度,便于模型对齐字段、检索与对比 + # - both: 调试/对照用,token 更高 + activity_stream_format: str = "narrative" + # 是否包含人物关系信息 include_relation: bool = True @@ -236,6 +242,11 @@ def load_config() -> KokoroFlowChatterConfig: config.prompt = PromptConfig( max_activity_entries=getattr(pmt_cfg, "max_activity_entries", 30), max_entry_length=getattr(pmt_cfg, "max_entry_length", 500), + activity_stream_format=getattr( + pmt_cfg, + "activity_stream_format", + getattr(pmt_cfg, "activity_format", "narrative"), + ), include_relation=getattr(pmt_cfg, "include_relation", True), include_memory=getattr(pmt_cfg, "include_memory", True), ) diff --git a/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py b/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py index 45af2665c..a61ec8bb7 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py +++ b/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py @@ -456,6 +456,11 @@ class ProactiveThinker: # 分离模式下需要注入上下文信息 for action in plan_response.actions: if action.type == "kfc_reply": + if "content" in action.params and action.params.get("content"): + logger.warning( + "[KFC ProactiveThinker] Split模式下Planner输出了kfc_reply.content,已忽略(由Replyer生成)" + ) + action.params.pop("content", None) action.params["user_id"] = session.user_id action.params["user_name"] = user_name action.params["thought"] = plan_response.thought @@ -495,7 +500,7 @@ class ProactiveThinker: # 执行动作(回复生成在 Action.execute() 中完成) for action in plan_response.actions: - await action_manager.execute_action( + result = await action_manager.execute_action( action_name=action.type, chat_id=session.stream_id, target_message=None, @@ -504,6 +509,10 @@ class ProactiveThinker: thinking_id=None, log_prefix="[KFC ProactiveThinker]", ) + if result.get("success") and action.type in ("kfc_reply", "respond"): + reply_text = (result.get("reply_text") or "").strip() + if reply_text: + action.params["content"] = reply_text # 🎯 只有真正发送了消息才增加追问计数(do_nothing 不算追问) has_reply_action = any( @@ -703,6 +712,11 @@ class ProactiveThinker: if self._mode == KFCMode.SPLIT: for action in plan_response.actions: if action.type == "kfc_reply": + if "content" in action.params and action.params.get("content"): + logger.warning( + "[KFC ProactiveThinker] Split模式下Planner输出了kfc_reply.content,已忽略(由Replyer生成)" + ) + action.params.pop("content", None) action.params["user_id"] = session.user_id action.params["user_name"] = user_name action.params["thought"] = plan_response.thought @@ -735,7 +749,7 @@ class ProactiveThinker: # 执行动作(回复生成在 Action.execute() 中完成) for action in plan_response.actions: - await action_manager.execute_action( + result = await action_manager.execute_action( action_name=action.type, chat_id=session.stream_id, target_message=None, @@ -744,6 +758,10 @@ class ProactiveThinker: thinking_id=None, log_prefix="[KFC ProactiveThinker]", ) + if result.get("success") and action.type in ("kfc_reply", "respond"): + reply_text = (result.get("reply_text") or "").strip() + if reply_text: + action.params["content"] = reply_text # 记录到 mental_log session.add_bot_planning( diff --git a/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py b/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py index 87528e30d..cb0a3ebeb 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py +++ b/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py @@ -284,6 +284,42 @@ class PromptBuilder: return "" + def _build_last_bot_action_block(self, session: KokoroSession | None) -> str: + """ + 构建“最近一次Bot动作/发言”块(用于插入到当前情况里) + + 目的:让模型在决策时能显式参考“我刚刚做过什么/说过什么”,降低长上下文里漏细节的概率。 + """ + if not session or not getattr(session, "mental_log", None): + return "" + + last_planning_entry: MentalLogEntry | None = None + for entry in reversed(session.mental_log): + if entry.event_type == EventType.BOT_PLANNING: + last_planning_entry = entry + break + + if not last_planning_entry: + return "" + + actions_desc = self._format_actions(last_planning_entry.actions) + + last_message = "" + for action in last_planning_entry.actions: + if action.get("type") == "kfc_reply": + content = (action.get("content") or "").strip() + if content: + last_message = content + + if last_message and len(last_message) > 80: + last_message = last_message[:80] + "..." + + lines = [f"你最近一次执行的动作是:{actions_desc}"] + if last_message: + lines.append(f"你上一次发出的消息是:「{last_message}」") + + return "\n".join(lines) + "\n\n" + async def _build_context_data( self, user_name: str, @@ -541,14 +577,39 @@ class PromptBuilder: 构建活动流 将 mental_log 中的事件按时间顺序转换为线性叙事 - 使用统一的 prompt 模板 + 支持线性叙事或结构化表格两种格式(可通过配置切换) """ - entries = session.get_recent_entries(limit=30) + from ..config import get_config + + kfc_config = get_config() + prompt_cfg = getattr(kfc_config, "prompt", None) + max_entries = getattr(prompt_cfg, "max_activity_entries", 30) if prompt_cfg else 30 + max_entry_length = getattr(prompt_cfg, "max_entry_length", 500) if prompt_cfg else 500 + stream_format = ( + getattr(prompt_cfg, "activity_stream_format", "narrative") if prompt_cfg else "narrative" + ) + + entries = session.get_recent_entries(limit=max_entries) if not entries: return "" - parts = [] + stream_format = (stream_format or "narrative").strip().lower() + if stream_format == "table": + return self._build_activity_stream_table(entries, user_name, max_entry_length) + if stream_format == "both": + table = self._build_activity_stream_table(entries, user_name, max_entry_length) + narrative = await self._build_activity_stream_narrative(entries, user_name) + return "\n\n".join([p for p in (table, narrative) if p]) + return await self._build_activity_stream_narrative(entries, user_name) + + async def _build_activity_stream_narrative( + self, + entries: list[MentalLogEntry], + user_name: str, + ) -> str: + """构建线性叙事活动流(旧格式)""" + parts: list[str] = [] for entry in entries: part = await self._format_entry(entry, user_name) if part: @@ -556,6 +617,95 @@ class PromptBuilder: return "\n\n".join(parts) + def _build_activity_stream_table( + self, + entries: list[MentalLogEntry], + user_name: str, + max_cell_length: int = 500, + ) -> str: + """ + 构建结构化表格活动流(更高信息密度) + + 统一列:序号 / 时间 / 事件类型 / 内容 / 想法 / 行动 / 结果 + """ + + def truncate(text: str, limit: int) -> str: + if not text: + return "" + if limit <= 0: + return text + text = text.strip() + return text if len(text) <= limit else (text[: max(0, limit - 1)] + "…") + + def md_cell(value: str) -> str: + value = (value or "").replace("\r\n", "\n").replace("\n", "
") + value = value.replace("|", "\\|") + return truncate(value, max_cell_length) + + event_type_alias = { + EventType.USER_MESSAGE: "用户消息", + EventType.BOT_PLANNING: "你的决策", + EventType.WAITING_UPDATE: "等待中", + EventType.PROACTIVE_TRIGGER: "主动触发", + } + + header = ["#", "时间", "类型", "内容", "想法", "行动", "结果"] + lines = [ + "|" + "|".join(header) + "|", + "|" + "|".join(["---"] * len(header)) + "|", + ] + + for idx, entry in enumerate(entries, 1): + time_str = entry.get_time_str() + type_str = event_type_alias.get(entry.event_type, str(entry.event_type)) + + content = "" + thought = "" + action = "" + result = "" + + if entry.event_type == EventType.USER_MESSAGE: + content = entry.content + reply_status = entry.metadata.get("reply_status") + if reply_status in ("in_time", "late"): + elapsed_min = entry.metadata.get("elapsed_seconds", 0) / 60 + max_wait_min = entry.metadata.get("max_wait_seconds", 0) / 60 + status_cn = "及时" if reply_status == "in_time" else "迟到" + result = f"回复{status_cn}(等{elapsed_min:.1f}/{max_wait_min:.1f}分钟)" + + elif entry.event_type == EventType.BOT_PLANNING: + thought = entry.thought or "(无)" + action = self._format_actions(entry.actions) + if entry.max_wait_seconds > 0: + wait_min = entry.max_wait_seconds / 60 + expected = entry.expected_reaction or "(无)" + result = f"等待≤{wait_min:.1f}分钟;期待={expected}" + else: + result = "不等待" + + elif entry.event_type == EventType.WAITING_UPDATE: + thought = entry.waiting_thought or "还在等…" + elapsed_min = entry.elapsed_seconds / 60 + mood = (entry.mood or "").strip() + result = f"已等{elapsed_min:.1f}分钟" + (f";心情={mood}" if mood else "") + + elif entry.event_type == EventType.PROACTIVE_TRIGGER: + silence = entry.metadata.get("silence_duration", "一段时间") + result = f"沉默{silence}" + + row = [ + str(idx), + md_cell(time_str), + md_cell(type_str), + md_cell(content), + md_cell(thought), + md_cell(action), + md_cell(result), + ] + lines.append("|" + "|".join(row) + "|") + + return "(结构化活动流表;按时间顺序)\n" + "\n".join(lines) + async def _format_entry(self, entry: MentalLogEntry, user_name: str) -> str: """格式化单个活动日志条目""" @@ -661,6 +811,7 @@ class PromptBuilder: ) -> str: """构建当前情况描述""" current_time = datetime.now().strftime("%Y年%m月%d日 %H:%M") + last_action_block = self._build_last_bot_action_block(session) # 如果之前没有设置等待时间(max_wait_seconds == 0),视为 new_message if situation_type in ("reply_in_time", "reply_late"): @@ -674,6 +825,7 @@ class PromptBuilder: return await global_prompt_manager.format_prompt( PROMPT_NAMES["situation_new_message"], current_time=current_time, + last_action_block=last_action_block, user_name=user_name, latest_message=latest_message, ) @@ -685,6 +837,7 @@ class PromptBuilder: return await global_prompt_manager.format_prompt( PROMPT_NAMES["situation_reply_in_time"], current_time=current_time, + last_action_block=last_action_block, user_name=user_name, elapsed_minutes=elapsed / 60, max_wait_minutes=max_wait / 60, @@ -698,6 +851,7 @@ class PromptBuilder: return await global_prompt_manager.format_prompt( PROMPT_NAMES["situation_reply_late"], current_time=current_time, + last_action_block=last_action_block, user_name=user_name, elapsed_minutes=elapsed / 60, max_wait_minutes=max_wait / 60, @@ -743,6 +897,7 @@ class PromptBuilder: return await global_prompt_manager.format_prompt( PROMPT_NAMES["situation_timeout"], current_time=current_time, + last_action_block=last_action_block, user_name=user_name, elapsed_minutes=elapsed / 60, max_wait_minutes=max_wait / 60, @@ -756,6 +911,7 @@ class PromptBuilder: return await global_prompt_manager.format_prompt( PROMPT_NAMES["situation_proactive"], current_time=current_time, + last_action_block=last_action_block, user_name=user_name, silence_duration=silence, trigger_reason=trigger_reason, @@ -766,6 +922,7 @@ class PromptBuilder: PROMPT_NAMES["situation_new_message"], current_time=current_time, user_name=user_name, + last_action_block=last_action_block, ) def _build_actions_block(self, available_actions: dict | None) -> str: @@ -926,15 +1083,17 @@ class PromptBuilder: """ from datetime import datetime current_time = datetime.now().strftime("%Y年%m月%d日 %H:%M") + last_action_block = self._build_last_bot_action_block(session) if situation_type == "new_message": - return f"现在是 {current_time}。{user_name} 刚给你发了消息。" + return f"现在是 {current_time}。\n\n{last_action_block}{user_name} 刚给你发了消息。" elif situation_type == "reply_in_time": elapsed = session.waiting_config.get_elapsed_seconds() max_wait = session.waiting_config.max_wait_seconds return ( - f"现在是 {current_time}。\n" + f"现在是 {current_time}。\n\n" + f"{last_action_block}" f"你之前发了消息后在等 {user_name} 的回复。" f"等了大约 {elapsed / 60:.1f} 分钟(你原本打算最多等 {max_wait / 60:.1f} 分钟)。" f"现在 {user_name} 回复了!" @@ -944,7 +1103,8 @@ class PromptBuilder: elapsed = session.waiting_config.get_elapsed_seconds() max_wait = session.waiting_config.max_wait_seconds return ( - f"现在是 {current_time}。\n" + f"现在是 {current_time}。\n\n" + f"{last_action_block}" f"你之前发了消息后在等 {user_name} 的回复。" f"你原本打算最多等 {max_wait / 60:.1f} 分钟,但实际等了 {elapsed / 60:.1f} 分钟才收到回复。" f"虽然有点迟,但 {user_name} 终于回复了。" @@ -954,7 +1114,8 @@ class PromptBuilder: elapsed = session.waiting_config.get_elapsed_seconds() max_wait = session.waiting_config.max_wait_seconds return ( - f"现在是 {current_time}。\n" + f"现在是 {current_time}。\n\n" + f"{last_action_block}" f"你之前发了消息后一直在等 {user_name} 的回复。" f"你原本打算最多等 {max_wait / 60:.1f} 分钟,现在已经等了 {elapsed / 60:.1f} 分钟了,对方还是没回。" f"你决定主动说点什么。" @@ -963,13 +1124,14 @@ class PromptBuilder: elif situation_type == "proactive": silence = extra_context.get("silence_duration", "一段时间") return ( - f"现在是 {current_time}。\n" + f"现在是 {current_time}。\n\n" + f"{last_action_block}" f"你和 {user_name} 已经有一段时间没聊天了(沉默了 {silence})。" f"你决定主动找 {user_name} 聊点什么。" ) # 默认 - return f"现在是 {current_time}。" + return f"现在是 {current_time}。\n\n{last_action_block}".rstrip() async def _build_reply_context( self, diff --git a/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py b/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py index 6d5090360..1cd2bc34e 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py +++ b/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py @@ -34,7 +34,7 @@ kfc_MAIN_PROMPT = Prompt( {tool_info} # 你们之间最近的活动记录 -以下是你和 {user_name} 最近的互动历史,按时间顺序记录了你们的对话和你的心理活动: +以下是你和 {user_name} 最近的互动历史,按时间顺序记录了你们的对话和你的心理活动(可能是线性叙事或结构化表格): {activity_stream} # 聊天历史总览 @@ -69,7 +69,7 @@ kfc_OUTPUT_FORMAT = Prompt( {{"type": "动作名称", ...动作参数}} ], "expected_reaction": "你期待对方的反应是什么", - - `max_wait_seconds`:预估的等待时间(秒),请根据对话节奏来判断。通常你应该设置为0避免总是等待显得聒噪,但是当你觉得你需要等待对方回复时,可以设置一个合理的等待时间。 + "max_wait_seconds": 0 }} ``` @@ -93,7 +93,7 @@ kfc_SITUATION_NEW_MESSAGE = Prompt( name="kfc_situation_new_message", template="""现在是 {current_time}。 -{user_name} 刚刚给你发了消息:「{latest_message}」 +{last_action_block}{user_name} 刚刚给你发了消息:「{latest_message}」 这是一次新的对话发起(不是对你之前消息的回复)。 @@ -108,7 +108,7 @@ kfc_SITUATION_REPLY_IN_TIME = Prompt( name="kfc_situation_reply_in_time", template="""现在是 {current_time}。 -你之前发了消息后一直在等 {user_name} 的回复。 +{last_action_block}你之前发了消息后一直在等 {user_name} 的回复。 等了大约 {elapsed_minutes:.1f} 分钟(你原本打算最多等 {max_wait_minutes:.1f} 分钟)。 现在 {user_name} 回复了:「{latest_message}」 @@ -119,7 +119,7 @@ kfc_SITUATION_REPLY_LATE = Prompt( name="kfc_situation_reply_late", template="""现在是 {current_time}。 -你之前发了消息后在等 {user_name} 的回复。 +{last_action_block}你之前发了消息后在等 {user_name} 的回复。 你原本打算最多等 {max_wait_minutes:.1f} 分钟,但实际等了 {elapsed_minutes:.1f} 分钟才收到回复。 虽然有点迟,但 {user_name} 终于回复了:「{latest_message}」 @@ -130,7 +130,7 @@ kfc_SITUATION_TIMEOUT = Prompt( name="kfc_situation_timeout", template="""现在是 {current_time}。 -你之前发了消息后一直在等 {user_name} 的回复。 +{last_action_block}你之前发了消息后一直在等 {user_name} 的回复。 你原本打算最多等 {max_wait_minutes:.1f} 分钟,现在已经等了 {elapsed_minutes:.1f} 分钟了,对方还是没回。 你当时期待的反应是:"{expected_reaction}" {timeout_context} @@ -161,7 +161,7 @@ kfc_SITUATION_PROACTIVE = Prompt( name="kfc_situation_proactive", template="""现在是 {current_time}。 -你和 {user_name} 已经有一段时间没聊天了(沉默了 {silence_duration})。 +{last_action_block}你和 {user_name} 已经有一段时间没聊天了(沉默了 {silence_duration})。 {trigger_reason} 你在想要不要主动找 {user_name} 聊点什么。 @@ -251,7 +251,7 @@ kfc_PLANNER_OUTPUT_FORMAT = Prompt( {{"type": "动作名称", ...动作参数}} ], "expected_reaction": "你期待对方的反应是什么", - - `max_wait_seconds`:预估的等待时间(秒),请根据对话节奏来判断。通常你应该设置为0避免总是等待显得聒噪,但是当你觉得你需要等待对方回复时,可以设置一个合理的等待时间。 + "max_wait_seconds": 0 }} ``` @@ -264,6 +264,7 @@ kfc_PLANNER_OUTPUT_FORMAT = Prompt( ### 注意事项 - 动作参数直接写在动作对象里,不需要 `action_data` 包装 +- **分离模式规则**:Planner 阶段禁止输出 `kfc_reply.content`(就算写了也会被系统忽略,回复内容由 Replyer 单独生成) - 即使什么都不想做,也放一个 `{{"type": "do_nothing"}}` - 可以组合多个动作,比如先发消息再发表情""", ) @@ -406,7 +407,7 @@ kfc_UNIFIED_OUTPUT_FORMAT = Prompt( {{"type": "kfc_reply", "content": "你的回复内容"}} ], "expected_reaction": "你期待对方的反应是什么", - - `max_wait_seconds`:预估的等待时间(秒),请根据对话节奏来判断。通常你应该设置为0避免总是等待显得聒噪,但是当你觉得你需要等待对方回复时,可以设置一个合理的等待时间。 + "max_wait_seconds": 0 }} ``` diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 63114a01a..084568628 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "8.0.0" +version = "8.0.1" #----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读---- #如果你想要修改配置文件,请递增version的值 @@ -638,6 +638,20 @@ enable_continuous_thinking = true # 是否在等待期间启用心理活动更 # 留空则不生效 custom_decision_prompt = "" +# --- 提示词/上下文构建配置 --- +[kokoro_flow_chatter.prompt] +# 活动流格式(你们之间最近发生的事) +# - "narrative": 线性叙事(更自然,但信息密度较低,长时更容易丢细节) +# - "table": 结构化表格(更高信息密度、更利于模型对齐字段;推荐) +# - "both": 同时输出表格 + 叙事(对照/调试用,token 更高) +activity_stream_format = "table" + +# 活动流最多保留条数(越大越完整,但 token 越高) +max_activity_entries = 5 + +# 表格单元格/叙事单条的最大字符数(用于裁剪,避免某条过长拖垮上下文) +max_entry_length = 500 + # --- 等待策略 --- [kokoro_flow_chatter.waiting] default_max_wait_seconds = 300 # LLM 未给出等待时间时的默认值