# 世界书激活业务逻辑说明 ## 概述 世界书(WorldBook)系统允许用户创建动态的知识条目,这些条目可以根据特定条件自动激活并注入到对话上下文中。本文档详细说明世界书条目的筛选和分类逻辑。 ## 核心流程 ### 1. 数据收集阶段 后端从两个来源加载世界书条目: 1. **全局世界书** (`globalBooks`) - 来自前端传递的全局世界书列表 - 所有对话都会检查这些世界书 2. **角色绑定世界书** (`characterBookId`) - 与当前角色卡绑定的世界书 - 仅在该角色的对话中检查 ### 2. 条目筛选阶段 对每个世界书条目进行以下检查: #### 2.1 禁用状态检查 ```python if entry_data.get("disable", False): continue # 跳过禁用的条目 ``` #### 2.2 触发条件检查 支持四种触发类型: ##### A. 常驻触发 (constant) - **配置**: `trigger_config.triggers.constant[0] == true` - **行为**: 总是激活,无需任何条件 - **适用场景**: 角色基础设定、世界观背景等始终需要的信息 ##### B. 关键词触发 (keyword) - **配置**: ```json { "key": ["关键词1", "关键词2"], "caseSensitive": false, "matchWholeWords": false } ``` - **检查范围**: - 用户当前输入 (`user_message`) - 聊天历史消息 (`chat_history`) - **匹配模式**: - 大小写敏感/不敏感 - 全词匹配/部分匹配 - **适用场景**: 当对话中提到特定概念时激活相关解释 ##### C. 条件触发 (condition) - **配置**: ```json { "conditions": [ {"text": "tb.力量 > 10"}, {"text": "tb.态度 包括 \"友好\""} ] } ``` - **支持的语法**: - 数值比较: `tb.字段名 >/=/<=/==/!= 数值` - 字符串相等: `tb.字段名 = "值"` - 字符串包含: `tb.字段名 包括 "子串"` - **逻辑**: 所有条件必须同时满足 (AND) - **适用场景**: 基于动态表格状态的 conditional 内容 ##### D. RAG触发 (暂未实现) - 预留接口,未来可支持向量检索激活 ### 3. 位置分类阶段 激活的条目按插入位置进行分类和排序: #### 位置编号及含义 | 位置 | 标签 | 权重 | 说明 | |------|------|------|------| | 0 | 角色定义之后 | 高 | AI读完人设紧接着就读到这里,适合补充角色的详细设定 | | 1 | 角色定义之前 | 中 | 在角色卡内容的最上方,用于定义角色的基础背景 | | 2 | 示例对话之前 | 低 | 在对话示例的最上方 | | 3 | 示例对话之后 | 低 | 用于在对话开始前提供最后的上下文补充 | | 4 | 系统提示/作者注释 | 极高 | AI对最近看到的信息记忆最清晰,适合动态信息 | | 5 | 作为系统消息 | 最高 | 强制作为System Prompt插入,用于强制指令 | | 6 | 深度插入 | - | 预留,待实现 | | 7 | 宏替换 | - | 预留,待实现 | #### 排序规则 ```python active_entries.sort(key=lambda x: (x.position or 0, x.order or 0)) ``` 1. **主排序**: 按 `position` 升序(位置编号小的先插入) 2. **次排序**: 同位置内按 `order` 升序(order值小的先插入) ### 4. 统计与日志 激活完成后,生成详细的统计信息: ``` [WorldBook] 📊 激活统计: - 总激活条目数: 5 - 按位置分布: * 角色定义之后 (pos=0): 2 个 * 系统提示/作者注释 (pos=4): 3 个 - 按触发类型分布: * constant: 2 个 * keyword: 2 个 * condition: 1 个 ``` ## 数据结构 ### 前端发送的数据格式 ```javascript { worldBookData: { globalBooks: [ { id: "...", name: "全局世界书1" }, { id: "...", name: "全局世界书2" } ], characterBookId: "角色绑定的世界书ID" }, mes: "用户输入的消息", chatHistory: ["历史消息1", "历史消息2"], dynamicTableData: { currentValues: { "力量": 15, "态度": "友好" } } } ``` ### 后端返回的激活条目格式 ```python { "type": "worldbook_active", "entries": [ { "uid": "uuid-string", "content": "条目内容", "position": 0, "order": 100, "trigger_config": {...}, ... } ] } ``` ## 实现细节 ### 关键方法 1. **`_collect_and_activate_worldbooks()`** - 主入口方法 - 负责加载世界书、检查激活条件、排序和统计 2. **`_check_entry_activation()`** - 检查单个条目的激活条件 - 支持 constant、keyword、condition 三种触发类型 3. **`_check_keyword_trigger_with_config()`** - 关键词匹配逻辑 - 支持大小写敏感和全词匹配选项 4. **`_parse_table_condition()`** - 解析动态表格条件表达式 - 支持数值比较和字符串操作 5. **`_get_trigger_type()`** - 识别条目的触发类型 - 用于日志和统计 6. **`_get_position_label()`** - 将位置编号转换为中文标签 - 用于日志和前端显示 ### 数据类型标准化 在激活前,对所有条目数据进行标准化处理: ```python def _normalize_worldbook_entry(entry_data): # content 必须是字符串 # uid 必须是字符串 # position 必须是整数 # group 必须是列表或None ``` ## 前端集成 ### WebSocket 消息接收 前端通过 WebSocket 接收激活条目: ```javascript // ChatBoxSlice.jsx else if (data.type === 'worldbook_active') { console.log('[WebSocket] 📚 收到世界书激活信息:', data.entries.length, '个条目'); import('../../Store/SideBarRight/WorldBookActiveSlice').then(module => { module.default.getState().setActiveEntries(data.entries); }); } ``` ### 显示组件 `WorldBookActive` 组件按位置分组显示激活的条目: ```jsx // 按位置分组 const groupedEntries = activeEntries.reduce((acc, entry) => { const pos = entry.position || 0; if (!acc[pos]) acc[pos] = []; acc[pos].push(entry); return acc; }, {}); // 渲染每个位置组 {Object.keys(groupedEntries).map(pos => (
{positionLabels[pos]} ({pos})
{/* 渲染该位置的所有条目 */}
))} ``` ## 扩展方向 ### 短期优化 1. 添加概率触发支持 (`probability` 字段) 2. 实现RAG检索触发 3. 支持逻辑表达式触发 (`logicExpression`) ### 长期规划 1. 实现深度插入 (position=6) 2. 实现宏替换 (position=7) 3. 添加条目冲突解决机制 4. 支持条目依赖关系 ## 调试建议 ### 查看激活日志 后端会输出详细的激活日志: ``` [WorldBook] 📖 加载全局世界书 '测试世界书',共 10 个条目 [WorldBook-Check] 📌 常驻触发 | UID: xxx-xxx-xxx [WorldBook] ✅ 全局世界书 '测试世界书' 条目激活 | UID: xxx | 触发: constant | 位置: 角色定义之后 [WorldBook-Check] 🔑 关键词触发(用户输入) | UID: yyy | 匹配关键词: ['魔法'] ``` ### 常见问题排查 1. **条目未激活** - 检查 `disable` 字段是否为 `true` - 检查触发条件配置是否正确 - 查看日志中的 `[WorldBook-Check]` 输出 2. **位置不正确** - 确认 `position` 字段是整数类型 - 检查 `order` 字段的排序是否符合预期 3. **关键词不匹配** - 检查 `caseSensitive` 设置 - 检查 `matchWholeWords` 设置 - 确认关键词拼写正确 ## 总结 世界书激活系统实现了: - ✅ 多源数据加载(全局 + 角色绑定) - ✅ 多种触发类型(常驻、关键词、条件) - ✅ 智能位置分类(8个插入位置) - ✅ 详细统计分析(按位置和触发类型) - ✅ 完整日志记录(便于调试) 这为动态上下文管理提供了强大的基础,可以根据对话内容智能地注入相关知识。