AI / MLLangChain.jsLLMmomento

LangChain.jsでChatの履歴をMomentoに保存させてみた

Chat形式のUIを提供する際には、過去の会話履歴を保存する必要があります。この記事では、MomentoのCacheに保存する方法を紹介しています。MomentoのSDKを使用するためには、MomentoのAPIを呼び出すためにSDKをインストールする必要があります。また、Cloudflare Workersなどの一部のエッジサービスでは、Web SDKをインストールする必要があります。具体的なコードのセットアップ方法も述べられています。コードの実行例や関連記事へのリンクもあります。

広告ここから
広告ここまで

Chat形式のUIをユーザーに提供する場合、過去の会話履歴をどこかに保存する必要があります。今回はMomentoのCacheに保存する方法をまとめました。

MomentoのSDKをインストールする

LangChainからMomentoのAPIを呼び出すのにSDKが必要です。npmからインストールしましょう。

npm i @gomomento/sdk

Cloudflare WorkersではWeb SDK

Cloudflare Workersなど、一部のエッジ系サービスではWeb SDK側をインストールする必要があります。

npm i @gomomento/sdk-web xhr4sw

Honoでアプリを作ってみる

今回もHonoを使ってAPIを作ってみます。まずは環境変数を.dev.varsに保存しましょう。

OPENAI_API_KEY=sk-lxxx
MOMENT_API_KEY=xxxxxx

続いてHonoのアプリをセットアップします。この際、Cloudflare Workersを使う時は、MomentoのSDKがMomento APIを呼び出す際のポリフィルを追加しましょう。

import XMLHttpRequestPolyfill from "xhr4sw";
/**
 * This is needed to polyfill as otherwise we get HttpRequest not defined
 */
Object.defineProperty(self, 'XMLHttpRequest', {
    configurable: false,
    enumerable: true,
    writable: false,
    value: XMLHttpRequestPolyfill
});


export const memoryApp = new Hono<{
    Bindings: {
        OPENAI_API_KEY: string;
        MOMENT_API_KEY: string;
    }
}>()

Momentoのキャッシュクライアントを作成し、その後BufferMemoryMomentoChatMessageHistoryにクライアントを渡しましょう。

    const cacheClient = new CacheClient({
        configuration: Configurations.Laptop.v1(),
        credentialProvider: CredentialProvider.fromString({
            apiKey: c.env.MOMENT_API_KEY,
        }),
        defaultTtlSeconds: 60,
    });
    // Create a unique session ID
    const sessionId = new Date().toISOString();
    const cacheName = "langchain";

    const memory = new BufferMemory({
        chatHistory: await MomentoChatMessageHistory.fromProps({
            client: cacheClient,
            cacheName,
            sessionId,
            sessionTtl: 300,
        }),
    });
    console.log(
    `cacheName=${cacheName} and sessionId=${sessionId} . This will be used to store the chat history. You can inspect the values at your Momento console at https://console.gomomento.com.`
    );

その後は会話を行うためのChainを、OpenAIなどのモデルを使って用意します。

    const model = new ChatOpenAI({
        modelName: "gpt-3.5-turbo",
        temperature: 0,
        openAIApiKey: c.env.OPENAI_API_KEY
    });

    const chain = new ConversationChain({ llm: model, memory });

    const res1 = await chain.call({ input: "Hi! I'm Jim." });
    console.log({ res1 });

    const res2 = await chain.call({ input: "What did I just say my name was?" });
    console.log({ res2 });

    return c.json({
        res1,
        res2
    })

Hono on Cloudflare Workersでのサンプルコード

ここまでのコードをまとめたのがこちらです。xhr4swまわりはNode.js環境やAWS Lambdaなどでは不要・・・のはずです。

import { Hono } from "hono";
import {
    CacheClient,
    Configurations,
    CredentialProvider,
  } from "@gomomento/sdk-web"; // `from "gomomento/sdk-web";` for browser/edge
  import { BufferMemory } from "langchain/memory";
  import { ChatOpenAI } from "langchain/chat_models/openai";
  import { ConversationChain } from "langchain/chains";
  import { MomentoChatMessageHistory } from "langchain/stores/message/momento";
  
import XMLHttpRequestPolyfill from "xhr4sw";
/**
 * This is needed to polyfill as otherwise we get HttpRequest not defined
 */
Object.defineProperty(self, 'XMLHttpRequest', {
    configurable: false,
    enumerable: true,
    writable: false,
    value: XMLHttpRequestPolyfill
});


export const memoryApp = new Hono<{
    Bindings: {
        OPENAI_API_KEY: string;
        MOMENT_API_KEY: string;
    }
}>()

memoryApp.get('test', async c => {
    const cacheClient = new CacheClient({
        configuration: Configurations.Laptop.v1(),
        credentialProvider: CredentialProvider.fromString({
            apiKey: c.env.MOMENT_API_KEY,
        }),
        defaultTtlSeconds: 60,
    });
    // Create a unique session ID
    const sessionId = new Date().toISOString();
    const cacheName = "langchain";

    const memory = new BufferMemory({
        chatHistory: await MomentoChatMessageHistory.fromProps({
            client: cacheClient,
            cacheName,
            sessionId,
            sessionTtl: 300,
        }),
    });
    console.log(
    `cacheName=${cacheName} and sessionId=${sessionId} . This will be used to store the chat history. You can inspect the values at your Momento console at https://console.gomomento.com.`
    );

    const model = new ChatOpenAI({
        modelName: "gpt-3.5-turbo",
        temperature: 0,
        openAIApiKey: c.env.OPENAI_API_KEY
    });

    const chain = new ConversationChain({ llm: model, memory });

    const res1 = await chain.call({ input: "Hi! I'm Jim." });
    console.log({ res1 });

    const res2 = await chain.call({ input: "What did I just say my name was?" });
    console.log({ res2 });

    return c.json({
        res1,
        res2
    })
})

動かしてみる

用意ができたので実行しましょう。res2の返答にres1の値が含まれているので、コンテキストを引き継げていることが伺えます。

% curl http://127.0.0.1:8787/memory/test | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   144  100   144    0     0     35      0  0:00:04  0:00:04 --:--:--    35
{
  "res1": {
    "response": "Hello Jim! It's nice to meet you. How can I assist you today?"
  },
  "res2": {
    "response": "You just said that your name is Jim."
  }
}

タイムスタンプがキャッシュキーですので、サーバーのログからキーを見つけましょう。キーさえあれば、MomentoのData Explorerで保存内容が見れます。

使ってみた感想

DynamoDBを試した時に感じた、「履歴をいつまで保持するのか」問題の対応案としてMomentoを使うのは一つかもしれません。とはいえこちらはこちらで1日でデータが消えるため、1週間程度保持したい場合などには、使い方を考える必要がありそうです。

あとは・・・Cloudflare Workersを使う場合、Workers KVが使えるといいなという気はします。ただ、LangChain.jsには2023/12時点でまだKVに対応していない様子なので、大人しく待機・もしくはプルリクエストを出してみることになりそうです。

余談

MomentoChatMessageHistoryがCloudflare Workersで動かない問題があったのですが、Issue / Pull Requestを出したところ、無事解決した様子です。もしこれを見ながら試してエラーが出た場合、LangChain.jsのバージョンをアップグレードしてみましょう。

https://github.com/langchain-ai/langchainjs/issues/3784

参考にした記事

https://js.langchain.com/docs/integrations/chat_memory/momento

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts