Pouchy World 规模上限,以及每条上限的原因

英文原版(以其为准):world-limits.md

基于 world API 1.48.0。下面每个数字都由服务端强制执行;机器可读的版本是 world OpenAPI 里的 maxItems / maxLength (components.schemas.StoryPackageContent,整包体积上限见 x-pouchy-max-bytes)。 你发送的内容超出上限时,服务端返回 400,并写明是哪条上限 (roles exceeds 24、story package is 1043211 bytes; the limit is 900000 …), 绝不会悄悄截断。第 5 节的上限属于另一类:运行时每一拍保存、展示或报告多少, 每一条旁边都写明了它的具体行为。


1. 1.48.0 改了什么

上限 之前 现在 常量
故事包角色数 12 24 STORY_MAX_ROLES
世界定义角色数 12 24 WORLD_MAX_ROLES(与上一行由测试钉为相等)
场景 50 100 STORY_MAX_SCENES
节点 100 200 STORY_MAX_NODES
分支 100 200 STORY_MAX_BRANCHES
整包体积 (未检查) 900,000 字节 STORY_PACKAGE_MAX_BYTES

这是一次放宽,只新增一种拒绝:超过 900,000 字节的故事包。超过 1 MiB 的包本来就存不进去, 现在改为返回一个说明原因的 400,而不是存储报错;介于 900,000 字节与 1 MiB 之间的包, 以前能发布,现在会被拒绝。已发布的修订不受影响:内容只在创建或发布时校验,读取时从不 重新校验,所以已被钉住的修订照常运行。只有再次发布它(或发布同样大小的新修订)才会遇到新上限。

2. 阵容

上限 数值 原因
每个故事 / 世界的角色数 24 产品取舍,不是技术限制。12 是"刻意取小",没有任何实测结论依赖它(见下方"成本")。
每个角色绑定的 agent 恰好 1 个,且互不相同 世界拒绝把同一个 agent 绑定给两个角色,所以 24 个角色的世界需要 24 个 agent。
每一拍开口的角色数 3(WORLD_TURN_MAX_ROLES) 戏剧取舍,刻意不放宽:三人是一场戏,再多观众就跟不上。它同时把每一拍的模型调用限制在最多 3 次。
一个事件最多唤醒的角色数 5(WORLD_MAX_ROLES_PER_EVENT) 与事件路由的扇出上限(MAX_EVENT_FANOUT)相等。如果某个事件需要唤醒的角色多于路由器能投递的数量,世界在发布时就会被拒绝,而不是运行时被截断。
每个角色的 secrets / goals 各 20 条 容量控制。每一条只会进入该角色自己的提示词。

成本不随阵容增长。 不在说话的角色,永远不会进入其他角色的提示词:它的 description、 goals、secrets 都不会。唯一与其他角色相关的内容,是同一拍里已经说过的台词(最多 2 句), 以及效果简报里两份有上限的 id 列表。24 个角色的故事和 3 个角色的故事,说话角色拿到的 提示词逐字节相同;world-envelope-composition.test.ts 在每次构建时都以最大阵容验证这一点。

大阵容需要由这一拍来决定"谁在场"。 3 个座位按 roles 的声明顺序填满。 不加指定时,第 4 到第 24 个角色每一拍都会被跳过:它们出现在 skippedRoles 中, code: "role_cap_reached"。请用 trigger.focusRoles(turn 接口,1.29.0 起)指定这一拍 的出场角色,或通过事件订阅来路由。如果某个角色"从来不说话",先查 skippedRoles。

3. 故事包

项目 上限 说明
场景 100
节点 200 每个节点必须指向一个已声明的场景
分支 200 每个分支连接两个已声明的节点
每个节点的前置条件 10
结局 60 早先已从 20 放宽,用于多集连续剧
既定事实 200
正史设定(canon) 100
约束 50
旗标(flags) 50
初始关系 50 与运行时状态能容纳的数量绑定(WORLD_STATE_MAX_RELATIONS)
剧集(series) 24
每集结局规则 / 每条规则的条件 20 / 10
每集回合预算 200 拍 证据窗口:更长的一集无法转成剧本
每条文本 500 个字符 canon、事实、secrets、goals、objective、条件、描述
整包 900,000 字节 见第 4 节

4. 体积上限:你真正会碰到的那一条

一个已发布的修订存储为一个 Firestore 文档,而 Firestore 拒绝任何超过 1 MiB (1,048,576 字节)的文档。故事包上限是 900,000 字节,按规范化后内容的 JSON 的 UTF-8 字节数计算,剩下约 140 KiB 留给修订记录自身的字段。

为什么它会比条目上限先碰到: 条目上限是相乘的。中文、日文、韩文每个字 3 字节, 所以一个写满的角色(20 条 secrets + 20 条 goals,每条 500 字)约 60 KB,24 个这样的角色 就是 1.44 MB。真实剧本远小于此,但长文本的中文故事包,会在达到 24 个角色或 200 个节点 之前,先碰到体积上限。

碰到时怎么办(400 story package is N bytes; the limit is 900000 …):

  • 先精简长文本字段:角色的 secrets / goals、canon、establishedFacts。
  • 参考资料(完整剧本、设定集)不要放进故事包。故事包只放运行时做判断、投影状态所需的内容; 原始剧本通过 source: { title, version } 引用,不要内嵌。
  • POST …/story-packages/import-candidate/validate 用同一个校验器校验但不发布, 返回同样的错误信息,可以在发布前先检查。

5. 你可能遇到的其他运行时上限

上限 数值 行为
每一拍的状态补丁操作数 20 超过则整批拒绝(补丁是全有或全无)
世界状态中的实体 / 关系 50 / 50 会让数量变成第 51 个的补丁被拒绝,整批一起拒绝。关系图很密的大阵容,会在达到 24 个角色之前先碰到 50 条关系:24 个角色有 276 种两两组合
每个角色在状态中的私人笔记 20 同上:会新增第 21 条的操作被拒绝
每一拍报告的分支选项 5 按声明顺序取前 5 个可达且未完成的分支;其余仍在故事里,前面的完成后才会出现
单个角色效果简报里的关系 id 8 个其他角色 只有 id;简报会报告截掉了多少
推演(deliberation) 2 个候选、3 个角色 服务端常量;请求只能要更少,不能更多
剧本导入(模型辅助) 16,000 个字符的剧本 更长的剧本会被拒绝;提取出的故事包同样遵守上面所有上限
剧本草稿 500 拍 一份草稿最多覆盖 500 个已提交的拍;更长的世界线请按集分别起草(episodeRunId,1.27.0)
每个项目启用的世界 / 故事包 1,000 / 1,000 达到上限时创建会被拒绝

6. 数字定义在哪里

src/lib/world/story-package.ts(故事上限与体积上限)、src/lib/world/definition.ts (世界定义),以及 src/lib/server/platform/world-coordinator.ts(WORLD_TURN_MAX_ROLES)。 控制台的世界创建向导直接引用同一组常量,并显示"n / 24 个角色",因此不会与合约脱节。