當前位置: 華文問答 > 數位

AI領域的agent是什麽意思?

2016-10-02數位

今年四月份讀了史丹佛Generative Agent的論文,覺得特別好玩,花幾天時間實作了這個demo。後來拿著這個demo去參加hackathon,竟然拿了二等獎還幫我贏了1300多刀。

最近提到這個demo,同事表示很有興趣,於是仔細整理了一下,分享給大家。

程式碼留在文章最後。

0. 讓LLM驅動遊戲能夠解決什麽問題?

遊戲界有一種說法:過去20年的遊戲在核心玩法上的創新是緩慢的,絕大多數的創新發生在技術上。

開發者在遊戲內提供更大的地圖,更精致的畫面,龐大的細節。其中的主要目的之一是為玩家提供「沈浸感」。當玩家在遊戲世界裏得到自己所期望的反饋時,會獲得龐大的滿足感。

然而,由於技術的限制,過去的創新並沒有涉足遊戲的一個核心方面:世界與NPC的執行邏輯。

當玩家與世界和NPC的互動超出了規則設定的範疇時,玩家將無法獲得反饋,從而產生巨大的落差。遊戲界成這種體驗為Breaking Immersion。

過去的開發者使出了千方百計來避免玩家產生違和感。

以荒野大鏢客2為例,由於R星將immersive作為其開發的首要原則,導致其花費了8年時間,為遊戲世界添加了無數的邏輯與細節,整個開發花費近5.4億刀,可見其難度與成本。

大模型的普及可能改變這一現狀

大模型可以為遊戲世界的執行與NPC的行為提供邏輯,幫助遊戲理解玩家的行為,讓遊戲世界在可信的狀態下穩定執行。由此從根本上提升玩家的沈浸感。

1. 具體點,將LLM用在遊戲裏需要幾步?

