跳至正文
my_ai_town 项目分析:Godot 与 AI 社会模拟是否匹配

my_ai_town 项目分析:Godot 与 AI 社会模拟是否匹配

项目来源:mewamew/my_ai_town · 相关视频:AI小镇发布啦!【B站AI创造公开赛】

AI 参与说明(Agent:Codex):本文由 Codex 阅读项目公开源码、README、发布记录、GitHub Actions 与 Godot 官方文档,辅助分析技术方案和玩法的匹配。源码分析固定于提交 43ef1d13f973cf90f0868209d0c1e3492d406312,资料整理于 2026-10-07;选型与改进建议是本文的工程判断。运行记录:模型 gpt-6.1-sol,reasoning effort ultra,执行入口 Codex Desktop,提供方 openai,运行时 CLI 版本 0.162.0-alpha.2(不代表桌面 App 版本)。

对于现在这款可观察、可化身进入的像素风居民生活与社交模拟,Godot + GDScript + LLM 是匹配的方案,继续使用现有引擎有充分理由。 它的优势来自明确分工:Godot 负责空间、表现和交互,LLM 提出居民的行为决定,游戏自己的世界系统维护事实并执行规则。

“是不是最好的匹配”要分两层看:引擎与当前玩法高度匹配;LLM 与开放式社交、故事生成匹配,但未必适合承担所有日常模拟。 如果目标变成严格可预测的经营数值、即时动作反应,或多人共享的持续在线小镇,就需要调整模拟或部署方案。仅把 Godot 换成 Unity,不能自动解决模型延迟、调用成本与玩法目标的问题。

这篇文章是Steam 独立游戏开发技术方案的具体案例:从一个真实项目检查“游戏类型决定技术选择”如何落到源码中。

先认识几个贯穿全文的名称。

英文术语中文名称简要解释
GodotGodot提供场景、图形、输入、物理和界面的游戏引擎
GDScriptGDScript本项目编写游戏规则与交互的脚本语言
LLM大语言模型根据输入的居民背景、记忆和环境生成行为决定或对话
Agent智能体本文指具有独立状态、记忆和决策流程的居民程序
World世界层本文沿用源码 world/ 的职责划分,指维护事实和结算行动的游戏系统
wake_packet唤醒数据包项目发送给居民决策流程的当前环境、事件和行动结果
HTTPRequestHTTP 请求节点Godot 用于异步发送网络请求的节点
BYOK自带密钥玩家配置自己的模型服务 API Key,调用由该服务账户承担

它实际是什么类型的游戏

项目 README 将其描述为由 LLM 驱动居民生活的单机像素小镇模拟。源码支持进一步细分:以居民生活与社交为中心、允许玩家观察和干预的模拟沙盒,包含职业、生产和服务系统。 固定版本 README

玩家或居民的行为已核实的实现对类型判断的意义
观察居民跟随角色,查看状态、关系、记忆与内心观察入口居民的变化与社会关系本身就是观看对象
化身进入小镇observer 与化身模式切换,读取方向输入,实际移动并与世界交互玩家可以在空间中探索,体验超出聊天页面
干预生活发布公告、改变天气、与附近居民交谈玩家通过改变条件,观察居民如何回应
居民日常能量、饱腹、社交与独处需求随时间变化居民具有持续生活状态,不只在被点击时回复
工作与生产捕鱼、花园地块、研究项目,以及工作任务、货物和职业服务有生产与组织元素,但不等于玩家主导的传统经营循环

对应源码:ResidentActionMenu、化身移动、天气与公告入口、生活需求、生产状态。

因此,不能因为场景里有商店、花园和工作,就直接把它看成“建造设施 → 获得利润 → 扩大小镇”的经营游戏。本次审查的核心界面与运行逻辑,尚不足以确认这种玩家主导的循环。它更适合用“我改变了一个条件,居民接下来怎样生活和相处”来理解。

技术方案:Godot 客户端中的模拟与模型调用

The project declares Godot 4.7 with the GL Compatibility renderer, and its resident presentation uses CharacterBody2D. project.godot · ResidentCharacterBody

不要把配置中的 Jolt Physics 字样当成 3D 玩法证据。实际审查到的是 2D 地图、2D 角色与像素风表现;地图底图由 Sprite2D 加载并使用 nearest filtering,也不能据此说地图一定通过 TileMap 实现。TownBase 的底图加载

层次本项目的方案负责的事情
场景与交互Godot、GDScript、2D 节点和 UI地图、角色表现、化身移动、室内外空间、摄像机、菜单
模拟规则TownWorldRuntime 与多个 World 模块时间、居民状态、需求、行动、关系、职业与生产
空间移动AStar2D 路网、World 路径采样、角色表现路径计算路线,结算实际位置,再表现移动过程
居民决策自有 Agent 协议、Prompt 编译和决定校验组装上下文,要求模型返回结构化决定,检查数据
模型传输HTTPRequest 与多个 ModelProvider连接云端服务或本地模型服务,解析响应与错误
记忆与存档JSON 文件、证据队列、会话保存协调保留居民记忆、世界证据和可恢复的会话状态

这是从源码归纳的职责表,不是项目依赖了六套独立框架。沿着默认客户端调用路径,Godot 可以直接请求配置的模型 endpoint;本地 Ollama 与 LM Studio 的预设也已存在,不要求先部署项目专属服务端。模型请求 · 本地服务配置

多数适配器采用 OpenAI-compatible 请求方式,但不能把所有供应商都写成同一种协议:例如 Ollama Cloud 适配器还支持原生 /api/chat 路径。模型接口最终必须提供项目需要的 JSON 决定;兼容聊天请求格式,不代表每个模型都能可靠遵守这个行为协议。OllamaCloudModelProvider

最关键的匹配:LLM 提议,World 决定事实

The LLM proposes a structured decision; the World validates and commits the action against its current state. 决定校验 · World 提交

下图展示决定通过校验后的成功路径。

flowchart TB
    A["World 当前状态<br/>与已确认事件"] --> B["wake_packet<br/>与居民记忆"]
    B --> C["Prompt 编译<br/>与 LLM 请求"]
    C --> D["DecisionExecution<br/>检查结构化决定"]
    D --> E["World 检查当前条件"]
    E --> F["执行行动<br/>并结算状态"]
    F --> H["已确认事件<br/>与 action_results"]
    H --> I["更新居民证据与记忆"]

图中省略了队列、预取和详细失败分支。World 已消费的拒绝会留下权威回执,部分未消费的拒绝会进入回退;过期请求的回包直接忽略。Provider 调用或决定校验失败的重试,另按错误类型判断。回退行动也必须经过 World 提交。Gateway 提交与拒绝处理 · 失败重试 · 连续性回退

例如,模型想让居民去找另一位居民谈话,返回时目标可能已经离开。项目会在执行前重新检查条件;目标离开等情况可能导致重新观察或拒绝,模型的文字不能直接把一次未发生的谈话写成事实。TownAgentDecisionActionRuntime

这个边界特别适合 AI 社会模拟:性格、意图和表达可以开放生成,地点、距离、资源、行动完成与否仍由规则结算。如果这两者混在一起,居民说“我送到了”就可能被误当成真的送达,后续记忆和工作都会失去依据。

世界推进与模型等待分开

World 由 RefCounted 对象承载,不依赖某个可见角色节点保存唯一状态。TownRuntime 每帧调用 World 的 advance(delta),World 再按游戏分钟结算需求、行动与社会事务。TownWorldContract · TownRuntime · TownWorldAdvanceRuntime

居民模型决策走待处理队列,由唤醒条件、行动边界等驱动,并非每个渲染帧都发起一次 LLM 请求。Gateway 居民决策流程的并发上限为 6,并为化身对话预留 1 个位置;本地模型的决策流程上限为 3,其中普通居民最多占 2 个位置。选择器统计在途 decision_id,包括准备和记忆整理阶段;其他独立模型请求应另行统计。队列与并发常量 · 请求挑选

Godot’s HTTPRequest is asynchronous, but a single node must not serve simultaneous requests. The project creates a request node for each dispatched HTTP operation. Godot 4.7 HTTPRequest · 项目的请求节点创建

异步传输让游戏继续运行,但 Prompt 组装、JSON 处理和世界结算仍有本地计算成本,不能因为请求异步就推断所有工作都在后台线程。项目另外检查 session_epoch、当前 decision_id 和 Gateway 的 generation,用于丢弃已失效或重复返回的结果。ResidentRuntime · Gateway

记忆保留的是证据与理解

项目把当前意图与已完成的事情分开:准备替换行动时,先记录 pending intent;收到 World 的事件和 action_results 后,才摄入相应证据。记忆整理把旧摘要与新证据交给模型,再检查结构与连续性。意图记录 · 证据摄入 · MemoryOrganizer

Current memory retrieval uses structured entries, ranking rules, and text anchors; the inspected implementation does not use embeddings or a vector database. 排序规则 · 锚点匹配

这对规模有限的小镇是合理起点:人物、地点和任务往往有明确标识,先用可解释的检索可以减少依赖。若长期游玩后出现遗漏相关往事、同义表达难以命中等问题,再用实际失败案例评估是否增加 embeddings;“有 Agent”本身不是引入向量数据库的理由。

