可选能力集成
本套件会使用原生 DSH 未提供的模型能力:嵌入、重排序、文本转语音、语音转文本和图片生成。这些能力来自另一组插件 dsh-ai-providers。其中,@dsh-ai-providers/core 定义契约,dsh-ai-providers 提供注册表、设置界面和已配置服务,dsh-ai-<vendor> 提供具体实现。它们把能力注册为 ctx.embeddings 等上下文服务。本套件只消费这些服务,没有它们也能运行。
当前使 用的能力
角色回忆的重排序使用 ctx.rerankers。回忆先通过线索、词语和可选的语义搜索取得多于所需的候选项并融合结果。重排序服务读取当前情境和各候选项后评分,系统再结合该评分、融合检索分、重要性和新近程度选择结果,详见记忆规范。只要存在重排序服务,核心插件就会为状态插件注册记忆排序器:
ctx.roleplayState.rankMemories(async ({ situation, candidates, signal }) => {
// candidates: the over-retrieved pool, { key, text, turn, importance }[];
// return a Map from key to 0..1, or undefined when there is nothing to judge with
})
其他插件也可注册自己的实现,最后注册的实现生效。实现抛错时,回忆退回到仅使用检索结果,并在日志中记录原因;取消信号会继续向上传递。
对话的嵌入设置
对话设置在 embedding.options 中保存所选嵌入提供方允许按请求设置的参数。它是由提供方自定参数名组成的扁平值集合。向量按对话存储和比较,所以选项也属于对话。提供方通过 @dsh-ai-providers/core 的 RequestOption 描述选项,并由 GET /ai-api/capabilities 提供。对话设置显示全部选项;开始对话时的高级设置只显示标有 atStart 的选项。例如,OpenAI 提供方的向量维数必须在第一次请求前选定,因为不同维数的向量不能比较。
存在 ctx.embeddings 时,host/memory/embedding-index.ts 会使用它。写入故事索引的文本在后台以文档形式生成嵌入;角色行动时的情境和关键词查询以查询形式生成嵌入,两者都带上该对话的选项。向量通过 sqlite-vec 扩展存入会话数据库。除短暂的在途窗口外,嵌入插件不另行缓存。没有该插件时,线索和词语检索仍可正常工作。
语音与媒体
- 文本转语音可朗读完整回复或单条角色发言。完整回复会拆成旁白和发言,按各自配置的声音并发生成,再按故事顺序合并。声音发现是可选能力。对于 LocalAI 等不枚举声音的 OpenAI 兼容服务器,手工填写的提供方声音 ID 仍然可用。
- 语音转文本使用 DSH 的实验性语音转文本提供方契约处理完成的录音。实时转写使用另一个可选的
streamingSpeechToText服务,角色扮演主机通过/roleplay-api/speech/capabilities检测它。DSH Voice Input 负责采集麦克风,并把完成的转写插入已有草稿,不会自动发送。
两项服务都在使用时查找。DSH Voice Input 和 SenseVoice 需要与角色扮演套件分开安装,这样它们的精确版本可以与 DSH 保持一致。启用 API STT 后,其提供方与 SenseVoice 并列注册;禁用 API STT 只撤回该提供方。
- 图片生成使用可选、与提供方无关的图片服务,生成规范肖像和临时场景图。支持参考图的 OpenAI 兼容驱动在有参考图时调用编辑接口,否则调用生成接口。身份、存储、任务和界面行为见图片系统规范。
用决策模型做判 断(ctx.decisions)
决策模型针对一个状态回答带类型的问题,一次性以概率给出答案(AI 提供方插件的 DecisionService)。凡是语言模型的任务只是封闭式的是非判断之处,套件都可以使用它,并且始终作为语言模型之外的第二条路径,而不是取代它。每个这样的环节在 decisions.* 中有一项设置,共四种模式:
llm(默认)使用语言模型,与没有决策服务时完全一样。decision只用决策模型。“是”需要至少(1 + confidence) / 2的概率;把握更小的一律算作“否”。hybrid在决策模型有把握(概率至少(1 + confidence) / 2或至多(1 - confidence) / 2)时使用它,其余部分只交给语言模型。shadow两者都问,采用语言模型的答案,并记录决策模型(按decision的方式读取)是否与之一致。
这些环节是触发器所等待的陈述(decisions.triggers,每条陈述一个是非问题,合并为一次请求,提示 roleplay/decide-trigger),以及用角色此后接收到的内容检查信念(decisions.reflection,信念之后出现的每件事一个问题,提示 roleplay/decide-reflection;只有决策模型有把握的答案才会认定矛盾)。问题的措辞和其他提示一样是随附的提示文件,因此可以按世界、预设或故事修改。
另有两个环节检查游戏主持人即将交付的内容,除非对话把它们打开,否则默认关闭(decisions.agency、decisions.refusal;模式 off、llm、decision、hybrid、shadow):叙述不得给玩家的角色玩家消息中没有写到的话语、动作、决定、想法或感受,输出不得跳出故事(拒绝、警告、免责声明、对玩家说的话)。它们是 outputGate 边界(host/decisions/gates.ts),在格式自身的检查之后由引擎的交付环节调用;各自一个问题(roleplay/gate-agency、roleplay/gate-refusal,决策模型的问题和语言模型的指令用同一段措辞),由模式指定的一方判断。决策模型的答案从 decisions.gateThreshold(0.5)起算作有问题,比它低 0.15 以内的概率为没有把握(hybrid 下交给语言模型判断,decision 下视为没有问题):决策模型即使看出了罕见的问题,给出的概率也偏低(实测:有问题的在 0.3 到 0.9 之间,正常文字低于 0.4),所以这两项检查不使用另外两个环节那种对称的 decisions.confidence。发现问题时,作为对 narrate 的拒绝退回给游戏主持人,与格式自身的拒绝共用上限(MAX_REFUSALS,两次):超过上限、由叙述者写的输出、已替游戏主持人修正过的输出以及脱离角色的回合,都原样交付。无法进行的检查只报告一次,绝不会让回合停下。
另有两个环节只为决策模型而设:它们是此前的框架没有的检查,没有语言模型版本可切换。除非对话把它们打开,否则默认关闭(decisions.rules、decisions.secrets;off 或 on),打开后每个回合多调用一次决策模型;关闭时与以往没有任何区别。两者都使用 decisions.gateThreshold,并且需要决策服务:没有时不做任何检查,原因只报告一次,该次运行仍计入 故事的统计。decisions.rules 是 ruleCheck 边界(host/decisions/extras.ts 的 ruleChecks),由引擎在游戏主持人以 allowed: true 调用 judge_action 时调用:对世界和玩家的每条规则各问决策模型一个问题(roleplay/check-rule),以玩家的消息为状态,放在同一个请求里。被认为很可能违反的规则会让该次调用每回合失败一次并点出这些规则,游戏主持人重新判断;以第二次判断为准。decisions.secrets 经由 outputGate,使用玩家的角色不知道的背景(只列给其他角色、与其没有知识边的背景,最多 16 条,段落中提到标题的优先,每条取 300 个字符;hiddenFrom):每个事实一个问题(roleplay/gate-secret),以这段文字为状态。发现被泄露的事实时,作为对 narrate 的拒绝退回并点出这些事实;每回合只退回一次,因此故事有意安排的揭示在游戏主持人再次交付时可以通过。在每个环节 24 个带标签的中英文用例上、阈值 0.5 的实测:Kev-9B 没有漏掉任何秘密、没有误报,12 个违规行动漏掉 3 个、误报 1 个;Kev-4B 漏掉 2 个秘密和 3 个违规行动。
缺少决策服务或其出错,都不会让故事停下:该环节的判断交给语言模型,原因只记录一次并保留。路由只有一个函数(host/decisions/route.ts 的 routeVerdicts),由各环节共用。每个环节做了什么会累加到故事数据库旁的 decisions.json(运行次数、已决策、已升级、已回退、一致、分歧、各路径耗时、最近的分歧),因此故事回退不会改变它;GET /roleplay-api/sessions/decisions?id= 把它连同服务状态提供给对话设置标签页。
决策模型以后台优先级、并通过该服务自己的并发能力 被调用,因此对它设置的限制不会让它排在语言模型任务之后。
消费能力的规则
- 可选能力在使用时通过
ctx.get查找,不作为硬性inject,因此缺少能力时套件仍可加载。 - 只改善结果的能力失败时可降级,例如重排序;用户明确请求的操作失败时应直接报错,例如朗读。
- 当某个模型只在部分部署中更好时,用第二条路径而不是替代:语言模型仍是默认和后备,每个环节各有开关,让用户在依赖之前先做比较。
- 有成本的能力按对话选择,设置放在
memory.*附近;较慢的能力默认关闭。
语言模型
智能体使用的模型可由 AI providers 插件提供给 DSH。提供 llm 的提供方注册路由,再由一个适配器统一提供。角色扮演插件不依赖该方式,只会把辅助智能体的控制参数交给实际响应的服务。它在使用时查找 ctx.aiProviders.policy。使用 DSH 自带适配器时,适配器会忽略这些参数,插件其余部分无需改变。
控制参数包括温度,以及辅助智能体是否必须通过工具调用作答。默认温度为:游戏主持人的 sampling.master 为 0.7,角色的 sampling.characters 为 0.8,建议作者的 sampling.suggestions 为 0.2,创作助手的 sampling.authoring 为 0.4,记录员和图片作者的 sampling.records 为 0.1。对话设置还包含 sampling.tools。导入与创作助手使用 importTemperature;其输出长度、时限、模型和推理等级分别由 importMaxTokens、importTimeoutMinutes、importModel 与 importReasoning 控制。这些项目都显示在设置表单中。
角色卡分类可以在语言模型之前选择使用决策能力。importDecisions: decision 会采用达到 importConfidence 的“指令/无关”判断;没有把握或调用失败时回退到语言模型。这只是优化,不是依赖:没有决策服务也能正常导入。
共享繁忙资源
AI providers 插件可通过并发设置限制一种资源同时处理的请求数。角色扮演套件会声明等待优先级:本回合中的角色和世界作者即时创建的事物优先;回合后的记录员、建议、记忆索引和自动场景图排在其后;玩家主动请求的图片或录音再次获得高优先级。新回合也不会在开始前等待上一回合的记录完成,只有需要回忆或修改故事状态的操作才会等待。