欧易 强大的 Web3 聚合投资平台

用邀请码注册可享各种优惠和福利,交易手续费折扣、奖励返还.

当前位置:首页>资讯>解构Project89:一个模块化、高性能的下一代 AI Agent框架设计

解构Project89:一个模块化、高性能的下一代 AI Agent框架设计

2025-01-27 By:Admin

原文:0xhhh

先说结论,@project_89采用一种全新的方式来设计AgentFramework,这是一个针对游戏开发的高性能的AgentFramework,与目前使用的AgentFramework相比更加模块化也有更好的性能。

这篇文章花了很长的时间来写,试图让所有人都懂这个框架相比传统Agent框架在架构上做了什么升级,前后改了很多次才有了这个版本,但是文中仍然有些部分太过技术,我没能很好的进一步通俗化,如果你对文章改进有任何建议欢迎留下你的评论。

开发者背景这是一篇技术博客,所以我们先来看看这个founder的技术实力

Founder在做project89之前做了Magick这个项目,也是一款利用AI进行编程的软件同时shaw也是这个项目排名第四的开发者,在shaw的履历里也可以看到这个项目

左上:project89的founder,右下:lalaune就是ai16z的shaw

而今天我们主要来介绍下project89里面的高性能AgentFramework。

一、为什么要用ECS来设计AgentFramework从游戏领域的应用来看,目前采用ECS架构的游戏有:

区块链游戏:Mud、Dojo传统游戏:守望先锋、星际公民等等而且目前主流的游戏引擎也在往ECS的方向进化比如Unity什么是ECSECS(Entity-Component-System)是一种在游戏开发与模拟系统中常用的架构模式。它将数据与逻辑彻底分离,以便在大规模可扩展场景下高效管理各种实体及其行为:

1.Entity(实体)

•仅仅是一个ID(数字或字符串),不包含任何数据或逻辑。

 •可以根据需要,挂载不同的组件来赋予它各种属性或能力。

2.Component(组件)

•用来存储实体的具体数据或状态。

3.System(系统)

•负责执行与某些组件相关的逻辑。

以一个具体的Agent行动的例子来理解这套体系:在ArgOS中将每一个Agent看成一个Entity,它可以注册不同的组件,比如在下面这幅图里,我们这个Agent拥有以下四个组件:

AgentComponent:主要存储类似Agent名称,模型名字等等基础信息PerceptionComponent:主要用来存储感知到的外界数据MemoryComponent:主要用来存储AgentEntity的Memory数据,类似做过的事情等等ActionComponent:主要存储要执行的Action数据System的工作流程:

在这个游戏里比如感知到了自己面前有一个武器,那么这个就会调用PerceptionSystem的执行函数来执行更新这个AgentEntity的PerceptionComponent里面的数据

然后再触发MemorySystem,同时调用PerceptionComponent和MemoryComponent,把感知到的数据通过Memory持久化到数据库之后

然后ActionSystem再调用MemoryComponent和ActionComponent,从记忆中获取周边环境的信息,然后最终执行相应的动作。

接着我们就得到一个每个Component数据都被更新的UpdateAgentEntity所以我们可以看到这里面System主要负责定义要对哪些Component执行对应的处理逻辑。

而且很明显在project89里面它是一个世界里面充斥着各种类型的Agent,比如有些Agent不仅仅拥有以上的基础能力还有做计划的能力。那么就会如下面这个图所示:

System的运行流程但是实际的system执行流程不是我们想象的PerceptionSystem执行完之后调用MemorySystem这种传统做法,不同System之间是不存在调用关系的,每个System都会在一个规定的周期内执行一次,比如:

PerceptionSystem可能2s执行一次来更新接收到的外界感知,并把它们更新到PerceptionComponent之中。

MemorySystem可能会是每1s执行一次,从PerceptionComponent之中提取数据加载到MemoryComponent之中。

PlanSystem可能是每1000s执行一次,根据接收到的信息判断自己需不需要根据对应的目标优化制定合理的计划,然后把这部分更新记录到PlanComponent之中。

ActionSystem可能也是每2s执行一次,这样可以根据外界的信息及时做出反应,同时如果PlanComponent有更新则需要根据这部分数据更新自己的ActionComponent,进而影响最初做出的Action。

文章到这里都是基于我对ArgOS的理解大大简化了它的架构方便大家更好理解,接下来我们来看真实的ArgOS。

二、ArgOSSystem架构ArgOS之中为了让Agent可以进行更加深度的思考执行更复杂的任务,设计了很多Component,以及很多System。

并且ArgOS之中将System分为“三种层次”(ConsciousnessLevel):

