先週、LLM(GPT-3.5)によって固有の性格や属性を持たせた25人のAIエージェントによる小規模社会シミュレーションの実現を試みたGenerative Agents論文が話題になりました。
論文そのものの内容についてはteftefさんの以下の記事に詳しいため、あわせてご参考ください。
で、この論文内にあるリフレクションを踏まえた長時間記憶の実装のアイデアはかなり役に立ちそうだよね、というところで前回のLangChainもくもく会でも話題になっていたのですが、昨晩早速LangChainのhwchase17氏がLangChainを用いたGenerative Agentsの実装について連続ツイートで解説されていました。
hwchase17氏の解説がかなり分かりやすかったので、前編ではその和訳と補足、また新しく追加されたTimeWeightedVectorStoreRetrieverについて見て行き、後編ではこの実装の中心となるGenerativeAgentクラスの設計と活用について見ていきたいと思います。
hwchase17氏による解説(和訳)
このツイートを読んだときはアブレーションの意味が分からなかったのですが、ここで言っている「アブレーション」とはアブレーション研究、またはアブレーション分析という研究方法を指しているようです。
アブレーション研究とはシステムの各機能またはコンポーネントを一時的に削除し、その削除がシステム全体のパフォーマンスにどのような影響を与えるかを調べる方法で、Generative Agents論文ではその手法で観察・計画・リフレクションが重要な寄与をしていることを示すと言っています。
Generative Agents論文で実装されていた、記憶が減衰していくメモリモデルを作成するために必要なリトリーバーを開発したとのことで、これだけでもだいぶありがたいことだなーと感じました。
TimeWeightedVectorStoreRetriever
ツイート内で紹介されているリトリーバーは、利用する分にはシンプルなモデルです。以下の計算式に基づいてストアされているドキュメントを評価し、その重み付けを反映した形でデータ抽出します。
意味類似性はベクトルDB側で計算されるので、アルゴリズムとして実装されるのは時間経過による減衰のみです。
例えば次のコードのように減衰係数を0.999のような大きめの数字に設定し、
embeddings_model = OpenAIEmbeddings()
embedding_size = 1536
index = faiss.IndexFlatL2(embedding_size)
vectorstore = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})
retriever = TimeWeightedVectorStoreRetriever(vectorstore=vectorstore, decay_rate=.999, k=1)
1日前のデータとして「hello world」、現在時刻のデータとして「hello foo」というデータを設定したとき、
yesterday = datetime.now() - timedelta(days=1)
retriever.add_documents([Document(page_content="hello world", metadata={"last_accessed_at": yesterday})])
retriever.add_documents([Document(page_content="hello foo")])
「hello world」というクエリによってデータを取得する場合、通常は意味類似性のみで評価されるため「hello world」が抽出されますが、リトリーバーによって昨日のデータの優先順位は低くなるため「hello foo」が抽出されます。
# "Hello Foo" is returned first because "hello world" is mostly forgotten
retriever.get_relevant_documents("hello world")
現場からは以上です。
後編はコチラ↓