Files
mai-bot/计划.md
LoveLosita 587aa0a531 fix(webui): disable dashboard auto update checks
feat(plugins): add plugin marketplace route
2026-05-12 11:20:28 +08:00

22 KiB
Raw Blame History

私聊拟人性增强分阶段计划

总体目标

  • 在尽量保留当前 maibot 主干能力与最近更新的前提下,增强私聊中的连续感、活人感与主动性。
  • 优先修复“私聊对象信息容易遗忘”“聊天断开后像失忆”“上下文窗口过于保守”这三类核心问题。
  • 再逐步增加“定时跟进”“主动私聊”“关系阶段推进”等能力。
  • 落地时坚持“平行新增、契约尽量不变”:
    • 不破坏现有 reply 语义
    • 新能力优先通过新工具、新配置、新任务表、新 metadata 增量扩展
    • 尽量不改现有 WebUI 聊天消息结构与事件结构

借鉴来源

1. MoFox-Core

  • 主要借鉴:
    • 私聊对象关系信息常态注入
    • 主动前护栏判断
    • WAITING / IDLE 状态机思路
    • 发完后等待回复、超时再判断是否继续发言的活人感逻辑
  • 不直接照搬:
    • AFC / KFC 全套 runtime
    • 强耦合插件系统
    • 其整套数据库结构

2. Muice-Chatbot

  • 主要借鉴:
    • 轻量主动开场/问候思路
    • 随机主动话题池思路
  • 不直接照搬:
    • 到点直接发送固定文本
    • 过于依赖固定 prompt 的主动对话实现

当前问题

  • 私聊对话者信息经常会被忘记,应该被常态化注入。
  • 当前上下文管理偏保守,没充分发挥大上下文模型的能力。
  • 私聊 runtime 重建后不会自动回灌最近历史,聊天断开一阵子后容易出现“失忆”。
  • 人物信息、关系信息、共同经历主要依赖临时检索,缺少稳定默认上下文。
  • planner 查到的信息不能稳定传递到 replyer导致回复阶段再次遗忘。

当前准备增加的能力

  • 定时跟进机制:允许 LLM 在当前私聊中创建未来跟进任务,到点后重新唤醒 planner 判断要不要主动开口。
  • 主动私聊发送工具:新增不依赖 msg_idsend_private_message,作为 replyer 的新发送出口,让主动聊天不再伪装成回复旧消息。
  • 到点前护栏机制:加入静默时段、最小主动间隔、可选每日上限,避免技术上能发但体验上打扰。
  • 阶段以及主线机制:允许你在私聊中像玩 galgame 一样,和小麦进行逐步推进的互动。
  • 为后续私聊状态机预留扩展:后面再补“发完等回复、超时再判断”的活人感机制。

兼容性原则

前后端契约

  • 现有 reply 工具保持原语义、原参数、原发送形态不变。
  • 新增 send_private_messageschedule_private_followup 时,采用与现有 builtin tool 平行的注册、执行、记录方式。
  • 现有聊天消息 WsMessage / ChatMessage / MessageSegment 契约尽量不变:
    • 主动私聊发出的消息仍然是普通 bot 可见消息
    • 不新增专用 MessageSegment.type 作为前提
  • 现有工具记录结构尽量不变:
    • 继续复用现有 tool record / tool result 链路
    • 新增内容尽量放在 tool_nametool_data、metadata 中

配置与 WebUI

  • 配置面优先平行新增独立配置块,默认值完整,保证旧配置不改也能运行。
  • WebUI V1 不应成为主阻塞项:
    • 新功能优先复用现有聊天渲染与工具渲染
    • 后续再考虑做任务管理页、状态展示页等增强 UI

阶段 0开发期稳定化

本阶段要解决的问题

  • 当前准备进入连续多阶段改造,如果开发过程中误触自动更新,容易导致本体与 WebUI 版本漂移。
  • 一旦前后端版本不一致,后续上下文、工具、调度器相关改造会很难排障。
  • private-main 开发期间需要一个尽量稳定、可复现的运行基线。

本阶段要增加/修改的点

  • 断开 WebUI 自动更新检测
  • 断开本体自动更新检测
  • 避免开发期自动拉取或自动提示更新
  • 保留显式手动恢复/更新路径

如何做

  • 找到当前 WebUI 与本体的更新检查入口:
    • 启动时自动检查
    • 定时轮询检查
    • 页面内自动提示
  • 开发期优先做“禁用自动检查”,而不是修改版本号或伪造远端结果。
  • 尽量采用可逆方案:
    • 配置开关
    • 环境变量
    • 显式开发模式判断
  • 如果本体和 WebUI 的更新逻辑是分开的,也应分别断开,避免只关一边。

