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

LangchainのRunnableWithMessageHistoryを使って会話履歴に沿った会話を実現する

Langchainで会話履歴に沿った会話を実装するには、ConversationBufferMemoryや、ConversationBufferWindowMemoryを使うことで実現できるが、今回は、RunnableWithMessageHistoryの使い方をまとめました。

RunnableWithMessageHistoryを使う利点として、IDごとに会話セッションをわけることができます。
実際の利用方法は後述しますが、

output = with_message_history.invoke(
    input={"question":"こんにちは。私の名前はPON吉です。"},
    config={"configurable": {"session_id": "123"}},
)

のように、session_idを利用して、セッションを分けることができます。

RunnableWithMessageHistoryの実装

#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.chains import LLMChain
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

#prompt_templateを設定
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をLCELで記述
chain = prompt_template|llm

#会話履歴はstoreに貯められていく
store = {}

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

with_message_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="question",
    history_messages_key="chat_history",
    #output_messages_key="output",
)

・1回目の会話

output = with_message_history.invoke(
    input={"question":"こんにちは。私の名前はPON吉です。"},
    config={"configurable": {"session_id": "123"}},
)

print(output.content)
こんにちは、PON吉さん!お会いできて嬉しいです。今日はどんなお手伝いをしましょうか?

・2回目の会話

output = with_message_history.invoke(
    input={"question":"私の名前を呼んでください。"},
    config={"configurable": {"session_id": "123"}},
)
print(output.content)
もちろんです、PON吉さん。今日はどんなことをお話ししましょうか?

・3回目の会話 (session_idを変えてみます。)

output = with_message_history.invoke(
    input={"question":"私の名前を呼んでください。"},
    config={"configurable": {"session_id": "456"}},
)
print(output.content)
申し訳ありませんが、あなたの名前はまだ教えていただいていないのでわかりません。お名前を教えていただけますか?

というように、idごとの会話が可能になります。

idごとの会話履歴を確認することもできます。

#idごとに会話履歴を表示する
history = get_session_history("123")
print(history)
Human: こんにちは。私の名前はPON吉です。
AI: こんにちは、PON吉さん!お会いできて嬉しいです。今日はどんなお手伝いをしましょうか?
Human: 私の名前を呼んでください。
AI: もちろんです、PON吉さん。今日はどんなことをお話ししましょうか?

clear()で、履歴をクリアします。

#会話をクリア
history = get_session_history("123").clear()
print(history)
None

おまけ

prompt_templateは、↓の形などでも取ることが、できます。

from langchain_core.prompts import PromptTemplate

template = """You are a helpful assistant.

chat history:
{chat_history}

user input:{question}

AI:
"""

prompt_template = PromptTemplate(
		template=template,
    input_variables=["chat_history", "question"]
)

chatアプリにmemoryを組み込むなら、セッションをわけることができるので、RunnableWithMessageHistoryの方が使いやすそうですが、履歴がstoreの中にどんどんたまってしまうので、注意が必要です。
一定数の会話をしたら、古い順に履歴を削除するロジックが必要になりますが、それは、こちらが参考になります。


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