我在 Project89 內看到下一代 Agent 框架
作者:0xhhh
先說結論,@project_89採用一種全新的方式來設計Agent Framework, 這是一個針對遊戲開發的高性能的Agent Framework,與目前使用的Agent Framework相比更加模塊化也有更好的性能。
這篇文章花了很長的時間來寫,試圖讓所有人都懂這個框架相比傳統Agent框架在架構上做了什麼升級,前後改了很多次才有了這個版本,但是文中仍然 有些部分太過技術,我沒能很好的進一步通俗化,如果你對文章改進有任何建議歡迎留下你的評論。
開發者背景
這是一篇技術博客,所以我們先來看看這個founder的技術實力:
Founder在做project89之前做了這個專案:https://github.com/Oneirocom/Magick,也是一款利用AI進行程式設計的軟體同時shaw也是這個專案排名第四的開發者,在shaw的履歷 裡也可以看到這個項目。
左上:project89的founder , 右下:lalaune 就是ai16z的shaw
而今天我們主要來介紹下 project89 裡面的高性能 Agent Framework:
https://github.com/project-89/argOS
一、為什麼要用ECS來設計Agent Framework
從遊戲領域的應用來看目前採用ECS架構的遊戲有: 區塊鏈遊戲:Mud、Dojo 傳統遊戲: 守望先鋒、星際公民等等而且目前主流的遊戲引擎也在往ECS的方向進化比如 Unity。
什麼是 ECS?
ECS(Entity-Component-System)是一種在遊戲開發與模擬系統中常用的架構模式。 它將資料與邏輯徹底分離,以便在大規模可擴展場景下高效管理各種實體及其行為:
Entity(實體) • 只是一個 ID(數字或字串),不包含任何資料或邏輯。 • 可以根據需要,掛載不同的元件來賦予它各種屬性或能力。
Component(元件) • 用來儲存實體的特定資料或狀態。
System(系統) • 負責執行與某些元件相關的邏輯。
以一個具體的Agent行動的例子來理解這套體系: 在ArgOS 中將每一個Agent看成一個Entity,它可以註冊不同的組件,比如在下面這幅圖裡,我們這個Agent擁有以下四 個組件: Agent Component:主要存儲類似Agent 名稱,模型名字等等基礎信息Perception Component:主要用來存儲感知到的外界數據Memory Component:主要用來存儲Agent Entity的Memory數據,類似做過的事情等等 Action Component:主要存儲要執行的Action 數據。
System 的工作流程:
在這個遊戲裡比如感知到了自己面前有一個武器,那麼這個就會調用 Perception System的執行函數來執行更新這個Agent Entity 的Perception Component 裡面的數據;
然後再觸發 Memory System, 同時調用 Perception Component 和 Memory Component, 把感知到的數據通過Memory持久化到數據庫之後;
然後 Action System 再調用Memory Component 和 Action Component ,從記憶中獲取周邊環境的信息,然後最終執行相應的動作;
接著我們就得到一個每個Component數據 都被更新的 Update Agent Entity 所以我們可以看到這裡面System 主要負責定義要對哪些Component 執行對應的處理邏輯。
而且很明顯在 project89 裡面它是一個世界裡面充斥著各種類型的 Agent,比如有些Agent不僅僅擁有以上的基礎能力還有做計劃的能力。 那麼就會如下面這個圖所示:
System的運作流程
但是實際的system 執行流程不是我們想像的Perception System執行完之後調用Memory System 這種傳統做法,不同System之間是不存在調用關係的,每個System都會在一個規定的周期內執行一次, 如:
Perception System可能2s執行一次來更新接收到的外界感知,並把它們更新到 Perception Component之中
Memory System 可能會是每1s執行一次,從Perception Component 之中提取資料載入到Memory Component之中
Plan System可能是每 1000s執行一次,根據接收到的資訊判斷自己需不需要根據對應的目標優化製定合理的計劃,然後把這部分更新記錄到 Plan Component之中
Action System 可能也是每2s執行一次,這樣可以根據外界的信息及時做出反應,同時如果Plan Component有更新則需要根據這部分數據更新自己的Action Component,進而影響最初做出的Action.
文章到這裡都是基於我對ArgOS 的理解大大簡化了它的架構方便大家更好理解,接下來我們來看看真實的ArgOS。
二、ArgOS System 架構
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之間的關係極其複雜,如下圖:
PerceptionSystem負責從外界或其他實體收集「刺激」(stimuli),並將其更新到代理(Agent)的 Perception 元件中。 判斷刺激是否顯著變化,根據穩定度、處理模式 (ACTIVE/REFLECTIVE/WAITING) 等做相應更新。 最終為後續的 ExperienceSystem、ThinkingSystem 等提供「當前感知」的資訊。
ExperienceSystem將 PerceptionSystem 收集到的 Stimuli 轉換為更抽象的「體驗」(Experience)。 會呼叫 LLM 或規則邏輯 (extractExperiences) 來識別新的體驗,並儲存到 Memory 元件。 去重、篩選、校驗體驗,同時透過 eventBus 觸發「experience」事件給其他系統或外部監聽者。
ThinkingSystem智能體自身的「思考」系統。 從 Memory、Perception 等元件中提取當前狀態,透過 generateThought(...) 與 LLM / 規則邏輯產生「思考結果」(ThoughtResult)。 根據思考結果,可能: • 更新 Memory 中的 thoughts (思考歷史)。 • 觸發新的 Action(放到 Action.pendingAction[eid])。 • 改變 agent 的外在 Appearance(表情、姿勢等),並產生相關 Stimulus 讓其他實體「看到」變化。
ActionSystem若某個 Agent 的 Action.pendingAction 非空,則通過 runtime.getActionManager().executeAction(...) 來真正執行動作。 執行完後將結果寫回 Action.lastActionResult,並通知房間或其他實體。 也會藉此產生 CognitiveStimulus(認知刺激),以便後續系統“知道”該動作已完成,或可以納入記憶。
GoalPlanningSystem週期性地評估 Goal.current[eid] 列表中目標的進度,或檢查外部/自身記憶是否出現重大變化 (detectSignificantChanges)。 當需要新目標或進行目標調整時,通過 generateGoals(...) 生成並寫入 Goal.current[eid]。 同時更新在進度中 (in_progress) 的目標,若符合完成或失敗條件就改變狀態,並向相應 Plan 發出完成/失敗信號。
PlanningSystem對“已有目標”(Goal.current[eid])生成或更新 Plan(執行計劃)。 如果檢測到某些目標沒有對應的活動中 (active) 計劃,則通過 generatePlan(...) 產生一個包含若干 steps 的執行路線圖,並將其寫入 Plan.plans[eid]。 也會在目標完成或失敗時更新與其關聯的 Plan 狀態,並產生相應認知刺激。
RoomSystem處理與房間(Room)相關的更新: • 取得房間內的佔用者清單(occupants),為每位agent 產生「外觀(appearance)」刺激,讓其他實體「看到」他的外貌或 動作。 • 建立房間環境 Stimulus (如貼切的「房間氛圍」訊息) 並進行關聯。 確保當 Agent 處於某個空間環境時,其他正在感知該空間的實體可以感知到他的外貌變化。
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]。 對比上一次 Stimuli Hash,認定“有顯著變化”,“重新激活”代理的 ProcessingState (ACTIVE 模式)。
ExperienceSystem看到 Agent(1) 的 Perception.currentStimuli 非空,於是把“Sword appears”之類的信息抽取為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 已到手,可能將該目標標記為完成。 如果產生/keySeatTr new changes (例如「新物件出現在房間」影響了 agent 追求的目標?),則根據 detectSignificantChanges 產生新的目標或放棄舊目標。
PlanningSystem (若有相關目標)對“獲得強力武器”這樣已完成或剛生成的目標,檢查是否需要新 Plan 或更新既有 Plan。 如果已完成,則把關聯的 Plan [status] 置為 “completed”;或若目標要擴展後續流程 (“研究魔法劍”),則生成更多步驟。
RoomSystem (每幀或每回合)更新房間(100)中的 Occupants 列表和可見實體。 若 agent(1) 外觀改變(比如 Appearance.currentAction = “holding sword”),就創建新的「appearance」視覺刺激,讓其他在同房間的 Agent2, Agent3 知道“agent1 拿起了劍”。
CleanupSystem移除已標記(Cleanup)的實體或刺激。 若拾取後「MagicSword」這個 Stimulus 不再需要保留,可以在 CleanupSystem 中刪除對應 Stimulus 實體。
透過這些系統的銜接,AI Agent 就實現了: • 感知環境變化(Perception) → 記錄或轉化為內在經驗(Experience) → 自我思考並決策(Thinking) → 付諸行動(Action) → 動態調整 目標與計畫(GoalPlanning + Planning) → 同步環境(Room) → 及時回收無用實體(Cleanup)。
三、ArgOS整體架構解析
1. 核心架構分層
2、元件(Component)分類
在 ECS 中,每個實體 (Entity) 可擁有若干組件 (Component)。 根據在系統中的性質和生命週期,大致可以將組件分為以下幾類:
核心身分類別 (Identity-Level Components) • Agent / PlayerProfile / NPCProfile 等人 • 用來唯一識別實體、存放核心角色或單位訊息,一般需要持久化到資料庫。
行為與狀態類 (Behavior & State Components) • Action, Goal, Plan, ProcessingState 等 • 代表了實體當前要做的事情或目標,以及對外部命令、內部思維的響應狀態。 • 包含 pendingAction, goalsInProgress, plans, 以及在隊列中的思考或任務等。 • 通常為中/短期狀態,很多會隨著遊戲回合或業務週期動態變化。 • 是否需要落庫視情況而定。 如果希望斷點續跑,可能定期寫入數據庫。
知覺與記憶類別 (Perception & Memory Components) • Perception, Memory, Stimulus, Experience 等 • 記錄了實體感知到的外在資訊 (Stimuli),以及感知後提煉成的經驗 (Experiences)。 • Memory 往往會累積大量數據,例如對話記錄、事件歷史等;常常需要做持久化。 • Perception 可能是即時或臨時訊息,多為短期內有效,可依需求決定是否寫入資料庫(例如只存重要的感知事件)。
外觀與交互類 (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 提供LLM Prompt範本、上下文管理等擴充功能。
中間的 SimulationRuntime (R):
• 是所有 Systems 的“調度者”,啟動或停止不同層級(Conscious/Subconscious等)的系統循環;
• 也在構造階段創建 Managers 並傳給各 System 使用。
CleanupSystem:
• 特別注意它還和 ComponentSync (CS) 交互,用於在回收實體時同步移除組件或事件訂閱。
結論: 每個 System 會在需要時透過對應的 Manager 讀寫資料或呼叫服務,而 Runtime 則在更高層次統一調度所有 System 與 Manager 的生命週期及行為。
5、 如何向量與數據庫進行交互
在 ECS 中,Systems 是真正執行邏輯的地方,而資料庫讀寫可以透過一個「持久化管理器 (PersistenceManager / DatabaseManager)」或「狀態管理器 (StateManager)」來完成。 大致流程可如下:
啟動或載入時 (Initial Load) • StateManager / PersistenceManager 從資料庫載入 Agents、Rooms、Goals 等核心持久化元件的數據,建立對應實體 (Entities) 並初始化相關元件欄位。 • 例如,讀取一批 agent 記錄插入 ECS 世界,給他們初始化 Agent、Memory、Goal 等元件。
ECS 運行時 (Systems Update Loop) • 系統在每個幀 (或回合) 內做事情:PerceptionSystem 收集“感知”並寫到 Perception 組件 (多為短期不落庫)。 ExperienceSystem 把新的“認知體驗”寫入 Memory.experiences,若是關鍵體驗可能同時調用 StateManager 做立即存儲,或打上“needsPersistence”標記以便後續批量寫入。 ThinkingSystem / ActionSystem / GoalPlanningSystem 等根據組件內容做決策並更新 ECS 中的字段。 如果某些組件 (比如 Goal.current) 發生重大變更且需要持久化(例如新的長遠目標),通過組件監聽或系統事件,通知 StateManager 將該字段寫入數據庫。
定期或事件驅動的持久化(Periodic or Event-Driven) • 可以在系統中的某些關鍵點(如目標計劃發生更新或Agent發生重要事件)時,調用PersistenceManager.storeComponentData(eid, "Goal ") 這類接口進行落庫。 • 也可以在 CleanupSystem 或定時器裡,讓 StateManager 掃描含有“needsPersistence”標記的組件或實體,一次性寫回數據庫。 • 此外,日誌或審計數據(如動作歷史、思考日誌)也可在這裡進行歸檔存儲。
退出或斷點保存(Manual or Shutdown Save) • 當服務器或進程要關閉時,通過StateManager.saveAll() 將還沒寫入的數據統一寫入數據庫,以確保下次加載能恢復ECS 狀態 。 • 對於一些單機/離線場景,也可以手動觸發存檔。
完整範例流程
以下給一個簡單的場景,演示組件和數據庫交互的可能方式:
啟動時:StateManager.queryDB("SELECT * FROM agents") → 得到一批 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”,則將其寫入資料庫(INSERT INTO memory_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 團隊開到這個框架,提供大家新的潛在的架構選擇!