借鉴来源

  • 不依赖 MoFox-CoreMuice-Chatbot
  • 这是当前 private-main 连续改造前的工程防护阶段。

验收标准

  • 启动本体时,不再主动发起自动更新检查。
  • 启动 WebUI 时,不再自动弹更新提示或自动轮询更新状态。
  • 本体日志和 WebUI 调试输出中,不再出现自动更新任务被触发的痕迹。
  • 若后续需要更新,仍存在显式、可控、可手动触发的更新路径。

阶段 1修复私聊遗忘问题

本阶段要解决的问题

  • 私聊对象信息经常被忘记。
  • 聊天断开后再回来,像从空白状态重新开始。
  • planner 查到的信息不稳定replyer 容易再次遗忘。

本阶段要增加/修改的点

  • 私聊对象信息常态注入
  • runtime 重建时自动回灌最近历史
  • planner 到 replyer 的信息继承增强
  • 上下文选择策略从“纯按条数裁切”调整为“更适合大上下文模型”的策略

本阶段目标预算

  • 以“大上下文真正可用,但不盲目塞满”为原则,先把私聊 planner 的目标输入预算定在 256K token 级别
  • 不建议把整整 256K 都让历史消息吃满,应预留系统提示、工具定义、注入块、输出空间。
  • 第一版建议按下面的思路分配:
    • 总目标预算:256K
    • 预留给系统提示 / 工具定义 / injected reminders / 输出余量:32K ~ 64K
    • 可用于“历史消息 + 人物信息块 + 共同事件块”的主预算:160K ~ 220K
  • replyer 阶段不必与 planner 一样大,可以显著更小:
    • 优先依赖 planner 已整理出的参考信息
    • replyer 可先控制在 32K ~ 64K 级别

本阶段要先定下的几个原则

  • 历史回灌 不是滑动窗口本身,而是滑动窗口的前置步骤。
  • token 滑窗 不应只做“超了就 pop”而应做“固定高优先级块保底 + 历史候选池按 token 预算裁切”。
  • 人物信息块、当前约定、最近共同事件 的优先级应高于普通旧聊天。
  • planner 与 replyer 的上下文策略不必完全一样
    • planner 负责大窗理解
    • replyer 负责在较小上下文内稳定生成
  • 必须保留降级路径
    • 即使 tokenizer 暂时不可用,也能退回近似估算模式
    • 但默认目标是本地 token 预算裁切,而不是继续硬按条数

如何做

  • 为当前私聊补一个轻量信息聚合入口:
    • 优先从现有 person_info
    • 再从 A_memorix 的人物画像/关系证据中补充
    • 统一格式化为稳定上下文块,默认注入 planner
  • 在 runtime 重建时,按 session_id 从消息库回灌最近一段真实聊天历史,而不是从空 _chat_history 开始。
  • replyer 生成阶段不再过度依赖临时工具结果,而是显式承接 planner 已整理出的稳定参考信息。
  • 调整上下文窗口策略:
    • 不再只用固定条数近似控制
    • 引入更大的私聊历史回放范围
    • 优先保留“人物关系/最近共同事件/当前约定”这类高价值上下文

1.1 runtime 历史重建

  • 触发时机:
    • 私聊 runtime 首次创建时
    • 私聊 runtime 被回收后再次恢复时
    • 定时跟进任务唤醒私聊 runtime 时
  • 基本流程:
    1. 根据 session_id 查询最近一段真实消息
    2. 将消息重新构造成 Maisaka 使用的 LLMContextMessage
    3. 写回 _chat_history
    4. 再叠加本轮新收到的消息与 injected reminders
  • 第一版建议:
    • 先取最近 200 ~ 1000 条私聊真实消息作为“候选历史池”
    • 不是全部送给模型,而是交给后续 token 滑窗裁切
  • 注意:
    • 历史重建应优先复用现有消息入库格式和 SessionBackedMessage 构建逻辑
    • 不要单独造一套“历史专用消息对象”

1.2 本地 tokenizer / token 预算器

  • 当前项目里已有 token 使用统计,但那是模型返回 usage 后的结果,不足以做请求前选窗。
  • 因此本阶段需要新增一个“请求前 token 估算器”抽象层。
  • 目标不是一开始追求 100% 精确,而是先把“按 token 预算裁切”跑通。
  • 建议方案:
    • 新增统一的 context_token_counter / prompt_token_estimator
    • 输入为即将送给模型的消息列表或其序列化结果
    • 输出为估算 token 数
  • tokenizer 选择建议:
    • 优先选择与当前 OpenAI-compatible 请求栈兼容的本地 tokenizer 方案
    • 若误差验证可接受,可直接作为私聊上下文预算器
    • 若误差过大,再考虑换成更贴近目标模型的 tokenizer
  • 降级方案:
    • tokenizer 初始化失败时,可暂时退回“字符数 / 中文字数近似预算”
    • 但只作为 fallback不作为主路径

