实时情感引擎
实时情感引擎(Character Runtime)是 NekoBot 的核心特性之一,它让 AI 角色具备"活人感"——角色不再只是静态的提示词,而是拥有动态的情绪、关系和记忆。
概述
实时情感引擎是一个独立的角色模拟层,位于 AI Pipeline 中间,负责:
- before_turn: 读取角色卡、状态、关系、记忆,分析用户输入信号,生成 ReactionPlan,编译提示词
- after_turn: 更新情绪、关系,保存状态,抽取记忆;每 6 回合触发一次 AI 自动状态评估
ChatRequest
↓
AIPipeline
↓
CharacterRuntime.before_turn()
├── 读取角色卡
├── 读取角色状态
├── 读取关系状态
├── 检索相关记忆
├── 分析用户输入信号
├── 生成 ReactionPlan
├── 世界书关键词匹配
└── 注册 PromptStack 注入项
↓
模型调用 / 工具调用
↓
CharacterRuntime.after_turn()
├── StateMachine 每轮更新情绪/关系
├── AutoState 每 6 回合 AI 更新情绪强度/六维关系
├── 保存运行时状态与关系状态
└── 角色记忆服务抽取
↓
Pipeline AutoMemory
└── 每 6 回合总结长期记忆
↓
ChatResponse核心模块
1. 数据模型 (models.md)
定义角色引擎的所有数据结构:
- CharacterProfile - 静态角色卡
- CharacterState - 角色运行时状态
- RelationshipState - 关系状态
- CharacterMemory - 角色记忆
- ReactionPlan - 反应计划
- CharacterIdentity - 角色身份标识
2. 动态提示词栈 (prompt_stack.md)
PromptStack 是实时情感引擎的核心机制,允许任意模块在任意阶段注册提示词注入项,最终统一合成为本轮顶部 system prompt。
核心原则:
- 动态注入只在本轮请求生效,不写入历史消息
- 按优先级排序合成
- 可调试、可观察
3. 运行时引擎 (runtime.md)
CharacterRuntime 是角色模拟的编排中心,协调各个模块完成角色模拟的完整生命周期。
4. 反应计划生成器 (planner.md)
根据角色状态、关系、信号和记忆,生成本轮的 ReactionPlan,控制角色的回复策略。
5. 状态机 (state_machine.md)
负责根据信号和反应计划更新角色状态和关系状态:
- 情绪惯性: 情绪不会一句话突变
- 数值边界: 所有关系值在 0-100 范围内
- 每轮变化限幅: 避免暴涨暴跌
5.1 自动状态评估
auto_state.py 会像自动记忆一样按角色、会话和目标用户维度累计对话,并继承 heartbeat、错误回复、跳过标记等过滤条件。每 6 回合调用当前 AI 模型,让模型根据最近互动输出 mood、mood_intensity_delta、energy_delta 和六维关系增量。系统会在写回前做边界校验和限幅,所以它用于补足每轮规则过于保守的问题,而不是让关系值瞬间跳变。
6. 信号分析器 (policies.md)
分析用户输入中的情绪信号,为 ReactionPlanner 和 StateMachine 提供输入。
7. 角色记忆服务 (memory.md)
按角色+用户隔离的记忆检索与存储。
8. 数据仓库 (repository.md)
通过 repository 接口访问存储层,业务逻辑不直接读写 JSON。
9. 世界书 (world_book.md)
关键词匹配的世界观设定注入系统。为角色绑定世界观设定,当用户消息命中关键词时自动注入到提示词栈中。
10. 多频道角色运行时 (channel-runtime.md)
跨频道角色运行时接入层,让 QQ、飞书、Telegram 等频道都能使用角色系统。
- CharacterChannelAdapter - 频道适配器协议,定义频道接入所需的最小接口
- CharacterRuntimeContextDispatcher - 统一调度器,负责 is_enabled / 触发策略 / 记忆作用域 / scope_id 构建
- ChannelRuntimeContext - 统一频道运行上下文
- ChannelRenderPolicy - 频道输出渲染策略
- build_scope_id() - 根据记忆作用域配置构建隔离 key
目录结构
nbot/character/
├── __init__.py # 模块入口
├── models.py # 数据模型
├── compiler.py # 角色提示词编译器
├── prompt_stack.py # 动态提示词栈
├── prompt_builder.py # 提示词构建器
├── runtime.py # 运行时引擎
├── auto_state.py # 6 回合 AI 状态评估
├── planner.py # 反应计划生成器
├── state_machine.py # 状态机
├── policies.py # 信号分析器
├── memory.py # 角色记忆服务
├── repository.py # 数据仓库接口
├── events.py # 事件系统与调试快照
├── world_book_matcher.py # 世界书关键词匹配器
├── world_book_injector.py # 世界书 PromptStack 注入器
├── channel_adapter.py # CharacterChannelAdapter 协议定义
├── channel_context.py # ChannelRuntimeContext / ChannelRenderPolicy
├── dispatcher.py # CharacterRuntimeContextDispatcher 调度器
├── runtime_request.py # CharacterRuntimeRequest / CharacterRuntimeResult
├── storage/ # 存储实现
│ ├── __init__.py
│ ├── json_store.py # JSON 文件存储
│ └── world_book_store.py # 世界书存储层
└── adapters/ # 适配器
├── __init__.py
└── nekobot.py # NekoBot 桥接适配器数据存储
实时情感引擎的数据存储在 data/character/ 目录:
data/character/
├── profiles.json # 角色卡
├── states.json # 角色状态
├── relationships.json # 关系状态
├── memories.json # 角色记忆
├── events.json # 事件记录
└── debug_snapshots.json # 调试快照
data/
└── world_books.json # 世界书数据使用示例
基本使用
from nbot.character.runtime import CharacterRuntime
from nbot.character.repository import (
ProfileRepository,
CharacterStateRepository,
RelationshipRepository,
)
from nbot.character.policies import SignalAnalyzer
from nbot.character.planner import ReactionPlanner
from nbot.character.state_machine import StateMachine
from nbot.character.memory import PromptManagerMemoryAdapter
# 初始化运行时
runtime = CharacterRuntime(
profile_repo=ProfileRepository(base_dir),
state_repo=CharacterStateRepository(base_dir),
relationship_repo=RelationshipRepository(base_dir),
memory_service=PromptManagerMemoryAdapter(),
signal_analyzer=SignalAnalyzer(),
planner=ReactionPlanner(),
state_machine=StateMachine(),
)
# before_turn: 准备角色上下文
turn_context = runtime.before_turn(chat_request, identity)
# ... 模型调用 ...
# after_turn: 更新状态
runtime.after_turn(chat_request, result, turn_context)使用 PromptStack
from nbot.character.prompt_stack import PromptStack
stack = PromptStack()
# 注册提示词注入项
stack.add(
key="character.runtime_state",
content="当前心情: 开心\n情绪强度: 0.8",
priority=PromptStack.PRIORITY_CHARACTER_STATE,
)
stack.add(
key="character.relationship",
content="好感: 75/100\n信任: 60/100",
priority=PromptStack.PRIORITY_CHARACTER_RELATIONSHIP,
)
# 合成最终提示词
composed_prompt = stack.render(base_prompt)调试
实时情感引擎支持完整的调试能力,每轮保存调试快照:
{
"prompt_injections": [], // 本轮注入的提示词
"reaction_plan": {}, // 反应计划
"state_before": {}, // 变化前状态
"state_after": {}, // 变化后状态
"relationship_before": {},
"relationship_after": {},
"retrieved_memories": [], // 命中的记忆
"signals": {} // 检测到的信号
}通过 CharacterEventLogger 可以获取调试快照:
from nbot.character.events import CharacterEventLogger
logger = CharacterEventLogger(base_dir)
snapshot = logger.get_latest_debug_snapshot(scope_id)与旧系统的兼容性
实时情感引擎设计为可选中间层,默认启用但不会影响现有功能:
- 不启用时,聊天行为与之前完全一致
- 启用时,通过 PromptStack 注入动态提示词
- 旧 personality 数据自动迁移到新的 character 系统
- 记忆系统通过 adapter 保持兼容
后续规划
- [ ] SQLite 存储支持
- [ ] LLM 驱动的 ReactionPlanner
- [ ] 主动消息生成
- [ ] 长期事件线
- [ ] 角色间关系
