話題のキャッシュSaaS「Momento」をLangChainで使ってみる（LLM編）

# キャッシュSaaS「Momento」がLangChainに正式対応！

AWSでDynamoDB等の開発に携わっていたKhawaja Shamsさんらが立ち上げたサーバーレスなキャッシュSaaS「Momento」。

かなりお手軽にキャッシュを利用でき、ElastiCacheやAzure Cache、Memorystore等の「マネージドだけどサーバーレスではない」キャッシュPaaSから簡単に移行できると話題になっています。

https://www.gomomento.com/jp/home-page

そんなMomentoが、大規模言語モデル（LLM）を活用したアプリケーション開発を便利にしてくれるライブラリ「LangChain」のIntegrationsとして正式に組み込まれました。



# 何ができるの？

Momento側プレスリリースにも記載されている２点が直近の想定ユースケースのようです。

① LangChainからの「LLM呼び出し」のキャッシュとしてMomentoを使う
② LangChainの「チャット履歴」のセッションストアとしてMomentoを使う

https://jp.gomomento.com/blog/momento-is-now-fully-integrated-into-the-langchain-ecosystem

いずれもLangChainのドキュメントにサンプルコードが公開されているので、実際に動かしながら何が嬉しいのか試してみます。



# ハンズオンの事前準備
- 作業用ディレクトリを作成し、ルートに.envファイルを配置しAPIキーを記載
    - Momento　https://console.gomomento.com/tokens
    - OpenAI　https://platform.openai.com/account/api-keys

```zsh:.env
OPENAI_API_KEY=hoGEhoGE
MOMENTO_AUTH_TOKEN=fuGAfuGA
```

- Python用ライブラリ（OpenAI、LangChain、Momento）のインストール

```zsh:ターミナル
pip install openai langchain momento
```


# LLM呼び出しキャッシュとしてMomentoを使ってみる

LangChainの公式ドキュメントはこちらです。

https://python.langchain.com/docs/ecosystem/integrations/momento

### Momentoが、ないとき〜 🥟

```py:llm-normal.py
# レイテンシー計測開始
import time
time_start = time.time()

# 環境変数のセット
from dotenv import load_dotenv
load_dotenv()

# AIへの質問文をセット
input = "KDDIアジャイル開発センター株式会社について教えて？"

# LangChainのLLMを呼び出し
from langchain.llms import OpenAI

llm = OpenAI(temperature=0)
output = llm.predict(input)

# AIからの回答を表示
print("【AIからの回答】")
print(output)

# レイテンシー計測終了
time_end = time.time()
tim = time_end- time_start

print()
print("【実行にかかった時間】")
print(tim)
```

実行してみると…

```
【AIからの回答】


KDDIアジャイル開発センター株式会社は、KDDIグループの中核企業であるKDDI株式会社が設立した、ソフトウェア開発を行う企業です。

KDDIアジャイル開発センター株式会社は、ソフトウェア開発を行うだけでなく、ソフトウェア開発プロセスを改善するためのアジャイル開発を推進しています。アジャイル開発とは、ソフトウェア開発プロセスを短時間で完了するための方法です。KDDIアジャイル

【実行にかかった時間】
5.999843120574951
```

### Momentoが、あるとき〜 🥟

```py:llm-momento.py
# レイテンシー計測開始
import time
time_start = time.time()

# 環境変数のセット
from dotenv import load_dotenv
load_dotenv()

# Momentoキャッシュの有効化
from datetime import timedelta

import langchain
from langchain.cache import MomentoCache
from momento import CacheClient, Configurations, CredentialProvider

cache_client = CacheClient(
    Configurations.Laptop.v1(),
    CredentialProvider.from_environment_variable("MOMENTO_AUTH_TOKEN"),
    default_ttl=timedelta(days=1))

cache_name = "langchain-llm"
langchain.llm_cache = MomentoCache(cache_client, cache_name)

# AIへの質問文をセット
input = "KDDIアジャイル開発センター株式会社について教えて？"

# LangChainのLLMを呼び出し
from langchain.llms import OpenAI

llm = OpenAI(temperature=0)
output = llm.predict(input)

# AIからの回答を表示
print("【AIからの回答】")
print(output)

# レイテンシー計測終了
time_end = time.time()
tim = time_end- time_start

print()
print("【実行にかかった時間】")
print(tim)
```

### レスポンス時間を比較！

Momentoキャッシュを利用した場合、初回の実行はキャッシュ作成時間が入るためか時間が伸びていますが、2回目以降は爆速になりました。

|   | Momentoなし | Momentoあり |
| - | - | - |
| 1回目 | 5.99秒 | 10.31秒 |
| 2回目 | 4.42秒 | 0.92秒 |
| 3回目 | 7.27秒 | 1.30秒 |

ちなみにキャッシュが確実に利用されるように `temperature=0` でOpenAI APIを実行しているのですが、試しに数値を上げてみるとどうなるかも検証してみました。

極端に `temperature=1` にしてみたところ、`llm_cache` を設定している場合はキャッシュが優先して利用されるようで、連続して同じ質問をしても毎回同じ回答が上記と同等の高速で返ってきました。



# レスポンス短縮以外にもメリットあり

LangChainのLLMキャッシュにMomentoを利用することで、以下のようなメリットがあります。

### LLMキャッシュ自体のメリット

- レスポンス時間の短縮
- LLMトークン消費量の節約（＝コスト削減）
- デバッグの効率化（毎回モデルを呼ばなくてよくなる）

### その中でもMomentoを利用するメリット

- 外部ストレージにキャッシュを保持できるため、LangChain実行サーバーがステートレスとなり耐障害性やスケーラビリティが向上する
- サーバーレスのためリソース運用管理の工数を削減できる
- 大手パブリッククラウドのキャッシュサービスよりも低コスト

### 逆に、LLMキャッシュ＆Momento利用時の注意点

- temperature設定に関わらず、TTL期間中はキャッシュ再利用が優先されてしまう
- パブリッククラウドと併せてプロダクションで利用する場合、パブリッククラウド側のキャッシュサービス（Amazon ElastiCache等）と比較すると新規SaaS製品が一つ増える形となるため、セキュリティ監査や調達などの事務対応が逆に嵩んでしまうデメリットもあり



# おわりに

続編も書きました。

https://qiita.com/minorun365/items/0ef6cb13cdcf7c8fb7bd

今回のサンプルコードはGitHubでも公開しています。

https://github.com/minorun365/langchain-momento