解密Prompt系列18. LLM Agent之只有智慧體的世界

風雨中的小七發表於2023-10-28

重新回來聊Agent,前四章的LLM Agent,不論是和資料庫和模型還是和搜尋引擎互動,更多還是大模型和人之間的互動。這一章我們來嘮嘮只有大模型智慧體的世界!分別介紹史丹佛小鎮和Chatdev兩篇論文。它們的共同特點是使用多個大模型智慧體協同完成任務。

多智慧相比單一智慧體可能有以下的應用場景

  • 協同任務完成/創意生成:透過多智慧體間的溝通,反思,校驗,完成複雜任務,激發創意的小火花
  • 模擬世界:多智慧體模擬社會環境,現實應用是遊戲NPC,腦洞再大一點是不是可以用於社會學研究,因果推斷,平行世界模擬??

生活番:Generative Agents

史丹佛小鎮算是這幾個月來看到的最有意思的大模型應用了,作者設計了虛擬的小鎮環境,並在其中設計眾多不同性格的虛擬智慧體,完全基於LLM的生成能力,讓眾多AI們在小鎮中開始了生活,思考和互動。

生活環境和經歷塑造了每一個個體,AI也不例外,所以後面的介紹我們會圍繞以下三個核心元件相關程式碼來展開

  • 沙盒環境: 描述AI們的生存環境,並讓AI感知當前所處環境,並隨AI行動更新環境狀態
  • 智慧體框架
    • 行為規劃:智慧體每一步行為的生成
    • 記憶流: 智慧體歷史記憶的儲存

在以上元件的加持下,小鎮中的智慧體們會發生以下基礎行為

  1. 智慧體行為:智慧體根據當前狀態和歷史經歷,決定下一步是吃飯睡覺還是打豆豆
  2. 智慧體互動:智慧體間的互動透過交流或指令進行,當智慧體處於同一環境中時可能會觸發交流對話
  3. 智慧體和環境互動:智慧體行為會改變環境狀態,例如智慧體睡覺時,環境中床的狀態就會變成“Occupied”。當然我們也可以直接修改環境狀態
  4. 智慧體規劃:想要觸發以上1和2的行為和互動,智慧體肯定不能在小鎮裡隨機遊走。論文的實現是讓智慧每天都生成一天的Todo List,根據計劃行動,並在行動中不斷更新當日計劃。
  5. 智慧體自我思考:透過對歷史經歷的不斷總結和反思得到更高階層次的自我思考,從而影響日常智慧體的行為
  6. 其他衍生能力:資訊在智慧體之間傳播,多智慧體合作,etc

沙盒環境

這裡我們把沙盒環境放到第一個部分,因為個人感覺如何定義環境,決定了

  • Perceive:智慧體能接收到哪些環境資訊
  • Action:智慧體可以做出哪些行為,包括在當前位置行為,和位置移動
  • Influence: 行為可以對環境產生哪些影響
  1. 地圖(maze.py)
    環境本身被抽象成一個二維矩陣,這類二維遊戲地圖也叫瓦片地圖(Tiled Map)。地圖上每一個瓦片,都是一個字典儲存了該瓦片內的所有資訊,以下資訊中的events欄位都是智慧體可以感知,並影響的環境資訊。
self.tiles[9][58] = {'world': 'double studio', 
'sector': 'double studio', 'arena': 'bedroom 2', 
'game_object': 'bed', 
'spawning_location': 'bedroom-2-a', 
'collision': False,
'events': {('double studio:double studio:bedroom 2:bed', None, None)}} 

同時Maze還儲存了一份倒排索引,也就是給定當前智慧體當前的地址,需要返回在地圖中對應的二維座標,這樣就可以規劃智慧體從當前位置到某個地點的行動路徑。

self.address_tiles['<spawn_loc>bedroom-2-a'] == {(58, 9)}
  1. 環境感知(perceive.py)
    有了環境,再說下智慧體如何感知環境。給定智慧體當前在地圖中的位置,智慧體可以感知周圍設定範圍內所有瓦片中最新的事件。如果周圍發生的事件太多,會先按照和智慧體之間的距離排序,選擇最近的N個。同時對於智慧體之前未感知的事件,會加入到智慧體的記憶流中。

記憶流

記憶流的設計算是論文的一大核心,分成以下兩個部分

  • 記憶提取:其一是傳統的RAG,也就是智慧體的每一步行為都需要依賴智慧體的歷史記憶,如何抽取相關記憶是核心
  • 記憶儲存:其二是智慧體的記憶除了感知的環境,還包含哪些資訊?

