ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Edge-DM实战:用本地大模型和RAG打造离线AI桌游城主

Edge-DM实战:用本地大模型和RAG打造离线AI桌游城主 上周日下午两点我收到一条微信“今天DM临时有事团还开吗”群里沉默了半分钟然后有人补了一句“要不让AI来顶一局”这要是放在两年前我会当成一句玩笑。但这次我们真的开成了。原因是我手里正好跑着一个叫Edge-DM的项目——一个完全本地部署的AI桌游城主Tabletop Game Master。那场游戏三个小时玩家跑完了一个小型调查任务中间还打了一场遭遇战。过程中AI确实犯了不少傻但整体体验已经超出了我原先对一个“聊天机器人带团”的预期。这篇文章不写产品发布会式的介绍我只想把自己在实际搭建和使用Edge-DM过程中的方案、踩过的坑、以及一整套让AI从“能聊天”变成“能主持”的调教思路完整记录下来。适合谁看如果你是跑团玩家想知道AI能不能解决“缺DM”的老大难或者你是AI应用开发者想了解本地模型在具体场景里怎么落地再或者你只是好奇“边缘AI”到底能做什么这篇文章应该都能给你点实在的东西。1. 当DM鸽了AI补位Edge-DM到底在解决什么问题1.1 跑团玩家的最大痛点DM是组织里最难约的人玩过TRPG的人都有感受。玩家到点上线就行DM得提前写好剧情线、设计遭遇、记住每个NPC的说话方式还得现场同时扮演十几个角色、维护战斗平衡、接住玩家各种离谱操作。DM的准备工作量和临场压力是普通玩家的好几倍。所以每个跑团圈子里最稀缺的资源永远是“愿意长期当DM的人”。我身边的情况是五个固定团友只有两个人带过团其中一个还是只带过三次就宣布“需要休整半年”。周末能不能开团取决于DM下周的心情和加班情况。时间一久大家都默认“约团约DM”。这正是Edge-DM这类工具最容易切入的位置——它不是要替代人类DM而是把最低门槛拉下来。哪怕你不懂规则书、不擅长即兴扮演只要把故事方向丢给AI它就能把一个夜晚的剧本、判罚、NPC台词全部撑起来。AI不会因为加班缺席也不会因为连续三次被玩家打死NPC就心态崩盘。1.2 为什么是“Edge”而不是云端API项目名里的“Edge”不是营销概念它代表整套系统跑在本地设备上。为什么当初坚持选边缘部署而不是直接调云端大模型API我整理过三个核心原因。第一个是数据隐私。跑团过程非常私人化。玩家在桌上聊的很多内容、角色卡上的背景故事、临时起意的暗黑脑洞都不适合被传到第三方服务器存档。本地部署意味着所有对话记录、剧本内容、状态文件全部留在自己电脑里。这点在“别人家的AI聊天工具”上很难满足但对一桌每周见面的人而言恰恰是安全感的前提。第二个是稳定性。云端API依赖网络而跑团地点经常是朋友家的客厅、周末短租的民宿Wi-Fi质量谁用谁知道。真在关键时刻断网AI突然“掉线”NPC全部原地发呆那是灾难。Edge-DM跑本地模型断网照常运行——这个优势在实测中比想象中还重要。第三个是可控性。你想让AI用什么样的语气描述地牢想让NPC的说话风格更街头还是更贵族想让系统对某类暴力场景降级处理云端接口的审核规则和系统提示词管不了那么细。本地模型则全由自己控制所有提示词、限制词、价值观倾向都可以按桌面规矩调整。这种自由度是API方案给不了的。1.3 这个项目适合谁说实话Edge-DM现在的完成度还没到“另外付费购买”的商品级它更接近一个极客向的DIY项目。但适合把它玩起来的人其实很清晰跑团玩家尤其是既当玩家也想偶尔当DM的新手用它做“DM练习器”先让AI带完一场低风险的团观察一个城主到底要做什么。独立开发者想在本地模型上做一个垂直场景应用TRPG是一个复杂度适中但用户黏性极高的方向它囊括了对话、规则检索、状态追踪、多人协同练手价值很高。AI应用爱好者平时只调API没接触过量化模型、RAG、上下文压缩这些东西的这个项目是一套完整的实战案例。2. 拆开Edge-DM一台离线AI城主由哪些零件组成Edge-DM不是一个单独的模型它是一套由本地LLM、检索模块、游戏状态缓存、骰子引擎和交互界面拼起来的系统。把这几个部分拆开看每一步都有很明确的“为什么”。2.1 模型选型本地跑LLM不是越大越好Edge-DM的核心是本地大语言模型。常见的做法是用Ollama或llama.cpp这类运行时加载GGUF格式的量化模型。别看“本地模型”四个字好像很轻巧选型上其实很讲究。当时我测试过三个档位的模型7B级别的小模型比如Qwen2.5-7B-Instruct、Llama 3.1 8B、14B级别的中档模型Qwen2.5-14B-Instruct最常见、以及32B以上的大模型。结论是7B在规则理解上明显撑不住经常把“体质豁免”和“力量检定”混为一谈上下文稍微长一点就开始前言不搭后语32B效果当然好但在普通家用显卡上响应速度会掉到每字好几秒一场团等得人着急。最终稳定用的是14B档位配合Q4_K_M量化。速度在显卡上约每秒15-25 token对跑团场景足够了——DM本来就要“想一想再说话”不需要ChatGPT那种实时流式输出。量化会让模型有一定能力损失但4bit量化对14B模型的语义理解影响可控换取的是显存占用降到10GB以下。如果显存只有6GB那建议考虑8B模型加更激进的上下文修剪策略我也试过效果稍弱但配合规则检索还是能带的。2.2 RAG规则库让AI先查规则再开口如果你直接把一套跑团规则书塞进系统提示词模型要么生成一堆规则幻觉要么被超长输入冲昏头脑。Edge-DM的做法是把规则处理成独立的知识库做成检索增强生成RAG管线。具体思路把规则手册后来又加入了几款扩展规则的合规摘要切成语义块喂给嵌入模型生成向量存进本地向量库。游戏过程中玩家的行动涉及某个规则点时系统先用玩家动作文本去向量库检索最相关的规则条目把检索结果作为“参考上下文”拼进发给模型的请求里。模型收到的是一条包含“玩家说了什么相关规则原文当前游戏状态”的复合提示词再让它输出判定和描述。为什么必须加这一层因为大模型的训练语料里固然有大量跑团规则文本但模型并不会稳定记忆那些具体数值。比如“火球术”范围内伤害骰是几d6它可能猜对但它会在更冷门的法术上自行发挥编出一个完全不存在的数据。RAG的价值在于“把正确答案直接推到模型嘴边”模型不需要背诵只需要引用。2.3 世界状态管理记住每一件掉在地上的道具模型本身是无状态的。每个人工智能聊天场景都会遇到“它忘了十分钟前说过什么”的问题跑团这种持续几个小时的场景更是如此。Edge-DM的做法是维护一个外置结构化的“世界状态”。这个状态文件用JSON或者YAML保存包括当前场景、在场角色与HP状态、已触发的事件标记、NPC对玩家的态度值、玩家背包里的道具清单。每轮玩家行动后程序会从模型输出中抽取结构化信息更新状态文件下次请求时再把状态关键摘要注入模型上下文。这听起来像工程上的笨办法但恰恰是AI做DM最关键的支柱。没有状态记忆AI会上一秒让NPC给了钥匙下一秒就不承认战斗打到一半它可能忘记谁已经倒下。有了状态文件至少“物理世界”是稳定的模型只是在稳定的舞台上发挥。2.4 骰子引擎把随机性还给桌面跑团里有一条铁律检定结果是骰子决定的不是DM说了算的。应用到AI城主身上这一条要反过来理解AI的文本生成是概率性的所以你绝对不能让AI自己“掷骰子”并报结果它会倾向于让结果往戏剧化、极端化走——战斗次次大成功或者关键线索次次检定失败导致剧情卡死。Edge-DM把骰子引擎做成独立模块。系统检测到玩家行动需要检定就从程序代码里调用真实随机数生成器掷出d20或d6的组合把结果作为“上帝数据”喂给模型。模型的任务变成了“在已知结果的情况下描述这个结果造成的后果”而不是“既当运动员又当裁判”。举个例子玩家潜行值7骰子掷出12总计19。程序先把19这个数字发给模型并附上目标NPC的被动感知值16。模型收到的信息是“检定通过”它只需要描述溜进去的姿势和细节。这让游戏既有随机性又不会被模型“嘴上跑火车”带偏。3. 让AI真正像DM主持逻辑与Prompt设计的三个关键系统架构准备好后真正决定成败的是Prompt工程。一个没有任何设计的聊天模型上来直接当DM会生成“嗯这是一个古老的宝箱你打开它发现……你想怎么做”这种毫无画面感的烂大街对白。我调试了好几轮才总结出三个最关键的设计原则。3.1 区分主持人声音与游戏世界声音人类DM的专业之处在于切换声道描述环境时是中立旁白扮演酒馆老板时是粗嗓门的市井语气安排战斗时是简短有力的节奏控制。如果所有台词都交给AI同一个声音生成玩家很快就会觉得“所有人都是一个模子印出来的”。解决方法是把系统提示词里同时定义多个“发言角色”。让模型在输出时先标注当前视角比如[叙事]描述环境、动作结果用中性但富有画面感的语言。[NPC铁匠]用粗犷短句信息量低但性格鲜明。[规则提示]用冷静而简短的话说明检定类型和DC。[DM内声]告诉模型这里是节奏控制不要展开描写。我在测试中发现加了这些视角前缀后模型生成的质量显著提升。因为它不再需要靠猜测来决定“这次该说谁的话”而是被明确定位成一名演员。玩家也能通过前缀快速理解当前信息的性质——要知道跑团中最糟糕的体验是玩家分不清“NPC在骗人”还是“旁白在陈述事实”。3.2 用结构化格式管理“游戏事实”大模型擅长写漂亮文字但不擅长维护事实一致性。为了避免它把“火把还没点燃”写成“火光摇曳”我要求模型在关键交互后以固定格式输出“事实更新片段”由程序解析并写入世界状态。实践中我设计了一种极其简单的工具调用格式[STATE_UPDATE] location: 废弃矿洞大厅 lit_torches: false npc_present: 拉文受伤的佣兵 discovered_clues: 地面上的爪痕 [/STATE_UPDATE]模型在完成一段文本后按需追加这个片段。程序用正则或JSON解析器读取它更新状态文件。这个设计把“语义世界的记忆”交给程序来管模型只负责在当前回合创造内容。时间长了以后模型不会靠自己的记忆回答“你之前看到什么”而是从状态文件中检索确保同一故事的连续性。3.3 给AI装上刹车和油门检定请求与节奏指令新手DM带团容易犯两个极端要么放太快玩家还没互动就连续推进剧情要么拖太慢一个开门动作能描述两分钟。AI默认倾向反而是“拖太慢”——它会非常详细地描绘每扇门、每个瓶瓶罐罐生怕画面不够丰满。我在Prompt里给模型加了一个“节奏档位”参数取值从1到5。1档是“快速推进”适合战斗和追捕指令要求模型最多两句话完成动作结果5档是“细致沉浸”适合探索和重要对话允许扩展感官细节。玩家可以在对话中用快捷指令“节奏3”随时切换。这个简单机制让AI避免了最尴尬的“过度描写综合征”。另一个关键设计是“检定请求协议”。要求模型在应对玩家行动时先判断“这个行动是否具有失败后果”。如果没有后果那就直接允许成功并描述如果后果有意义才触发检定。普通的对话模型默认对所有行动都只回应文字不会主动发起规则判定所以必须在提示词里写清楚触发条件。3.4 一套实际的系统提示词骨架示例可能有人觉得上面说的太抽象。我把当时调试出的精简版系统提示词骨架结构放上来虽然不是完整可运行版本但足以让人理解设计套路。你是Edge-DM一名桌面角色扮演游戏的AI城主。 你的目标不是写小说而是主持一场公平、有趣、连贯的桌上游戏。 【发言视角规则】 - 使用[叙事]描述环境与动作要有画面感但每次不超过4句。 - 使用[NPC角色名]扮演指定NPC。NPC说话要有辨识度短句为主。 - 使用[规则提示]在需要检定时说明类型与DC语言简洁。 - 使用[节奏]标记当前节奏档位。 【检定流程】 1. 判断玩家行动是否需要检定是否存在失败后果。 2. 如需检定输出[ROLL_REQUEST] skill技能名 dc难度 相关属性... 3. 收到检定结果后用结果决定剧情走向禁止让玩家“无意义地重试”。 【事实一致性】 - 关键物品、NPC、事件必须通过[STATE_UPDATE]更新。 - 不要假设任何未记录的事实。你不确定时就查询世界状态。 - 如果当前信息不足用[叙事]引导玩家继续行动而不是凭空补设定。 【剧情原则】 - 玩家行动永远值得一个回应禁止说“你做不到”。 - NPC可以是敌人但不能是傻子。敌意NPC也有目标和智商。 - 保持桌面安全与舒适避免主动输出过度血腥或色情内容。注意最后一条——这既是安全底线也是游戏体验保障。AI城主不是用来制造猎奇内容的它要让玩家在尊重边界的前提下享受剧情张力。4. 实测记录Edge-DM带完一场“废弃矿洞”遭遇战理论说得再多不如实跑一场真实见真章。我在周六晚组织了一次四人局全员玩家我旁观并记录使用Edge-DM跑一个自制的短模组玩家受邀调查附近村庄人畜失踪事件线索指向深山一座废弃矿洞。4.1 开局场景描述与玩家入场开场时模型用了三段式描述先写黄昏时分的村庄氛围再写村长的委托对话最后暗示矿洞入口处的异常气息。整体画面感合格但节奏偏慢——第一段自然是5档细致描写用了一分多钟玩家已经在群里发“进度条呢”。我直接发了一句“节奏2”模型立刻把后续描述压缩成两句话村长也快速进入正题。这个实测确认了一件事节奏档位必须由玩家主动控制不能指望AI自己判断什么时候该快。4.2 途中感知检定与NPC对话进入矿洞后骑士玩家说“我环顾四周想看看有没有近期有人活动的痕迹。”模型检索到“调查”相关规则输出了一条检定请求感知检定 DC12。骰子引擎掷出d209加上感知修正211距离成功差1点。这里出现了一个非常有意思的情况AI城主知道结果失败了但它的描述策略是先铺垫再转折“你隐约觉得地上有些碎石有被翻动过的痕迹但当你蹲下去细看时却说不清哪些是人留下的哪些是洞穴坍塌自然形成的。你感到一阵没来由的烦躁。”这个处理很聪明——差1点的失败不是完全无信息而是给出模糊线索同时制造悬念。玩家群体中有人后悔没有使用“帮助”动作有人决定继续深入。从玩家角度看这场失败没有让人沮丧反而激发了讨论。当然AI不是每次都这么智能。同一个晚上另一个玩家试图从撑木上判断矿洞开挖年代模型直接判了个历史检定DC20导致玩家什么也没得到。事后我在日志里发现模型对这个不太常见的检定缺乏规则支持纯粹是“宁可错过也不给”。这是后面要处理的泛化问题。4.3 战斗AI最容易露怯的地方矿洞深处遭遇了两只变种灰狼。战斗流程按我们预设的逻辑每个玩家角色行动时模型先判断动作类型——进攻/移动/使用物品然后调用攻击检定规则骰子引擎扔出d20加值命中后再掷伤害骰。第一轮比较顺利。AI城主记住了先攻顺序并在每次行动之间穿插简短的怪物行为描述。但到第二轮问题出现了灰狼A已经重伤玩家选择向它投掷火把意图把野兽逼退。模型一开始没有判断这是攻击还是环境行为犹豫了一下直接把它按“徒手攻击”处理伤害骰又投了一个d4显得不符合火把引燃皮毛的效果。我的处理方式是在系统提示词里补充了一类“环境利用动作”的判断规则如果玩家使用了非武器物件且意图是改变环境或施加状态而不是直接造成伤害则交由骰子引擎判定效果等级而不是走攻击检定。这个小修正在后续战斗中很有效火把确实成功吓退了另一只狼玩家还为此兴奋了好一阵。4.4 失败复盘哪里出戏怎么修的整场下来玩家满意度打分在“及格到良好”之间。我记下了三个明显的出戏点一是局部细节的“不确定性幻觉”。AI描述地面时声称“有不少脚印”但玩家追问脚印方向时模型又改口说“看不太清可能是光影造成的错觉”。这类前后矛盾主要来自模型对局部状态的泛化修复方案是在状态文件里强制记录“脚印”这个事实点AI可以描述它的存在但不能随意否定它。二是战斗中的战术单一。AI扮演怪物时只有“扑咬最靠近的角色”这一种策略没有利用地形优势也没有表现出群体合作。这一点短期内靠提示词很难解决——小模型本来就不擅长策略推理更彻底的办法是给怪物行为配置独立的战术选择表由程序随机决策。三是对角色特性的响应用得不够。一个扮演盗贼的玩家明确说了“我会猫着腰尽量让锁甲不发出声响”但AI城主在描述时没有体现玩家的这个行为细节检定结果却照常通过了。模型似乎只关注了“潜行检定”的结果忽略了行为描写。这种时候我会在后续对话里补充一条“行为-结果一致性”规则要求模型在结果描述中至少要回扣玩家行动的一个具体细节。5. 踩坑实录本地AI主持人的五个常见翻车现场从Edge-DM能跑通到“接近能带团”中间隔着的全是大大小小的坑。下面这些是我实际踩过、并且给出来修方案的五个问题做这类本地AI应用的朋友可以参考。5.1 模型幻觉毁掉了关键线索第一次完整测试时AI城主需要给出一条关键线索矿洞墙上有一道被凿开的暗门。玩家走进房间后模型直接描述“墙上的破洞后面是一条通道”线索还没找就提前揭晓了。原因是模型从“调查行动”里推断出“应该有个发现”自己补了一段剧情。这属于经典的补充幻觉。修法是双重限制第一在系统提示词中写明“未被STATE_UPDATE记录的事实不得凭空出现”第二把关键线索用“线索状态机”管理未满足前置条件时模型请求中根本不包含该线索的任何检索片段。前者治标后者治本。5.2 上下文耗尽前情全忘跑了半小时后模型开始频繁回看早期对话回答新问题时提到“不久前你在矿洞口说……”但说错细节。这是上下文窗口被大量历史对话占满的典型症状。初版方案是把对话历史直接截断只保留最近20条。结果导致AI忘了第一个NPC的名字。后来我换了两个策略一是把“不可遗忘事实”全部抽到世界状态里二是对对话历史做“动态摘要”每隔几轮让一个独立进程压缩旧对话生成几百字的剧情摘要作为长期记忆最新20轮作为短期记忆。这样处理以后即便上下文窗口有限长期记忆也不会丢。5.3 对规则一知半解的“AI法盲”如果你让模型不经过RAG直接回答“法术‘魅惑人类’的作用范围是多少”十个模型里八个会答错。它会混淆法术等级、施法时间甚至把不同法术的效果嫁接在一起。我的解决方案分三层第一层是通过RAG给出规则原文只让模型“引用”不“编造”第二层是当模型不确定时必须输出“我确认一下规则”而不是硬着头皮乱编第三层是在判定引擎里做硬校验——凡是涉及具体数值的规则点伤害骰、法术距离、豁免DC如果程序从模型输出中解析到了数字会与规则库再对照一次不一致时触发修正。这三层叠加下来规则方面的错误率才降到可以接受的范围。5.4 多人对话中“认不清谁是谁”四个玩家同时发言AI城主容易把角色身份搞混。尤其是当一个玩家说了“我转身向另一个队友询问意见”模型会把这句话当成那个队友本人的发言接着让NPC队友替玩家回答。这事的本质是对话角色归属不明确。修法是引入“发言者标签”机制每次发给模型的请求都带一个元数据块标明“当前发言玩家骑士玩家”并列出在场角色ID与对应玩家ID。同时系统提示词里明确要求“只响应当前发言者的行动其他角色若要发言需由城主主动让他们行动”。这个机制恰好也缓解了“抢话”问题——桌面游戏里一个人替另一个人做决定是大忌。5.5 量化与速度的取舍本地部署的最大掣肘还是性能。我试过Q4_K_M、Q5_K_M和Q8_0三档量化。Q8_0效果最好但显存占用高响应速度慢Q5_K_M在规则遵守方面提升不大Q4_K_M在速度和资源占用上性价比最高。我用14B模型加Q4量化是权衡后的结果。如果你用Apple Silicon芯片推荐尝试MLX格式的模型显存占用和速度比GGUF更好一点。但如果是N卡无脑选GGUF加llama.cpp或Ollama就够了生态更成熟文档也多。6. 从单机DM到多元宇宙Edge-DM还能往哪走Edge-DM目前的形态是一个单机、独立运行的AI城主。但顺着这个架构往下想它其实有不少值得继续扩展的方向。6.1 语音化改造把键盘还给骰子现在的人机交互还是文字为主。桌面游戏最自然的交流方式当然是说话。下一步很明确的改造方向是接入本地语音识别模型比如Whisper的本地版本和语音合成模型把玩家说话转成文本再把AI城主的话念出来。这样就能实现“全场靠说”不需要每个人都盯屏幕打字。我试过简单接入最明显的感受是语音输出让AI NPC“活”了很多。原来的文字读起来可能觉得生硬但同一句话由语音合成带点语气说出来玩家对NPC的印象完全不同。当然本地语音合成目前还带着明显的“机器味”但随着开源语音模型质量上升这只是时间问题。6.2 局域网共享一人开团全桌可问目前的架构是“一台电脑当主机所有玩家共用一个屏幕/键盘”。多人体验往往会有一个“打字员”角色体验很割裂。更好的方案是加一层简单的服务端接口让每个玩家用自己的手机或笔记本作为客户端接入同一个Edge-DM会话。程序负责把各玩家输入按角色ID路由给模型再把模型输出分发回所有人的界面。这个架构不难实现难点还是状态同步和消息秩序——要不要做成实时流式要不要允许玩家私下悄悄话都需要结合实体的“桌面主持人”工作流来设计。6.3 地图联动与视觉化场景如果说语音是加了耳朵和嘴巴那地图联动就是给AI城主加了眼睛。很多跑团系统支持网格地图和Token角色棋子如果模型能读取玩家Token的位置信息它就可以在描述中自然加入“你面前5英尺处”这样的空间信息而不是模糊地说“敌人冲过来”。我设想过用本地视觉模型处理地图截图再告诉LLM“当前位置的网格坐标是……左侧有一扇门前方有两个怪物Token”。这样模型的描述就有了空间锚点战斗描述的真实感会强很多。不过这部分目前还很粗糙也远没到稳定可用。6.4 微调一只专属模型RAG和提示词能解决规则与事实问题但不能解决“AI城主的文风”问题。如果想要更鲜明的叙事风格——每场团都像某个特定作家写的黑暗奇幻或者像轻松的冒险喜剧——更彻底的办法是拿一批高质量跑团记录文本做LoRA微调让模型本身具备“城主DNA”。我的实测体会是微调应该放在整个系统完全跑通之后再做。因为微调很难单独解决系统性问题它只会放大现有管线的表现。如果你对Prompt调优还不熟练直接就上微调大概率会得到一个“更流畅地胡说八道”的模型。最后说一点我个人实际操作中的体会。一开始我做Edge-DM满脑子想的是“怎么让AI更聪明”让它能应对更多规则、写出更漂亮的文案。但带了几场之后我发现玩家真正满意的时刻往往不是AI展现出“智力”的时候而是它做好“主持人本职”的时候——记住玩家叫什么、公平地判定每一次尝试、让每个角色的高光时刻得以成立、在大家卡住时轻轻推一把剧情。AI城主做得最好的部分其实不是创造而是陪伴它永远有耐心永远不敷衍永远愿意接住玩家的任何选择。只要能持续记住发生过的事它的主持下限就能稳定超过一个准备不足的人类DM。而这个项目真正的魅力也在于它逼着你把“主持”这件事本身拆解清楚然后你才发现原来当好一个DM从来都不是靠想象力爆棚而是靠让所有人都愿意继续玩下去。
返回列表