Chemdah NPC 对话 (chemdah)
chemdah 扩展包将 Chemdah NPC 对话接入 ArkPilot 的一次性对话树生成流程。
和旧版“每轮调用 AI”不同,当前模式是:
- 玩家开始对话时,后台异步生成完整对话树 JSON。
- 生成完成后把根节点选项注入 Chemdah Session。
- 玩家后续点击选项只走本地分支推进,不再等待 LLM。
扩展包
chemdah 是可选扩展包,需要将 arkpilot-chemdah.jar 放入 plugins/ArkPilot/expansions/,且服务器必须安装 Chemdah。
工作流程
text
玩家右键 NPC
-> ConversationEvents.Pre
-> 解析 arkpilot 人设
-> 计算可用任务 + 剩余配额
-> quota 满且 no-quest-behavior=static 时:不拦截,走 Chemdah 原生
-> 尝试命中对话树缓存
-> 缓存命中:直接注入对话树,跳过 LLM 生成
-> 缓存未命中:写入 greeting + "请稍候..."
-> ConversationEvents.Post
-> 缓存命中时:直接渲染,跳过生成
-> 缓存未命中时:
-> 异步生成 DialogueTree(JSON)
-> 写入缓存 + 存入运行态
-> 用 root.reply/root.options 刷新 Session
-> ConversationEvents.SelectReply
-> 取消 Chemdah 默认 action
-> 本地推进 currentNode = selectedOption.next
-> 执行节点 action(quest_offer/quest_accept/quest_check/end)
-> quest_accept 成功时自动失效该玩家所有缓存
-> 刷新 npcSide/playerSide
-> 到叶子或 end 后延迟关闭 Session配置 NPC
在 Chemdah 对话配置里添加 flags: [arkpilot] 与 arkpilot: 段。
yaml
village-elder:
npc id:
citizens: 15
option:
title: "村长李伯"
flags: [arkpilot]
arkpilot:
name: "村长李伯"
personality: |
你是这个村子的村长,已经在这里生活了五十年。
说话慢条斯理,常引用古话。
knowledge: |
- 村子北边的矿洞最近出现了僵尸
- 东边的森林有一片隐藏的花田
greeting: "哦,年轻人,你来了。有什么事吗?"
max-accept: 2
no-quest-behavior: chat
no-quest-line: ""
tree-depth: 3
quest-depth: 5
quests:
- id: clear-mine-zombies
description: 清除北矿洞的 10 只僵尸
hint: 当玩家问到矿洞或者需要帮忙时引出
hidden: false
require: ""
- id: find-flower-field
description: 找到东边森林的隐藏花田
hint: 只有玩家聊到森林或探索话题时才暗示
hidden: true
require: ""
- id: repair-bridge
description: 修复村西断桥
hint: 玩家问到村子设施时提起
hidden: false
require: clear-mine-zombies人设字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name | string | 空 | NPC 显示名,优先于 option.title |
personality | string | 空 | NPC 性格描述,必填 |
knowledge | string | 空 | NPC 独有知识 |
greeting | string | 空 | 对话根节点台词 |
max-accept | int | 0 | 任务接取上限,0 表示不限制 |
no-quest-behavior | string | chat | 达到上限后的行为:chat/brief/static |
no-quest-line | string | 空 | static 或 brief 可使用的固定台词 |
tree-depth | int | 3 | 闲聊路径深度 |
quest-depth | int | 5 | 任务路径深度 |
model | string | 空 | 模型覆盖,空时使用助手模型 |
max-tokens | int | 512 | 生成对话树时的 token 上限 |
temperature | double | 0.9 | 生成温度 |
cache-ttl-minutes | int | -1 | 对话树缓存有效时间(分钟),-1 使用全局配置,0 禁用该 NPC 缓存 |
quests 字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | string | - | Chemdah 任务模板 ID |
description | string | 空 | 给模型理解任务语义用 |
hint | string | 空 | 提示任务引出时机 |
hidden | bool | false | 是否隐藏任务 |
require | string | 空 | 前置任务 ID |
配额与模式
可用任务过滤逻辑:
- 排除进行中任务。
- 排除已完成任务。
- 排除前置任务未完成任务。
- 用
已接受 + 已完成与max-accept比较。 - 达上限后进入
no-quest-behavior。
行为模式:
chat:仍生成对话树,但为纯闲聊,不出现新任务分支。brief:生成 1 层、2-3 选项的简短寒暄后结束。static:不拦截 Chemdah 对话,显示no-quest-line或greeting。
对话树缓存
为避免每次右键 NPC 都等待 LLM 生成,插件支持对话树缓存。第一次对话后缓存生成的对话树,再次右键同一 NPC 时直接使用缓存,秒开对话。
扩展配置(expansions/chemdah/config.yml)
yaml
dialogueTreeCache:
enabled: true
ttlMinutes: 10NPC 级覆盖
在 NPC 的 arkpilot: 段中设置 cache-ttl-minutes 可覆盖全局 TTL:
yaml
arkpilot:
cache-ttl-minutes: 5 # 该 NPC 缓存 5 分钟
# cache-ttl-minutes: 0 # 禁用该 NPC 的缓存
# cache-ttl-minutes: -1 # 使用全局配置(默认)缓存失效条件
- 任务状态变化:玩家接取/完成任务后,缓存自动失效,下次对话重新生成。
- 超时:超过配置的 TTL 后缓存过期。
- NPC 配置变化:人设、知识、任务列表等配置修改后缓存自动失效。
- 手动清除:扩展卸载或插件重载时清除所有缓存。
运行时动作
DialogueTree 节点支持动作:
{quest_offer: quest_id}{quest_accept: quest_id}{quest_check: quest_id}end
执行规则:
quest_offer/accept/check由代码直接调用QuestOfferTool/QuestAcceptTool/QuestCheckTool。quest_accept前做硬校验:若已达max-accept,回复“你手上的事情已经够多了,先忙完再来吧。”并结束。- 任一叶子节点(无选项)或
end动作,都会延迟关闭 Chemdah Session。
助手资源
扩展包仍会生成 assistants/npc-conversation/,但该助手现在只负责“生成对话树 JSON”。 不再使用:
- DM 模式自由打字
/npcreply命令npc_show_options/npc_end_conversation工具链npc-roleplay技能
故障排查
右键 NPC 后一直显示“请稍候...”
- 检查模型配置是否可用。
- 检查 API Key 是否存在。
- 查看控制台是否出现对话树生成异常;若异常会自动 fallback 到最小树(再见分支)。
玩家点击选项没有反应
- 确认对话在
flags: [arkpilot]下触发。 - 确认未处于树生成中(占位选项点击会提示等待)。
- 检查是否有外部脚本同时改写了
playerSide.reply。
任务接取失败
- 检查
quests[].id是否对应有效 Chemdah 模板。 - 检查前置任务是否满足。
- 检查是否已达到
max-accept上限。