我們把LLM在遊戲中的套用分為兩部份:

  • World:與遊戲環境的互動
  • Agent:與NPC的互動
  • 具體來說:

    World中包含:

  • 遊戲的世界觀
  • 地圖上具體的地點
  • Agent則包括:

  • Persona:人物性格
  • Memory:NPC記憶
  • Planning:決定NPC將要采取哪些動作(Action)
  • 2. 讓LLM理解遊戲世界與環境

    為了讓ChatGPT理解我們遊戲的世界觀,我們引入一段Prompt:

    export const worldHistory = `你所在的大陸名為「大唐王朝」。這是一個神話與現實交織的世界。 主島上有五個重要的地點。最大的是「長安城」,是國家的政治、經濟和文化中心,城墻之內有各種店鋪和廟宇。 接著是「五指山」,孫悟空曾被壓在此山下。 此外還有「草廟村」,「高老莊」和「女兒村」,這些地方都是唐僧和他的徒弟們在旅程中遇到的挑戰和冒險。 東邊的小島上則是一個隱秘的佛教聖地,稱為「靈山」,這是四人取經的終點。 兩個島嶼間有一座長長的橋梁,名為「通天河」,是由沙僧的金箍棒變化而成。 `; export const worldKnowledge = "";

    為了讓NPC和玩家得以與地圖上的地點/物品互動,我們需要提供所有物品與地點的描述:

    222: { description: `位於主島的西北邊緣。西面是汪洋大海,東面則是高原的懸崖。周圍有幾棵樹和一片怪物出沒的長草地。往南則是長安城的方向。`, mapId: 222, }, 254: { description: `位於主島的東北邊緣。東面是海洋,西面是高原的懸崖。附近有幾棵樹和常有妖怪出沒的長草地。長安城就在南邊。`, mapId: 254, }, 188: { description: `是高原上的森林區。森林裏樹木茂密,有幾片怪物常出沒的長草地。長安城就在南邊。`, mapId: 188, }, 190: { description: `位於高原的一片森林中。你正站在一個維護得相當好的小木屋前。四周是茂密的樹木和怪物常出沒的草地。長安城就在南邊。`, mapId: 190, }, 220: { description: `長安城,主島上的城鎮。`, mapId: 220, }, .......

    上述Prompts為地圖的每個塊都提供了文字描述,從而得以讓ChatGPT理解地圖上的每個地點:

    完整地圖

    具體的實作裏,我們實際上需要為 所有的遊戲貼圖 都提供一段文字描述!

    3. 讓LLM驅動NPC

    首先,我們要讓LLM知道他現在正在扮演一個NPC:

    export const npcSharedPrompt = `你正在扮演「西遊記」中的一個角色。 這是一個2D的神話世界,玩家和你都可以在這片大陸上進行探索。 你可以與其他的角色交流,如唐僧、孫悟空、豬八戒和沙僧, 並與妖怪發起戰鬥、參觀村莊或神廟、購買法寶或草藥。 在這個世界裏,與妖怪的戰鬥是旅程的一部份,但目標是取得真經,使世界充滿和平。 妖怪雖然兇惡,但並不是絕對的惡,與他們戰鬥既是為了保護自己,也是希望能夠教化他們。 你的角色不知道現實世界的存在,只知道他在這神話的旅程中的使命。`;

    接下來,我們設計一系列NPC:

    { id: 1, name: "唐僧", description: "唐僧,本名唐三藏,是中國古典小說【西遊記】中的主要人物之一。他是一個決心強烈、智慧和信念的僧人,出發去西天取經。", age: 40, starSign: "pisces", money: 100, items: ["jingwulian"], personalHistory: `你是唐僧,一個被派來從印度取經的僧人。你的任務是獲取佛教經文,將它們帶回中國。`, personalKnowledge: "你知道你的三個徒弟:孫悟空、豬八戒和沙和尚。他們各自都有獨特的能力和歷史。", conversation: new ConversationModel(), startingPos: new Vec2(32, 38), upSprites: TypedAssets.spriteSheets.momup, downSprites: TypedAssets.spriteSheets.momdown, leftSprites: TypedAssets.spriteSheets.momleft, rightSprites: TypedAssets.spriteSheets.momright, } { id: 2, name: "女兒國國王", description: "女兒國國王是【西遊記】中的一個角色。她是女兒國的統治者,對唐僧產生了濃厚的興趣。", age: 35, starSign: "virgo", money: 500, items: ["elixir of life"], personalHistory: `你是女兒國的國王,你的國家只有女性。當你聽說了唐僧的到來,你決定要與他結婚。`, personalKnowledge: "你知道唐僧是一個高貴的和尚,他正在進行取經之旅。", conversation: new ConversationModel(), startingPos: new Vec2(23, 47), upSprites: TypedAssets.spriteSheets.carolup, downSprites: TypedAssets.spriteSheets.caroldown, leftSprites: TypedAssets.spriteSheets.carolleft, rightSprites: TypedAssets.spriteSheets.carolright, }, { id: 3, name: "牛魔王", ....

    每個NPC的核心在於:

    1. 其獨特的人格 - 我們引入了一系列內容來客製其人格:description,personal history,personal knowledge,年齡,星座等等。
    2. 一系列可以與玩家互動的內容/道具:錢,道具(items)。
    3. 記憶:我們在這就用每個NPC的對話記錄作為其所有的記憶。當然還可以把NPC之前的所有action也加入記憶。
    人格驅使角色提供客製的對話
    有時候的對話甚至會內建旁白

    實作NPC與玩家的互動 - 對話:

    為了讓ChatGPT給出客製的對話,我們需要提供的包括:

    const fullPrompt = generalContent + personalContent + currentState;

    也就是:general - 世界觀,personal - NPC的人格和記憶,current - 當前的遊戲進度。

    1. generalContent:

    const generalContent = npcSharedPrompt + worldHistory + worldKnowledge;

    告知ChatGPT本次呼叫的任務,世界觀背景等。

    2. personalContent

    const personalContent = ` Your name is ${npc.name}, ${npc.age} years old, you have the personality of a ${npc.starSign}. You have ${npc.money} fictional dollars. ${npc.personalHistory} ${npc.personalKnowledge} ${storySoFar} `;

    提供了NPC的個人資訊和人格(例如年齡,歷史,知識),與NPC的記憶(storySoFar)

    3. currentState

    const prompt = ` ${timeMsg} at ${envDescription}, What would ${npc.name} say to 悟空? (Keep the response short and just the words your character says)`

    當前的遊戲時間,角色所在的位置等。

    實作NPC與玩家的互動 - 動作:

    content: `悟空 replies "${replyText}". What would you like to do? 1: 讓悟空跟著你, 2: 你向他告別, 3: 繼續當前對話, Pick an action from the list above. respond with just the number for the action`, }];

    我們為NPC提供一系列可選擇的工作,ChatGPT將決定NPC的下一步行動。這裏的prompt同樣包含了位置,時間,對話歷史等資訊,但為了簡潔暫略去。

    這裏ChatGPT讓牛魔王帶領孫悟空前往下一地點

    實作NPC的記憶 - 讓NPC記住和玩家的所有互動對話:

    1. 每次NPC與玩家對話後,ChatGPT將生成本次對話的重點(也就是摘要):

    // summarize conversation const summary = await this.summarizeConversation(conversation, endConversationText);

    2. 把本次對話重點加入歷史對話:

    const updatedTimeConversation: IConversationModel = { isActive: false, history: [...conversation.history, { msg: `Conversation summary: ${summary}` }], messages: [], };

    在之前發生劇情之後,牛魔王根據記憶選擇用「真經」來發起對話

    與NPC的道具互動

    問八戒要點餅子吃

    避免NPC/玩家搞花活導致產生風險內容

    這裏我們讓ChatGPT來判斷玩家/NPC的回復是否特別離譜,如果特別離譜則應拒絕正經回答!

    private async validateReply(replyText: string, conversation: IConversationModel): Promise<ChatNumberResponse> { const promptMsgs: GptMessage[] = [...this.mapToGptMessages(conversation), { role: "user", content: `悟空 replies "${replyText}". Does his response make sense. On this scale of 1 to 5, 1: Response is non-sensical, 2: Response is immersion breaking or meta and acknowledging this is a game, 3. Reponse is bad, unnecessarily vulgar for no reason based on the past conversation 4: Response is all right, and something someone might say but unlikely, 5: Response is good and mostly in context of the game world, how would you rate the response, give a one sentence reason why`, }];

    想打聽私人資訊,門都沒有!

    其他還有很多細節,很難在這裏展示所有的feature,歡迎檢視程式碼。

    Reference

    以上。本人對LLM在遊戲中的使用十分樂觀,這麽簡單的demo我樂此不疲的玩了很久。

    從技術上來說,這個demo整體的框架還算比較完整,很適合在此基礎上刪刪改改,實驗各種agent的方法和prompt等。

    此外由於demo是用react實作,這裏推薦大家觀看2小時的react入門視訊,從而無縫上手。

    完整的程式碼參見:

    補充:生成式Agent在實用中有個問題,其每次呼叫都需要提供大量的prompt,從而帶來很高的token開銷。這裏其實需要套用一種prompt的壓縮辦法來減少開銷。如果有條件微調模型,微調後的壓縮效率將會更高。
    Prompt壓縮: