見出し画像

【#1】Generative Agents解説



1. Generative Agentsとは


こんにちは、大学院生のYukiです。

映えある第1講目の解説内容として「Generative Agents」を選ばせていただきました。


日本語の記事を検索すると、AI AgentsよりもGenerative Agentsの方がHIT数が多いですね。人によっては後者の方が聞き馴染みのある方が多いかもしれません。

既に概要を知っている方は、こちらの章は飛ばしてください。

Generative Agentsは、2023年UISTのカンファレンスにスタンフォード大学とGoogleの研究者たちが合同で発表した論文です。2023年の4月から既にSNS記事が出回って、日本でも話題になっていました。

この研究では、25体のAI Agentsを2D RPG風の仮想都市に配置し、観察を通じて人間らしい社会的行動をシミュレートできることを実証しました。

逐次世間の関心を調べておりましたが、2024年の6月段階でGoogle scholarの引用数が800だったのに、9月初旬の段階ではすでに1100を超えております。間違いなく、以降数年はAgents関連の論文で頻繁に見かけることになるであろうMilestone Paperの一つですね。


既存研究と比較してユニークな所(Yukiの所感)

  • まるでゲームの世界、論文1ページ目から引き込まれるワクワク感

  • LLMの画期的応用方法の提示

  • AI同士で、社会行動が可能であることを証明

まず研究において何より大事なのが、研究を他者に面白いと思ってもらう事だと思ってます。その点に関しては、この論文はAIやLLMに知識関心がある人だけでなく、その他多くの層の引き込みに成功しています。

昨今のTransformerを使用したChat Botの精度は広く知れ渡っている所ではありましたが、それらを実際の人間の思考フローをなぞるように設定することで、このように応用できるなんて…。

私はかつてこの論文の説明をする際は、「コロンブスの卵」という言葉を頻用していました。


Generative Agentsが残した課題(Yukiの所感)

  • コストがかかり、実用化のビジョンが見えない

  • 人間の社会構造をトレースするにはアーキテクチャが不十分

実用化したら様々な事が革新するだろう素晴らしい論文でしたが、
それ故に稼働時のコスト問題は致命的でした。

また、Future Researchへ余白があるとも言えますが、
その後1年で発表された関連研究と比較するとアーキテクチャが非常にシンプルです。

頭の良くなった「Sims」(利用料金 数十万/日)を見ている感覚でしょうか。



2. フォルダ構造と主要ファイル


ここからはGenerativeAgentsのコードを読み解きたい実装者向けの話をします。
(どうコーディングするか、ではなく、どんな機能がどこにあるかの解説になります。)

バックエンド(Generative Agentsの部分)の構造が知りたいという人が多いと思うので、そちらを中心に話をします。
コード内にParkさんが多くのコメントを残しているので、簡単な英語に忌避感ない方は、
ぜひ直接コメント付きでコードを読んでみてください。

reverie
├── backend_server
│   ├── global_methods.py
│   ├── maze.py
│   ├── path_finder.py
│   ├── persona
│   │   ├── cognitive_modules
│   │   │   ├── converse.py
│   │   │   ├── execute.py
│   │   │   ├── perceive.py
│   │   │   ├── plan.py
│   │   │   ├── reflect.py
│   │   │   └── retrieve.py
│   │   ├── memory_structures
│   │   │   ├── associative_memory.py
│   │   │   ├── scratch.py
│   │   │   └── spatial_memory.py
│   │   ├── persona.py
│   │   └── prompt_template
│   │       ├── defunct_run_gpt_prompt.py
│   │       ├── gpt_structure.py
│   │       ├── print_prompt.py
│   │       ├── run_gpt_prompt.py
│   │       ├── safety
│   │       │   └── anthromorphosization_v1.txt
│   │       ├── v1
│   │       │   ├── action_location_object_v1.txt
│   │       │   ├── action_location_object_vMar11.txt
│   │       │   ├── ...
│   │       │   └── test_prompt_July5.txt
│   │       ├── v2
│   │       │   ├── agent_chat_v1.txt
│   │       │   ├── bed_hour_v1.txt
│   │       │   ├── ...
│   │       │   └── whisper_inner_thought_v1.txt
│   │       └── v3_ChatGPT
│   │           ├── action_location_object_v1.txt
│   │           ├── action_location_sector_v2.txt
│   │           ├── ...
│   │           └── whisper_inner_thought_v1.txt
│   ├── reverie.py
│   └── test.py
├── compress_sim_storage.py
└── global_methods.py

さて、こちらのバックエンド、
いざ「コードを読むぞ!」とフォルダを見ると、論文であった重要ワードが殆ど現れず驚くでしょう。

backend_server/reverie.py でParkさんが記載していますが、元々Generative Agentsは「personas(ペルソナ)」、memory streamは「associative memory」、全てのバックエンドのフレームワークを「reverie(レヴェリー)」という名前で呼んでいたんですって。

それを認識していれば、最初に紐解くべき2つのファイルが自ずと見えてきます。


reverie.py: バックエンドで最初に実行されるコード。
25人の人物のプロフィールや地図情報、ゲーム時間の設定など、実験環境の初期設定を担う。

persona.py: Agent個人に実装される、「GenerativeAgents」部分。
知覚(perceive)、記憶の取得(retrieve)、計画(plan)、実行(execute)、反省(reflect)などの認知機能を各モジュールから呼び出している。