記憶提取(retrieve.py)

話接上面的環境感知部分,智慧體感知到了周邊的環境是第一步,第二步就是用感知到的資訊,去召回智慧體相關的歷史記憶。這裡被召回的記憶,除了之前感知的環境和事件,還有思考記憶,思考後面會講到。召回除了使用embedding相似度召回之外, 記憶召回加入了另外兩個打分維度時效性重要性

其中時效性打分是一個指數時間衰減模組,給久遠的記憶降權,哈哈時效性打分是個寶,在很多場景下都是相似度的好伴侶,實際應用場景中RAG真的不止是一個Embedding模型就夠用的。

重要性打分是基於大模型對每個記憶的重要程度進行打分。打分指令如下

最後在召回打分時,相似度,時效性,重要性進行等權加和。

記憶儲存 (reflect.py)

智慧體記憶流中儲存的除了感知到的環境之外,論文還增加了一類很有趣的思考記憶。哈哈不由讓我想起了工作中聽到的一個梗"老闆說不能只幹活,你要多思考!!"

觸發機制也很有insight,就是每個智慧體會有一個重要性Counter,當近期智慧體新觀察到的各類事件的重要性打分之和超過某個閾值,就觸發思考任務。哈哈今天你思考了麼?沒有的話來學習下智慧是如何思考的,對打工人很有啟發喲

  • 第一步定位問題??論文取了智慧體近100條的記憶,透過指令讓模型從中提N個問題。指令如下
Given only the information above, what are !<INPUT 1>! most salient high-level questions we can answer about the subjects grounded in the statements?
1)
  • 第二步反思問題??針對以上N個問題進行相關記憶的抽取,然後基於抽取記憶進行思考。這裡允許召回的記憶本身是之前生成的思考,也就是基於思考再思考,基於反思再反思。從這裡我真的看好智慧體成為天選打工人......
What !<INPUT 1>! high-level insights can you infer from the above statements? (example format: insight (because of 1, 5, 3))
1.

最後生成的思考會儲存入記憶流中,用於之後的行為規劃或者再進一步的思考。

行為和規劃

最後一個模組是行為規劃(plan.py),也是最主要的模組,決定了智慧體在每一個時間點要做什麼,也是之智慧體記憶流中的第三種記憶型別

除了基於當前狀態去生成下一步行為之外,論文比較有意思的是先規劃了智慧體每一天的待辦事項,然後在執行事項的過程中,進行隨機應變。從而保證了智慧體在更長時間軸上連續行為的連貫性,一致性,和邏輯關聯。

長期規劃:每日待辦

智慧體每日待辦事項是透過自上而下的多步拆解,使用大模型指令生成的(plan.py)

第一步,冷啟動,根據任務特點,生成智慧體的作息時間,如下

第二步,生成小時級別的事項規劃。這裡並非一次生成所有事項,而是每次只基於智慧體的所有靜態描述,包括以上生成的生活作息,個人特點等等(下圖),和上一個生成事項,來規劃下一個事項。模型指令是1-shot,輸出事項和事項持續的事件

第三步,是把小時級的事項規劃進行事項拆解,拆分成5-分鐘級別的待辦事項。模型指令同樣是1-shot,模板給出一個小時級別任務的拆分方式,讓模型去依次對每個小時的事項進行拆解,模型指令中1-shot的部分格式如下:

Today is Saturday May 10. From 08:00am ~09:00am, Kelly is planning on having breakfast, from 09:00am ~ 12:00pm, Kelly is planning on working on the next day's kindergarten lesson plan, and from 12:00 ~ 13pm, Kelly is planning on taking a break. 
In 5 min increments, list the subtasks Kelly does when Kelly is working on the next day's kindergarten lesson plan from 09:00am ~ 12:00pm (total duration in minutes: 180):
1) Kelly is reviewing the kindergarten curriculum standards. (duration in minutes: 15, minutes left: 165)
2) Kelly is brainstorming ideas for the lesson. (duration in minutes: 30, minutes left: 135)
3) Kelly is creating the lesson plan. (duration in minutes: 30, minutes left: 105)
4) Kelly is creating materials for the lesson. (duration in minutes: 30, minutes left: 75)
5) Kelly is taking a break. (duration in minutes: 15, minutes left: 60)
6) Kelly is reviewing the lesson plan. (duration in minutes: 30, minutes left: 30)
7) Kelly is making final changes to the lesson plan. (duration in minutes: 15, minutes left: 15)
8) Kelly is printing the lesson plan. (duration in minutes: 10, minutes left: 5)
9) Kelly is putting the lesson plan in her bag. (duration in minutes: 5, minutes left: 0)