1.3 token 滑动窗口

  • 目标不是“把 256K 塞满”,而是“尽量稳定地用到 256K 级别能力”。
  • 建议采用“两层预算”:
    • 第一层:固定保底块
    • 第二层:历史滑窗块
  • 固定保底块建议包含:
    • 系统提示
    • 当前私聊对象信息块
    • 当前约定 / 当前跟进原因
    • 最近共同事件摘要
    • 必要的工具定义
  • 历史滑窗块建议逻辑:
    1. 从最近消息开始向前累加
    2. 每加入一条,重新累加 token
    3. 超预算则停止
    4. 保证最近几轮真实对话优先进入窗口
  • 不建议简单地“全拼后从头一直 pop 到合法”作为唯一策略。
  • 更推荐:
    • 先固定高优先级块
    • 再对普通历史做从近到远的预算填充

1.4 高优先级上下文保底

  • 下面这些信息不应与普通旧聊天放在同一优先级:
    • 当前私聊对象是谁
    • 你和对方目前是什么关系
    • 近期共同事件
    • 最近承诺/约定
    • 当前定时跟进原因
  • 这些内容即使在历史极长的情况下,也应尽量保底进入窗口。
  • 这部分内容应从:
    • person_info
    • A_memorix 的人物画像 / 关系证据 / episode
    • 当前会话内最近承诺 统一汇总出来

1.5 planner → replyer 信息继承

  • 目前 replyer 容易再次遗忘,核心原因之一是它并不稳定承接 planner 已经查到和整理过的信息。
  • 第一版建议:
    • planner 输出时显式生成“稳定参考信息块”
    • replyer 直接消费这块,而不是只依赖再看一遍历史
  • 这样即使 replyer 窗口比 planner 小很多,也能保持人物信息连续性。

1.6 配置建议

  • 本阶段建议新增但保持默认兼容的配置项,例如:
    • chat.private_context_rebuild_enabled
    • chat.private_context_rebuild_recent_limit
    • chat.private_context_token_budget
    • chat.private_context_reserved_tokens
    • chat.private_context_inject_relation_info
    • chat.private_context_recent_events_limit
    • chat.replyer_context_token_budget
  • 默认值应尽量保守,避免对现有用户造成突然的延迟或成本上升。

借鉴来源

  • MoFox-Core
    • 借鉴其“关系信息 + 印象 + 偏好 +聊天流印象”统一拼装进私聊上下文的思路
  • Muice-Chatbot
    • 基本不借鉴实现,只参考“最近历史 + 旧记忆回注入”的轻量骨架

验收标准

  • 同一个私聊会话在沉默一段时间后再次收到消息bot 不应明显忘记对方是谁。
  • 重建后的 runtime 能带上最近一段真实聊天历史,而不是只看最后一条消息。
  • 私聊中不需要用户重复提醒bot 也能较稳定记住:
    • 对方称呼
    • 近期正在聊的事
    • 最近约定/承诺
  • 在日志或调试信息里,能看到“重建历史条数”“对象信息注入块”的明确痕迹。
  • 能在日志或调试信息里看到:
    • 候选历史条数
    • 最终入窗条数
    • 估算 token 数
    • 被预算裁掉的原因
  • 在高上下文测试下planner 能稳定工作在 256K 级别预算附近,而不是仍然被 60 条历史限制住。
  • replyer 即使使用更小窗口,也不应明显丢失 planner 已确认的人物信息。

阶段 2定时跟进 V1

本阶段要解决的问题

  • 当前私聊没有“我之后再来找你”的能力。
  • 即使用户和 bot 约好了未来某个时间点,系统也无法主动在那时重新思考。
  • 需要主动发言时,只能强行伪装成 reply(msg_id=...),不自然。
  • 如果直接让 planner 裸写 message_text 并发送,会让主动私聊和普通回复走成两套文案体系。

本阶段要增加/修改的点

  • 新 builtin toolschedule_private_followup
  • 新 builtin toolsend_private_message
  • 私聊定时跟进任务表
  • 后台调度器
  • runtime 的“带 reminder 唤醒 planner”入口

