LangChainのメモリ応用編：Google Colabで学ぶ長期記憶とコンテキスト管理

## この記事で扱うトピック

- **LangChain のメモリの概要**
- **会話要約や長期履歴の管理**
  - ConversationSummaryMemory / ConversationBufferMemory
- **メモリ拡張による大規模対話フローの設計**
- **ユーザ別のコンテキスト学習**

## 1. はじめに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/1302ff5e-c5d1-9330-f550-453d22bb999e.png)

対話型アプリケーションを開発する際、チャットボットがユーザとの複数ターンの対話を正確に把握するためには、適切なメモリ管理が欠かせません。LangChain では「Memory」という仕組みを通じて、以下のような要件を実現できます。

- 直前の会話履歴を簡単に参照する
- 会話要約（サマリー）を生成し、長期的に情報を持続させる
- 特定ユーザごとの個別コンテキストを維持する

本記事では、`ConversationSummaryMemory` を中心に、`ConversationBufferMemory` 以外のメモリタイプも活用しながら、より高度な対話フローを設計する手法を紹介します。

---

## 2. LangChain のメモリ機能とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/3553fd3f-daaa-ff41-a483-b25246d8977a.png)

### 2-1. Memory とは

LangChain の `Memory` とは、チャットボットの **コンテキスト** を管理する機能です。ユーザとの対話履歴を格納し、後段のモデルに適切なプロンプトとして再提供することで、継続的な対話を実現します。

### 2-2. 主なメモリクラス

- **ConversationBufferMemory**
  - 直近の会話履歴をそのまま保持します。最もシンプルですが、会話が長くなるにつれ情報が多くなりすぎるという課題があります。
- **ConversationSummaryMemory**
  - 過去の会話を自動的に要約し、要点のみを保持します。対話が長くなっても、メモリサイズをコンパクトに維持できるのが利点です。
- **ConversationBufferWindowMemory**
  - 会話履歴のうち、直近の一定数のターンのみを保持します。すべてを保持しないことでリソースを節約します。
- **VectorStoreRetrieverMemory** / **ConversationKGMemory** など
  - さらに応用的なメモリ。ベクトルストアに会話を保存したり、知識グラフを用いて関係性を管理したりできます。

この記事では特に `ConversationSummaryMemory` にフォーカスを当てながら、長期的な履歴管理やユーザ別の学習について解説します。


## 3. Google Colab でのセットアップ

まずは Google Colab 上で LangChain を使えるようにします。以下のコードを実行して、必要なライブラリをインストールしましょう。

```python
!pip install langchain openai langchain_community
```

> **注意**: `openai` モジュールを使う場合は、OpenAI API キーが必要です。環境変数 `OPENAI_API_KEY` または別途コードでキーを設定してください。

---

## 4. ConversationSummaryMemory の活用例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/911eb1ea-230d-d9a3-decb-8a60cf844400.png)


### 4-1. 基本的な使い方

```python
import os
import openai
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationSummaryMemory
from langchain.chains import ConversationChain

# APIキーの設定（例）
openai.api_key = "YOUR_OPENAI_API_KEY"

# モデルとメモリを準備
llm = ChatOpenAI(temperature=0)
summary_memory = ConversationSummaryMemory(llm=llm)

# ConversationChain にメモリを設定
conversation = ConversationChain(
    llm=llm,
    memory=summary_memory,
    verbose=True  # 対話ログを出力
)

# ユーザとのやり取りをシミュレーション
conversation.predict(input="こんにちは！あなたはどんなことが得意ですか？")
conversation.predict(input="趣味はプログラミングです。どの言語がおすすめ？")
conversation.predict(input="じゃあPythonについて詳しく教えて。")
```

### 4-2. 対話履歴の中身を確認する

```python
summary = summary_memory.load_memory_variables({})
print(summary["history"])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/f2ab0a64-546b-4a11-749d-39512910d8d3.png)


## 5. 大規模対話フローへの応用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/5d36ab55-a53f-6ba6-ecfc-98dd8003b30d.png)

### 5-1. 要約メモリ + バッファメモリの組み合わせ

- 長期の要約用に `ConversationSummaryMemory` を使いつつ、直近の応答は `ConversationBufferMemory` で保持する構成も考えられます。

### 5-2. ユーザ別のコンテキスト学習

- 複数ユーザが利用するチャットボットの場合、ユーザごとにメモリインスタンスを用意し、それぞれで要約や履歴を管理します。

### 5-3. Vector Store との併用

- 会話で出てきた固有名詞やイベント情報を、ベクトルストアに登録することで、必要に応じて検索・再利用ができます。

---

## 6. 実例：ユーザ別メモリの切り替え

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/c641e735-9e28-e96b-e5e9-718ddff7f89f.png)


```python
import uuid

# ユーザの識別用に、メモリをディクショナリで管理
user_memories = {}

def get_memory_for_user(user_id):
    if user_id not in user_memories:
        user_memories[user_id] = ConversationSummaryMemory(llm=llm)
    return user_memories[user_id]

def chat_with_user(user_id, message):
    memory = get_memory_for_user(user_id)
    conversation = ConversationChain(
        llm=llm,
        memory=memory,
        verbose=False
    )
    response = conversation.predict(input=message)
    return response

# 例: 2人のユーザが交互に発話する
user1_id = "user1"
user2_id = "user2"

print("User1:", chat_with_user(user1_id, "こんにちは、Botさん！"))
print("User2:", chat_with_user(user2_id, "はじめまして。あなたは何が得意ですか？"))
print("User1:", chat_with_user(user1_id, "さっきの話の続きだけど..."))
print("User2:", chat_with_user(user2_id, "おすすめの本を教えてください。"))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/05729120-5e62-1695-5c3a-4e176119029b.png)

## 7. まとめ

LangChain を使った高度なメモリ活用により、チャットボットの対話性能が大きく向上します。ぜひ Google Colab 上で試してみてください。