最終分鐘級別的待辦事項會作為智慧體當日的主線行為,寫入以上的記憶流中,在之後的每一次行為規劃中,提醒智慧體,當前時間要乾點啥。

短期規劃:隨機應變

以當日長期行為規劃為基礎,智慧體在按計劃完成當日事項的過程中,會不時的感知周圍環境。當出現新的觀測事件時,智慧體需要判斷是否需要觸發臨時行為,並調整計劃。這裡主要分成兩種臨時行為:交流和行動。這兩種行為的觸發會基於智慧體當前的狀態,和大模型基於上文的指令輸出,例如對於是否產生對話行為的判斷

當智慧體A,出現在當前智慧體可以感知的環境範圍內時,透過以上的環境感知模組,智慧體的記憶流中會出現智慧體A的當前行為。這時智慧體會在記憶流中檢索和智慧體A相關的記憶,合併當前狀態作為上文,使用大模型指令判斷是否要發起和A的對話

如果判斷需要發起對話,則觸發對話模組進行交流,而交流是所有社會性行為產生的根本。

效果

主要模組基本就說這麼多,技術評估就不多說了,在智慧體行為上論文驗證了當前框架會產生一定的社會效應,包括資訊會在智慧體之間傳播,智慧體之間會形成新的關係,以及智慧體間會合作完成任務等等。

論文也討論了當前框架的一些不足,包括如何在更長時間週期上泛化,如何避免智慧體犯一些低階錯誤,例如躺上有人的床哈哈哈哈~

個人感覺還需要討論的是如何在當前的記憶流中衍生成更高階的,抽象的思考,以及對世界的認知。這些認知是否有更高效,結構化的儲存和召回方式。只依賴反思和記憶流的線性儲存可能是不夠的。

職場番:ChatDev

哈哈如果說史丹佛小鎮對標綜藝桃花塢,那ChatDev就是對標令人心動的Offer。論文參考了史丹佛小鎮的記憶流,CAMEL的任務導向型對話方案,透過智慧體間對話協同完成特定軟體開發任務

論文把軟體開發流程,抽象成多個智慧體的對話型任務。整個開發流程分成設計,程式設計,測試,文件編寫四個大環節,每個環節又可以拆分成多個執行步驟,其中每個步驟都由兩個角色的智慧體透過對話合作來完成,如下

在進入主要流程前,讓我們先完成準備工作。開發流程的準備工作需要定義三類配置檔案,原始碼提供了預設的配置檔案,使用者可以根據自己的需求,選擇覆蓋部分配置。配置檔案從Top to Bottom分別是

  1. ChatChainConfig:定義了整個任務鏈的所有步驟和執行順序(phrase),以及所有參與的智慧體角色。

以預設配置為例,任務鏈包含以下步驟:DemandAnalysis -> LanguageChoose -> Coding -> CodeCompleteAll -> CodeReview -> Test -> EnvironmentDoc -> Manual

參與智慧體角色包括:CEO,CFO, CPO, CCO, CTO, programmer,Reviewer,Tester等

  1. PhaseConfig:下鑽到每個步驟,分別定義了每個步驟的prompt指令,以及參與的兩個Agent角色。

  2. RoleConfig:下鑽到每個角色,分別定義了每個角色的prompt指令

初始化配置檔案後我們進入軟體開發的四個主要流程~

Design

產品設計環節,負責把使用者需求轉化成專案方案,包括兩個原子步驟:CEO和CPO進行需求分析和產品設計,CEO和CTO選擇程式語言。考慮每個phase的實現其實是相似的,只不過參與智慧體不同,以及phase對應的指令和多輪對話形式不同,這裡我們只說CEO和CPO之間關於需求分析對話實現(role_play.py)~

這裡融合了CAMEL的Inception Prompting和史丹佛小鎮的記憶流和自我反思來完成任務導向的對話。

  1. Role Assignment

首先初始化參與phase的兩個智慧體角色,並生成初始prompt(Inception Prompt)。包括使用者需求(task_prompt),本階段的任務描述(phase_prompt)和兩個智慧體的角色描述(role_prompt)。

