
Pi Narrative Engine — 阶段性成果说明
Pi Narrative Engine
对话驱动 AI 辅助叙事创作引擎 —— Pi 智能体扩展
这是什么
一个帮助小说作者管理"故事世界"的工具。你写小说时,角色、地点、物品、事件之间的关系越来越复杂——谁认识谁、谁在什么时候知道了什么、某件物品现在在谁手里。传统做法是写设定集、画关系图、做 Excel 表格,但它们不会随着故事推进自动更新。
叙事引擎做的事情:把小说内容压缩成一张"世界地图",记录故事每个时刻的世界状态——哪些实体存在、它们各有什么属性、之间有什么关系、每个角色分别知道什么信息。然后你可以随时查询"在第 3 章的时候,林墨知道苏晚晴的真实身份吗?"
目前是 V3 工程化阶段,代码可运行但尚未发布正式版本。
核心概念
世界图 —— 故事的"存档文件"
就像游戏存档记录了你当前的等级、装备、任务进度,世界图记录了故事在某个时刻的全部状态。它包含四样东西:
- 实体:故事中存在的所有"东西"。分为四类——角色(有意志的人)、地点(场景)、物品(武器/道具/信物)、概念(世界观规则/组织/魔法系统)
- 状态声明:每个实体"是什么样"。比如"林墨的心情=愤怒""青霜剑的位置=林墨手中"。每条声明都标注了它是客观事实、某人的主观信念、还是未证实的推测
- 关系:实体之间的连接。"林墨认识苏晚晴""青霜剑属于林墨""竹林位于青云山"
- 可见性:每个角色分别知道什么信息。"第 2 章时,林墨知道苏晚晴会武功吗?"
所有这些数据都带时间标记——每条信息都记录了"从哪个时刻开始生效、到哪个时刻失效"。所以你可以穿越到故事的任意时刻,查看当时的世界状态。
事件流 —— 故事的"操作日志"
如果世界图是存档文件,事件流就是操作日志。每条事件记录了一次世界状态的变化:一个新实体登场、一个已有实体的属性改变、一个实体退场。事件之间可以标注因果关系——"因为事件 A 发生了,所以事件 B 发生"。
事件只有三种类型:
- 诞生:实体首次出场
- 变更:已有实体的属性发生变化
- 消亡:实体退场(死亡/离开/消失)
导入器 —— 从小说到数据的"压缩机"
这是整个系统最核心也最难的模块。它的任务是把一本小说的全文,自动分析提取成世界图和事件流。当前方法是:把小说按章节拆分,每章送给 AI 分析,让 AI 识别实体、提取事件、推断关系和可见性,最后写入数据库。
一共 8 个步骤:分章 → 全书实体预扫描 → 逐章事件提取 → 实体别名消解 → 关系抽取 → 可见性推断 → 写入世界图 → 质量校验
当前导入器的定位:这是一个验证性实现,目的是证明世界图确实能接收外部小说导入的数据。能跑通流程,但数据质量存在明显问题——长篇文本下实体抽取覆盖不全(部分配角/物品漏掉)、关系不够明确(隐式关系经常被忽略)、属性内容缺乏统一标准(同类实体的属性字段不一致)、变更事件的粒度忽粗忽细(什么该拆成多个事件、什么该合并,缺乏规则约束)。导入器的算法策略需要从零重新设计,这是整个项目下一步最优先的工作。
仓库结构
pi-narrative-engine/
├── packages/
│ ├── world-graph/ # 世界图核心(TypeGraph + SQLite 数据库)
│ └── novel-importer/ # 小说导入器(8 阶段 AI 管道)
├── src/
│ ├── index.ts # Pi 扩展入口(注册 20 个工具)
│ ├── embedder.ts # 语义向量化(本地中文模型)
│ ├── search.ts # 全文+语义混合检索
│ └── visualizer/ # 可视化服务端
├── visualizer-ui/ # 可视化前端(Vue 3 + Element Plus 工作台)
├── prototype/v3/ # 3D 世界图原型演示(独立 HTML 页面)
├── tests/ # 引擎集成测试
└── docs/ # 文档
├── api.md # 完整 API 参考
├── visualization-design.md # V2 可视化设计(旧版,已被 V3 替代)
└── visualization-v3-design.md # V3 可视化设计(已实现)
代码量统计(不含 vendor 第三方库和旧版文档):
| 模块 | 代码行数 | 说明 |
|---|---|---|
| novel-importer 源码 | ~4,200 | 8 阶段导入管道 |
| visualizer-ui 前端 | ~3,200 | Vue 3 可视化工作台 |
| 引擎入口+嵌入+检索+可视化服务端 | ~1,700 | Pi 扩展核心 |
| world-graph 源码 | ~900 | 世界图数据库 |
| novel-importer 测试 | ~1,600 | 导入器测试 |
| world-graph 测试 | ~700 | 世界图测试 |
| 引擎测试 | ~700 | 端到端测试 |
| 文档(非旧版) | ~2,100 | API + 设计文档 |
总计约 15,000 行代码 + 文档,28 个 Git 提交。
当前进度
已完成
- 世界图核心:Entity / Fact / Relation / Visibility 四类节点,bi-temporal 时态管理(每条数据都有生效/失效时间),birth / kill / change 事件处理。支持因果链追溯(causedBy)
- 事件日志:JSONL 格式的事件记录,追加式写入,支持全量查询
- 角色视角:五步过滤算法,计算"角色 X 在时刻 T 能看到什么",区分亲眼目睹/传闻/推断三种来源
- 语义检索:全文检索 + 向量检索 + 混合检索,本地中文语义模型 Xenova/bge-small-zh-v1.5(512 维,无需联网),通过 sqlite-vec 实现向量存储和 cosine 相似度查询
- Pi 扩展接入:20 个工具注册到 Pi 框架,包括实体 CRUD、关系管理、事件应用、可见性设置/推断、角色视角查询、全文检索、世界状态摘要、可视化启动、小说导入。session 级生命周期管理(启动时自动初始化世界图+嵌入器+检索器,关闭时清理)
- 可视化服务端:零依赖 HTTP 服务(node:http),提供 JSON API(/api/status、/api/graph、/api/search、/api/entities/:id、/api/events 等),支持独立运行或嵌入 Pi 会话
- 可视化前端 V3:Vue 3 + Element Plus 三栏数据工作台,包含—— 时间轴滑块(按 storyTime 穿越)、左栏实体列表(搜索+类型筛选)、中栏三视图(邻域 3D 关系图/全景 3D 力导向图/世界快照表)、右栏详情编辑器(属性/关系/可见性编辑,编辑操作自动生成 change 事件)、角色视角模式(选择角色后只显示/高亮该角色可见的信息,不可见属性置灰)、事件链时间线页签、新建实体对话框、新手帮助弹窗。无构建、离线可用、纯静态文件
- 3D 原型演示:prototype/v3 独立 HTML 页面,可运行的 3D 世界图只读演示
- 导入器核心:8 阶段管道代码完整——EPUB 分章、全书实体预扫描、逐章事件流生成(按章节并行、LLM 子代理调用+schema 校验+重试)、实体消解(Jaro-Winkler 相似度+LLM 语义判断)、关系抽取、可见性推断、写入世界图(含 causedBy 因果链构建)、向量补齐+P0/P1 校验。已注册为 Pi 工具
import_novel。注意:这是验证世界图可导入外部数据的临时性设计,能跑通流程但数据质量差——实体覆盖不全、关系模糊、属性不统一、变更粒度不一致。导入算法策略需要从零重写 - 完整 API 文档:docs/api.md 覆盖全部 20 个工具的参数、返回值和调用示例
进行中
- 导入器文本压缩算法:当前方案把"从小说文本到结构化事件"的压缩决策全部外包给 AI 的直觉判断,缺乏一致性和可验证性。正在重新设计压缩策略,从"AI 直觉提取"转向"可验证的信号检测+规则化提取"
尚未开始
- 导入器端到端实书验证:尚未用完整小说跑通 8 阶段导入全流程
- 调度器:多角色子代理编排,自动推进剧情
- 扩散机制:事件后果自动传播(一个事件发生后,自动推导出连锁影响)
- 渲染器:世界图状态 → 自然语言叙事输出
- 多分支支持:故事分叉与对比
现在能做什么
如果你有技术背景的朋友帮你部署,当前可以:
- 创建世界图:在终端创建一个新的故事世界数据库
- 手动录入实体和事件:通过 20 个工具 API,手动创建角色、地点、物品,记录事件,建立关系
- 查询世界状态:穿越到任意故事时刻,查看当时所有实体的属性和关系
- 角色视角查询:查询"角色 X 在时刻 T 能看到哪些信息",区分亲眼所见/传闻/推断
- 全文/语义搜索:用自然语言搜索实体——"找所有带剑的角色""主角的师父是谁"
- 打开可视化界面:在浏览器中浏览世界图,查看 3D 关系图、实体列表、时间轴、快照表,编辑属性,切换角色视角
- 从 EPUB 导入小说:选择 EPUB 文件,AI 自动分析提取(需要 AI 服务,约 10 分钟处理 11 章)。注意:当前导入数据质量较差,实体覆盖不全、关系模糊、属性不一致、变更粒度忽粗忽细。导入器是验证性实现,产出的数据仅适合调试和验证流程,不适合直接用于创作
现在不能做什么(这些依赖调度器和扩散机制,尚未实现):
- 不能自动推进剧情
- 不能让 AI 角色互相"对话"生成故事
- 不能从一个事件自动推导出连锁后果
- 不能把世界图状态"渲染"成自然语言叙事
当前系统的定位是**"世界状态管理器和查询器"**,还不是一个完整的"自动写故事引擎"。它解决的是"记住故事世界里发生了什么"的问题,"接下来发生什么"的问题仍在设计中。
怎么使用
以下说明面向有 Node.js 和 TypeScript 经验的技术用户。
环境要求
- Node.js >= 20
- npm >= 10
安装
git clone https://github.com/lmy414/pi-narrative-engine.git
cd pi-narrative-engine
npm install
构建
npm run build
作为 Pi 扩展使用
在 Pi 项目中配置扩展路径,会话启动时自动加载 20 个叙事工具。工具列表见 docs/api.md。
独立可视化
# 启动可视化服务(需要先创建世界图)
node scripts/visualizer.mjs --db <world.db路径> --events <events.jsonl路径>
# 浏览器打开 http://localhost:3456
导入小说
# 从 EPUB 导入(需要配置 AI 服务)
node scripts/import-novel-v3.ts --epub <小说文件.epub> --output <输出目录>
运行测试
# world-graph 子包测试
cd packages/world-graph && npm test
# novel-importer 子包测试
cd packages/novel-importer && npm test
# 引擎集成测试
npx tsx --test tests/**/*.test.ts
下一步计划
- 重新设计导入器压缩策略:从"AI 直觉提取"转向"可验证的信号检测+规则化提取",这是整个系统最难的模块
- 端到端实书测试:用完整小说验证导入全流程
- 调度器原型:多角色子代理编排,事件→扩散自动化
- 渲染器原型:世界图状态 → 叙事文本输出
- 长期方向:从 Pi 扩展走向标准 MCP 工具,不绑定特定 AI 平台
许可证
GPL v3
作者
Mirror (lmy414)