如何做

  • schedule_private_followup
    • 只允许在当前私聊里创建未来任务
    • 记录触发时间、跟进原因、当时承诺话术
  • 后台调度器
    • 轮询 pending 任务
    • 到点后 claim 任务并唤醒当前私聊 runtime
  • runtime 新入口
    • <system-reminder> 形式注入“这不是用户新消息,而是一次到点跟进触发”
    • planner 基于当前上下文重新判断要不要发
  • send_private_message
    • 不直接裸发 message_text
    • 而是作为 replyer 的新发送语义出口
    • 复用现有人设、表达习惯、replyer 文案生成链路
    • 最终仍复用现有 send_service / Platform IO / 写库 / 历史同步

借鉴来源

  • MoFox-Core
    • 借鉴“主动思考不是直接发消息,而是先重进上下文再判断”的理念
  • Muice-Chatbot
    • 明确不采用其“到点直接发固定文本”的路径
  • 当前 maibot 架构
    • 延续“planner 负责想、replyer 负责写”的职责分离,不让主动私聊成为例外

验收标准

  • 私聊中可以成功创建一条未来跟进任务。
  • 到点后系统会唤醒 planner而不是直接发写死文本。
  • planner 可以根据当前情况选择:
    • 主动发一条消息
    • 什么都不发,直接结束
    • 再次约下一次跟进
  • 主动发出的消息是普通 bot 消息,不带旧消息引用。
  • 主动发出的文本风格应与普通 reply() 路径保持一致,不应明显像另一套文案系统。
  • 发送成功后仍会进入:
    • 现有消息存储
    • Maisaka 历史同步
    • memory automation

send_private_message 设计细化

工具职责

  • 在当前私聊会话中主动发出一条可见消息。
  • 不依赖 msg_id
  • 不默认带引用回复。
  • 语义上是“主动开口”,但文案生成仍应走 replyer,而不是绕开 replyer 直接裸发。

参数设计建议

  • 不建议把主参数设计成裸 message_text
  • 更推荐让 planner 提供“为什么说”,让 replyer 负责“具体怎么说”。
  • 第一版建议参数:
    • proactive_reason
      • 类型:string
      • 含义:这次主动发言的直接理由,作为 replyer 的“最新推理”
    • reference_info
      • 类型:string
      • 含义:本轮主动发言依赖的事实性参考信息
    • trigger_source
      • 类型:string
      • 含义:触发来源,例如 scheduled_followup
    • assistant_commitment_text
      • 类型:string
      • 含义:若这次主动发言是在延续先前承诺,可作为风格一致性参考

实现建议

  • send_private_message 应复用当前 reply() 已有的 replyer 生成链路。
  • 推荐执行路径:
    1. planner 调用 send_private_message
    2. tool 内部获取当前会话 replyer
    3. 以“主动发言场景”调用 generate_reply_with_context(...)
    4. 此时 reply_message=None
    5. reply_reason=proactive_reason
    6. reference_info 中整理注入 reference_info + assistant_commitment_text + trigger_source
    7. replyer 生成文本后,再复用现有发送链路发出

返回建议

  • 成功时至少返回:
    • session_id
    • generated_message_text
    • sent_message_id
    • maisaka_source_kind
  • 失败时返回明确原因:
    • 非私聊
    • replyer 生成失败
    • 发送失败

阶段 3主动私聊护栏与轻量主动能力

本阶段要解决的问题

  • 即使有定时跟进,系统也缺少“主动前的工程护栏”。
  • 后续如果要做更常态化的主动私聊,没有最小打扰控制会很容易打扰用户。

本阶段要增加/修改的点

  • 静默时段
  • 最小主动间隔
  • 可选每日上限
  • skip reason 与 guardrail snapshot
  • 轻量主动开场/问候 fallback

如何做

  • 在“任务到期”与“真正唤醒 planner”之间插入规则层
    • 私聊校验
    • 状态校验
    • 静默时段判断
    • 最小主动间隔判断
    • 可选每日上限判断
  • 对被跳过的任务记录:
    • skip_reason
    • guardrail_snapshot_json
  • 为未来“非约定型主动私聊”预留轻量主动开场能力:
    • 轻问候
    • 轻话题冒泡
    • 但此时仍不做完整主动聊天系统

借鉴来源

  • MoFox-Core
    • 重点借鉴其主动思考调度器中的工程护栏思路
  • Muice-Chatbot
    • 借鉴其轻量问候/轻话题池思路,仅作为 fallback

验收标准

  • 明显不适合打扰的时段,任务会被安全跳过或延后,而不是强行唤醒 planner。
  • 日志中能明确看到“为什么没发”的 skip reason。
  • 即使以后加入更强主动私聊,这一层规则也能直接复用。

阶段 4私聊状态机活人感增强