1)有意识(CONSCIOUS)系统

包含RoomSystem,PerceptionSystem,ExperienceSystem,ThinkingSystem,ActionSystem,CleanupSystem)

更新频率通常较高(如每10秒)。

更贴近“实时”或“显意识”层面的处理,如环境感知、实时思考、执行动作等。

2)潜意识(SUBCONSCIOUS)系统

GoalPlanningSystem,PlanningSystem

更新频率相对较低(如每25秒)。

处理“思考”的逻辑,如周期性检查/生成目标和计划。

3)无意识(UNCONSCIOUS)系统

目前暂时还没有启用

更新频率更慢(如50秒以上),

所以在ArgOS之中是将不同的System根据ConsciousnessLevel划分,来规定这个System多久之后执行一次。

为什么要这么设计呢?因为ArgOS之中各个system之间的关系极其复杂,如下图:

1.PerceptionSystem负责从外界或其他实体那里收集“刺激”(stimuli),并将其更新到代理(Agent)的Perception组件中。判断刺激是否显著变化,根据稳定度、处理模式(ACTIVE/REFLECTIVE/WAITING)等做相应更新。最终为后续的ExperienceSystem、ThinkingSystem等提供“当前感知”的信息。 

2.ExperienceSystem将PerceptionSystem收集到的Stimuli转换为更加抽象的“体验”(Experience)。会调用LLM或规则逻辑(extractExperiences)来识别新的体验,并存储到Memory组件。去重、筛选、校验体验,同时通过eventBus触发“experience”事件给其他系统或外部监听者。 

3.ThinkingSystem智能体自身的“思考”系统。从Memory、Perception等组件里提取当前状态,通过generateThought(...)与LLM/规则逻辑生成“思考结果”(ThoughtResult)。根据思考结果,可能:

 •更新Memory中的thoughts(思考历史)。

•触发新的Action(放到Action.pendingAction[eid])。 

•改变agent的外在Appearance(表情、姿势等),并生成相关Stimulus让其他实体“看到”变化。 

4.ActionSystem若某个Agent的Action.pendingAction非空,则通过runtime.getActionManager().executeAction(...)来真正执行动作。执行完后将结果写回Action.lastActionResult,并通知房间或其他实体。也会借此产生CognitiveStimulus(认知刺激),以便后续系统“知道”该动作已完成,或可以纳入记忆。 

5.GoalPlanningSystem周期性地评估Goal.current[eid]列表中目标的进度,或检查外部/自身记忆是否出现重大变化(detectSignificantChanges)。当需要新目标或进行目标调整时,通过generateGoals(...)生成并写入Goal.current[eid]。同时更新在进度中(in_progress)的目标,若符合完成或失败条件就改变状态,并向相应Plan发出完成/失败信号。 

6.PlanningSystem对“已有目标”(Goal.current[eid])生成或更新Plan(执行计划)。如果检测到某些目标没有对应的活动中(active)计划,则通过generatePlan(...)产生一个包含若干steps的执行路线图,并将其写入Plan.plans[eid]。也会在目标完成或失败时更新与其关联的Plan状态,并产生相应认知刺激。 

7.RoomSystem处理与房间(Room)相关的更新:

•获取房间内的占用者列表(occupants),为每位agent生成“外观(appearance)”刺激,让其他实体“看到”他的外貌或动作。

•创建房间环境Stimulus(如贴切的“房间氛围”信息)并进行关联。

确保当Agent处于某个空间环境时,其他正在感知该空间的实体可以感知到他的外貌变化。 

8.CleanupSystem定期查找并移除标记了Cleanup组件的实体。用于回收不再需要的Stimulus或其他对象,防止ECS中遗留大量无效的实体。 

示例:从“看到物体”到“执行动作”的一次循环

下面的场景示例展示了各个System如何在一回合(或几帧)内依次配合完成一次完整流程。

场景准备:世界(World)中存在一个Agent(EID=1),正在“Active”状态,且处在某个Room(EID=100)。该Room里新出现了一个道具“MagicSword”,生成了相应的Stimulus。

PerceptionSystem检测到“MagicSword”的出现,对Agent(1)生成Stimulus(type=“item_appearance”)并添加到Perception.currentStimuli[1]。对比上一次StimuliHash,认定“有显著变化”,“重新激活”代理的ProcessingState(ACTIVE模式)。

ExperienceSystem看到Agent(1)的Perception.currentStimuli非空,于是把“Swordappears”之类的信息抽取为1条或多条新Experience(type:“observation”)。存储到Memory.experiences[1]里,并发射“experience”事件。

