资讯动态

AI Agent多智能体模拟世界实践:从my_ai_town看大模型驱动的角色决策

发布时间:2026/8/27 9:46:46 来源:尧图企业网站定制
在 Ask HN 上出现过这样一个问题Is discovery channel using AI? 如果把这个标题当成技术材料来拆解它其实是模糊的因为 discovery 既可能指探索频道也可能指发现机制、服务发现、内容发现。但这类问题真正指向的是一个可以观察 AI 系统自主决策的场景。my_ai_townAI小镇恰好提供了这种场景一个开源的多智能体模拟世界多个大模型驱动的角色在小镇里生活、交流、执行计划用户能启动服务、观察日志、注入事件再看到角色做出反应。这篇文章会以 my_ai_town 为主线讲清楚 AI Agent 模拟世界从概念到落地的完整过程并给出可复现的启动、验证、排错和扩展方法。1. 从“发现频道是否在用 AI”到 AI 小镇项目先搞清楚问题边界1.1 一个 HN 问题背后的技术诉求“Ask HN: Is discovery channel using AI?” 这个问法看起来像是针对某个媒体频道提问但放到技术语境里它真正想知道的往往是AI 是否已经能够深入到一个原本由人、环境和流程共同驱动的系统中持续地发现线索、做出判断并采取行动。这里的 discovery 可以拆出三层含义内容发现AI 是否负责筛选、生成或推荐内容。服务发现AI Agent 如何在动态环境里找到可交互的对象、可执行的任务。自主发现AI 在没有显式指令的情况下能否自己观察环境、形成常识性判断、发起行动。如果把第一层含义当作主要讨论对象容易变成媒体报道分析但后两层才是工程上能落地、能写代码、能验证的部分。my_ai_town 恰恰就是从第二、第三层切入的项目它模拟了一个小镇小镇里有多个 AI 角色每个角色都会基于当前环境和自己的记忆生成行动。用户看到的不只是“答一句问题”而是“一个角色在某个时间点决定去做什么”。1.2 my_ai_town 是一个什么样的项目项目没有提供太多官方说明只能看到开源地址和一句“游戏下载: ai小镇_macw”。从名称和常见 AI 小镇类项目可以判断它属于大模型驱动的多智能体模拟世界。这类项目的通用特点是世界里存在一张地图地图上有地点和角色。每个角色由一个 AI Agent 驱动Agent 的核心是大语言模型。角色会感知周围状态比如当前时间、自己所在位置、附近有哪些角色。角色会通过模型生成行动指令例如移动到某地、开始对话、做某个动作。世界有一个时间循环每隔一定时间刷新所有角色状态。my_ai_town 的具体技术栈、实现语言和依赖需要以仓库 README 和源码为准。这里不假设它是 Python 还是 Node.js也不假设它使用哪个模型服务因为这类项目版本变化很快。可以确定的是它面向普通用户提供了 mac 和 Windows 的下载包也保留了 GitHub 源码说明既可以直接体验也可以拿来学习和改造。1.3 这篇文章适合谁能获得什么这篇文章适合以下几类读者第一次接触 AI Agent想找一个能运行的真实项目来观察 Agent 行为的人。已经在做 Agent 开发但想了解多智能体模拟世界的工程结构、时间循环、记忆存储如何处理的人。需要把 AI 小镇这类项目接入自己产品但不确定依赖、配置、排错从哪里入手的人。读完并跟着操作后你应该能自己完成三件事第一把 my_ai_town 或类似项目跑起来看到 AI 角色产生行为第二读懂它内部大致的工作链路知道角色为什么会有某个动作第三遇到启动失败、模型调用失败、角色无响应等问题时能按照日志和配置逐步排查。由于输入素材没有给出详细 README 内容文中命令和配置会以通用示例为主落地前务必以仓库实际文档为准。2. 跑通前先理解 AI Agent 小镇的核心机制2.1 智能体模拟世界的通俗模型可以先把 AI 小镇理解成“一群有记忆、有目标、会说话的 NPC”。传统游戏里的 NPC 通常只能播放固定动画或响应固定对话比如走到某个位置就触发同一句台词。AI 小镇里的角色不同它们接收环境状态把状态交给大模型模型输出一个动作或一段对话然后系统再把这个输出应用到世界上。举一个典型场景早上 8 点角色 A 在自己的房间醒来。系统读取到当前时间和地点把“现在是早上 8 点你在卧室”发送给大模型。模型根据角色设定和记忆生成一个计划“去厨房吃早餐”。角色 A 移动到厨房。厨房里已经有角色 B。两个角色触发互相感知系统把“对方正在喝咖啡”和之前的聊天记忆打包给模型模型生成一句对话。角色 A 说“早上好今天有什么计划”角色 B 回答并把这次互动写入记忆。整个过程不是由一个巨大模型控制整个世界而是多个 Agent 各自独立运行再通过共享世界状态产生交互。世界本身像是一个沙盘Agent 是沙盘里的个体大模型是每个个体的“大脑”。2.2 AI Agent 的四个关键模块在类似 my_ai_town 的项目中一个 AI Agent 要正常工作通常会包含四个关键模块。环境感知模块负责把世界状态转换成模型能看懂的文本或结构化数据。例如{ time: 08:00, location: bedroom, weather: sunny, nearby_agents: [Alice], current_activity: sleeping }这一步很关键因为大模型本身没有眼睛它只能通过字符串理解世界。世界状态写得不清晰角色的行为就会混乱。记忆模块负责存储角色过去的经历。长期记忆可能放在文件或数据库里短期记忆可能只保留最近几轮对话。角色在生成计划前需要从记忆中检索与当前场景相关的片段否则它无法记住“昨天和 Alice 约好一起去公园”这种关系。规划模块负责把当前观察和检索到的记忆组合成一条指令。规划不一定复杂常见的做法是让模型先说出“你现在想做什么”再让系统解析成可执行动作。行动执行模块负责把模型的文本输出映射成世界变化。模型可能输出“move to kitchen”系统就要修改角色坐标输出“say: hello”系统就要把对话推送到其他 Agent 的观察中。2.3 容易误解的三个点第一不要把“每个角色调用一次大模型”当成完整方案。角色调用完模型只是得到了一串文本后面还要有动作解析、状态校验、冲突处理和记忆写入。省掉这些步骤角色会频繁出现“开口说要去厨房但还站在原地”的问题。第二不要以为大模型输出什么世界就发生什么。模型可能输出一个不存在的动作比如“move to moon”也可能输出超出世界规则的内容。生产级实现需要对模型输出做白名单校验或者把动作格式限制成 JSON让模型只能在固定字段里填写。第三不要把 AI 小镇等同于聊天机器人。聊天机器人只关心“你问什么我答什么”而 AI 小镇里的 Agent 有持续的时间线。它们在没有人输入时也会行动需要按 tick 循环不断推进。真正复杂的不是单次回复质量而是事件之间的因果连续性。3. 环境准备与项目获取3.1 环境要求虽然仓库没有给出明确要求但从多智能体模拟类项目的一般情况看环境准备可以按下面的表格来核对。实际安装时要以 my_ai_town 的 README 或 package.json、requirements.txt 等文件为准。环境项推荐配置说明操作系统macOS 12 或 Windows 10/11项目提供 mac 和 Windows 下载包源码通常跨平台运行时Node.js 18 或 Python 3.9取决于项目后端语言先查看仓库判断包管理器npm 或 pip与运行时对应Git2.x拉取源码使用大模型服务OpenAI 兼容 API 或本地模型远程 API 需要网络本地模型需要足够内存内存8 GB 以上本地模型和前端服务同时运行时会比较吃内存浏览器Chrome、Edge 或 Firefox 最新版用于打开小镇界面如果选择远程大模型 API还需要准备 API Key并确保运行终端可以访问到服务地址。如果选择本地模型建议先用命令行单独测试模型接口确认连通后再接入 my_ai_town这样可以减少排错变量。3.2 获取 my_ai_town 源码和发行包获取项目有两种方式。第一种是直接下载游戏包。进入 GitHub 仓库的 Releases 页面找到对应标签下载名称为 ai小镇 且后缀为 mac 或 windows 的压缩包解压后按说明启动。这种方式适合只想体验效果、不想改代码的人。第二种是克隆源码适合学习和二次开发。打开终端执行git clone https://github.com/mewamew/my_ai_town.git cd my_ai_town克隆完成后先不要急着安装依赖先看仓库根目录下的 README 文件、配置文件示例和最外层目录结构。很多启动问题都出在跳过 README 直接运行命令。建议优先使用源码方式。这是因为 AI 小镇这类项目处于快速迭代阶段发布包可能滞后于源码从源码运行至少能保证代码和当前模型接口、日志输出一致。如果需要在自己项目里复用 Agent 机制源码也更适合改造。3.3 项目结构速览下面是一个通用多智能体项目的结构示例实际项目不一定完全一致但基本可以按这个思路去阅读my_ai_town/ ├── README.md ├── package.json ├── src/ │ ├── agent/ │ │ ├── memory.py │ │ ├── planning.py │ │ └── action.py │ ├── world/ │ │ ├── map.py │ │ ├── clock.py │ │ └── event.py │ └── llm/ │ └── client.py ├── config/ │ ├── world.json │ └── agents.json ├── data/ │ ├── locations.json │ └── characters.json ├── server/ │ └── app.py └── web/ └── index.html阅读项目时优先按下面的顺序看config/世界配置、角色配置决定了小镇里有哪些地点和角色。src/llm/模型服务接入层决定了如何调用大模型。src/world/世界状态和时间循环决定了 Agent 运行的节奏。src/agent/Agent 的记忆、规划和行动逻辑是最核心的部分。web/界面层负责把世界状态可视化。如果仓库目录和上面不一致不要硬套只需找到“模型调用”“世界状态”“角色决策”这三块入口即可。4. 配置模型接入并启动 AI 小镇4.1 AI 服务的接入方式my_ai_town 这类项目通常不会内置模型权重而是通过 API 调用推理服务。常见接入方式有两种。第一种是接入远程模型 API例如 OpenAI 兼容接口。这种方式简单不用部署本地模型但需要申请 API Key并且要认真管理密钥不要提交到公开仓库。第二种是接入本地模型推理服务比如 Ollama、vLLM 等工具暴露的 OpenAI 兼容端点。本地模型没有联网依赖但需要下载模型文件并占用较多内存和 CPU/GPU 资源。在配置之前建议先用一个最小请求测试模型服务是否可用。比如本地 Ollama 启动后可以执行curl http://localhost:11434/v1/models如果能返回模型列表说明服务可用。这样把“模型服务问题”和“项目代码问题”分开后面接 my_ai_town 时就会简单很多。4.2 最小配置文件示例假设项目使用环境变量方式配置那么可以创建一个.env文件内容类似下面这种结构# my_ai_town 示例环境变量具体变量名以仓库 README 为准 AI_API_BASEhttp://localhost:11434/v1 AI_API_KEYlocal AI_MODELqwen2.5:7b AI_TEMPERATURE0.7 AI_TIMEOUT120 AGENT_TICK_INTERVAL5这里的几个参数含义如下参数含义常见值调大影响调小影响AI_API_BASE模型服务地址远程或本地服务地址无无AI_API_KEYAPI 密钥远程 API 使用真实 Key无无AI_MODEL模型名称取决于服务商或本地模型模型效果和响应时长都会变模型能力可能下降AI_TEMPERATURE随机性0.7行为更多样但可能不稳定行为更稳定但容易重复AI_TIMEOUT单次请求超时120 秒避免误杀长回答但失败恢复慢快速失败但长任务容易超时AGENT_TICK_INTERVAL世界刷新间隔5 秒角色行动慢资源占用低反应更快但模型请求更频繁这里要特别提醒不同的项目对环境变量命名可能完全不同。有的是OPENAI_API_KEY有的是MODEL_API_KEY有的项目在config.json里配置而不是.env。所以正确做法是先查看仓库里的.env.example或config.example.json再复制成自己的配置。不要把上面示例直接当成标准配置使用。4.3 启动步骤和验证假设项目是 Node.js 前端加 Python 后端的结构那么启动顺序通常是先启动后端再启动前端。下面的命令是常见示例不是 my_ai_town 的确定命令实际要以 README 为准。后端启动pip install -r requirements.txt python server/app.py前端启动npm install npm run dev如果项目完全使用 Node.js也可能是npm install npm start启动完成后需要做几个验证而不是看到窗口打开就结束。第一验证后端进程是否正常。终端里不应该只看到“Listening on 0.0.0.0:8000”还要确认没有模型连接异常。如果有/health或/api/status接口可以访问它curl http://localhost:8000/health第二验证前端是否能加载世界状态。打开浏览器访问终端输出的地址比如http://localhost:3000。页面应该能看到小镇地图、角色位置和角色当前状态。第三验证角色是否真的在行动。保持页面开启观察一段时间看角色位置或动作标签有没有变化。同时回到后端终端查看是否有模型调用日志比如每个 Agent 输出了什么计划、执行了什么动作。如果角色没有行动可以优先做两件事检查AGENT_TICK_INTERVAL是否设置过大检查模型返回结果是否为空或不符合动作格式。这些细节通常能覆盖大部分“启动成功但世界不动”的情况。5. 深入解读 AI Agent 的运行链路5.1 时间循环从感知到行动AI 小镇的核心是一个时间循环。世界像一个游戏主循环每隔一定时间推进一次每个 Agent 都在这个循环里完成“感知、规划、行动”三步。伪代码如下while world.running: current_time world.clock.now() for agent in world.agents: # 1. 感知 observation agent.perceive(world, current_time) # 2. 规划 plan agent.plan(observation) # 3. 行动 action agent.execute(plan) # 4. 写回世界 world.apply(agent, action) # 5. 记录记忆 agent.remember(observation, action) # 防止循环过快导致模型接口被频繁调用 time.sleep(world.tick_interval)这里的 tick_interval 很重要。如果所有 Agent 同时请求大模型启动瞬间可能产生大量并发请求导致模型服务超时或限流。常见做法包括串行调用、限制每轮 Agent 数量、为每个 Agent 设置请求间隔。另外世界循环并不是越短越好。角色在小镇里移动、聊天本来就不需要毫秒级响应。5 到 10 秒的刷新间隔在演示项目中足够也能显著降低模型调用成本。5.2 对话、记忆和个性生成角色之间的对话不是无状态问答。当两个角色相遇时系统至少需要把三类信息传给模型当前场景时间、地点、周围角色。对方状态对方正在做什么、情绪如何。历史记忆这两个角色过去是否聊过天关系如何。一个简化的对话请求结构可以是这样{ system_prompt: 你是小镇里的角色 Alice性格开朗。你的目标是完成今天的计划同时可以和遇到的人聊天。, context: { time: 09:00, location: town_square, nearby: [ {name: Bob, activity: walking, relation: friend} ] }, memory: [ {time: 昨天 18:00, event: 你答应 Bob 今天一起去公园} ] }个性信息通常通过 system prompt 注入。模型本身不知道角色背景它只能看到 prompt 里写的设定。这是最容易出问题的地方如果项目没有把角色设定整理好所有角色都会变成同一个“AI 默认口吻”小镇会失去多样性。记忆的注入需要做筛选不能把全部历史都塞给模型。一个常用的做法是给每条记忆记录时间戳、重要性分数和关键词在生成请求前按相关度检索前 N 条。这样既能控制 token 长度又能保证模型参考到关键信息。5.3 数据存储角色状态如何保存AI 小镇需要保存两类数据世界数据和角色数据。世界数据包括小镇地图、地点类型、角色当前位置角色数据包括角色属性、当前状态、记忆流。常见的存储方式有三种存储方式优点缺点适用场景JSON 文件简单直接方便调试数据量大时读写慢小规模演示SQLite单文件数据库事务可靠并发写性能有限本地单机项目PostgreSQL/MySQL支持并发、查询能力强需要额外部署和维护生产级服务如果项目默认使用 JSON 文件角色状态在每次行动后都要写回磁盘。写入频率过高会导致 IO 压力可以改成定期批量保存或者退出时统一保存。一张简化的角色数据表可以设计为CREATE TABLE agents ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, location TEXT DEFAULT home, energy REAL DEFAULT 1.0, personality TEXT, current_plan TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE memories ( id INTEGER PRIMARY KEY, agent_id INTEGER NOT NULL, content TEXT NOT NULL, importance REAL DEFAULT 0.5, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (agent_id) REFERENCES agents(id) );设计时要注意记忆表要带上created_at否则检索时无法按时间排序importance 字段用于决定哪些记忆优先进入长期记忆。如果只存内容不存元数据Agent 的“记忆”就没有了时间维度行为连续性也会变差。6. 常见问题与排查路径6.1 启动失败依赖、路径和端口问题启动失败是最常见的问题现象通常有几种命令找不到模块、服务启动后立刻退出、页面打不开。排查顺序应该固定为确认当前目录在项目根目录不能站在子目录里运行npm install。确认运行时版本符合 README 要求比如 Node.js 版本过低会导致语法解析失败。确认依赖完整安装。Python 项目可以用pip list检查关键依赖Node.js 项目可以用npm ls。确认端口没有被占用。如果默认端口被其他服务占用项目会启动失败这时需要改配置或停止占用进程。查看终端日志中第一条异常栈从最底部往上找项目自己的代码路径。常见原因和处理现象可能原因检查方式处理建议ModuleNotFoundError依赖未安装pip list重新安装 requirements.txtcommand not found运行时未安装或未加入 PATHnode -v/python --version安装正确版本并重开终端端口被占用其他服务占用默认端口lsof -i:3000修改端口或停掉占用服务页面 404前端和后端路径不匹配查看接口请求地址确认前端代理配置或后端前缀6.2 模型调用超时或返回异常如果项目能启动但角色没有反应终端出现超时或模型返回错误问题大概率出在模型接入层。先看这几类现象ConnectionError网络不通或 API 地址写错。TimeoutError单次请求超过 AI_TIMEOUT 设置。401 UnauthorizedAPI Key 错误或没有权限。model not found模型名称与服务商实际可用的模型名称不一致。返回内容不是期望的 JSON模型输出格式不符合动作解析代码的要求。检查方式按顺序执行# 1. 确认服务地址可达 curl -v http://localhost:11434/v1/models # 2. 确认 API Key 有效 curl -v -H Authorization: Bearer 你的KEY https://api.example.com/v1/models # 3. 确认模型名称存在 curl -v http://localhost:11434/v1/models如果模型返回超时优先降低本轮角色并发数或者增大 AI_TIMEOUT。如果模型经常返回非 JSON可以在 prompt 里增加强约束并在代码里做二次解析。不要直接把模型输出当 JSON 解析至少加一层 try-catch失败后让 Agent 重试一次或跳过本轮。6.3 角色无行为或行为停滞角色能启动、不报错但一直站在原地或重复同一个动作这类问题最隐蔽。可能原因有以下几种。第一个原因是记忆检索为空。如果角色没有任何历史记忆模型只能根据当前时间地点做反应输出会非常单调。可以检查 memory 表或日志确认角色是否在启动时注册了初始记忆。第二个原因是动作解析失败。模型可能输出了“go to kitchen”这种自然语言但系统只接受{action: move, target: kitchen}的 JSON。两者不匹配时角色不会行动。查看日志中是否有“parse action failed”之类关键词。第三个原因是 Tick 循环没有启动。有些项目把循环放在后端需要手动点击界面上的“开始运行”按钮。如果没有点击世界是静止的。阅读 README 时要特别注意是否有“play/run/simulation toggle”这类交互。第四个原因是模型温度设置过低。当 temperature 为 0 时模型总是选概率最高的动作容易出现所有角色都做同一个动作。把温度调到 0.5 到 0.8 之间行为会更多样。6.4 日志、性能与资源占用排查多智能体项目比普通 Web 项目更依赖日志。因为角色行为是大模型生成的你无法从代码里直接推断“它为什么这么做”只能看日志链观察到了什么、记忆检索到了什么、模型返回了什么、执行结果是什么。启动时建议打开详细日志。如果项目支持LOG_LEVELDEBUG可以设置后观察。一个理想的日志片段应该像这样[12:00:00] world tick start, agents5 [12:00:00] agentAlice observe time12:00 locationpark nearby[Bob] [12:00:01] agentAlice retrieve 3 memories, top_score0.92 [12:00:02] agentAlice plan_output{action:chat,target:Bob,text:...} [12:00:03] agentAlice action applied如果项目不支持日志级别配置至少留意两个指标单次模型请求耗时、每轮循环总耗时。当世界内角色数量增加时模型请求会变成主要瓶颈系统响应会明显变慢。性能优化方向包括多个 Agent 之间的共享状态写操作要加锁避免并发修改。模型请求在内存中做好缓存相同观察和记忆可以复用响应。控制单轮循环中参与决策的 Agent 数量不要让全部 Agent 每 tick 都请求模型。7. 工程化扩展与最佳实践7.1 从演示走向生产要补全的能力my_ai_town 这类项目在本地跑通只说明演示链路可用。如果要放到生产环境还需要补几块能力。第一配置外置化。把 API 地址、Key、模型名、tick 间隔等参数放到环境变量或配置中心不能写死在代码里。部署时通过环境注入可以避免密钥泄露。第二持久化升级。如果角色数量增长建议用 PostgreSQL 替换 JSON 文件并给记忆表增加索引。定期归档过期记忆避免数据表无限增长。第三异常处理和重试。模型服务可能因为限流、网络抖动而失败。生产实现要为每个 Agent 的模型调用增加超时、重试和熔断机制。重试时要控制次数避免拖垮整个循环。第四内容安全审核。角色生成的内容来自大模型可能包含不符合产品规范的内容。在写入日志和展示到界面前应该增加过滤和关键信息记录。第五监控与告警。至少监控三件事单次模型调用成功率、单轮循环耗时、角色活跃度。设置告警规则当成功率低于阈值或循环耗时超过设定值时及时报警。7.2 可复用检查清单在投入新项目前可以用下面的清单快速检查避免走弯路。阶段检查项环境检查运行时版本是否满足 README环境检查依赖是否完整安装环境检查模型服务是否可用、模型名称是否正确环境检查API Key 权限是否足够环境检查默认端口是否被占用配置检查配置模板是否复制到了正确文件配置检查模型地址、Key、超时、温度是否合理启动检查后端是否先启动成功前端是否有代理地址运行检查日志中是否出现角色决策输出运行检查页面地图上角色位置是否随时间变化运行检查角色对话是否能被写入记忆排错检查异常日志是否记录模型原始返回内容排错检查动作解析失败时是否存在兜底逻辑发布检查密钥是否没有提交到代码仓库发布检查数据是否定期备份发布检查模型调用是否有超时和重试这个清单看起来简单但能覆盖 AI 小镇类项目 80% 以上的问题。遇到异常时先按执行顺序核对而不是直接改代码。7.3 下一步可以做什么跑通 my_ai_town 后可以从下面几个方向继续深入。第一个方向是扩展角色和世界。增加新的地点、角色和初始记忆观察不同设定下角色行为是否出现明显差异。这时候你会发现系统提示词和记忆数据质量对 Agent 表现的影响远大于模型本身。第二个方向是替换模型。把默认模型换成参数更小或更大的模型对比决策质量和响应速度记录一组自己的评测结果。这个方向可以帮助你理解模型能力和工程成本之间的取舍。第三个方向是把单机版改成服务化。将世界状态和 Agent 运行逻辑独立成后端服务通过 API 对外暴露。这样其他应用可以申请一个“AI 角色”并介入其中比如作为一只 AI NPC 接入自己的产品。第四个方向是深入实现记忆系统。当前项目可能只做简单的 top-N 检索你可以引入向量数据库把记忆转化为 embedding再做相似度查询这样角色对历史的感知会更细腻。整个过程中最重要的不是把某个具体项目背熟而是建立“模型只是大脑世界、记忆、动作校验才是工程主体”的认知。把这个认知带到下一个 AI Agent 项目里你会发现很多启动失败和角色卡死的问题都可以用同一套方法快速定位。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价