基於初始指令,之後兩個智慧體會透過對話相互為對方生成指令,而人工參與的部分只有最初的角色描述和任務描述,所以叫初始指令。產品涉及環節的具體指令如下,需求分析階段的任務指令使用了few-shot,給出不同的產品形態例如圖片,文件,應用等實現方式,並明確了對話的兩個智慧體的討論主題,以及終止討論的條件,即確定產品形態

以下是論文附錄給出的一個需求分析階段的具體對話示例,不過對話終止符似乎變成了<END>

  1. Memory Stream

老實說感覺這裡的memoery stream和上面小鎮中實現的memory stream關聯似乎並不是很大。看程式碼實現,對話是直接使用上文對話history作為輸入,只有當輸入上文長度超長的時候,會保留Inception prompt和最近的N輪對話......難道是我漏看了程式碼,如果是請評論指出 >.<

  1. Self-Reflection

小鎮中自我反思是為了產生更抽象,更高階的個人思考。而在這篇論文self-Reflection其實更像是會議總結模組,當多輪對話完成,但是並未出現對話停止<END>符號,這時可以觸發總結模組,把前面的多輪對話作為上文,來總結對話得到的結論,用於後續步驟的進行,如下

Coding

程式設計環節包括兩個基本步驟:後端寫程式碼,和前端設計互動介面。程式設計環節最大的難點就是如何避免模型幻覺,最大正度保證程式碼的正確性,以及在多輪對話中如何進行復雜長程式碼的編寫和修改。這裡同樣我們只說下後端編寫程式碼這一個步驟。

程式碼編寫步驟的核心指令如下,CTO智慧體給程式設計師智慧體的指令是:以物件導向的程式語言python為基礎,先給出核心類和方法。程式設計師智慧體會按照指令以markdown為語法進行程式碼和註釋的編寫。之後程式碼編寫環節會迴圈執行N次多輪對話,不斷對程式碼進行更新最佳化。

在指令的基礎上,為了最佳化複雜程式碼的編寫效果,論文在程式碼編寫環節引入了version control環節。在每一步程式碼編寫完成後,會使用difflib對兩版程式碼進行比對,並從記憶流中刪除舊版本的程式碼,這樣對話會永遠基於最新的程式碼版本進行,對最新程式碼進行不斷更新。

Testing

測試環節包括兩個基本步驟:程式碼評審和測試環節。

評審環節,程式設計師智慧體會給評審智慧體指令,讓其對程式碼進行檢查,例如是否有未實現的類或方法,以及整個專案是否符合使用者需求等等(角色指令如下圖),並給出評審建議。其次程式設計師之智慧體會基於以上建議對程式碼進行調整。

測試環節是基於程式碼執行後出現的bug進行修復。論文在這裡引入了Thought Instruction,有點類似Decomposed Prompt的任務拆分。因為如果直接基於程式碼執行bug讓大模型進行修復,問題可能過於複雜導致模型無法直接修復,或者產生幻覺。因此透過多輪對話引入一步任務拆分,先經過TestErrorSummary步驟對測試bug的位置和產生原因進行總結,再基於以上總結進行程式碼調整。

Documentation

文件生成環節就比較簡單了,包括多個phase步驟,一個phase對應一類文件說明。這裡使用了few-shot指令來引導智慧體生成requirements.txt, README.MD等使用者文件,以下是生成requirements.txt的指令示例

效果

效果上ChatDev從CAMEL程式設計相關的任務中隨機抽了70個任務進行測試,任務平均程式碼量是131行程式碼,4個檔案,3個上游依賴庫,說明ChatDev整體生成的軟體還是偏簡單,小型,不涉及複雜的設計。具體效果大家可以直接去Chatdev的程式碼庫裡給的生成案例感受下。在這樣的程式碼複雜度下,ChatDev最終程式碼的執行成功率在86% ,平均任務完成時間在7分鐘左右,且呼叫成本相對較低。

除了以上提到了兩個比較火爆的多智慧體協同應用,還有很多相關應用和開源實現,這裡就不一一介紹了,感興趣的同學可以去自己試試看

  • AgentSims:國內開源的類似史丹佛小鎮
  • AgentVerse:多模型互動環境
  • MetaGPT:覆蓋軟體公司全生命流程,例如產品經理等各個職業的AutoGPT
  • CAMEL:任務導向型,溝通式多智慧體協同框架,Chatdev的基礎

想看更全的大模型相關論文梳理·微調及預訓練資料和框架·AIGC應用,移步Github >> DecryPrompt

相關文章