ThinkingSystem读取Memory、Perception等状态信息,调用generateThought:“我看到了MagicSword,也许能捡起来看看它能干什么...”该思考结果包含一个待执行的Action:{tool:"pickUpItem",parameters:{itemName:"MagicSword"}}ThinkingSystem将此Action写入Action.pendingAction[1]。若有appearance改动(例如“面带好奇的表情”),则更新Appearance并产生视觉刺激。

ActionSystem看到Action.pendingAction[1]={tool:"pickUpItem",parameters:...}。通过runtime.getActionManager().executeAction("pickUpItem",1,{itemName:"MagicSword"},runtime)执行“拾取”动作逻辑。得到结果:{success:true,message:"你捡起了魔法剑"},更新到Action.lastActionResult[1],并触发“action”事件广播给房间(100)。同时产生认知刺激(type=“action_result”),写入Memory或让ThinkingSystem下个回合捕获。

GoalPlanningSystem(若该agent有目标)周期性地评估agent的目标,如果此时agent的某个目标是“获得强力武器”,并检测到MagicSword已到手,可能将该目标标记为完成。如果产生/keySeatTrnewchanges(比如“新物体出现在房间”影响了agent追求的目标?),则根据detectSignificantChanges生成新的目标或放弃旧目标。

PlanningSystem(若有相关目标)对“获得强力武器”这样已完成或刚生成的目标,检查是否需要新Plan或更新既有Plan。如果已完成,则把关联的Plan[status]置为“completed”;或若目标要扩展后续流程(“研究魔法剑”),则生成更多步骤。

RoomSystem(每帧或每回合)更新房间(100)中的Occupants列表和可见实体。若agent(1)外观改变(比如Appearance.currentAction=“holdingsword”),就创建新的“appearance”视觉刺激,让其他在同房间的Agent2,Agent3知道“agent1拿起了剑”。

CleanupSystem移除已标记(Cleanup)的实体或刺激。若拾取后“MagicSword”这个Stimulus不再需要保留,可以在CleanupSystem中删除对应Stimulus实体。

通过这些系统的衔接,AIAgent就实现了:

 •感知环境变化(Perception)→记录或转化为内在经验(Experience)→自我思考并决策(Thinking)→付诸行动(Action)→动态调整目标与计划(GoalPlanning+Planning)→同步环境(Room)→及时回收无用实体(Cleanup)

三、ArgOS整体架构解析1.核心架构分层

2、组件(Component)分类在ECS中,每个实体(Entity)可拥有若干组件(Component)。根据在系统中的性质和生命周期,大致可以将组件分为以下几类:

核心身份类(Identity-LevelComponents)•Agent/PlayerProfile/NPCProfile等•用来唯一标识实体、存放核心角色或单位信息,一般需要持久化到数据库。

行为与状态类(Behavior&StateComponents)•Action,Goal,Plan,ProcessingState等•代表了实体当前要做的事情或目标,以及对外部命令、内部思维的响应状态。•包含pendingAction,goalsInProgress,plans,以及在队列中的思考或任务等。•通常为中/短期状态,很多会随着游戏回合或业务周期动态变化。•是否需要落库视情况而定。如果希望断点续跑,可能定期写入数据库。

感知与记忆类(Perception&MemoryComponents)•Perception,Memory,Stimulus,Experience等•记录了实体感知到的外部信息(Stimuli),以及感知后提炼成的体验(Experiences)。•Memory往往可积累大量数据,例如对话记录、事件历史等;常常需要做持久化。•Perception可能是实时或临时信息,多为短期内有效,可根据需求决定是否写入数据库(比如只存重要的感知事件)。

环境与空间类(Room,OccupiesRoom,Spatial,Environment,Inventory等)•代表房间、环境、位置、物品容器等信息。•

Room.id

、OccupiesRoom、Environment等字段常常需要持久化,如房间首页描述、地图结构等。•不断变化的组件(比如Entity在不同房间之间移动)可以做事件式或定期写入。外观与交互类(Appearance,UIState,Relationship等)•记录实体对外的“可见”或“交互”部分,如Avatar,pose,facialExpression,与其他实体的社交关系网络等。•一部分可只在内存中处理(实时表现),另一部分(比如关键社交关系)可能要持久化。

辅助或运维类(Cleanup,DebugInfo,ProfilingData等)•用于标记哪些实体需要回收(Cleanup)、或者记录调试信息(DebugInfo)以便在监控和分析时使用。•一般只在内存中存在,很少会同步到数据库unless日志或审计需要。

3.System架构上面已经介绍