Godot 为什么合适,何时才值得换方案

Godot provides a dedicated 2D renderer and physics engine, with built-in support for animation, tilemaps, and navigation. Godot 4.7:Introduction to 2D · 2D navigation overview

项目已经把引擎能力用于实际玩法:角色是 CharacterBody2D,化身会进行物理移动,居民有室内外空间与路线,摄像机可以跟随居民。其 AStar2D 路网生成的 minutePositions 用于 World 的位置结算,presentationPath 用于视觉移动;可见动画和权威位置并非同一份状态。路线生成 · 移动结算 · 角色表现

以下比较是基于产品目标的工程建议,不是性能实测排名。

目标更合适的起点原因与代价
继续做可探索的 2D 单机小镇,保留化身、地图与角色行为保留 Godot当前场景与规则已经围绕这些体验工作;迁移会重做大量交互,无法消除模型等待
体验主要是居民观察、对话和事件时间线,优先链接即开Web 界面,按空间需求加入 Phaser 或 Canvas更符合网页分发目标;需重新处理客户端存储、模型接入和空间表现
团队已有成熟 C# / Unity 工作流,或目标改成更复杂的 3D 角色与资源生产比较 Unity 与现有方案既有经验和生产工具可能抵消迁移成本;仅因 AI 代码复杂而换引擎,收益不足
多人共同干预同一个持续在线的小镇服务端维护权威 World,客户端负责表现持续运行、并发修改和成本控制成为部署问题;Godot 仍可作为客户端
主要挑战是精确资源配置、利润与生产效率规则驱动日常模拟,LLM 只处理对话与特殊事件减少模型波动影响数值平衡,保留居民表达的变化

因此,当前最有价值的调整大多在“哪些事需要 LLM”,而不是“用哪个引擎”。寻路、饥饿变化、工作进度和货物转移有明确规则;人物动机、谈话与社会反应更能发挥模型作用。

技术成立之后,还需要一个可感知的玩法循环

实现很多系统,不等于玩家已经拥有持续游玩的理由。 观察型沙盒可以没有强制胜负,但仍需要让玩家看懂变化、形成期待,并找到值得再次介入的机会。

从已实现的观察、公告、天气和化身互动入口出发,一个适合验证的循环是:玩家提出问题或改变条件 → 居民作出反应 → World 记录实际后果 → 玩家理解关系和生活如何变化 → 再次尝试。这里的循环是本文建议,不是声称项目已经设计了相应关卡。

例如,可用以下三种体验分别检验,而不必同时扩张成大型经营游戏:

  • 观察实验:改变一次天气或公告后,读者能否从世界日志和居民行为看出谁受到了影响、为什么改变计划?
  • 化身关系:玩家与同一居民反复接触后,对方能否根据已发生的互动表现出可辨认的态度变化?
  • 有限目标:如果希望增加挑战,可围绕一个工作任务或一场社会事件设置目标,让玩家的行动产生明确后果。目标可以是短期情境,不必引入庞大的经济系统。

更适合这种类型的质量判断是“变化是否有因果、是否能被玩家理解”,而不是单看居民说了多少句话。独立居民记忆、权威事件和日志,正好为这种反馈提供基础;是否已经达到好玩的程度,需要实际游玩验证。

下一步优先解决什么

1. 用请求数据衡量等待与成本

并发上限只能限制负载,不能保证模型返回及时。应分别记录请求到达队列的时间、派发时间、完成时间、被接受或失效的结果,以及实际 token usage。项目 Provider 已将响应中的 usage 写入 diagnostics,可作为采集入口。usage 记录

一个假设算例:15 位居民,每位每个真实分钟触发 4 次基础行为决定,总计每分钟 60 次。若每次平均占用决策槽 8 秒,要避免持续积压,平均需要约 60 ÷ 60 × 8 = 8 个决策槽。这超过 Gateway 的上限 6;若有位置预留、重试和额外记忆整理,普通居民可用容量还会更少。这些数字不是项目实测,也不是项目固定的唤醒频率,只用于说明为什么应先减少无必要调用,再评估提高并发。

建议先采集“每个真实分钟调用数、队列等待、化身对话等待、回退比例、输入与输出 token 数”。快速模拟、普通模拟和玩家对话应分别统计;游戏时间加速并不意味着云端模型能按同样倍数加速。

2. 验证回退能否维持生活连续性

Gateway 的 MAX_DECISION_ATTEMPTS 为 2,并按失败情况决定是否重试;最后可以采用继续当前行动、选择可用活动、待着或结束对话等回退。重试判断 · 回退活动选择

