chat-gpt3.5-turboで以前の会話を保持する

これなーに

chat-gpt凄い!APIも使えて便利!
だけどAPIって以前の会話覚えてくれない。。それを再現したいよね。

cha-gpt3.5-turboのAPI

OpenAIにAPIの利用申請をするとAPI_KEYが発行される。
これを使うと簡単にAPIが利用できる。
例えばpythonで利用する例は以下の通り。

# coding=utf-8
import openai

openai.api_key = 'your_api_key'

def main():
    request = """
    こんにちは!私の名前はraishi12です!
    """
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": request},
        ]
    )
    print(response["choices"][0]["message"]["content"])

if __name__ == '__main__':
    main()

これを実行すると、以下のようなレスポンスを取得できる。

こんにちは、raishi12さん!私はAIアシスタントです。ご質問やご要望などございましたら何でもお知らせください。
お手伝いできることがあれば、喜んでお手伝いいたします。

その後、些細な内容の会話を続けていくと、APIでは過去の会話内容を記憶していないことが分かる。

raishi12:今日はいい天気でしたね〜
AI:申し訳ありませんが、私は天気情報を受信できません。何か他のご質問がありましたら、お答えいたします。

raishi12: 私の名前を知っていますか?
AI: 申し訳ありませんが、私はあなたの名前や個人情報を知ることはできません。私は人工知能チャットボットであり、私は全く知らない人と会話するためにプログラムされています。私はあなたの質問に答えるだけで、あなたの個人情報を収集しないように注意しています。

chat-GPTは、chat形式で過去の質問を記憶しており、これが結構便利。

APIでもこれを実現する方法はないか・・・??

langchainのConversationBufferWindowMemory

langchainとは、gptの拡張機能のようなもので色々なことをサポートするためのツール郡。
この中のConversationBufferWindowMemoryを使うと、過去の会話を記憶してくれる。
コード

ConversationBufferWindowMemoryを用いた過去の会話を記憶したやりとり用のコードは以下。

import pathlib
import yaml
from langchain.memory import ConversationBufferWindowMemory
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.prompts.prompt import PromptTemplate

base_path = pathlib.Path.cwd()

template = """
# introduction
- You are my exclusive professional advisor.
- Please output the best results based on the following constrains

# Constrains
- Your answer must be in Japanese.
- About 200 characters.
- No important keywords are left out.
- Keep the text concise.
- If you cannot provide the best information, let us know.

{history}
Human: {input}
Assistant:
"""

def run():
    # apikeyのロード
    conf_file = base_path / 'config' / 'config.yaml'
    with open(conf_file, 'r') as inf:
        config = yaml.safe_load(inf)
    api_key = config['openai_api']['api_key']

    # メモリの初期化(kは、直近のやり取りを保存する数)
    memory = ConversationBufferWindowMemory(k=2)

    # LLM の初期化
    llm = OpenAI(
        temperature=0.2,
        openai_api_key=api_key,
        model_name='gpt-3.5-turbo',
        max_tokens=200
    )

    prompt = PromptTemplate(
        input_variables=['history', 'input'],
        template=template
    )

    # `ConversationChain` の初期化
    conversation = ConversationChain(
        llm=llm,
        memory=memory,
        prompt=prompt
    )

    # 会話を開始
    user_input=input("You: ")

    while True:
        response = conversation.predict(input=user_input)
        print(f"AI: {response}")
        user_input = input("You: ")
        if user_input == "exit":
            break


if __name__ == '__main__':
    run()

templateの{history}が肝のようで、ここに人間の言葉とその時の出力が格納され、
これを毎回受け取ることで過去の会話内容を記憶する仕組み。

ConversationBufferWindowMemory(k=2)のkの値が直近X回の会話の保持となっている。

これで会話をすると以下のように、前の会話を保持してくれる。

しかし、指定回数の2回より前の会話は記憶から吹っ飛ぶ。

ということで、ConversationBufferWindowMemoryを使うと、指定回数前の会話内容を保持してくれるよって話でした。
kを大きくすれば以前の内容をより多く保持してくれるが、tokenの数が増えるので料金に注意です。

蛇足

templateの書き方面白いですね〜
これは拾い物ですが、日本語でとか200文字以内にとか、簡潔に回答してとかこの辺がプロンプトエンジニアリングの本領発揮場所ですね