4.Manager架构有了Component和System之外我们其实还缺少一个资源管理者,比如如何访问数据库,当状态更新有冲突怎么处理等等。

左侧Systems(PerceptionSystem、ExperienceSystem、ThinkingSystem等):

•每个系统在ECS循环中被SimulationRuntime调度执行,查询并处理自己关心的实体(通过组件条件)。

•在执行逻辑时,需要和Managers进行交互,例如:

调用RoomManager(RM)查询/更新房间信息。

使用StateManager(SM)获取或保存世界/代理状态,如Memory、Goal、Plan等。

借助EventBus(EB)对外广播或监听事件。

在某些需要自然语言处理或提示语时,调用PromptManager(PM)。

----------------

右侧Managers(EventBus、RoomManager、StateManager、EventManager、ActionManager、PromptManager等):

•提供系统级功能,基本不主动“驱动”逻辑,而是被Systems或Runtime调用。

•典型示例:

ActionManager专门管理动作(Action)的注册与执行。

EventManager/EventBus用于事件发布与订阅机制。

RoomManager管理rooms、布局与occupant。

StateManager负责ECS与数据库或存储的同步。

PromptManager提供LLMPrompt模板、上下文管理等扩展。

中间的SimulationRuntime(R):

•是所有Systems的“调度者”,启动或停止不同层级(Conscious/Subconscious等)的系统循环;

•也在构造阶段创建Managers并传给各System使用。

CleanupSystem:

•特别注意它还和ComponentSync(CS)交互,用于在回收实体时同步移除组件或事件订阅。

结论:每个System会在需要时通过对应的Manager读写数据或调用服务,而Runtime则在更高层面统一调度所有System与Manager的生命周期及行为。

5、如何向量与数据库进行交互在ECS中,Systems是真正执行逻辑的地方,而数据库读写可以通过一个“持久化管理器(PersistenceManager/DatabaseManager)”或“状态管理器(StateManager)”来完成。大致流程可如下:

启动或加载时(InitialLoad)•StateManager/PersistenceManager从数据库加载Agents、Rooms、Goals等核心持久化组件的数据,创建对应实体(Entities)并初始化相关组件字段。•例如,读取一批agent记录插入ECS世界,给他们初始化Agent、Memory、Goal等组件。

ECS运行时(SystemsUpdateLoop)•系统在每个帧(或回合)内做事情:PerceptionSystem收集“感知”并写到Perception组件(多为短期不落库)。ExperienceSystem把新的“认知体验”写入Memory.experiences,若是关键体验可能同时调用StateManager做立即存储,或打上“needsPersistence”标记以便后续批量写入。ThinkingSystem/ActionSystem/GoalPlanningSystem等根据组件内容做决策并更新ECS中的字段。如果某些组件(比如Goal.current)发生重大变更且需要持久化(例如新的长远目标),通过组件监听或系统事件,通知StateManager将该字段写入数据库。

定期或事件驱动的持久化(PeriodicorEvent-Driven)•可以在系统中的某些关键点(如目标计划发生更新或Agent发生重要事件)时,调用PersistenceManager.storeComponentData(eid,"Goal")这类接口进行落库。•也可以在CleanupSystem或定时器里,让StateManager扫描含有“needsPersistence”标记的组件或实体,一次性写回数据库。•此外,日志或审计数据(如动作历史、思考日志)也可在这里进行归档存储。

退出或断点保存(ManualorShutdownSave)•当服务器或进程要关闭时,通过StateManager.saveAll()将还没写入的数据统一写入数据库,以确保下次加载能恢复ECS状态。•对于一些单机/离线场景,也可以手动触发存档。

完整示例流程

以下给一个简单的场景,演示组件和数据库交互的可能方式:

启动时:StateManager.queryDB("SELECT*FROMagents")→得到一批agent记录,依次为每条记录创建Entity(EID=x),并给其初始化Agent、Memory、Goal等组件字段。同时从“rooms”表里加载房间信息,创建Room实体。

运行阶段:PerceptionSystem在某个房间检测到事件“MagicSword出现”,写入Perception.currentStimuli[eid]。ExperienceSystem将Stimuli转化为Experience,赋值到Memory.experiences[eid]。ThinkingSystem通过Memory、Goal等信息决定执行下一步行动,生成Action.pendingAction[eid]。ActionSystem执行该动作后,将结果写到Memory或Action.lastActionResult。若这是一次重大剧情事件,会把Memory.experiences[eid]的最新部分标记为needsPersistence。StateManager在一段时间后发现Memory.experiences[eid]带有“needsPersistence”,则将其写入数据库(INSERTINTOmemory_experiences...)。

停止或断点:基于ECS或系统调度,在“服务器关闭”时调用StateManager.saveAll(),把仍在内存中的关键组件字段(Agent,Memory,Goal等)它们的最新状态写进数据库。下次重启时,就能从数据库中加载并恢复ECS的世界状态。

•将组件分类,既方便在项目中清晰地管理实体数据,也能帮助我们控制“需要持久化”与“仅在内存中存在”的数据边界。•与数据库的交互通常由一个专门的Manager(如StateManager)来处理,Systems在需要读写数据库时通过它进行操作,避免在System里直接写SQL或类似底层语句。•这样能同时享受到ECS在逻辑上的高效与灵活,以及数据库带来的持久化、断点续跑与数据统计分析优势。

五、架构创新点

整个架构的亮点在于:

每个System都是独立运行的,不会跟其他的System之间有调用关系,因此即便我们希望实现Agent的“感知环境变化(Perception)→记录或转化为内在经验(Experience)→自我思考并决策(Thinking)→付诸行动(Action)→动态调整目标与计划(GoalPlanning+Planning)→同步环境(Room)→及时回收无用实体(Cleanup)”能力的时候,各个System在功能上会有很多互相依赖的点,但是我们依然可以通过ECS架构把整体结构成各个互不相关的System,每个System依然可以独立运行,不会跟其他的System有人和耦合关系。我想这也是为什么Unity这几年越来越往ECS架构迁移最主要的原因。

而且比如我现在只是希望一个Agent拥有一些基本能力,我只需要在定义Entity的时候减少注册一些Component以及减少注册System就可以轻易的实现,都不用改几行代码。

如下图:

同时如果你在开发过程中希望增加新的功能,也不会对其他的System有任何影响,可以很轻易的把自己希望的功能加载进去。另外当前这种架构的性能其实会比传统面向对象架构的性能强很多,这在游戏圈是一个公认的事实,因为ECS的设计更加适合进行并发,那么当我们在复杂的Defai场景下,采用ECS架构也有可能会更有优势,特别是希望采用Agent做量化交易的场景下,ECS也会有用武之地(不仅仅是在Agent游戏场景下)。

将System分成有意识、潜意识和无意识来区分不同类型的System应该在多久后执行一次,是极其高明的设计,已经是一个很具象的人的能力了

从我个人的观点来看,这是一个极其模块化,性能极其优秀的框架,同时代码质量也很高并且包含了很好的设计文档,不过可惜的是$project89项目一直缺少对这个框架的宣传,因此我才花了很长的时间(4天)写了这篇文章,我觉得好的东西还是值得被发现,明天应该还会发一个英文版本,希望能有更多的游戏团队或者Defai团队开到这个框架,为大家提供一种新的潜在的架构选择!

相关新闻

如何解决国内无法访问欧意交易所(OKX)的问题?

如何解决国内无法访问欧意交易所(OKX)的问题?

12 Aug, 2019

如果你在国内访问欧意交易所(OKX)时遇到打不开的情况,不用担心。这类问题通常是由于访问限制或网络问题引起的。<

  • 604
  • 欧易
如何修改欧易交易所绑定的邮箱:详细操作指南

如何修改欧易交易所绑定的邮箱:详细操作指南

12 Aug, 2019

在使用欧易(OKX)交易所时,邮箱是账户管理和安全验证的重要工具。邮箱绑定后,用户将通过它接收平台的通知、交易确认以及安全验证等重要信息。<

  • 588
  • 欧易
无法登录欧意交易所?解决国内无法访问问题的有效方法

无法登录欧意交易所?解决国内无法访问问题的有效方法

12 Aug, 2019

如果你在国内使用欧意交易所(OKX)时遇到登录不上或者打不开官网(www.okx.com)的情况,不用太担心。<

  • 572
  • 欧易
如何在欧意交易所注销账户后重新注册?

如何在欧意交易所注销账户后重新注册?

12 Aug, 2019

在使用欧意(OKX)交易所的过程中,部分用户可能由于各种原因选择注销账户。<

  • 553
  • 欧易
欧意交易所账户被冻结如何解封?解决方法全解析

欧意交易所账户被冻结如何解封?解决方法全解析

12 Aug, 2019

在使用欧意交易所(OKX)进行交易时,账户被冻结可能会给用户带来不小的困扰。<

  • 529
  • 欧易
欧意交易所实名认证失败怎么办?实用解决步骤

欧意交易所实名认证失败怎么办?实用解决步骤

12 Aug, 2019

在使用欧意交易所(OKX)进行加密货币交易时,实名认证(KYC)是不可绕过的重要步骤。<

  • 526
  • 欧易