这说明项目已经考虑模型失败,不能笼统说断网后所有居民必然卡死。但这种回退也不等于完整的离线 Agent:它能维持一些行动连续性,无法自动提供和正常模型同等的社交推理、故事与对话。

可执行的验收方式是:让测试 Provider 返回超时、错误 JSON 和迟到结果,分别检查居民是否继续合理活动、错误是否可解释、旧结果是否被丢弃、恢复后能否重新决策。使用本地模型时,还要检查模型服务未启动和本地推理排队的情况。

3. 保持事实、记忆与存档对齐

会话保存由协调器处理 World 候选、Agent 存档与最终 manifest,并带有事务 gate、journal 和恢复流程。它不是把所有跨文件状态通过一次 rename 就完成原子提交。保存入口 · Agent 与 World 提交 · manifest 发布

适合继续验证的场景是:居民正在等待模型时保存;恢复后旧请求返回;居民任务已经完成但摘要整理尚未完成;保存写入中断后重新启动。通过标准应围绕实际事实:没有重复完成任务、没有用旧记忆覆盖新状态、没有把计划当成完成记录。

4. 先收紧模块职责,再考虑迁移语言

当前 TownWorldRuntime.gd 已拆分为多个模块,仓库还有限制主文件指标和模块私有访问增长的架构检查。本次运行检查得到:主文件 2,412 行、211 个函数、44 个顶层状态,运行模块存在 128 次 world._成员 直接访问。检查脚本

这些数量不能单独证明设计好坏,但说明它已经是一套有维护成本的模拟系统。继续明确状态归属、用稳定接口减少模块对私有状态的依赖,比仅改写成 C# 更直接。若性能测量指向某个热路径,再针对那个部分优化;不能从代码行数推断 GDScript 已成为运行瓶颈。

下载版本、Steam 与再利用边界

仓库已有公开 Pre-release:v0.1.0-beta.5 发布于 2026-08-20,提供 Windows x86_64、macOS universal、Android arm64 包及 SHA256SUMS。这个 Release 对应 e31f342 开头的历史提交,与本文审查的 43ef1d1 主线快照不同,不能把本文全部源码能力视作该下载包已经包含的能力。

当前发布 workflow 会验证、导出并创建 draft prerelease;审查的 workflow 中没有 Steam 上传步骤。若继续作为 Steam 独立游戏推进,应另行验收桌面导出、输入体验、存档兼容和模型配置流程,再按需要接入 Steam 功能。release-build.yml · Steam 选型与发布路径

BYOK 适合愿意配置模型的体验者,也让不同模型成为可选择的变量;若面向普通付费玩家,API Key 配置、服务余额、模型能力差异都会影响首次体验。若改成开发者承担推理费用,应单独设计服务端凭据、额度和长期运营方案,不能把服务方密钥放进发行客户端。

项目当前会把玩家密钥存入本地加密文件,密码由项目标识与设备标识派生;这不是操作系统 Keychain 托管。TownProviderCredentialStore · 密码派生

源码公开可查看,但本快照没有根 LICENSE;README 明确说明第三方资源按各自许可使用,项目代码与自有素材的统一许可仍在整理。可以研究架构,不能据此假定整个仓库已经授予统一的商用或再分发许可。README:授权说明

如何复现本文的一项源码核查

下面的 shell 命令需要 Git、Python 3 和网络;检查脚本只读取源码与基线,不需要 Godot、API Key 或模型调用。使用固定提交避免后续更新改变统计结果。

sh
git clone https://github.com/mewamew/my_ai_town.git my-ai-town-review
cd my-ai-town-review
git checkout --detach 43ef1d13f973cf90f0868209d0c1e3492d406312
python3 -B tools/guards/world_runtime_architecture_check.py --check

本次在该提交运行检查的实际输出为:

text
TownWorldRuntime 架构棘轮通过:lines=2412 functions=211 states=44 private_accesses=128。

仓库同一提交的 formal-validation 运行记录 显示成功;其 Agent suite 显式设置 AI_TOWN_PROVIDER_TEST_NO_NETWORK=1,这是自动回归证据,不能用来证明真实模型的延迟、费用和长期对话质量。formal-validation.yml

本次未启动游戏或测量帧率、模型等待与游玩体验。相关视频仅核验公开简介与项目关联,未播放视频或取得字幕。本文能支持的结论是:当前技术职责与当前游戏类型相符,下一步应优先验证玩法反馈和模型运行质量,再根据目标变化决定是否调整方案。

本文共 5149 字,以 CC 署名-非商业性使用-禁止演绎 4.0 国际 协议进行许可。

评论

博客助手

正在打开博客助手…