基于Go与Claude Code的AI桌游引擎SkillsWeaver架构解析
在游戏开发领域,将大语言模型(LLM)与传统游戏引擎结合,正成为探索AI应用的新范式。其核心原理在于通过API调用,让AI模型理解结构化数据与规则,并驱动动态叙事。这种技术架构的价值在于,它能将AI的生成能力模块化、工具化,从而构建出规则严谨、体验连贯的智能系统。典型的应用场景包括自动化游戏内容生成、智能NPC交互以及单人游戏体验的增强。本文以SkillsWeaver项目为例,深入剖析了一个由Go
1. 项目概述:一个由AI驱动的桌面角色扮演游戏引擎
如果你和我一样,既是桌游爱好者,又对AI技术如何赋能传统游戏体验充满好奇,那么SkillsWeaver这个项目绝对值得你花时间深入研究。它不是一个简单的脚本集合,而是一个完整的、由Go语言构建的桌面角色扮演游戏引擎,其核心创新在于深度集成了Anthropic的Claude Code,让AI从一个被动的工具,转变为一个能够理解游戏规则、管理游戏状态、甚至驱动叙事的“地下城主”。
简单来说,SkillsWeaver将《龙与地下城》第五版的开源规则作为骨架,用Go语言编写了一系列命令行工具作为肌肉和关节,最后通过Claude Code的“技能”与“代理”系统为其注入了灵魂。它解决了传统TRPG(桌面角色扮演游戏)中一个经典痛点:当没有真人城主时,如何维持一个规则严谨、叙事连贯的游戏体验?SkillsWeaver给出的答案是,让AI来担任这个角色。你可以通过一个现代化的Web界面或一个功能强大的命令行REPL,与这位AI城主进行实时互动,它会根据你的行动,调用内置的工具库来投骰子、查询怪物数据、生成宝藏、记录日志,并编织出相应的故事。
这个项目适合几类人:首先是希望单人体验TRPG魅力的玩家;其次是游戏设计师或开发者,想了解如何将大语言模型深度集成到复杂的应用逻辑中;最后是任何对“AI作为协调者”这一范式感兴趣的技术爱好者。它不仅仅是一个玩具,更是一个展示了如何将AI能力模块化、工具化,并嵌入到具体业务流中的优秀工程范例。
2. 核心架构与设计思路拆解
SkillsWeaver的架构清晰地分为了三个层次:数据层、工具层和交互层。理解这个分层,是理解其如何工作的关键。
2.1 数据层:结构化游戏世界的基石
任何游戏引擎的核心都是数据。SkillsWeaver的数据层完全基于JSON文件,这确保了数据的可读性和可扩展性。在 data/ 目录下,你会发现一个精心组织的世界:
-
characters/: 存放玩家角色档案。每个角色JSON文件不仅包含力量、敏捷等基本属性,还完整定义了种族特性、职业能力、技能熟练项、装备和法术。这遵循了D&D 5e SRD的完整规则集。 -
adventures/: 每个冒险都是一个独立的子目录。里面不仅包含冒险元数据(adventure.json),还有队伍构成(party.json)、共享库存(inventory.json)、会话历史(sessions.json)以及最重要的——游戏日志(journal-session-*.json)。这种设计让每个冒险完全自包含,便于备份和分享。 -
world/: 这是项目的“软设定”部分。factions.json定义了四个风格迥异的王国(如航海商贸的瓦尔多林、军事至上的卡尔瓦思),为角色背景和故事提供了丰富的土壤。geography.json和npcs.json则进一步填充了世界细节。 -
monsters.json,treasure.json: 这些是直接从D&D 5.2 SRD文档中提取并结构化的硬数据。怪物数据包括完整的战斗属性(护甲等级、生命值、攻击模式),宝藏表则严格按照官方挑战等级(CR)对应的财宝生成规则实现。
设计心得 :使用纯JSON而非数据库,极大地降低了项目的复杂度和入门门槛。你不需要搭建任何后端服务,所有数据都是明文,方便调试和修改。但这种设计也意味着在高并发或数据量极大时可能存在性能瓶颈,不过对于单人/小规模游戏场景,这完全不是问题。
2.2 工具层:Go语言实现的模块化能力
数据是静态的,工具是动态的。SkillsWeaver用Go语言编写了十多个独立的命令行工具( sw-* ),每个工具负责一个非常具体的领域。这种“单一职责”的Unix哲学设计,带来了极高的灵活性和可测试性。
-
sw-dice: 骰子引擎。它不仅仅能解析“1d20”或“2d6+3”这样的标准表达式,还支持“4d6kh3”(投4个六面骰,取最高的3个)这种角色创建专用语法,以及优势/劣势投掷。其核心是一个健壮的表达式解析器。 -
sw-character: 角色管理器。它处理从属性生成(支持标准数组或4d6弃最低规则)、种族与职业加成计算,到技能选择、装备购买的完整流程。 -
sw-monster&sw-treasure: 游戏内容查询器。它们封装了官方数据,确保AI城主做出的每一个关于怪物强度或宝藏价值的判定,都有规则可依,而非随意编造。 -
sw-adventure: 冒险状态管理器。这是游戏会话的“保存/加载”系统,负责维护队伍、库存、日志和会话进度的完整性。 -
sw-image: 通过fal.ai的API,将文字描述转化为视觉图像。这对于增强沉浸感至关重要。
这些工具本身就可以在命令行中独立使用,为Claude Code的集成提供了坚实的基础。AI不需要“知道”如何生成一个角色,它只需要知道可以调用 sw-character create 这个命令,并传递正确的参数。
2.3 交互层:Claude Code技能与代理系统
这是项目的“魔法”所在。Claude Code允许开发者通过编写Markdown文件来定义“技能”和“代理”。SkillsWeaver巧妙地利用了这一机制。
- 技能(Skills) : 位于
.claude/skills/目录下。每个.md文件都是一个“说明书”,用自然语言告诉Claude:“当你遇到X类任务时,可以按Y步骤,调用Z工具。” 例如,dice-roller.md会详细说明各种骰子表达式格式,并给出调用sw-dice命令的示例。这相当于为AI编写了详细的API文档和使用手册。 - 代理(Agents) : 位于
.claude/agents/目录下。代理是更高级的、有“角色”设定的技能。最核心的是dungeon-master(地下城主)。这个代理文件定义了AI在游戏会话中应该扮演的角色(一个叙事者、规则仲裁者),它被授予了调用所有相关技能(骰子、怪物、日志等)的权限,并被灌输了游戏的基本目标和叙事风格。
当你在Claude Code中与AI对话时,Claude会读取这些技能和代理定义,理解自己可以做什么,并在对话中主动或在你的要求下,调用相应的Go工具来执行任务。这个过程是动态的、对话式的。例如,你说“我要创建一个精灵游侠”,Claude会启动 character-creator 代理,通过一系列问答引导你完成创建,并在后台调用 sw-character 工具将结果保存为JSON文件。
2.4 两种游戏模式:Web与CLI的哲学
SkillsWeaver提供了两种截然不同的前端体验,这反映了其设计上的双重目标:易用性与控制力。
-
sw-web(Web界面) : 这是为追求沉浸感和便捷性的玩家设计的。它基于Gin框架构建,提供了一个现代化的单页应用。其最大亮点是 自动化的战役规划 。你只需要提供一个冒险主题(如“科尔多瓦的魔法六分仪”),AI就能生成一个完整的三幕式战役结构,包括反派动机、关键伏笔和节奏安排。游戏过程中,所有交互通过Server-Sent Events实现实时流式响应,地图和图片直接内嵌在聊天界面中,体验接近一个轻量级的虚拟桌面。 -
sw-dm(命令行城主) : 这是为技术爱好者和追求纯粹AI交互的玩家设计的。它是一个独立的Go应用,直接调用Anthropic API,运行一个完整的智能体循环。它不依赖Claude Code的对话环境,而是自己维护会话状态、管理上下文(智能截断以避免token超限),并直接调用内部的Go工具包。这种模式剥离了Web UI的“包装”,让你直接与AI城主的“大脑”对话,响应更快,也更适合集成到其他自动化流程中。
核心考量 :
sw-web降低了使用门槛,将复杂性隐藏在友好的界面之后;而sw-dm则暴露了更多的控制力和透明度,适合那些想了解背后机制,或需要将其作为组件集成到更大系统中的开发者。项目同时维护这两条路径,展示了如何为不同受众提供适配的接口。
3. 从零开始:完整搭建与初体验指南
让我们抛开理论,亲手搭建一个SkillsWeaver环境,并创建第一个冒险。我会以macOS/Linux环境为例,Windows用户使用WSL或Git Bash可以获得类似体验。
3.1 环境准备与项目初始化
首先,你需要准备好三把钥匙:Go语言环境、Anthropic API密钥,以及可选的fal.ai密钥。
步骤一:安装Go语言 SkillsWeaver要求Go 1.25或更高版本。你可以通过包管理器安装:
# macOS
brew install go
# Ubuntu/Debian
sudo apt update
sudo apt install golang-go
# 验证安装
go version
确保你的 GOPATH 环境变量已正确设置,通常安装程序会自动处理。
步骤二:获取API密钥
- Anthropic API密钥(必需) : 访问 Anthropic Console ,注册并创建一个API密钥。
sw-dm(命令行城主)和sw-adventure enrich(日志增强)功能依赖于此。 - fal.ai API密钥(可选但推荐) : 访问 fal.ai ,注册后同样创建一个API密钥。这将用于在游戏过程中生成角色肖像、场景和战斗地图,极大提升沉浸感。
步骤三:克隆项目并设置环境变量
# 克隆项目到本地
git clone <skillsweaver仓库地址>
cd skillsweaver
# 设置环境变量(推荐写入你的shell配置文件,如 ~/.zshrc 或 ~/.bashrc)
export ANTHROPIC_API_KEY="sk-ant-xxx..." # 替换为你的真实密钥
export FAL_KEY="your_fal_key_here" # 如果使用图像生成
步骤四:构建所有工具 项目使用Makefile来简化构建过程。
# 一键构建所有命令行工具
make build
如果 make 命令不可用,你也可以手动构建所有工具:
go build -o sw-web ./cmd/web
go build -o sw-dm ./cmd/dm
go build -o sw-dice ./cmd/dice
# ... 以此类推,构建其他所有 cmd/ 下的工具
构建完成后,当前目录下会出现一系列 sw-* 的可执行文件。
3.2 创建你的第一个角色与冒险
现在,让我们创建一支冒险者小队并开启一段旅程。这里我演示最推荐的Web界面方式。
步骤一:启动Web服务器
./sw-web
默认情况下,服务器会监听 http://localhost:8085 。打开浏览器访问这个地址。
步骤二:通过Web界面创建冒险
- 在主页点击 “New Adventure” 按钮。
- 在表单中填写:
- Name :
翡翠溪谷的迷雾(给你的冒险起个名字) - Description :
一支冒险者小队被雇佣调查翡翠溪谷中突然出现的诡异迷雾,以及随之而来的村民失踪事件。(简要描述) - Theme (可选) :
一场古老的德鲁伊仪式失控,将山谷与妖精荒野的边界撕裂。当地的蜥蜴人族群试图利用这股力量,而幕后黑手是一位渴望自然力量的堕落贵族。(提供一个更详细的主题或梗概)
- Name :
- 点击 “Create” 。
幕后发生了什么? 当你提供“Theme”时,SkillsWeaver的Web后端会做一件非常酷的事情:它会调用Claude API,基于你的主题,自动生成一个结构化的 战役计划 ( campaign-plan.json )。这个计划通常包括:
- 三幕结构 :开端(调查迷雾)、转折(发现蜥蜴人阴谋)、高潮(对抗堕落贵族与修复边界)。
- 主要反派 :包括其动机、目标和角色弧光。
- 关键伏笔 :2-3个在故事早期埋下,在中后期回收的线索。
- 节奏预估 :预计需要多少游戏会话,每个阶段的大致时长。
- 重要地点与麦高芬 :如“仪式石阵”、“被污染的溪流源头”、“德鲁伊圣物”。
同时,系统会自动将 data/characters/ 目录下已有的任何角色模板复制到你的新冒险中,并初始化好 party.json , inventory.json 等所有必需的文件。
步骤三:创建或导入角色 如果 data/characters/ 目录是空的,你需要先创建角色。你可以:
- 在Web界面中手动创建 (如果未来功能支持)。
- 使用命令行工具快速创建 (更高效)。打开另一个终端,执行:
# 创建一个人类战士
./sw-character create "艾丹" --species=human --class=fighter --str=16 --dex=13 --con=15 --int=10 --wis=12 --cha=8
# 创建一个精灵游侠
./sw-character create "瑟兰" --species=elf --class=ranger --str=12 --dex=17 --con=14 --int=11 --wis=16 --cha=10
# 创建一个矮人牧师
./sw-character create "格隆" --species=dwarf --class=cleric --str=14 --dex=10 --con=16 --int=9 --wis=17 --cha=12
创建后,这些角色JSON文件会保存在 data/characters/ 下。 你需要刷新Web页面,或重新创建冒险 ,系统才会将这些新角色加入你的冒险队伍。
属性生成技巧 :D&D 5e官方推荐使用“标准数组”(15, 14, 13, 12, 10, 8)分配给六个属性。但很多老玩家喜欢用“4d6弃最低”来随机生成,追求角色的独特性。
sw-character工具支持后者,但需要你在创建时明确指定使用随机规则。对于新手,我建议先用标准数组,确保队伍平衡。
步骤四:开始游戏 回到Web界面,在你的冒险卡片上点击 “Play” 。你会进入游戏主界面。
- 左侧面板 :实时显示队伍状态(生命值、护甲等级、等级)、共享库存和最近的日志条目。
- 中央区域 :是与AI城主的对话界面。一个系统提示会首先出现,简要介绍战役计划和当前场景。
- 右上角 :模型选择器。你可以根据需求在Haiku(快速响应)、Sonnet(平衡)、Opus(最强叙事能力)之间切换。
现在,输入你的第一句话,例如:“艾丹握紧长剑,示意瑟兰和格隆保持警戒,我们沿着溪流边缘,向迷雾最浓处缓缓前进。”
按下回车,等待魔法发生。AI城主会开始流式输出它的回应,描述环境,可能还会主动进行一些感知检定,并将事件记录到日志中。
4. 核心机制深度解析与实战技巧
成功运行一次游戏后,你可能想深入了解其内部机制,以便更好地驾驭它,或进行自定义。下面我们来拆解几个最关键的部分。
4.1 AI城主的智能体循环是如何工作的?
无论是Web版的 sw-web 还是CLI版的 sw-dm ,其核心都是一个与Claude API交互的智能体循环。这个循环可以简化为以下步骤:
- 用户输入 :你输入一句话,如“我攻击左边的地精”。
- 上下文构建 :系统会将以下信息组合成一个提示(Prompt)发送给Claude:
- 系统指令 :定义AI扮演“地下城主”的角色,说明其职责(叙事、裁决规则、维护游戏乐趣)。
- 游戏状态 :当前冒险的元数据、队伍信息、库存、当前地点、以及最近若干条游戏日志(为了节省Token,会进行智能截断,保留最重要的部分)。
- 可用工具列表 :以结构化格式(如OpenAI的Function Calling格式)列出所有AI可以调用的工具及其参数说明(
roll_dice,get_monster,log_event等)。 - 用户消息 :你刚才输入的话。
- AI分析与决策 :Claude分析整个上下文,理解你的意图。它判断:“用户想进行攻击。攻击需要先进行攻击检定,命中后再投伤害。我需要调用
roll_dice工具两次,并查询地精(get_monster)的属性来确定是否命中以及计算伤害。最后,需要将这次攻击记录到日志(log_event)。” - 工具调用 :Claude的回复中会包含一个或多个“工具调用”请求。例如:
{ "tool_use": { "id": "attack_roll_1", "name": "roll_dice", "input": {"notation": "1d20+5"} } } - 工具执行 :SkillsWeaver的后端(Go程序)接收到这个请求,在本地调用对应的
sw-dice工具逻辑(注意,不是启动新进程,而是直接调用内部函数),得到结果(例如{“total”: 17, “rolls”: [12, 5]})。 - 结果返回与AI续写 :工具执行结果被附加到对话上下文中,再次发送给Claude。Claude看到“攻击检定=17”,结合之前查询到的地精护甲等级(AC)为13,判断命中,于是它决定调用
roll_dice投伤害骰(如1d8+3),然后根据伤害结果,生成一段叙事文本:“你的长剑划破空气,精准地命中地精的肩膀(命中17 vs AC 13)。随着一声闷响,你造成了8点穿刺伤害(1d8+3)。地精痛呼一声,向后踉跄了几步。” 同时,它可能还会调用log_event记录“艾丹对地精造成8点伤害”。 - 流式输出 :最终生成的叙事文本会以流式(Server-Sent Events)的方式实时传输到前端,让你看到一个字一个字蹦出来的效果,极具沉浸感。
性能与成本优化心得 :这个循环中,最耗时的部分是AI的思考(步骤3和6)。为了控制成本和延迟,SkillsWeaver做了几件事:1) 使用Haiku模型作为默认 :Haiku是Anthropic模型中最快、最便宜的,虽然创造力稍逊,但对于规则裁决和基础叙事足够用。你可以在Web界面手动切换到更强大的Sonnet或Opus。2) 上下文智能管理 :游戏日志会不断增长,不能全部发送。系统会优先保留最近的事件、关键剧情点(如遇到重要NPC)和战斗摘要,舍弃过于琐碎的描述。3) 工具设计的精确性 :工具的定义(名称、参数描述)必须极其清晰,避免AI误解或进行不必要的调用,每一次工具调用都意味着额外的Token消耗。
4.2 数据文件结构与自定义扩展
SkillsWeaver的强大之处在于其数据驱动设计。几乎所有游戏内容都来自可编辑的JSON文件,这意味着你可以轻松地修改或扩展这个世界。
自定义一个怪物 : 打开 data/monsters.json ,你会发现它是一个怪物对象的数组。想添加一个自己设计的BOSS“暗影编织者”吗?复制一个现有怪物(比如“法师”)的JSON结构,然后修改它:
{
"name": "暗影编织者",
"size": "中型",
"type": "类人生物",
"alignment": "混乱邪恶",
"armor_class": 15,
"hit_points": 120,
"speed": "30尺",
"strength": 10,
"dexterity": 18,
"constitution": 14,
"intelligence": 16,
"wisdom": 12,
"charisma": 17,
"challenge_rating": 5,
"actions": [
{
"name": "暗影触须",
"desc": "近战法术攻击,命中+7,触及10尺,单一目标。命中:14 (2d8+5) 点暗影伤害,且目标的下一次攻击检定具有劣势。"
},
{
"name": "编织恐惧(充能5-6)",
"desc": "暗影编织者释放出一圈恐惧灵光。30尺内每个它可见的生物必须进行一次DC15的感知豁免,豁免失败者将陷入恐惧状态1分钟。"
}
],
"legendary_actions": [
{
"name": "阴影步",
"desc": "暗影编织者传送到30尺内一个它能看到的、未被占据且处于微光或黑暗环境的空间。"
}
]
}
保存文件后,重启你的游戏会话(或重新加载工具),AI城主就能在战斗中生成或调用这个全新的怪物了。 sw-monster 工具会直接从这份JSON数据中读取信息。
创建你自己的世界王国 : 同理,你可以编辑 data/world/factions.json ,添加第五个王国。定义它的文化、政体、主要种族和与现有势力的关系。当你通过 sw-character 创建角色时,就可以选择这个新的出身地,AI城主在叙事中也会引用这些背景信息,让故事更具深度。
扩展性警告 :修改数据文件时,请务必保持JSON格式的正确性。一个多余的逗号或缺失的引号都可能导致整个工具无法读取该文件。建议使用能校验JSON格式的编辑器(如VSCode)。另外,对于大型修改,最好先备份原文件。
4.3 图像生成与日志增强的协同工作流
sw-image 和 sw-adventure enrich 是两个能极大提升游戏后期体验的工具,它们构成了一个自动化的工作流。
第一阶段:日志增强 在游戏过程中,日志条目( log_event )可能比较简略,比如“队伍在酒馆遇到了神秘人”。 sw-adventure enrich 命令会扫描这些条目,对没有详细描述( description 字段)的条目,调用Claude Haiku模型来生成一段 双语描述 。
# 为“翡翠溪谷的迷雾”这个冒险的所有日志条目生成描述
./sw-adventure enrich "翡翠溪谷的迷雾"
AI会生成类似这样的内容:
📝 EN: Aldric, Lyra, and Thorin cautiously enter the fog-shrouded valley, the ancient standing stones humming with a faint, unnatural energy. The air is thick with the scent of damp earth and ozone.
📝 FR: Aldric, Lyra et Thorin pénètrent avec prudence dans la vallée enveloppée de brouillard, les pierres levées anciennes vibrant d'une énergie faible et contre-nature. L'air est chargé de l'odeur de terre humide et d'ozone.
英文描述用于后续的图像生成提示词,法文描述(或其他目标语言)则用于游戏内的阅读。这个过程是增量且低成本的,Haiku模型足以胜任这种描述性任务。
第二阶段:图像生成 有了丰富的英文描述, sw-image 就可以大显身手了。
# 为增强后的日志生成图像
./sw-image journal "翡翠溪谷的迷雾"
这个命令会:
- 读取冒险目录下所有日志条目。
- 筛选出那些带有英文描述(
description_en)的条目。 - 为每一条描述,调用fal.ai的API生成一张图片。
- 将图片保存在
data/adventures/<冒险名>/images/目录下,并以会话和条目编号命名。
在Web界面中,当你回顾游戏日志时,这些图片会自动显示在对应的条目旁,将文字记忆转化为视觉记忆,极大地增强了故事的沉浸感和回味价值。
成本控制技巧 :fal.ai的
schnell模型速度快、成本低(约$0.003/张),适合批量生成初稿。banana模型质量更高,但也贵十倍以上。我的建议是:先用--dry-run预览哪些条目会生成图片,然后用schnell模型全部生成。对于其中特别关键的场景(如BOSS战、重大剧情转折),再手动用banana模型重新生成一次,替换掉原来的图片。这样能在质量和成本间取得很好的平衡。
5. 高级用法与自定义开发指南
当你熟悉了基本操作后,可能会不满足于现有功能,想要进行更深入的定制或集成。SkillsWeaver的模块化设计为此提供了可能。
5.1 集成到自己的应用或聊天机器人中
sw-dm 的核心是一个Go包( internal/agent/ ),你可以将其作为一个库集成到你自己的Go项目中。假设你想开发一个Discord机器人版的城主:
package main
import (
"fmt"
"log"
"github.com/bwmarrin/discordgo"
"skillsweaver/internal/agent" // 假设SkillsWeaver的agent包已模块化
"skillsweaver/internal/adventure"
)
var dmAgent *agent.Agent
func main() {
// 1. 初始化城主智能体
adv, err := adventure.Load("my-adventure")
if err != nil {
log.Fatal(err)
}
dmAgent, err = agent.NewDungeonMasterAgent(adv, "claude-3-haiku-20241022")
if err != nil {
log.Fatal(err)
}
// 2. 创建Discord会话
dg, err := discordgo.New("Bot " + "YOUR_TOKEN")
if err != nil {
log.Fatal(err)
}
dg.AddHandler(messageCreate)
err = dg.Open()
if err != nil {
log.Fatal(err)
}
defer dg.Close()
<-make(chan struct{})
}
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
if m.Author.ID == s.State.User.ID {
return
}
// 假设我们在一个特定频道进行游戏
if m.ChannelID != "GAME_CHANNEL_ID" {
return
}
// 3. 将用户消息发送给城主智能体
response, err := dmAgent.ProcessMessage(m.Content)
if err != nil {
s.ChannelMessageSend(m.ChannelID, "城主陷入了沉思(出错): "+err.Error())
return
}
// 4. 将城主的回复发送回Discord频道
// 注意:这里response可能包含工具调用的中间结果,需要处理
// 简化处理,只发送最终叙事文本
s.ChannelMessageSend(m.ChannelID, response.NarrativeText)
}
这个例子展示了如何将 sw-dm 的“大脑”剥离出来,嵌入到任何需要AI城主功能的Go程序中。你需要处理更复杂的对话状态、工具调用结果的回调以及可能的多用户并发问题。
5.2 开发一个新的技能或工具
SkillsWeaver的生态是开放的。如果你想添加一个新功能,比如一个“随机遭遇生成器”,你需要两步:
第一步:创建Go工具 在 cmd/ 目录下创建一个新的文件夹,例如 cmd/encounter/ ,并编写 main.go :
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"math/rand"
"time"
)
type Encounter struct {
Environment string `json:"environment"`
Difficulty string `json:"difficulty"` // easy, medium, hard, deadly
Monsters []string `json:"monsters"`
Description string `json:"description"`
}
func main() {
env := flag.String("env", "forest", "Environment (forest, dungeon, urban, etc.)")
level := flag.Int("level", 1, "Average party level")
flag.Parse()
rand.Seed(time.Now().UnixNano())
// 这里可以调用 internal/monster 包来根据环境和等级筛选怪物
// 简化示例:
encounter := generateEncounter(*env, *level)
output, err := json.MarshalIndent(encounter, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(output))
}
func generateEncounter(env string, level int) Encounter {
// 实际的生成逻辑...
return Encounter{
Environment: env,
Difficulty: "medium",
Monsters: []string{"Goblin", "Wolf"},
Description: fmt.Sprintf("A group of goblins riding wolves ambushes you in the %s.", env),
}
}
然后在项目根目录的 go.mod 文件中确保模块路径正确,并运行 go build -o sw-encounter ./cmd/encounter 进行构建。
第二步:为Claude Code创建技能文件 在 .claude/skills/ 目录下创建 encounter-generator.md :
# Encounter Generator Skill
When the user wants to generate a random encounter for their D&D 5e game, you can use this skill.
## Usage
Call the `sw-encounter` command with the following parameters:
- `--env`: The environment (forest, dungeon, urban, mountain, etc.)
- `--level`: The average level of the player party (default: 1)
## Examples
- User says: "Generate a random encounter for a level 3 party in a dungeon."
- You should execute: `sw-encounter --env=dungeon --level=3`
- User says: "We're traveling through the forest, what might we meet?"
- You should execute: `sw-encounter --env=forest` (assumes party level 1)
## Output
The command outputs a JSON object describing the encounter, including suggested monsters and a narrative hook.
现在,当你在Claude Code中说“为我们在山脉中旅行的5级队伍生成一个随机遭遇”,Claude就会识别到这个技能,并调用你新编写的 sw-encounter 工具。
5.3 性能调优与故障排除
随着冒险的进行,日志文件会越来越大,这可能会导致两个问题:1) 加载速度变慢;2) 发送给AI的上下文Token数超标。以下是一些应对策略:
问题一:Web界面加载冒险列表或游戏时变慢
- 原因 :每次加载都需要读取并解析所有冒险目录下的JSON文件。
- 解决方案 :可以考虑为
sw-web添加一个简单的缓存层。例如,在内存中维护一个map[string]*AdventureSummary,只在文件更改时更新。对于个人使用,更简单的方法是定期归档旧的、已完成的冒险,将其移动到备份位置,减少data/adventures/目录下的活动项目数量。
问题二:AI响应变慢或出错,提示上下文过长
- 原因 :游戏日志(
journal-session-*.json)无限制增长,最终会超过Claude模型的最大上下文窗口(如Haiku-3.5的200K Token)。 - 解决方案 :
sw-dm和sw-web的后端已经实现了基础的上下文管理(internal/agent/context.go中的TruncateContext函数)。它的策略通常是:- 保留最近N条日志(例如最近20条)。
- 保留标记为“重要”的日志条目(如“遇到最终BOSS”、“获得关键道具”)。
- 对更早的日志,生成一个高度概括的摘要(例如“之前,队伍探索了地牢第一层,击败了若干哥布林,发现了通往第二层的密门”)。 你可以通过调整这些策略的参数来优化。例如,在长时间战役中,你可以修改代码,增加摘要的频率和精度。
问题三:图像生成失败或质量不佳
- 检查fal.ai密钥 :确保
FAL_KEY环境变量设置正确,并且账户有余额。 - 调整提示词 :
sw-image工具内部会将日志的英文描述转换为图像生成提示词。如果生成的图片总是偏离预期,你可以手动编辑journal-session-*.json文件,修改特定条目的description_en字段,使其更具体、更具画面感。例如,将“他们进入了一个房间”改为“三位冒险者举着火把,踏入一个布满灰尘、蛛网密布的圆形石室,中央有一个雕刻着诡异符文的神坛”。 - 切换模型 :如前所述,在速度和质量之间权衡。对于重要的场景,手动使用
sw-image指定--model=banana重新生成。
6. 项目理念、局限性与未来展望
SkillsWeaver不仅仅是一个工具,它代表了一种人机协作进行创意工作的范式。它将AI定位为“副驾驶”或“游戏引擎”,而非取代人类的“玩家”。人类玩家负责提出目标、做出关键决策、注入情感;AI则负责处理繁琐的规则计算、维护一致性、提供无穷的叙事可能性和内容生成。这种分工充分发挥了双方的优势。
然而,它也有其局限性:
- 对规则的机械性遵循 :AI城主严格依赖预设的JSON数据和工具,它无法像人类城主那样灵活地“无视规则”或进行超越规则的即兴创作来服务于更好的故事。一切必须“有据可依”。
- 叙事深度的天花板 :尽管Claude模型很强大,但其叙事仍可能陷入套路,或难以维持一个跨越多个会话的、有深度的角色弧光。它更擅长处理“场景”而非“史诗”。
- 技术门槛 :虽然Web界面降低了使用门槛,但初始的搭建、环境配置、API密钥管理以及对TRPG规则的基本了解,仍然将一部分纯休闲用户挡在门外。
对于想要借鉴此项目思路的开发者,我的建议是: 聚焦于定义清晰的、可工具化的领域 。SkillsWeaver的成功在于它将TRPG这个庞大领域,拆解成了掷骰、角色、怪物、物品、叙事等一个个边界清晰、输入输出明确的子问题。对于你想用AI解决的任何复杂问题,都可以尝试进行类似的“工具化”分解,然后为每个子问题编写一个可靠的、可测试的小工具或函数,最后用AI的“技能”系统将它们粘合起来。这样构建的系统,比试图让AI一次性解决所有问题要可靠、可控得多。
最后,这个项目本身也在快速进化。从最初仅支持基础奇幻RPG,到完全转向D&D 5e,再到加入Web界面和自动战役规划,它的功能越来越丰富,体验也越来越流畅。未来,我们或许可以期待更强大的世界状态管理、更智能的NPC对话系统(而不仅仅是生成静态卡片),甚至与其他虚拟桌面软件(如Foundry VTT)的集成。无论怎样,SkillsWeaver已经为我们点亮了一条道路,展示了AI作为复杂系统协调者的巨大潜力。
更多推荐



所有评论(0)