reverie.pyでは起動に必要なjsonフォルダの読み込みや時間設定などを行っています。
もしGenerative AgentsのGitのリポジトリの指示に従いローカル環境で起動するなら、こちらの情報を読み込んでいるはずです。(3人村)

どのような入力項目を扱っているか、
reverie.pyと比較しながら直接確認しに行ってみましょう。

また、recerie.pyでは128行目でAgentの名前とプロフィールjsonを使用してpersona.pyを呼び出し、それぞれに「Generative Agents」を実装しています。

persona.pyでは、各エージェントの
「知覚(perceive)、記憶の取得(retrieve)、計画(plan)、実行(execute(act))、反省(reflect)」
を、cognitive_modulesフォルダ内の各モジュールからメソッドを使用してアーキテクチャを組み立てています。

具体的には、persona.pyのインスタンスのmoveメソッドに下記引数を渡してあげて、「知覚〜実行」までのメインシークエンスが順番に実行しています。

  • maze(Mapのインスタンス情報)

  • personas(全てのエージェント情報)

  • curr_tile(現在位置)

  • curr_time(現在時刻)

Agent全員のメインシークエンスはreverie.pyの279行目のstart_server()にてWhile(True)(サーバーが終了するまでのループ)で管理されています。

Whileの1ステップがsec_per_step秒(meta.jsonによると10秒)です。
それぞれのエージェントは「知覚〜反省」のシークエンスを1ステップにつき1回行う計算です。


3. メモリの管理方法


perceive、retrieve、plan、execute(act)、reflectの確認はできたので、続いてはメモリの管理方法を確認します。

メモリの取得、追加、検索は、様々なモジュールから行われています。これらを取り扱うモジュールは以下の三つのファイルです。

associative_memory.py: いわゆるMemory Stream。
「イベント」、「思考」、「会話」の3タイプに関しての長期記憶を管理する。

scratch.py: 1日のスケジュールや現在の状態など、短期記憶を管理する。

spatial_memory.py: 周囲のオブジェクトに関しての情報ツリー。
上記のAgentsが主体の記憶とは異なり、Map上のAgentsがインタラクト可能なオブジェクトを保持。(例:『キッチン』など)

Agentのインスタンス作成時にjsonから自動的に初期のメモリが読み込まれ、
それぞれのインスタンスに保持されています。

associative_memoryは、「イベント」、「会話」記憶はperceiveモジュールでのみ追加され、「思考」記憶はplan、reflectモジュールでのみ追加されます。

scratchは頻繁に様々なモジュールからアクセスがありますが、インスタンス変数にある物(現在時刻や現在位置など)に変更があれば適宜書き換えをしていました。

spatial_memoryはアクセスのみで追加変更機能はないようです。

メモリ周りの取得や検索は非常にややこしく、文面での説明が困難です。
実装を考えている方は既存コードから「.a_mem」「.s_mem」「.scratch」でそれぞれ検索をかけて使用箇所を辿ると、理解しやすくなると思います。


4. GPTについて


  • run_gpt_prompt.py

 GPTを呼び出すためのメソッドを格納しています。
それぞれがプロンプトテキストを持っており、指定された形式で GPTからの返答を受け取りモジュール等に値を返します。

各モジュールで呼び出し回数は以下です。

  • Perceive: 2回

  • Retrieve: 0回

  • Plan: 15回

  • Execute(act): 0回

  • Reflect: 7回

上記の回数はあくまで参考の回数です。
一度のAgentの「知覚〜反省」までのシークエンスで呼び出されるGPTの回数は、単純な足し算にはなりません。

例えば、Planにある「run_gpt_prompt_generate_hourly_schedule」ですが、これは1日の1時間ごとのAgentの予定を日付変更時に作成します。事前にインプットした起床時間で回数は変動しますが、この処理だけで最大24回の呼び出しを行う可能性があります。


5. 最後に


今回はコードを理解したい実装者向けに、
全体のフォルダ構成や、主要ファイルと機能について解説しました。

Generative Agentsのアーキテクチャは基本的にシンプルですが、
メモリ処理の複雑さとMaze(マップ、移動機能)の統合により、「Generative Agents」の機能を単独で切り出すことが難しくなっています。

Generative Agentsを使用してオリジナルのアプリケーションを作成したい方は以下の手順に従って開発を進めてみてください。

  1. フロントエンドを独自に開発

  2. backend_serverフォルダはそのまま利用

  3. maze.py、path_finder.py、およびこれらのインスタンスやx、y座標を使用している部分を、自身のフロントエンド仕様に合わせて修正

  4. アプリケーションに適したオリジナルのJSONデータを準備


独自のアーキテクチャでオリジナルAgentsを開発したい方向けには、
今後より詳細な解説を提供したいと考えています。



6. 参考リンク


取り扱ったGenerative Agentsの論文
Park, J.S., O'Brien, J., Cai, C.J., Morris, M.R., Liang, P. and Bernstein, M.S., 2023, October. Generative agents: Interactive simulacra of human behavior. In Proceedings of the 36th annual acm symposium on user interface software and technology (pp. 1-22).

公開されているGenerative AgentsのGithub
https://github.com/joonspk-research/generative_agents

この記事が気に入ったらサポートをしてみませんか?