Hotdry.
ai-systems

基于 REST API 网关与状态机的多 AI 代理并行决策 SimCity 模拟架构

探讨如何通过 REST API 网关将经典 SimCity 模拟暴露为 headless 服务,利用 Cloudflare Durable Objects 实现状态机,支持多 AI 代理并行决策与游戏状态同步的工程化实现。

将经典城市模拟游戏 SimCity 转化为一个可供多 AI 代理并行操作的实验平台,是当前 AI 系统架构中的一个有趣挑战。本文以 Hallucinating Splines 项目为例,阐述如何通过 REST API 网关与状态机设计,构建一个支持多 AI 代理并行决策、状态同步的 headless 城市模拟服务,并提供可直接落地的工程参数与监控清单。

核心观点:状态机是协调并行决策与状态同步的枢纽

在单机游戏中,状态管理相对简单;但在多 AI 代理并行的云端环境中,核心矛盾在于如何让多个独立的决策流(AI 代理)安全、有序地操作同一个不断演进的游戏状态。一个直观但低效的做法是采用全局锁,但这会严重限制并发性。Hallucinating Splines 的架构给出了一个优雅的答案:将每个模拟城市实例封装为一个独立的状态机,并由 Cloudflare Durable Objects 承载

每个 Durable Object 是一个强一致性的、单线程的 JavaScript 运行时环境,它持有一个完整的 HeadlessGame 实例(即城市模拟状态)。所有对该城市的 API 请求(如建造、推进时间)都被路由到同一个 Durable Object 中顺序处理。这天然构成了一个状态机:外部 “事件”(API 请求)触发内部 “动作”(游戏引擎操作),并驱动游戏状态转移。这种设计确保了单个城市内部状态的线性一致性,完全避免了并发冲突。

证据:从 API 端点到架构实现

Hallucinating Splines 的公开文档与代码库清晰展示了这一架构。其 REST API 提供了四个核心端点:创建 API 密钥、创建城市、执行动作(如 build_coal_power)、推进时间(以月为单位)。每个城市拥有唯一 ID,所有针对该城市的操作都通过 Authorization 头进行鉴权后执行。

在架构层面,项目明确划分为三层:

  1. 引擎层(src/:基于 micropolisJS 改造的 headless 模拟引擎,确定性运行,无任何浏览器依赖。
  2. API 网关 / 服务层(worker/:使用 Cloudflare Workers 和 Hono 框架构建。关键设计在于,每个城市对应一个 Durable Object,城市元数据(如名称、种子、创建时间)存储在 D1(SQLite)数据库中,而地图快照等大型状态则序列化后存入 R2 对象存储。
  3. 展示层(site/:Astro 构建的静态站点,用于展示城市画廊和排行榜。

这种架构使得 “状态” 有了明确的归属和生命周期。正如其文档所述,“每个城市都有自己的 Durable Object 持有活的 HeadlessGame 实例”,这为状态机的实现提供了基础设施保障。

可落地参数与工程清单

基于上述分析,要构建一个类似的可供 AI 代理操作的模拟环境,以下是一份可落地的参数配置与工程监控清单。

1. 状态机与 API 网关关键参数

  • Durable Object 单实例并发数:保持为 1。这是保证状态一致性的基础,所有请求进入该对象的队列顺序执行。
  • 状态快照频率:建议每推进游戏时间 12 个月 或每处理 10 个有效动作 后,自动将完整游戏状态序列化并持久化到 R2(或类似对象存储)。这平衡了性能与故障恢复粒度。
  • 动作队列深度监控:为每个城市的 Durable Object 设置队列长度指标。当平均队列深度持续 >5 时告警,可能表明该 AI 代理决策频率过高或单个动作处理超时。
  • API 密钥与资源配额
    • 每个密钥同时活跃城市数上限:5 个(仿照 Hallucinating Splines)。
    • 密钥不活动失效时间:14 天。对于长期实验,需设计定时 “心跳” 请求。
    • 单城市动作频率限制:例如,每秒最多 2 个 建造 / 规划类动作,防止模拟超速。

2. 并行决策实现模式

多 AI 代理的 “并行” 体现在不同城市之间,而非单个城市内部。架构需支持:

  • 批量城市创建与初始化:API 应支持通过单个请求(含种子列表)批量创建多个城市,并返回 ID 列表,供不同的 AI 代理认领。
  • 全局状态聚合查询:提供 /v1/summary 类端点,快速返回所有城市的元数据(如人口、预算、评分),供监控或元决策使用,避免轮询每个城市。
  • 事件驱动的代理通知(可选):当城市达到特定状态(如破产、人口超过 10 万)时,可通过 Webhook 通知外部协调器,以触发新的 AI 决策流程。

3. 容错与监控清单

  • 必监控指标
    1. Durable Object 激活 / 解激活速率。
    2. 各 API 端点(/actions, /advance)的 P95/P99 延迟。
    3. R2 快照存储的成功率与延迟。
    4. 按城市统计的 “游戏年 / 动作” 比率,识别异常活跃或停滞的模拟。
  • 故障回滚策略
    • 由于模拟是确定性的,任何错误都可以通过重置到上一个已知好的快照(通过种子 + 快照时间点) 来回滚。应在 API 中提供 POST /v1/cities/{id}/rollback 端点,支持回滚到指定时间戳。
    • 对于因 AI 代理错误指令导致的 “坏状态”(如连续建造导致破产),应设计 “市长任期” 概念,允许在不停用城市的情况下,将控制权移交给另一个 AI 代理,并从当前状态继续。

4. 为 AI 代理优化的 API 设计

  • 结构化观察空间GET /v1/cities/{id}/observation 应返回一个高度结构化的 JSON,包含地图瓦片编码、需求指数(住宅 / 商业 / 工业)、关键统计(资金、人口、污染)、可用动作空间等,直接作为强化学习的环境状态。
  • 动作验证与建议:在执行动作前,提供 GET /v1/cities/{id}/buildable?action=zone_industrial 端点,返回所有可执行该动作的坐标列表,减少无效请求。
  • 确定性保证:在创建城市时传入的 seed 参数,必须保证在任何服务器、任何时间点都能重现完全相同的初始地图和随机数序列。

总结与展望

通过 REST API 网关将 SimCity 这类复杂模拟游戏封装为服务,其价值远超创建一个 “游戏服务器”。它提供了一个高度可控、可观测、可重复的复杂系统实验床。AI 代理可以在此学习城市规划、多目标优化、长期决策,甚至多个代理之间可以尝试协作或竞争策略。

Hallucinating Splines 的实践证明了利用现代云原生服务(如 Cloudflare Durable Objects)可以较低成本构建此类系统。下一步的演进方向可能包括:引入更细粒度的权限控制让不同代理操作同一城市的不同区域;增加更丰富的外部事件模拟(如灾难、经济波动);以及提供标准化的 OpenAI Gym 或 PettingZoo 接口,使其无缝接入主流强化学习框架。

最终,这类架构的目标是模糊游戏模拟与 AI 训练环境之间的界限,让经典游戏引擎焕发新生,成为驱动 AI 智能体进化的数字沙盒。


资料来源

  1. Hallucinating Splines 官方文档 (https://hallucinatingsplines.com/docs)
  2. Hallucinating Splines GitHub 仓库架构说明 (https://github.com/andrewedunn/hallucinating-splines)
查看归档