1. 项目概述当AI智能体成为你的爬塔队友如果你是一位《杀戮尖塔2》Slay the Spire 2 以下简称STS2的硬核玩家同时又对AI技术充满好奇那么你很可能已经厌倦了在“重开”与“学习”之间反复横跳。每一局爬塔都是一次复杂的决策树遍历从卡牌选择、遗物搭配到战斗中的能量分配、目标优先级每一个环节都充满了变数。现在想象一下你有一个永不疲倦、能瞬间分析所有可能性的“超级大脑”作为你的队友它会是什么样子CharTyr/STS2-Agent项目正是这样一个将幻想变为现实的桥梁。它不是一个外挂也不是一个简单的脚本而是一个结构精巧的“AI智能体集成框架”。其核心由两部分构成一个注入到STS2游戏进程中的MODSTS2AIAgent以及一个遵循MCPModel Context Protocol标准的服务器mcp_server。MOD负责“感知”游戏世界实时抓取每一帧的游戏状态——包括你的手牌、敌人的意图、场上的增益减益、地图节点信息等并通过一个本地的HTTP API默认在127.0.0.1:8080暴露出来。而MCP服务器则扮演“翻译官”和“调度员”的角色它将这个原始的HTTP API包装成一套标准化、结构化的工具Tools使得任何支持MCP协议的AI客户端例如Claude Desktop、Cursor AI、甚至是你可以编程调用的自定义客户端都能像调用本地函数一样读取游戏状态并下达“出这张牌”、“移动到下一个节点”、“购买这个遗物”等指令。简单来说这个项目为STS2这个单机游戏打开了一扇“自动化”与“AI辅助决策”的大门。它适合以下几类人一是希望用AI来测试自己游戏策略极限的硬核玩家二是对游戏AI、强化学习感兴趣想以STS2为沙盒环境进行算法研究的开发者三是想要打造个性化游戏助手实现半自动爬塔或数据收集的技术爱好者。通过这个项目你不再仅仅是游戏的参与者更成为了游戏规则的观察者与交互架构的设计者。2. 核心架构与设计思路拆解2.1 为什么是“MOD MCP Server”的双层架构这个设计是项目成功的关键它清晰地分离了关注点并充分利用了现有生态。2.1.1 MOD层游戏内部的“传感器”与“执行器”MODSTS2AIAgent.dll是直接与游戏引擎Unity交互的部分。它的首要任务是“无侵入”或“低侵入”地获取游戏内存中的数据。对于像STS2这样逻辑复杂的游戏直接通过内存地址读取状态是极其脆弱且容易随游戏更新而失效的。因此一个更稳健的做法是利用游戏原有的Mod支持框架如果存在或者通过Harmony等库对游戏方法进行“织入”Hook在游戏逻辑执行的关键节点如回合开始、卡牌打出后、伤害计算时截获数据。这个MOD的核心功能是状态暴露将游戏内部复杂的、面向渲染和逻辑的对象模型序列化为结构化的JSON数据。这不仅仅是简单的数据转储它需要做大量的“语义化”工作。例如将“敌人意图”从内部的枚举值翻译成“攻击”、“防御”、“施加虚弱”等可读描述并计算出预期的伤害数值。动作抽象将玩家的操作点击、拖拽抽象为一套原子性的API指令。比如/play_card接口需要接收卡牌ID、目标ID等参数MOD在内部将其转换为模拟一次鼠标点击和拖放事件或者直接调用游戏内部的出牌函数。HTTP服务提供一个轻量级的Web服务器。选择HTTP协议而非更底层的TCP或IPC极大地降低了外部程序连接的复杂性。任何能发送HTTP请求的工具如curl、Postman、Python的requests库都能立即与游戏交互便于调试和快速验证。2.1.2 MCP Server层生态系统的“适配器”如果只有HTTP API那么每次想要让AI比如Claude来玩游戏你都需要写一大堆胶水代码来告诉AI每个API的用法、参数格式、返回结构。这非常低效且容易出错。MCPModel Context Protocol是由Anthropic提出的一种开放协议旨在标准化AI模型与外部工具、数据源之间的交互方式。你可以把它想象成AI世界的“USB标准”。一个MCP Server对外提供一组定义清晰的Tools工具和Resources资源。sts2-mcp-server的作用就是工具封装将/game_state、/legal_actions、/play_card等HTTP端点包装成MCP标准的Tool。每个Tool都有严格的输入输出JSON Schema描述。AI客户端在连接时会一次性获取所有可用的Tool定义之后就可以像调用函数一样使用它们完全无需关心底层的网络通信。协议转换处理MCP的stdio或HTTP传输层。stdio模式允许AI客户端如Claude Desktop以子进程方式启动MCP Server通过标准输入输出进行通信集成度最高。HTTP模式则提供了网络灵活性允许远程连接或多客户端连接。提供上下文除了动态的游戏状态MCP Server还可以将静态的游戏元数据如所有卡牌的完整描述、所有遗物的效果、所有敌人的行为模式作为Resources提供给AI。这相当于给了AI一本完整的游戏百科全书使其决策基础更加牢固。这种双层架构的优势在于MOD层保持轻量和专注只负责与游戏对话MCP Server层负责与AI生态对话。任何支持MCP的新AI客户端出现都能立即与这个项目兼容无需修改MOD代码。这种设计极大地提升了项目的可扩展性和生命周期。2.2 关键特性事件驱动与状态轮询的权衡在实时交互系统中一个核心问题是AI如何知道游戏状态发生了变化项目文档提到了“reducing polling through SSE events”这指向了两种典型的模式。轮询PollingAI客户端每隔一个固定时间比如100毫秒就主动调用一次get_game_state工具来获取最新状态。这种方式实现简单但会产生大量无效请求尤其在游戏动画播放、玩家思考等状态未变化的时段浪费资源且可能给游戏带来不必要的性能压力。事件驱动Event-Driven游戏状态一旦发生重要变化如回合结束、新敌人出现、获得新卡牌MOD主动通过Server-Sent Events (SSE) 向MCP Server推送一个事件。AI客户端可以订阅这个事件流仅在状态真正更新时才被唤醒进行处理。这种方式更高效、更实时。从项目描述看它很可能采用了混合模式MCP Server通过SSE从MOD获取事件通知从而知道何时该去主动拉取poll新的完整状态。这是一种最佳实践既保证了响应的实时性又避免了高频轮询的 overhead。对于AI Agent的设计者而言理解这一点至关重要你的Agent不应该在一个死循环里疯狂轮询而应该设计成事件监听模式在收到“turn_start”事件后才开始规划本回合操作在收到“card_played”事件后更新内部状态模型。3. 从零开始环境部署与核心配置详解3.1 MOD安装不仅仅是复制粘贴虽然快速指南列出了步骤但其中隐藏着许多新手容易踩坑的细节。3.1.1 定位准确的游戏目录对于Steam版游戏默认路径通常是正确的。但如果你使用了Steam库文件夹转移、或者通过其他平台如GOG购买游戏路径可能不同。一个万无一失的方法是在Steam库中右键点击《Slay the Spire 2》。选择“管理” - “浏览本地文件”。这将直接打开正确的游戏根目录。3.1.2 理解mods/目录的机制STS2很可能使用了与一代类似的Mod加载机制。mod_id.json文件是这个MOD的“身份证”游戏启动时会扫描mods/文件夹下的所有此类文件然后加载对应的.dllWindows或.soLinux文件。关键点在于你必须确保三个文件直接位于mods/下而不是在一个子文件夹里。错误的放置方式如mods/STS2AIAgent/STS2AIAgent.dll会导致Mod加载失败。3.1.3 验证MOD加载成功启动游戏后访问http://127.0.0.1:8080/health。如果返回一个包含status: ok的JSON恭喜你MOD运行正常。如果无法连接请按顺序排查游戏是否真正启动请确认游戏窗口已经出现并过了初始加载画面。有时启动器进程和游戏进程是分开的。防火墙拦截Windows Defender或第三方防火墙可能会阻止本地回环地址127.0.0.1的特定端口。首次运行时请留意是否有防火墙弹窗询问是否允许SlayTheSpire2.exe访问网络。端口冲突8080端口可能被其他程序占用。你可以查看MOD的配置文件如果有的话或源代码看是否可以修改默认端口。通常这类信息会在config.json或环境变量中设置。3.2 Python环境与uv工具链的搭建项目推荐使用uv这是一个用Rust写的、速度极快的Python包管理器和运行器。它解决了传统pip和venv的诸多痛点如依赖解析慢、环境隔离繁琐等。3.2.1 安装Python 3.11确保你的Python版本符合要求。在命令行输入python --version或python3 --version查看。如果版本过低建议从Python官网下载安装。重要提示在Windows上安装时务必勾选“Add Python to PATH”否则后续命令可能找不到Python。3.2.2 安装并配置uv按照文档的命令安装即可。安装完成后一个很好的实践是配置uv的镜像源以加速国内下载。你可以设置环境变量# Linux/macOS export UV_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple export UV_PIP_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple # Windows (PowerShell) $env:UV_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple $env:UV_PIP_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple或者在项目目录下创建一个.env文件写入上述内容。这能显著提升依赖安装速度。3.2.3 启动MCP Server的两种模式项目提供了两种启动脚本对应MCP的两种传输方式start-mcp-stdio.sh/ps1启动stdio模式。这是与桌面AI客户端如Claude Desktop集成的推荐方式。该脚本会使用uv run启动MCP Server并将其输入输出连接到标准流。当你在Claude Desktop的设置中添加此MCP Server时实际上就是配置它执行这个启动脚本。start-mcp-network.sh/ps1启动HTTP模式。这会启动一个监听在http://127.0.0.1:8765的服务器。任何能发送HTTP请求的客户端包括你自己写的脚本、Postman、或者支持HTTP MCP的AI客户端都可以连接。这种方式更适合调试、多客户端连接或远程连接场景。实操心得初次接触时建议先使用HTTP模式进行测试。你可以用简单的cURL命令来验证服务器是否工作curl -X POST http://127.0.0.1:8765/mcp \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 1, method: tools/list, params: {} }如果返回一个包含所有工具定义的JSON列表说明MCP Server运行成功且协议通信正常。4. 核心功能实操打造你的第一个STS2 AI Agent4.1 理解MCP工具集AI的“游戏手柄”连接上MCP Server后AI客户端会获得一套工具。根据项目文档这套工具至少涵盖以下核心领域状态读取工具如get_game_state。这是最重要的工具返回一个庞大的JSON对象包含run当前运行信息如生命、金币、药水、地图路径、combat战斗状态如玩家能量、手牌、抽牌堆、弃牌堆、耗牌堆、敌人列表及意图、screen当前游戏处于哪个界面如战斗、地图、商店、宝箱、事件等。动作查询工具如get_legal_actions。在给定当前状态下返回所有可执行的操作列表。例如在战斗中可能返回[{type: play_card, card_id: strike, target: enemy_0}, {type: end_turn}]。这比让AI去解析完整状态再推断合法动作要可靠得多。动作执行工具一系列工具如play_card,end_turn,choose_map_path,purchase_item,choose_event_option等。每个工具都需要特定的参数如card_id,target。元数据查询工具如get_card_metadata,get_relic_metadata。这些工具提供静态数据帮助AI理解“打击”这张牌的基础伤害是多少“蛇眼”这个遗物有什么效果。注意事项AI在决策时必须先调用get_legal_actions然后从返回的列表中选择一个动作来执行。直接根据状态“想象”出一个动作并调用执行工具很可能会因为动作非法而失败。这是设计AI决策循环时的铁律。4.2 构建一个简单的回合制战斗AI让我们设想一个最简单的AI一个只会出攻击牌的打脸机器人。它的决策逻辑可以这样实现以伪代码描述# 伪代码简单攻击AI决策循环 while game_is_in_combat: # 1. 获取当前游戏状态 state call_tool(get_game_state) # 2. 检查是否是我的回合player_turn 为 true if not state.combat.player_turn: wait_for_event(turn_start) # 等待事件通知 continue # 3. 获取当前所有合法动作 legal_actions call_tool(get_legal_actions) # 4. 过滤出“出牌”动作并优先选择攻击牌 play_actions [a for a in legal_actions if a.type play_card] attack_actions [] for action in play_actions: card_meta call_tool(get_card_metadata, {id: action.card_id}) if 攻击 in card_meta.keywords or card_meta.type ATTACK: # 假设有关键字 attack_actions.append(action) # 5. 执行动作有攻击牌则打出第一张否则结束回合 if attack_actions: target_action attack_actions[0] # 可能需要选择目标这里简单选第一个敌人 if target_action.needs_target: target_action.target state.combat.enemies[0].id call_tool(play_card, target_action) else: call_tool(end_turn) # 6. 短暂等待避免请求过快 sleep(0.1)这个AI虽然简单但已经包含了核心循环获取状态 - 检查合法性 - 决策 - 执行 - 等待反馈。在实际项目中你会用更复杂的策略如价值网络、规则引擎、大语言模型提示来替换第4步的决策逻辑。4.3 利用SSE事件优化AI响应如前所述轮询get_game_state是低效的。更优雅的方式是让AI客户端订阅MCP Server提供的事件流。虽然项目文档没有给出具体的事件列表但我们可以推断出可能的事件类型game_state_updated: 通用状态更新。turn_start: 玩家回合开始。turn_end: 玩家回合结束。card_played: 一张牌被打出。combat_end: 战斗结束。在支持SSE的客户端中你的AI可以这样工作# 伪代码基于事件的AI import asyncio async def event_listener(): async for event in subscribe_to_sse(http://localhost:8765/events): if event.type turn_start: # 回合开始触发决策流程 asyncio.create_task(make_decision()) elif event.type card_played: # 更新内部状态模型 update_internal_state(event.data) # ... 处理其他事件 async def make_decision(): # 这里是你的核心决策逻辑同上一节的循环体但只在收到事件后触发 legal_actions await call_tool(get_legal_actions) # ... 决策并执行 # 启动事件监听和决策循环 asyncio.run(event_listener())这种方式将AI从繁忙的轮询中解放出来使其行为更贴近真实玩家的“事件-反应”模式同时也大幅降低了系统负载。5. 高级应用与自定义开发指南5.1 集成大型语言模型LLM作为决策核心MCP的魅力在于它能无缝对接各种AI。你可以将Claude、GPT-4等LLM作为决策大脑。基本流程如下系统提示词设计这是最关键的一步。你需要给LLM一个清晰的角色定义和游戏规则。你是一个《杀戮尖塔2》的专家玩家。你将通过一系列工具与游戏交互。 游戏状态会以JSON格式提供给你。你的目标是赢得每一场战斗并尽可能高效地通关。 在每一轮你的回合中请遵循以下步骤 1. 使用get_game_state工具获取当前状态。 2. 使用get_legal_actions工具了解你能做什么。 3. 分析状态计算伤害、评估威胁、规划能量使用。 4. 从合法动作中选择你认为最优的一个并使用对应的工具执行它如play_card。 5. 重复直到你的回合结束。 记住不要假设任何游戏规则所有信息都从工具调用中获得。上下文管理LLM有token限制。你不能每次都把完整的游戏状态可能很大塞给它。需要设计一个“状态摘要”函数从完整的game_state中提取最关键的信息如玩家血量、能量、手牌简述、敌人血量及意图以简洁的文本形式提供给LLM。工具调用使用支持“Function Calling”或“Tool Use”的LLM API如OpenAI的gpt-4-turbo或Anthropic的Claude 3。将MCP Server提供的工具列表以JSON Schema格式传给LLM。LLM会在回复中指定它想调用哪个工具以及参数是什么由你的客户端程序负责解析并实际调用MCP工具然后将结果返回给LLM进行下一步推理。记忆与规划简单的回合制决策可能不需要长期记忆但对于跨回合的策略如保留一张关键牌到下回合、跨房间的路线选择LLM需要记住之前发生的事。这可以通过在对话历史中保留关键摘要来实现或者引入更复杂的向量数据库来存储游戏历史片段。5.2 构建分层智能体与技能系统项目仓库中有一个skills/目录这暗示了更高级的架构可能性分层智能体。底层技能封装原子操作。例如一个“计算最优攻击序列”的技能输入是手牌、能量、敌人血量输出是一套出牌顺序。另一个“评估遗物价值”的技能专门用于商店购买决策。中层管理器根据当前游戏阶段战斗、地图、商店、事件调用相应的技能。战斗管理器调用战斗技能商店管理器调用评估技能。高层控制器负责最顶层的目标制定和资源分配。例如“本局游戏目标是走最大化精英怪的路线来获取遗物”或者“当前血量危险优先选择篝火路径恢复”。你可以利用MCP Server作为这些技能的统一执行后端。每个技能都是一个独立的模块它们通过调用标准的MCP工具来感知和行动。这种架构使得AI系统更模块化、更易维护和调试。5.3 从零构建自定义MCP客户端如果你想完全掌控AI逻辑或者进行强化学习训练你可能需要构建自己的MCP客户端。这个过程并不复杂建立连接根据MCP Server的模式stdio或HTTP建立相应的通信通道。初始化发送initialize请求协商协议版本。列出工具发送tools/list请求获取所有可用工具的定义。主循环 a. 调用get_game_state。 b. 你的自定义AI算法可以是规则引擎、神经网络、搜索树根据状态计算出一个动作意图。 c. 调用get_legal_actions验证该意图是否合法或直接从合法动作中选择。 d. 调用对应的工具执行动作。 e. 等待下一次状态更新通过轮询或SSE事件。使用Python一个极简的HTTP模式客户端框架如下import requests import json class STS2MCPClient: def __init__(self, server_urlhttp://127.0.0.1:8765/mcp): self.url server_url self.request_id 1 def call(self, method, paramsNone): payload { jsonrpc: 2.0, id: self.request_id, method: method, params: params or {} } self.request_id 1 response requests.post(self.url, jsonpayload).json() if error in response: raise Exception(fRPC Error: {response[error]}) return response.get(result) def get_tools(self): return self.call(tools/list) def call_tool(self, tool_name, arguments): return self.call(tools/call, {name: tool_name, arguments: arguments}) # 封装具体工具 def get_game_state(self): return self.call_tool(get_game_state, {}) def play_card(self, card_id, targetNone): args {card_id: card_id} if target: args[target] target return self.call_tool(play_card, args) # ... 封装其他工具 # 使用客户端 client STS2MCPClient() state client.get_game_state() print(f当前生命值: {state[run][current_hp]})有了这个基础客户端你就可以在其中集成任何你想要的AI算法了。6. 故障排查、性能优化与注意事项6.1 常见问题与解决方案速查表问题现象可能原因排查步骤与解决方案访问http://127.0.0.1:8080/health无响应1. MOD未正确安装。2. 游戏未启动。3. 防火墙/杀软拦截。4. 端口冲突。1. 检查mods/目录下三个文件是否齐全且直接放置。2. 确认游戏进程已完全启动。3. 暂时关闭防火墙/杀软测试或添加出入站规则。4. 使用netstat -ano | findstr :8080(Win) 或lsof -i :8080(macOS/Linux) 查看端口占用。MCP Server启动失败提示Python或uv错误1. Python未安装或版本过低。2. uv未安装或不在PATH。3. 项目依赖安装失败。1. 确认python --version 3.11。2. 重新安装uv并确认命令行可执行uv --version。3. 在mcp_server/目录下尝试手动运行uv sync安装依赖。检查网络或配置镜像源。MCP Server能启动但调用工具返回“连接游戏失败”1. MOD的HTTP服务未运行。2. MCP Server配置的MOD地址错误。1. 首先确保/health端点可访问。2. 检查MCP Server的配置文件或环境变量如STS2_AGENT_URL确认其指向正确的http://127.0.0.1:8080。AI执行动作后游戏无反应1. 动作非法如目标错误、能量不足。2. 游戏处于动画状态不接受输入。3. 网络延迟或请求丢失。1.务必在执行前调用get_legal_actions进行验证。2. 在AI逻辑中加入等待。例如执行动作后等待一段时间或等待特定事件如card_played后再进行下一步。3. 增加简单的重试和错误处理逻辑。游戏运行卡顿或出现异常1. AI请求频率过高给游戏造成负担。2. MOD存在内存泄漏或性能问题。3. 与其它MOD冲突。1.最重要的优化降低轮询频率改用事件驱动。在非关键时段如敌人动画添加休眠如time.sleep(0.2)。2. 关注游戏和MOD的更新日志。3. 尝试在纯净游戏环境下无其他MOD运行测试。6.2 性能优化要点减少不必要的状态获取get_game_state返回的数据量可能很大。如果你的AI只关心战斗那么在非战斗界面如地图可以减少调用频率或者只获取部分字段如果MCP Server支持。利用本地缓存静态元数据卡牌、遗物信息在一次游戏会话中不会改变。可以在AI客户端启动时一次性获取并缓存避免重复调用get_card_metadata等工具。设计高效的决策间隔不要试图在每一帧都做决策。人类玩家也有反应时间。设定一个合理的决策周期如每秒2-5次决策并在游戏动画期间主动暂停决策循环。日志与监控为你的AI客户端添加详细的日志功能记录每一个状态、决策和结果。这不仅能帮你调试逻辑错误还能分析AI的决策质量。可以记录每回合用时、平均伤害输出、胜率等指标。6.3 伦理、合规与社区准则并非外挂请将此项目视为一个“研究辅助工具”或“自动化测试框架”。它的目的是理解和探索游戏机制而不是在多人游戏或排行榜中获取不公平优势。STS2是纯单机游戏这降低了相关风险但仍应秉持尊重游戏设计者和社区的态度。尊重开源协议该项目采用AGPL-3.0协议。这意味着如果你修改了项目代码并部署了网络服务你有义务开源你的修改。在基于此项目进行二次开发或集成时请仔细阅读许可证条款。关注游戏更新游戏更新可能会修改内部数据结构导致MOD失效。关注项目的GitHub仓库维护者通常会及时更新。在游戏更新后如果MOD失效应耐心等待更新而非尝试破解或使用过时版本。分享与贡献如果你改进了AI策略、修复了bug或增加了新功能考虑向原项目提交Pull Request。开源社区的力量正是来自于此。这个项目打开了一扇门门后是游戏与AI交叉的广阔领域。你可以用它来实践软件集成、智能体架构设计也可以深入游戏策略的算法求解。最重要的是动手尝试从让AI打出一张“打击”开始逐步构建起能征服高进阶难度的智能体。在这个过程中你收获的将远不止是游戏通关的成就感。