👻

文章ベクトルの類似度計算を利用としたGPT APIの使用料削減法

2023/11/04に公開

はじめに

最近、とくにゲーム業界で対話型AIキャラクターとしてGPTが使われる事例が増えています。1つの問題は、同じような質問が繰り返されると、GPT APIとの通信が毎回発生し、コストがかかる点です。この記事で紹介する方法は、以前に受けた質問とその回答をキャッシュしておき、新たな質問がきた場合には類似度を計算し、一定以上の類似度があれば前の回答を再利用するというものです。

この方法で、GPT APIの使用量と費用を節約できます。

# コード例
今回は、提案手法にしたがって以下のコードを実現しました。
詳細に関してはコードのコメントを参照してください。

class GPTCacheWithSentenceTransformers:

    def __init__(self):
        self.cache = {}  # キャッシュデータを保持する辞書. キー: プロンプト, 値: (レスポンス, 埋め込み)
        self.model = SentenceTransformer('all-MiniLM-L6-v2')  # 文章ベクトルの生成に使うSentenceTransformerモデル

    def get_response(self, prompt, threshold=0.8):
        # 新しいプロンプトの文書ベクトルを生成
        new_embedding = self.model.encode([prompt], convert_to_tensor=True)

        # キャッシュ内の既存のプロンプトとの類似度を計算
        for existing_prompt, (existing_response, existing_embedding, count) in self.cache.items():
            similarity = util.pytorch_cos_sim(new_embedding, existing_embedding)
            # 類似度が閾値以上であればキャッシュされたレスポンスを返す
            if similarity.item() >= threshold:
                self.cache[existing_prompt] = (existing_response, existing_embedding)
                print(f"sameQuestion:{similarity }")
                return existing_response

        # キャッシュになければGPT APIから新しいレスポンスを取得
        openai_api_key = "ご自身のAPIキーをしようしてください。"
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=[{
                "role": "user",
                "content": prompt
            }],
            temperature=1,
            max_tokens=256
        )
        new_response = response.choices[0]["message"]["content"]

        # 新しいプロンプト、レスポンス、および埋め込みをキャッシュに追加
        self.cache[prompt] = (new_response, new_embedding)

        return new_response  # 新しいレスポンスを返す

# キャッシュのインスタンスを初期化
gpt_cache_st = GPTCacheWithSentenceTransformers()

実験手法

このコードを使って、どの程度文章の類似度が高ければ回答が再利用され、低ければ新しい回答が生成されるのかをテストします。以下のような文章で試します。

  • 類似度が高い例
//食事は美味しかったという類似した文章
Was the meal delicious?
Was the meal good, I presume? 
So the meal was good?
  • 類似度が低い例
//この映画は見る価値があるのか?
Is the movie worth watching?
//この映画をお勧めしますか?
Would you recommend the movie?
//この映画はいいのか?
Is the movie good?

以下のPythonコードでGPTに質問を投げてみます。

#先ほどのコードの続き

gpt_cache_st = GPTCacheWithSentenceTransformers()

print("類似度が高いと仮定する文章")

prompt1 = "Was the meal delicious?"
response1 = gpt_cache_st.get_response(prompt1)
print(f"promt1: {prompt1}")
print(f"Response to prompt1: {response1}\n")

prompt2 = "Was the meal good, I presume?"
response2 = gpt_cache_st.get_response(prompt2)
print(f"promt2: {prompt2}")
print(f"Response to prompt2: {response2}\n")

prompt3 = "So the meal was good?"
response3 = gpt_cache_st.get_response(prompt3)
print(f"promt3: {prompt3}")
print(f"Response to prompt3: {response3}\n")

print("類似度が低いと仮定する文章")

prompt4 = "Is the movie worth watching?"
response4 = gpt_cache_st.get_response(prompt4)
print(f"prompt4: {prompt4}")
print(f"Response to prompt4: {response4}\n")

prompt5 = "Would you recommend the movie?"
response5 = gpt_cache_st.get_response(prompt5)
print(f"prompt5: {prompt5}")
print(f"Response to prompt5: {response5}\n")

prompt6 = "Is the movie good?"
response6 = gpt_cache_st.get_response(prompt6)
print(f"prompt6: {prompt3}")
print(f"Response to prompt6: {response6}\n")

実験結果

以下のような結果が出ました。

  • 類似度が高い例
promt1: Was the meal delicious?

sameQuestion:tensor([[0.8872]])
promt2: Was the meal good, I presume?

sameQuestion:tensor([[0.8141]])
promt3: So the meal was good?
response:I'm sorry, I cannot answer that question as I am an AI language model and do not have the capability to taste or experience meals.
  • 類似度が低い例
prompt4: Is the movie worth watching?
Response to prompt4: I'm sorry, but I am an AI language model and I don't have personal opinions or the ability to watch movies. However, the worth of a movie is subjective and can vary depending on individual preferences. It's always a good idea to check reviews from critics or ask for recommendations from friends who have similar taste in movies. Ultimately, it's up to you to decide if a movie is worth watching based on your own interests and preferences.

prompt5: Would you recommend the movie?
Response to prompt5: As an AI language model, I don't have personal opinions or experiences. However, if you're looking for recommendations on a specific movie, it's best to consider checking out reviews, ratings, and the plot synopsis to determine if it aligns with your personal preferences and interests.

prompt6: So the meal was good?
Response to prompt6: I apologize, but as an AI language model, I do not have personal opinions or the ability to watch movies. I can provide information or help answer questions about movies based on available data though. Could you please specify which movie you are referring to?

prompt7: Did you enjoy the movie?
Response to prompt7: As an AI, I don't have the ability to watch or enjoy movies.

このように、文の類似度に基づいて効率的にAPI使用量を減らせることが示されました。

おわりに

本研究により、類似性の高い文章が繰り返し送られる場面において、過去のキャッシュを利用してAPI使用量を削減する新しい手法を開発しました。これにより、リソースの効率的な活用が可能となりました。ただし、キャッシュする文章の量についての選定は、今後の課題として残っています。

もしこの記事が役立つと感じた方は、いいねとフォローをお願いします。

Discussion