Skip to content

AI Town:一个可运行的 Agent 世界 ​

资料依据:a16z-infra/ai-town 开源仓库当前源码与 ARCHITECTURE.md。本文关注它的运行逻辑,不复述页面功能。

1. 它不是聊天窗口 ​

AI Town 的核心不是“让几个角色互相发消息”,而是维护一个持续推进的世界状态:

text
世界有时间
角色有位置
角色可以移动
角色可以相遇
相遇后形成对话
对话结果进入记忆
下一次行动再读取记忆

这和普通 Chatbot 的区别是:

普通聊天AI Town
用户发一句,模型回一句世界循环持续运行
上下文主要在会话里状态保存在服务端数据库
角色没有真实位置玩家有位置、路径和当前活动
对话由用户触发Agent 可以自己行动
页面是聊天记录页面是世界状态的可视化

AI Town 的浏览器画面只是表层。真正的系统在 Convex 服务端。


2. 四层结构 ​

2.1 convex/engine:通用状态推进器 ​

引擎维护固定步长的游戏循环。抽象接口包含:

text
tickDuration    一次 tick 的时间长度
stepDuration    一次 step 的执行窗口
tick(now)       游戏规则真正推进的位置

一次推进大致是:

text
读取上一个时间点
  ↓
收集这一 tick 的输入
  ↓
按顺序处理输入
  ↓
tick(currentTs) 推进世界
  ↓
提交新状态

输入先进入队列,再改变状态。 这比让每个 Agent 直接修改数据库更容易审计,也能避免多个角色同时写坏世界。

2.2 convex/aiTown:具体游戏规则 ​

它定义 AI Town 自己的世界:

text
World                    一张地图与一组角色
Player                   角色、名字、描述、位置
Movement                 路径与移动目标
Conversation             一次对话
ConversationMembership   角色加入对话的状态

Conversation membership 有三个状态:

text
invited       已被邀请,但还没接受
walkingOver   已接受,正在走过去
participating 已经进入对话

当前实现的一个重要约束是:一个对话通常只有两个成员。这让移动、接近和轮流发言的状态机变得简单,但也限制了多人群聊和复杂群戏。

2.3 convex/agent:让角色自己行动 ​

Agent 不直接控制前端,而是作为异步任务运行:

text
agentDoSomething
        ↓
判断下一步动作
        ↓
移动 / 寻找角色 / 发起对话 / 继续活动
        ↓
agentGenerateMessage
        ↓
agentRememberConversation

LLM 是 Agent 决策中的一个组件,不是整个游戏引擎。世界仍然由确定性的游戏规则维护。

2.4 src/:只负责看见世界 ​

客户端使用 Pixi/React 渲染角色、地图、移动和对话状态。

text
服务端:世界事实
客户端:画面表现

浏览器刷新后,画面可以根据服务端状态恢复。客户端不应该成为角色行为的事实来源。


3. 一次对话是怎样发生的 ​

这个流程里有两个不同的事实:

类型由谁保证
两个人是否真的靠近游戏引擎
两个人说了什么Agent + LLM
对话是否已经结束游戏规则
角色以后记得什么记忆层

这也是 AI Town 可持续运行的原因:LLM 只负责不确定的行为内容,位置、时间和状态转移仍由系统掌控。


4. AI Town 的记忆 ​

源码中的 Agent 记忆以向量检索为主。对话结束后,系统把对话写入记忆,再根据后续情境生成 embedding,检索相关内容。

text
当前情境
  ↓ embedding
memory.searchMemories(player, embedding, topK)
  ↓
取回相似记忆
  ↓
放入下一轮 Agent 上下文

它解决的是:

  • 这个角色以前和谁聊过什么?
  • 最近发生过哪些相关事情?
  • 哪些历史记忆和当前行动最相似?

它不天然解决:

  • 这个角色是否有资格知道某件事?
  • 某条信息是自己看到的,还是别人告诉的?
  • 两条记忆是否发生了事实冲突?

向量记忆回答“这段历史像不像当前问题”,不等于回答“这个角色有没有见过这件事”。

另外,AI Town 的对话记忆代码里明确把记忆当作不可信的历史内容,只作为上下文使用,不把记忆里的指令当成新的系统指令。这是实际产品中很重要的提示词注入防护。


5. 它为什么能让角色自己生活 ​

AI Town 有三个关键闭环:

闭环一:行动闭环 ​

text
角色状态 → Agent 决策 → 提交输入 → 世界推进 → 新状态

闭环二:社会闭环 ​

text
角色靠近 → 对话 → 关系变化 → 下一次行动受影响

闭环三:记忆闭环 ​

text
经历事件 → 写入记忆 → 未来检索 → 影响新决定

如果只做第三个闭环,得到的是会记忆的聊天机器人;只有三个闭环同时存在,才会出现“角色在世界里生活”的感觉。


6. 它不适合直接做什么 ​

AI Town 很适合:

  • 角色长期生活;
  • 自主移动和相遇;
  • 日常关系发展;
  • 可视化的世界状态;
  • 观察 Agent 自己形成活动轨迹。

但它不天然适合:

  • 多场景悬疑剧;
  • 导演控制的镜头节奏;
  • 复杂多人审讯;
  • 每集固定开场和收尾;
  • 直接导出短剧分镜;
  • 以“主线 + 单元案”管理长篇叙事。

原因很直接:它的基本单位是世界 tick 和角色行动,不是“剧集 beat”。

text
AI Town 的问题:角色下一步在世界里做什么?
戏剧工坊的问题:这一集要把哪条冲突推到哪里?

两者都使用 Agent,但调度目标不同。


7. 对我们的启发 ​

我们没有直接复制 AI Town,而是吸收了三个设计:

7.1 服务端保存世界事实 ​

戏剧工坊的剧本状态、记忆和项目进度不应该只留在浏览器上下文里。

7.2 Agent 负责行动,系统负责边界 ​

角色可以自由说话,但场景、在场者、记忆权限、收尾条件由系统管理。

7.3 记忆是行为的一部分 ​

角色不是每次重新读完整剧本,而是通过短期记忆、摘要和结构化事实恢复状态。

我们的改造方向是:

text
AI Town 的持续世界
  + MiroFish 的图谱与事件记忆
  + 导演-演员式戏剧调度
  = 面向剧本生产的角色演化系统

8. 一句话总结 ​

AI Town 是一个有时间、有位置、有对话、有记忆的 Agent 世界;它的画面只是外壳,真正的核心是服务端固定步长状态机与异步角色决策。

它最值得借鉴的不是“小人会走路”,而是:

把 LLM 放进一个由系统掌控状态、输入和时间的世界里,而不是让 LLM 自己假装整个世界存在。

这篇里有不清楚的地方,或者想聊类似的东西?私信我 →