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

531 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 私聊拟人性增强分阶段计划
## 总体目标
- 在尽量保留当前 maibot 主干能力与最近更新的前提下,增强私聊中的连续感、活人感与主动性。
- 优先修复“私聊对象信息容易遗忘”“聊天断开后像失忆”“上下文窗口过于保守”这三类核心问题。
- 再逐步增加“定时跟进”“主动私聊”“关系阶段推进”等能力。
- 落地时坚持“平行新增、契约尽量不变”:
- 不破坏现有 `reply` 语义
- 新能力优先通过新工具、新配置、新任务表、新 metadata 增量扩展
- 尽量不改现有 WebUI 聊天消息结构与事件结构
## 借鉴来源
### 1. `MoFox-Core`
- 主要借鉴:
- 私聊对象关系信息常态注入
- 主动前护栏判断
- `WAITING / IDLE` 状态机思路
- 发完后等待回复、超时再判断是否继续发言的活人感逻辑
- 不直接照搬:
- AFC / KFC 全套 runtime
- 强耦合插件系统
- 其整套数据库结构
### 2. `Muice-Chatbot`
- 主要借鉴:
- 轻量主动开场/问候思路
- 随机主动话题池思路
- 不直接照搬:
- 到点直接发送固定文本
- 过于依赖固定 prompt 的主动对话实现
## 当前问题
- 私聊对话者信息经常会被忘记,应该被常态化注入。
- 当前上下文管理偏保守,没充分发挥大上下文模型的能力。
- 私聊 runtime 重建后不会自动回灌最近历史,聊天断开一阵子后容易出现“失忆”。
- 人物信息、关系信息、共同经历主要依赖临时检索,缺少稳定默认上下文。
- planner 查到的信息不能稳定传递到 replyer导致回复阶段再次遗忘。
## 当前准备增加的能力
- 定时跟进机制:允许 LLM 在当前私聊中创建未来跟进任务,到点后重新唤醒 planner 判断要不要主动开口。
- 主动私聊发送工具:新增不依赖 `msg_id``send_private_message`,作为 `replyer` 的新发送出口,让主动聊天不再伪装成回复旧消息。
- 到点前护栏机制:加入静默时段、最小主动间隔、可选每日上限,避免技术上能发但体验上打扰。
- 阶段以及主线机制:允许你在私聊中像玩 galgame 一样,和小麦进行逐步推进的互动。
- 为后续私聊状态机预留扩展:后面再补“发完等回复、超时再判断”的活人感机制。
## 兼容性原则
### 前后端契约
- 现有 `reply` 工具保持原语义、原参数、原发送形态不变。
- 新增 `send_private_message``schedule_private_followup` 时,采用与现有 builtin tool 平行的注册、执行、记录方式。
- 现有聊天消息 `WsMessage / ChatMessage / MessageSegment` 契约尽量不变:
- 主动私聊发出的消息仍然是普通 bot 可见消息
- 不新增专用 `MessageSegment.type` 作为前提
- 现有工具记录结构尽量不变:
- 继续复用现有 tool record / tool result 链路
- 新增内容尽量放在 `tool_name``tool_data`、metadata 中
### 配置与 WebUI
- 配置面优先平行新增独立配置块,默认值完整,保证旧配置不改也能运行。
- WebUI V1 不应成为主阻塞项:
- 新功能优先复用现有聊天渲染与工具渲染
- 后续再考虑做任务管理页、状态展示页等增强 UI
---
## 阶段 0开发期稳定化
### 本阶段要解决的问题
- 当前准备进入连续多阶段改造,如果开发过程中误触自动更新,容易导致本体与 WebUI 版本漂移。
- 一旦前后端版本不一致,后续上下文、工具、调度器相关改造会很难排障。
- private-main 开发期间需要一个尽量稳定、可复现的运行基线。
### 本阶段要增加/修改的点
- `☐` 断开 WebUI 自动更新检测
- `☐` 断开本体自动更新检测
- `☐` 避免开发期自动拉取或自动提示更新
- `☐` 保留显式手动恢复/更新路径
### 如何做
- 找到当前 WebUI 与本体的更新检查入口:
- 启动时自动检查
- 定时轮询检查
- 页面内自动提示
- 开发期优先做“禁用自动检查”,而不是修改版本号或伪造远端结果。
- 尽量采用可逆方案:
- 配置开关
- 环境变量
- 显式开发模式判断
- 如果本体和 WebUI 的更新逻辑是分开的,也应分别断开,避免只关一边。
### 借鉴来源
- 不依赖 `MoFox-Core``Muice-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 tool`schedule_private_followup`
- `☐` 新 builtin tool`send_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. 阶段/主线推进