和 AI 讨论这篇文章
ChatGPTClaude

Agora 每个核心模块的设计都有出处

📊 幻灯片

Agora · 第 3 篇 / 共 7 篇


第一篇讲了这个赛道基本是空的,第二篇讲了为什么不 fork。这篇讲具体怎么干:不 fork,但把这些项目里好的设计全偷过来——从哪个项目偷什么,怎么拼成一个平台的架构。

这轮调研做下来,有几个判断慢慢清楚了:

  1. 偷的是设计模式,不是代码。代码一行不抄,抄的是「它为什么这么设计」。
  2. 每个核心模块最好都有一个设计出处——你能说清楚它为什么长这样,是从哪个项目学来的。
  3. 架构其实不太需要从零想。二十多个项目翻一遍,共性摆在那,把它读出来就行。

真正值得偷的就六处

调研了二十多个项目,真正值得偷的设计集中在六个地方,一个一个讲。

AgentScope → agent 接口 + 消息隔离

AgentScope 的 agent 设计我很喜欢,整个接口就两个方法:reply()observe()

reply 就是「轮到你了,给个回答」;observe 就是「这条消息你需要知道,但不用回」。所有 agent 行为基本都能拆成这两个动作:辩论里轮到你发言是 reply,听别人发言是 observe;狼人杀里投票是 reply,听到淘汰公告是 observe。

这个抽象好在哪呢——它把「生成回复」和「接收信息」拆成了两个独立的动作。大部分框架是混在一起的,agent 收到消息就必须回复。但很多场景里 agent 需要听但不说。狼人杀白天讨论阶段,已经被淘汰的 agent 还得 observe 后续消息(它进了墓地频道),但不再 reply。

它的 MsgHub 也值得偷,做消息隔离用的,核心就三个机制:嵌套作用域、自动广播开关、动态订阅管理。翻译成平台的概念大概是:频道可以有子频道,频道可以控制消息要不要自动推给所有订阅者,agent 可以在运行时被动态加进或者移出一个频道。

ChatArena → 三层架构

ChatArena 这个项目已经废弃了,但它的架构是我这轮调研里看到最干净的:Arena > Environment > Players。

Arena 是运行时容器,相当于平台本身。Environment 定义游戏规则——状态怎么转换、谁算赢、谁能看到什么信息。Players 是参与者,各自有自己的策略和记忆。

三层之间的依赖关系也很干净:Players 不知道 Arena 的存在,Environment 不关心 Players 具体怎么实现,Arena 只负责把它们组装起来,然后驱动循环。

映射到我要做的多 agent 平台,就是 Platform > Mode > Agent。Platform 是基础设施——房间、频道、流程控制、实时通信。Mode 是规则配置——狼人杀、辩论、剧本杀各自定义自己的角色、频道、流程、决策格式。Agent 是参与者,各自有人设、模型、记忆。

ChatArena 给我的最大收获,就是确定了把游戏规则单独抽成一个可插拔的层,这个抽象粒度是对的。

斯坦福 Generative Agents → 记忆反思循环

斯坦福 2023 年那篇 Generative Agents 论文,基本定义了 agent 记忆系统的标杆。核心是一个三步循环:observe → reflect → plan。

observe 是 agent 观察到事件,存进记忆流。reflect 是定期回顾近期记忆,用 LLM 提炼出更高一层的认知。plan 是基于记忆和反思的结果,去规划下一步的行为。

关键在 reflect 这一步。没有反思,agent 的记忆就是流水账——「张三说他是好人」「李四投了王五」。有了反思,它能形成更高层的判断——「张三最近三轮都在替李四说话,他们可能是同伙」。

对多 agent 游戏来说,这个真不是可有可无的。剧本杀需要 agent 交叉比对线索、形成理论、调整怀疑方向;TRPG 需要 AI 地下城主记住三个 session 前玩家做过的选择。没有反思循环,agent 就是个只看最近 N 条消息的复读机。

不过这个模块第一阶段用不上。圆桌辩论和狼人杀,一个消息数组就够了。反思循环到剧本杀阶段再引入,时间上完全来得及。

AgentScope 狼人杀 sample → 结构化决策

