😸

ChatGPT-APIの出力をプログラムに落としこむ(Text-Embeddings)

2023/03/13に公開

目的

例えばChatGPTに人間同士の議論の審判をさせるというケースを考えます。
ネット上のバイアスやそもそも意味を理解できているのかという問題がありますが、AIに議論の判定(もしくは進行)をさせるというのは中立性の面からも将来主流になるのではと思います。
ではChatGPTにAとBの議論の勝敗判定をさせたとして、その出力は当然文章になるわけですが、プログラムで扱うにはAIから得られた文章を

  • A勝ち
  • B勝ち
  • 引き分け

に分類する必要があります。
ChatGPTに出力の形式を指定するという方法もあるのですが、安定性に難あり、トークンを余計に使う、などの問題があります。
そこでOpenAI-APIにあるText-Embeddingsを用いればいいのではと思い、試すことにしました。

プロンプト

今回使用したプロンプトは以下です。
議題は「賃貸か持ち家か」。
ここではわざとAとBの意見の質に差をつくっています(A<B)。

[議題]
賃貸か持ち家か
[Aの意見]
賃貸がいいと思います。持ち家は隣人とトラブルに遭ったときに気軽に引っ越せなくて困るからです。
[Bの意見]
・長期的に見てコストが削減される
持ち家は初めは購入費用が高いかもしれませんが、長期的に見てコストが削減される傾向があります。一方、賃貸物件では毎月の家賃を支払い続ける必要があり、長期的に見てコストが高くなる可能性があります。
・自由度が高い
持ち家は自分の所有物であるため、自分の好きなように改築やリフォームができます。一方、賃貸物件では、大規模な改築やリフォームはできない場合が多いため、自由度が低くなります。
・安心感がある
持ち家は自分のものであるため、長期的な安定感を持って生活することができます。また、自分たちの家であれば、周りの人たちとのつながりを深めることができ、コミュニティ形成がしやすくなります。
・将来的な投資としての価値がある
持ち家は将来的な投資としての価値があると考えられます。購入した物件の価格が上がれば、その差額を利益として得ることができます。また、将来的に不動産を売却することで、大きな資産を手にすることができます。
以上の理由から、私は持ち家が賃貸物件よりも優れていると考えます。
[審判(審判はA、Bどちらの意見が優れているのかを判定します。判定には論理展開、話の真偽、人々への受け入れやすさ、文章のうまさを考慮します。内容についてはあまり考慮しなくてもよいです。)]

得られたChatGPTの回答は以下です。

AとBの意見にはそれぞれ優れた点があると思いますが、私はBの意見が優れていると判定します。
Bの意見には、長期的なコスト削減や自由度の高さ、安心感のある点、将来的な投資価値がある点があり、これらが人々に受け入れやすく、論理的に展開されていると感じました。
一方、Aの意見は、隣人トラブルへの対策という1点に絞られており、他の面を考慮していないと感じました。
また、主張が一方的で、対立するBの意見を全く反論していない点も見受けられました。そのため、Bの意見がより優れたものと考えました。

いい感じですね。
人間から見れば、ChatGPTの判定はBが勝ちであることを意味していることは明らかですがこれをプログラムが解釈できる形にしないといけません。

埋め込み表現とコサイン類似度

では、ChatGPTの回答がどういう勝敗判定となっているかを調べます。
そのために、文章埋め込み表現を用います。
文章埋め込みは文章を数値ベクトル(関連のある文章のベクトル同士を空間上の近い場所に配置した)で表現したものです。
ChatGPTの回答が以下の三つの文章のうちどれに一番近いのかを調べることで、勝敗を分類します。

  • "Aの意見の方が優れている"
  • "Bの意見の方が優れている"
  • "どちらの意見が優れているのか判断できない。引き分け"

距離としてはコサイン類似度を用います(OpenAIにもこれを使えと書いてあります)。
以下はコード例です。

import numpy as np
import openai

def get_api_key():
    with open("./api_key","r") as f:
        key = f.read()
    return key
def cos_sim(x,y):
    return np.dot(x,y)/(np.linalg.norm(x)*np.linalg.norm(y))
def sims(a,b,hikiwake,chatgpt_text):
    cos_sim_a = cos_sim(chatgpt_text,a)
    cos_sim_b = cos_sim(chatgpt_text,b)
    cos_sim_hikiwake = cos_sim(chatgpt_text,hikiwake)
    return [cos_sim_a,cos_sim_b,cos_sim_hikiwake]
def embedding(text):
    openai.api_key = get_api_key()
    model =  "text-embedding-ada-002"
    res = openai.Embedding.create(
        model= model,
        input=text
    )
    return np.array(res["data"][0]["embedding"])

a_win_em = embedding("Aの意見の方が優れている")
b_win_em = embedding("Bの意見の方が優れている")
hikiwake_em = embedding("どちらの意見が優れているのか判断できない。引き分け")
chatgpt_em = embedding("AとBの意見にはそれぞれ優れた点があると思いますが、私はBの意見が優れていると判定します。Bの意見には、長期的なコスト削減や自由度の高さ、安心感のある点、将来的な投資価値がある点があり、これらが人々に受け入れやすく、論理的に展開されていると感じました。一方、Aの意見は、隣人トラブルへの対策という1点に絞られており、他の面を考慮していないと感じました。また、主張が一方的で、対立するBの意見を全く反論していない点も見受けられました。そのため、Bの意見がより優れたものと考えました。")

sims(a_win_em,b_win_em,hikiwake_em,chatgpt_em)

結果

>>> sims(a_win_em,b_win_em,hikiwake_em,chatgpt_em)
[0.8978647725177573, 0.9055372542198694, 0.8734859027622555]

無事判定ができました。
これがどのくらいの精度なのかは各自調べてください。

Discussion