本阶段要解决的问题

  • 当前主动私聊即使能发,也缺少“发完之后等你回复”的真实感。
  • 系统无法区分“及时回”“晚回”“一直没回”。

本阶段要增加/修改的点

  • WAITING / IDLE 私聊状态机
  • 主动发送后的等待态
  • 超时后再判断是否继续等、追问或闭嘴
  • 连续超时计数与打扰保护

如何做

  • 在阶段 2 的基础上,扩展主动发送后的状态记录:
    • 最近一次主动发送时间
    • 是否正在等待回复
    • 等待配置
    • 连续超时计数
  • 收到用户消息时区分:
    • reply_in_time
    • reply_late
    • new_message
  • 等待超时后,再重新进行一轮轻量判断:
    • 继续等
    • 轻追问
    • 结束等待,不再打扰

借鉴来源

  • MoFox-Core
    • 这是最核心的借鉴来源,重点是其 WAITING / IDLE 与超时后再思考的设计
  • Muice-Chatbot
    • 基本不借鉴

验收标准

  • 主动发言后,系统能进入等待态,而不是把这件事完全忘掉。
  • 用户及时回复和很久后才回复时,系统的反应能出现可区分差异。
  • 多次未回复后,系统会自动降低继续打扰的倾向。

阶段 5关系阶段与主线推进

本阶段要解决的问题

  • 当前即使记住了人、能主动聊,也还没有真正的关系推进结构。
  • 缺少“朋友 → 更亲密阶段”的可持续演进逻辑。

本阶段要增加/修改的点

  • 关系阶段状态
  • 阶段推进条件
  • 近期主线事件/共同事件摘要
  • 更适合私聊恋爱化推进的上下文注入

如何做

  • 在现有 person_info / A_memorix 证据层之上,增加一层更明确的关系状态表达。
  • 阶段推进仍然尽量保持轻规则,不急着做全硬编码 romance engine。
  • 优先做:
    • 阶段状态
    • 最近共同事件摘要
    • 对阶段敏感的 prompt 注入
  • 后续再看是否要加入更强规则。

借鉴来源

  • MoFox-Core
    • 借鉴其“关系分数 + 关系阶段 + 印象文案”的分层思路
    • 不直接采用其当前阶段命名作为最终产品逻辑
  • Muice-Chatbot
    • 不足以支撑这一阶段

验收标准

  • 私聊中的称呼、关心方式、主动发言方式,会随关系阶段出现可感知变化。
  • 最近共同事件能够被作为关系推进依据,而不是每次都从零开始。
  • 系统在长期私聊中呈现出更稳定的关系连续性,而不是只有短期记忆连续性。

配置与 WebUI 影响评估

配置面

  • 配置面预计是“小改”,不是大改。
  • 建议新增独立配置块,例如:
    • private_followup.enabled
    • private_followup.scheduler_interval_seconds
    • private_followup.quiet_hours_start
    • private_followup.quiet_hours_end
    • private_followup.min_interval_between_proactive_seconds
    • private_followup.max_daily_followups_per_session
    • private_followup.inject_relation_info
    • private_followup.recent_shared_events_limit
  • 原则:
    • 默认值完整
    • 老配置不动也能跑
    • 优先改模板并递增版本号

WebUI 面

  • V1 到 V3 原则上不需要大改聊天协议。
  • 聊天渲染层:
    • send_private_message 发送的仍然是普通 bot 消息
    • 不要求新增 MessageSegment.type
  • 工具渲染层:
    • 新工具复用现有 tool record 展示链路
    • 前端最多看到新的 tool_name
  • 可选增强:
    • 定时跟进任务列表
    • 任务取消/重试管理页
    • 主动护栏状态可视化
    • 私聊状态机状态展示

分阶段验收顺序建议

  • 第 0 阶段先稳定开发环境,避免自动更新打断改造过程。
  • 第一阶段先解决遗忘与历史重建,不急着上主动聊天。
  • 第二阶段打通定时跟进 V1。
  • 第三阶段补主动护栏与轻量主动能力。
  • 第四阶段再做 WAITING / IDLE 状态机。
  • 第五阶段最后做关系阶段与主线推进。

当前最推荐的开发顺序

  1. 断开 WebUI / 本体自动更新检测
  2. 私聊对象信息常态注入
  3. runtime 历史重建
  4. planner → replyer 信息继承增强
  5. schedule_private_followup
  6. send_private_message
  7. send_private_message 的 replyer 驱动实现
  8. 后台调度器与 runtime 唤醒入口
  9. 到点前护栏
  10. WAITING / IDLE 扩展
  11. 阶段/主线推进