AgentScope 的狼人杀 sample 里有个细节,值得单独拿出来讲:用 Pydantic schema 去约束投票目标。

投票的时候,schema 动态生成一个枚举,里面只有当前存活玩家的名字。agent 调 LLM 的时候把这个 schema 传进去,LLM 的输出就被强制限在这个枚举范围内。

效果就是 agent 物理上投不了死人,编不出不存在的名字,也输出不了「我弃权」——除非你把弃权也放进枚举里。你在 prompt 里写「请只投给以下玩家」,那只是个建议,模型不一定听;schema 是硬约束,输出根本出不了那个范围。多 agent 游戏要是投票都能投出 bug,整局就废了,所以这里必须上硬约束。

翻译到 TypeScript 这边很直接:Zod 的 z.enum() 干的就是同一件事,配合 Vercel AI SDK 的 generateObject(),结构化决策这条路就通了。

evotraders → 前端视觉模式

AgentScope sample 里还有个 evotraders,一个多 agent 交易模拟,前端做得意外地好。两个组件值得偷。

AgentFeed,agent 的活动流。它不是普通的聊天气泡——每个 agent 有自己的颜色、头像、状态标识,正在思考的 agent 有个呼吸灯效果,刚发言的 agent 气泡会高亮。就这些视觉细节,把一堆文字变成了一群正在互动的角色。

RoomView,语音气泡加头像布局。agent 围成一圈或者坐在桌旁,谁发言谁头上弹气泡。用户一眼就能看懂空间关系和轮次。

多 agent 平台最大的 UX 问题就是:一堆 AI 在对话,怎么让用户看着不像在读 log 文件。这两个组件基本把这个问题回答了。

Accio Work → 建群聊这个交互

阿里国际的 Accio Work,给了我这轮调研里最重要的一个产品洞察。

它做的事情不复杂,就是让多个 agent 协作完成任务,但交互方式选得特别对:像建微信群一样组建 agent 团队。你创建一个 agent,就跟加了个联系人一样;要组个团队就是建个群;派任务就是往群里发消息。

这个隐喻厉害在,你完全不需要教用户什么是 agent 编排、什么是消息路由、什么是频道隔离——群聊这个心智模型所有人都懂。

这个发现也直接影响了技术选型。要做出 Accio Work 这个级别的 UI 体验,Python 全栈是做不到的,Gradio 和 Streamlit 的上限离群聊式交互还差得远。上一篇加权打分里 Web UI 这个维度给 fork 方案打了低分,根本原因就在这。

拼在一起:三层架构

六个出处拼起来,就是一个三层架构:

模式层:    圆桌辩论 | 狼人杀 | 剧本杀 | TRPG | 自定义
            (角色模板 + 频道规则 + 流程配置 + 决策格式)
平台核心:  Agent | 房间 | 频道 | 流程控制 | 记忆 | 事件总线
基础设施:  Vercel AI SDK | Socket.io | PostgreSQL | Next.js

模式层对应 ChatArena 的 Environment。每个模式就是一个配置包,定义角色模板、频道规则、流程配置、决策格式。以后要新增一种游戏,不用改平台代码,写一个新的模式配置就行。

平台核心对应 ChatArena 的 Arena。agent 用 AgentScope 的 reply/observe 双接口;频道用 MsgHub 的嵌套作用域加动态订阅;流程控制从简单到复杂做四种实现——自由发言、轮流、状态机、层级——用哪种由模式决定;记忆分两级,session 内做消息压缩,跨 session 做向量检索加反思,按需加载。

基础设施层就是纯工具选择了:LLM 用 Vercel AI SDK 做多模型路由和结构化输出,实时通信用 Socket.io,存储用 PostgreSQL 加 pgvector,前端 Next.js。

这样每一层的设计决策都有出处,随便挑一个模块问为什么长这样,都能指到某个具体的项目。

频道系统是最关键的一块

六个模块里,频道系统是最关键的。

信息隔离这件事,就是多 agent 交互和「一堆 AI 在同一个聊天框里说话」的本质区别。没有频道隔离,狼人杀跑不了——狼人的讨论不能让平民看到;剧本杀跑不了——每个角色手里有独占的线索;三省六部也跑不了——部门之间有信息壁垒。

