見出し画像

AzureからGPTを使ってみる|memoryを使って会話履歴に沿って会話する。その3

LangchainのRunnableWithMessageHistoryで保持する会話数を規定する

RunnableWithMessageHistoryを使って会話履歴に沿ってGPTと会話するコードを以前書きました。


RunnableWithMessageHistoryの特徴として、

・過去のやり取りを踏まえた応答ができる。
・IDで会話セッションを分けることができる。

以上の点において非常に便利でした。しかしながら、"ConversationBufferWindowMemory"のように保持する会話履歴の数を規定することができませんでした。このことは、チャットアプリを構築する上で、不必要に入力トークン数を増やすことになり、金銭面、GPTの応答時間の面からとても非効率的です。

そこで今回は、RunnableWithMessageHistoryに保持する会話履歴数を規定するclassを実装してみたいと思います。
実装するclassは、以下のようになります。

class LimitedChatMessageHistory(ChatMessageHistory):
    def add_message(self, message):
        super().add_message(message)
        # 履歴が4件(2ターン)を超える場合、古いメッセージを削除
        if len(self.messages) > 4:              #ここと、
            self.messages = self.messages[-4:]  #ここの数字を変えます。

全文

 #langchain -openai=0.1.15 #langchain =0.2.7   #langchain -community=0.2.7 #langchain -core=0.2.12  
from langchain_openai import AzureChatOpenAI
from langchain_core.messages import SystemMessage
from langchain_core.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    MessagesPlaceholder,
)
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

from dotenv import load_dotenv
import os

# OpenAI APIキーの設定
dotenv_path = ".env"
load_dotenv(dotenv_path)

OPENAI_API_BASE = os.getenv('OPENAI_API_BASE')
OPENAI_API_VERSION = os.getenv('OPENAI_API_VERSION')
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')

os.environ["AZURE_OPENAI_API_KEY"] = OPENAI_API_KEY
os.environ["AZURE_OPENAI_ENDPOINT"] = OPENAI_API_BASE

# プロンプトテンプレートを設定
template_messages = [
    SystemMessage(content="You are a helpful assistant."),
    MessagesPlaceholder(variable_name="chat_history"),
    HumanMessagePromptTemplate.from_template("{question}"),
]
prompt_template = ChatPromptTemplate.from_messages(template_messages)

# LLMを定義
llm = AzureChatOpenAI(
    api_version=OPENAI_API_VERSION,
    azure_deployment="gpt4o"  # azure_deployment = "deployment_name"
)

# チェーンを定義
chain = prompt_template | llm

# カスタムクラスを定義
class LimitedChatMessageHistory(ChatMessageHistory):
    def add_message(self, message):
        super().add_message(message)
        # 履歴が4件(2ターン)を超える場合、古いメッセージを削除
        if len(self.messages) > 4:
            self.messages = self.messages[-4:]

# 会話履歴を保持するストア
store = {}

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = LimitedChatMessageHistory()
    return store[session_id]

# RunnableWithMessageHistoryの使用
with_message_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="question",
    history_messages_key="chat_history",
)

prompt = "こんにちは。私の名前はPON吉です。"

output = with_message_history.invoke(
    input={"question":prompt},
    config={"configurable": {"session_id": "456"}},
)

print(output.content)
history = get_session_history("456")
print(history)

Human: こんにちは。私の名前はPON吉です。
AI: こんにちは、PON吉さん!お会いできて嬉しいです。今日はどんなお手伝いができますか?
Human: 私の名前を呼んでください。
AI: もちろんです、PON吉さん!他に何かお手伝いできることがありますか?

一旦2ターン会話してみました。次に、

prompt = "私は、カレーが好きです。"

と、入力します。履歴を見てみると、

Human: 私の名前を呼んでください。
AI: もちろんです、PON吉さん。何か他にお手伝いできることはありますか?
Human: 私は、カレーが好きです。
AI: カレーは美味しいですよね!どんな種類のカレーが好きですか?

という具合に、古い会話履歴が削除されています。

prompt = "私は、ハンバーグも好きです。"

Human: 私は、カレーが好きです。
AI: カレーは美味しいですよね!どんな種類のカレーが好きですか?
Human: 私は、ハンバーグも好きです。
AI: カレーもハンバーグも美味しいですね!ハンバーグカレーなんて組み合わせも最高ですね。どちらも手作りされることはありますか?

prompt = "私の名前を呼んでください。"

Human: 私は、ハンバーグも好きです。
AI: カレーもハンバーグも美味しいですね!ハンバーグカレーなんて組み合わせも最高ですね。どちらも手作りされることはありますか?
Human: 私の名前を呼んでください。
AI: ごめんなさい、あなたの名前が分からないのでお聞かせいただけますか?


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