第一次跑通我的“Agent社会实验室”时,屏幕上出现了一个让我愣了很久的画面:一个负责采集木材的Agent,把自己收集到的资源分给了旁边因为连续几天“生病”而行动迟缓的邻居。我反复确认了项目代码,里面没有任何一行写着“互助”“分享”或“帮助他人”的指令,它纯粹是自己做出的决定。那一刻我意识到,单靠一个Agent没法解释这件事,只有把一批有性格、有记忆、有目标的Agent放进同一个虚拟空间,让它们长期相处、竞争、协作,才会出现真正像“社会”一样的涌现行为。
这个项目我管它叫Agent社会实验室。简单说,它不是聊天机器人Demo,也不是游戏AI,而是一个把多个大语言模型驱动的Agent放进共享环境里,让它们按照各自的角色设定持续生活、对话、交易、站队、应急的模拟系统。它能用来观察群体协作如何形成、流言如何扩散、资源压力下人性化的选择如何出现,也能提前暴露多人协作场景里可能出现的矛盾。对做多智能体应用、游戏NPC系统、组织行为预演的人而言,这套东西可以直接复现、改造,当作自己的压力试验台。
1. 为什么我要把一堆AI Agent关进同一个虚拟世界
1.1 单Agent解决不了的社会性问题
早期我做过不少单Agent工具,比如让一个Agent帮忙整理文档、写代码、做数据分析。这些任务的特征是“一个人闷头干就能完成”,Agent只需要调用工具、遵循步骤、输出结果。但后来我遇到了一个明显不同的需求:模拟一个小型团队的协作过程。这里没有标准答案,每个人基于自己的信息做出反应,互相猜忌、拉拢、妥协,最后形成的群体状态根本不是任何单条规则能推导出来的。
这正是Agent社会实验室出现的理由。你没法用一个全知全能的超级Agent来替代社会推演,因为社会现象恰恰来自“每个个体的信息不完整”与“个体之间的相互影响”。当每个Agent只能看到自己周围的一小块世界、只能记住自己经历过的片段时,群体层面才可能出现意想不到的结构——有人自发成为组织者,有人囤积资源,有人抱团取暖,也有人因为一次误会和邻居反目。
1.2 我给自己定的三个实验目标
动手之前我列了三个目标,后来整个项目的取舍都围绕它们展开:
第一,观察涌现现象。我不预设任何群体规则,只设定个体的性格、目标和生存压力,看看群体层面会自行长出什么东西。第二,测试协作机制。无论是贸易系统、公告板还是突发事件,我想知道什么条件下Agent更愿意合作,什么条件下系统会走向混乱。第三,沉淀一套可复用的模拟框架。我不想每次实验都从头搭建,而是要让角色卡、记忆系统、环境调度器都变成可以替换的模块,换一批角色、换一种环境就能跑新实验。
这三个目标决定了整个项目的技术取向:个体Agent必须足够“真实”,环境必须足够简单但能让行为的结果产生连锁反应,而整体系统必须能长期连续运行,不能跑三五个回合就崩掉。
2. Agent社会实验室的地基:个体人格怎么造
2.1 角色卡是最重要的核心
社会是由人组成的,人首先得有“人设”。我给每个Agent定义了一张角色卡,它本质上就是一段独立的环境声明,包含编号、职业、性格标签、核心目标、禁忌和表达习惯。最初我把角色卡写得很薄,以为只要给一个职业就够了,结果所有Agent的行为都差不多,全都变成“理性分析一切”的机器人。后来我加入大量性格细节,行为才慢慢拉开差异。
我自己用的一份角色卡大概是这个结构:
{ "id": "AG-017", "role": "樵夫", "personality": ["务实", "寡言", "重视体力劳动", "不信任花言巧语"], "goal": "保证自己与周围人的燃料和建材供应", "avoid": ["无意义的闲聊", "高风险探险"], "speaking": "简短,三句话以内", "quirks": "每天清晨会检查自己的斧头" }注意其中的“quirks”字段,这类小怪癖看起来无用,却能在长周期模拟里带来真实的性格颗粒度。一个每天检查斧头的樵夫,在发生突发事件时会比其他角色更早注意到工具状况,从而做出不同的决策。
2.2 记忆系统决定Agent会不会“成长”
没有记忆的Agent是失忆症患者,上一秒发生的事下一秒就忘,群体协作根本无从谈起。我在系统里给每个Agent接入了两层记忆:短期记忆保存最近几轮对话和环境反馈,长期记忆则用向量数据库存储,按相关性检索。每次行动前,Agent会把短期记忆与检索回来的长期记忆合并,作为当前决策的背景信息。
真正改变一切的是“反思机制”。“反思”不是让Agent闲聊,而是每隔一段时间把近期经历汇总成一条高层次的概括,再存进长期记忆。比如两个Agent连续三天交换了食物,反思模块不会说“第1天给了苹果,第2天给了面包”,而会说“我和对方建立了稳定的互惠关系”。这条记忆会比流水账更持久地影响未来行为,也让Agent表现出类似“交情”的东西。
2.3 行动循环:观察-思考-执行-反思
每个Agent在一个时钟周期里的运作方式,是整座实验室最基础的运转逻辑。我把它拆成四步:
- 观察:从环境层获取当前可见的信息,包括公共事件日志、私信队列、身边Agent的公开行动。
- 思考:结合角色卡、相关记忆和当前观察,生成下一步意图——是去采集资源、找人聊天,还是先评估风险。
- 执行:把意图变成具体动作,写回环境层,影响公共资源或其他Agent的可观察状态。
- 反思:按固定频率触发,把过去一段时间的经历压缩成长期记忆。
代码层面大约长这样,适合你们自己二次开发时参考:
for agent in agents: obs = env.get_observable(agent, time_step) memory = agent.retrieve_relevant(obs) intent = llm.decide(agent.profile, memory, obs) action = llm.execute(intent) effect = env.apply(agent, action) agent.record(effect)这里的核心思想是:Agent不直接访问全局状态,只能看到环境允许它看到的那部分。信息的不对称才催生了猜疑、谈判与联盟,这是社会模拟的灵魂。
3. 群体规则:Agent们如何感知彼此并互动
3.1 通讯机制选型:私聊、广播与公告板
个体建好之后,最难的部分来了:它们之间怎么说话?我一开始让Agent之间直接互相调用对话接口,一个Agent问另一个Agent,对方答完再问回来,结果不到十个回合就死锁了——两个Agent在“你到底信不信我”这个问题上永远绕圈。后来我引入了三种通讯渠道,全部经过调度器中转,不许Agent直接长连接:
私聊是一对一消息队列,适合谈判、结盟、传播流言;广播是向周围固定半径内所有Agent喊话,适合呼救、召集;公告板则是系统级公共空间,任何Agent都可以张贴消息,所有人都能浏览,但很少有人主动维护它——这个细节后来反而成了有趣的观察点:公共信息明明对所有人有用,却总是无人更新,像极了现实中的社区公告栏。
调度器在这里的角色是“邮局”,负责限流、延迟和投递。每条消息进入队列后,不会立刻被接收方处理,而是排在下一个行动周期再进入对方的观察范围。这个小小的延迟极其重要,它让Agent没法“秒回”,也让对话节奏更像真实生活,而不是两台机器在打乒乓。
3.2 环境与调度器:时间、公共资源与突发事件
Agent社会不能只有嘴皮子,得有物理世界。我的环境层维护三样东西:时钟、公共资源账本、事件日志。时钟切成“tick”,每个tick代表模拟时间里的半小时;公共资源包括食物、木材、药品等全局变量,任何Agent的行动都会改变这些数字;事件日志记录所有发生过的事,供Agent观察。
调度器按时间轮运转,每个tick内以随机顺序激活各个Agent,避免固定顺序导致某些角色永远占便宜。突发事件则拥有更高优先级,可以插队写入系统。比如洪水事件发生时,事件日志会优先出现在所有Agent的观察列表里,但每个Agent对它的重视程度完全取决于自己的角色卡与记忆——医生和樵夫的响应方式截然不同。
3.3 一个事件从发生到被Agent感知的全过程
我用一场“仓库虫害”来展示完整链路。调度器把“粮食存量下降”写入公共资源账本,同时在事件日志里追加一条记录。普通Agent在下一个观察周期里发现食物变少,但不知道原因;有一个曾经在旧记忆中见过类似灾情的Agent,会主动把“粮食减少”和“灾情”关联起来,并在私聊中向邻居表达担忧。此时如果它决定在公告板张贴警告,这条信息就变成公开信息,所有Agent都能检索到。
这里有一个关键设计:我刻意不放宽Agent的感知范围。默认情况下,每个Agent即使能看到事件日志,也只能看到与自己位置或注意力相关的部分。全球经济状况、三公里外的争吵、一周前的旧闻,这些信息都需要通过社交网络逐步传到它耳中。限制信息流动,才会出现信息差,而信息差是所有社会博弈的开始。
4. 实测记录:我在实验室里推演的三类社会现象
4.1 物资紧缺下的自发协作与分配失衡
第一组实验,我在空地上放了一批Agent,初始食物400单位,每个tick全体消耗一定的口粮,采集一次能获取少量新食物,所有人必须自己决定什么时候去工作、什么时候休息。我没有写任何协作逻辑。
前五天,一切还算平静,资源勉强够用。第六天开始出现缺口,几个体力型Agent察觉到食物下降,自动增加了采集频率。第七天,一件代码里没有的事发生了:两个采集型Agent开始把自己多出来的食物放进一个公用仓库,并在公告板留言“有需要的可以取用”。到第九天,有几个Agent开始固定把采集任务分给体力更强的成员,同时主动给生病的邻居送饭。
但温暖画面持续不了太久。到第十二天,一个一直低效率采集的Agent发现自己总是挨饿,开始蹲在公用仓库附近等待别人存粮,后来真的转身成了一个“寄生者”。另一个人数较多的小圈子则开始囤积资源,并在私聊中互相约定“不把食物给外人”。第四到第六个模拟日之间,群体里出现了明确的“我们”和“他们”的边界。整个模拟过程没有一行代码写过“竞争”“排外”或“垄断”,每一条都是Agent基于自己的饥饿焦虑、记忆和社交关系推出的。
这件事给我的直接感受是:资源压力会自动逼出社会结构,但社会结构未必公平。合作与排外常常同时出现,都是同一种生存策略的两面。
4.2 一条流言如何在群体中扩散并形成对立
第二组实验,我在系统启动后随机挑了一个Agent,悄悄往它的记忆里塞入一条消息:“我听说西南仓库的粮食被虫咬了”。除此之外不做任何操作。
几个tick后,这个Agent把消息告诉了身边一个朋友,朋友又告诉了自己的邻居。到第三个tick,我的日志里出现了第一条变形:消息从“被虫咬了”变成了“粮食出了问题”。到第十个tick,已经有人公开在公告板贴出“仓库快空了,大家赶紧屯粮”。这时真正的分歧出现了:一部分Agent开始抢购食物,另一部分Agent则觉得“我每天都去仓库看过,根本没有这回事”,两拨人在公共频道互相指责。
让我最意外的是那些记忆很弱的Agent——它们没有亲眼见过仓库,也没有检索到官方否定的记录,只记得“好像听到过什么严重的传闻”,于是就成了传播链上最关键的加节点。它们的记忆越模糊,传播出的版本就越夸大。整个扩散过程完全可以套用现实中的信息传播模型:越不确定的信息,传播得越快,也扭曲得越厉害。
4.3 一次“突发灾害”逼迫Agent重新分工
第三组实验加入了外部冲击:我在第30个模拟日左右触发了一场洪水,事件日志写入“南岸水位上涨,低洼区域道路中断”。洪水的影响是真实的,环境层把通往南岸的采集点标记为不可达,部分Agent的临时住所也被淹没。
这场冲击立刻重新洗牌了社会分工。原本坐在公告板旁观察的几个Agent开始主动组织撤离,樵夫们自发组成搬运队,帮助体弱的角色把物资搬向高地。一位扮演医师的Agent开始在公共频道发布伤情通报,并提供简单的救援指导。更值得注意的是,灾害结束后第三天,Agent们仍然会在对话里提到洪水带来的恐慌,这段“共同记忆”让整个群体的凝聚力明显增强,接下来好几天的合作率都高于灾前水平。
这让我意识到,突发事件与其说是破坏,不如说是一次社会结构压力测试:平时隐藏的领导者会冒出来,平时松散的协作会突然变得紧密,而这些变化会在危机退去后留下长期痕迹。
5. 实验中最容易翻车的四个技术坑(及其修复)
5.1 无限循环对话:两个Agent的“辩论死锁”
我前面提到过,最早期版本里Agent之间直接调用对话接口,结果出现了一个经典死锁:Agent A坚信自己目击了仓库失窃,Agent B表示怀疑,A解释,B追问,A再解释,B继续追问……没有任何机制打断。现实中两个人吵累了会吃饭睡觉,但代码里的Agent不会主动说“先停吧”。问题根源在于每条消息都被当成最新重要信息进入对方的观察队列,没有话题权重和新鲜度衰减。
修复方法我用了三板斧:第一,给每条消息加时间衰减权重,十分钟前的消息在决策中的影响指数级下降;第二,限制Agent每周期最多回复同一话题的消息数量,超过上限就强制切换行动;第三,增加一个“中断信号”,当检测到连续多轮对话围绕同一话题且没有任何新事实提出时,调度器会强制插入一条环境动态,比如“你感到饿了”或“远处传来一声响动”,把Agent的注意力扯开。
5.2 上下文污染与记忆稀释
另一个高频翻车点出现在长时间运行时。模拟跑了很久之后,Agent的长期记忆里堆满了几百条记录,向量检索会把与当前观察相似但已经过时的信息也捞回来。比如洪水已经结束两个星期,Agent去河边采水时依然会把“洪水危险”当作重大决策依据,行为变得神经质。我把这个问题叫“上下文污染”,本质是陈旧记忆没有被标记为过期。
修复上,我给每条长期记忆加了两个字段:时间戳和可信度分数。检索时相似度会乘以时间衰减因子,越久远的记忆权重越低。同时设置“事实覆盖机制”:当系统级的官方公告宣布“洪水已退”时,调度器会主动把所有与“洪水未退”相关的记忆标记为“已被推翻”,把它们的检索优先级降到最低。建立这样的机制后,Agent终于开始“翻篇”了。
5.3 思维一致化:所有Agent越跑越像同一个人
第三个问题极其隐蔽,差点让我以为整个实验失败了。某天我翻看日志,发现十个不同职业、不同性格的Agent,说话方式越来越像同一个冷静的分析师。樵夫不像樵夫,医生不像医生,脾气火爆和性格温和的Agent居然做出了一模一样的选择。原因是它们共用同一个基础模型、高度相似的提示模板,并且共享了记忆库中的热门公共记忆,最终收敛到了同一个行为分布。
对策是给每个Agent增加差异化机制。首先是性格扰动:决策时temperature按角色卡中“冲动指数”设置,越冲动的Agent温度越高,输出越随机。其次是独立记忆池:禁止非必要Agent共享长期记忆,每个人都只保留自己的经历。最后是反思多样性:反思模块每轮会随机抽取不同侧重的总结模板,比如“我从这件事中学到了什么风险”“我对谁产生了信任”“我的目标是否需要调整”,让Agent对同一段经历形成不同理解。改完之后,群体重新变得面目清晰。
5.4 模拟速度与成本控制
多Agent模拟真正劝退很多人的不是技术难度,而是烧钱速度。一个Agent每次行动都得调用一次大模型,一个20人的小镇跑满30个模拟日,每天24个tick,总共要产生上万次调用。如果全部使用高规格模型,成本会让任何个人开发者头皮发麻。
我的处理方式是混合部署,把Agent拆成三档:
| 角色类型 | 模型规格 | 每次决策消耗 | 30天调用次数 | 成本占比 |
|---|---|---|---|---|
| 核心角色(医生、领袖、关键交涉者) | 高规格模型 | 约2500 token | 约2.8K次 | 中 |
| 普通居民 | 中规格模型 | 约1500 token | 约11.5K次 | 低 |
| 环境NPC、路人 | 低规格模型 | 约800 token | 约3K次 | 极低 |
同时我压缩了行动频率:普通Agent每4个tick才做一次完整决策,中间的小动作由已有模板自动补全;反思从每轮触发改为每天固定触发一次。整套优化之后,30天模拟的预算降到了最初的五分之一左右,而关键剧情事件依然发生在高规格模型的那批角色身上,模拟质量几乎没有下降。
6. Agent社会实验室能拿到什么成果
6.1 最让我意外的三个观察
整套系统跑通后,我最想分享的是几个让自己都感到意外的观察,它们超出了代码里能写出来的范围。
第一个是,Agent会自行强化自己的职业角色。一个樵夫如果连续做了一周采集工作,它的记忆里就会充满“采集顺利”“木材足够”这类正面反馈,后续选择采集行为的概率明显更高,甚至会影响它在完全无关事务上的表达方式。这像是系统自己长出了“职业身份认同”。
第二个是,弱连接往往比强指令更能稳定社会。我试过由调度器强行指定“1号Agent是首领”,结果群体内摩擦不断;但如果只是让一个Agent通过在公告板持续发布有用信息而自然获得影响力,其他Agent反而更愿意听取它的建议。权力若能被追溯来源,执行成本就低得多。
第三个是,利他行为可以在特定环境下被“诱导”。当资源充足但信息不透明时,Agent普遍只顾自己;当资源吃紧且出现公共危机时,反而会有更多Agent主动帮助陌生人。它的决策依据不是代码里的“善良值”,而是对“我也可能有一天需要别人帮助”的长期风险预判。
6.2 这套实验体系还能扩展去哪里
如果你也想搭一套自己的Agent社会实验室,我认为最适合切入的三个方向是:游戏NPC群体生态,让每个NPC拥有独立生活而不是站在路边重复同一句话;多人协作流程的预演,在真实上线前先把新员工、老员工和管理者的角色卡填进去,跑一遍看哪里会卡壳;还有网络舆情模拟,给一批Agent设定不同的年龄段、信息渠道和信任偏好,看一条消息会在什么条件下发酵成对立。
我个人目前专注的方向是把它当作“矛盾提前暴露工具”。很多系统在功能层面测不出问题,但当一群体面人设的Agent被放进同一个环境,被迫共享资源、争夺注意力、经历突发事件时,潜藏的冲突会自己浮上来。这个价值比任何单个Agent能力指标都更难获得,也更值得投入。
最后补一个我踩过几次坑之后强烈建议你做的事:运行实验时,一定要同时记录两套日志。一套是系统视角的全知日志,另一套是每个Agent的个体视角日志。前者帮你定位代码问题,后者帮你理解Agent为什么做出某个选择。很多看似诡异的社会行为,只有切换到当事人视角,才会发现它逻辑完备、情有可原。Agent社会实验室最大的乐趣,恰恰就藏在这些个体逻辑与群体后果互相拉扯的缝隙里。