AgentScope 的 MsgHub 帮我验证了三个核心机制:

  1. 嵌套作用域。 频道可以有子频道。狼人杀主频道下面可以嵌套狼人夜间频道、先知查验频道、医生行动频道。
  2. 动态订阅。 agent 在运行时可以被加进或者移出频道。被淘汰的狼人从狼人频道移出去,加进墓地频道。
  3. 广播控制。 有的频道消息要立刻推给所有订阅者(白天讨论),有的要手动拉取——剧本杀的线索分发就是后者,线索放在频道里,只有调查了对应地点的 agent 才能看到。

但 MsgHub 是代码级别的实现,翻译成平台还要再加一层:频道规则由模式定义,运行时由平台自动管理。模式说「狼人杀需要五个频道,订阅关系如下」,平台就在房间启动的时候自动把这些频道创建出来、绑好订阅关系,状态转换的时候再动态调整。

这块大概 300-500 行核心代码。这么关键的模块我不会交给第三方,频道系统本身就是这个平台最核心的竞争力,自己写。

记忆系统

记忆系统就是上一篇说的「10% 遗憾」集中的地方。实际拆开看了一遍之后,发现遗憾比想象的小。

会话记忆压缩。 九人狼人杀跑完一局,大概有 200 多条消息,全塞进 context 的话,一半都是前几轮的重复讨论。解决方案直接偷 AgentScope 的:设一个阈值,比如 40 条,超过之后用便宜的模型(Haiku 级别的就行)把旧消息总结成一段摘要,agent 的 context 就变成「摘要 + 最近 15 条消息」。这块大概 80 行代码。

长期语义检索。 这个管跨 session 的记忆——TRPG 角色要记住三个 session 前的选择,剧本杀 agent 在新一局里带着上一局学到的策略。偷 AgentScope 的长期记忆模块,加上斯坦福那个反思循环。核心就三个方法:

  • record(event, importance) — 把事件文本向量化,存入 pgvector
  • retrieve(context, limit) — 余弦相似度检索相关记忆,注入 prompt
  • reflect() — 定期回顾近期记忆,用 LLM 提炼出更高层的认知,存回记忆库

pgvector 直接跑在 PostgreSQL 里,不用单独再起一个向量数据库。大概 100 行代码。

两块加起来 200 行左右。当然达不到 AgentScope 记忆系统 100% 的能力——它还有记忆重要性衰减、自动清理、记忆冲突检测这些细节。但对一个多 agent 游戏平台来说,80% 够用了,剩下 20% 等有用户反馈了再迭代。

而且圆桌辩论和狼人杀阶段完全用不上这个模块,消息数组加系统提示词就够。记忆系统到剧本杀阶段才引入。

偷的方法论

最后把这次的做法整理一下,以后调研别的方向应该也能照着干。大概五步:

第一步:广度扫描。 用关键词搜 GitHub,不预设筛选条件。每个项目花 15 分钟:看 README,看核心接口定义,跑一下 demo。

第二步:按维度分类打分。 不要笼统地说这个项目好或者不好,拆成具体维度——agent 抽象设计得怎么样?消息隔离做得怎么样?前端体验怎么样?同一个项目在不同维度上的得分可能天差地别。

第三步:给每个模块找出处。 对你要自建的每一个核心模块,找到一个在这个维度上做得最好的项目,设计直接借鉴它。不是抄代码,是搞明白它为什么这样设计,然后用自己的语言重新实现一遍。

第四步:画偷取矩阵。 一张表:行是模块,列是出处项目、偷什么、怎么翻译到你自己的栈。这张表本身就是设计文档,每一行都解释了一个核心模块的设计是从哪来的。

第五步:标记时间线。 不是所有模块都要一开始就偷,记忆系统可以晚做,频道系统必须早做。在矩阵上标注每个模块的引入阶段,按需偷取。


这是 Agora 系列的最后一篇。四篇文章覆盖了从初始愿景赛道分析技术选型到架构设计的完整决策链。

Agora 的代码在 GitHub 上。

和 AI 讨论这篇文章
ChatGPTClaude

订阅更新

新文章发布时发到你的邮箱,不发别的。


© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0