OpenAIのAPIを使う

はじめに

OpenAIChatGPT が人気ですが、これとほぼ同様な機能が API として提供されています。これをPythonから使うパッケージ openai があります。これを使ってみましょう(よりハイレベルのパッケージとして LangChainGPT Index(LlamaIndex に改称)などがあります)。

自分のプログラムからAPIを使うには、こちらで登録してAPIキーを発行してもらわなければなりません。費用が発生します(ただし3ヶ月間有効な18ドルの無料枠があります)。最も強力なDavinciモデルの場合、1000トークンあたり0.02ドル(2〜3円)かかります。1トークンは、英語なら頻出単語1語(日本語なら1文字)にほぼ相当します。頻出でない語は2トークン以上になります。だいたい1000トークンが英語の750語にあたります。英語のほうが概してトークン数が少ないので安上がりです(答えも的確です)。トークン化の様子はOpenAIの Tokenizer で調べられます。

APIの詳しい説明は https://platform.openai.com にあります。Playgroundでお試し利用もできます。OpenAI Cookbook も参考になります。

Pythonのパッケージは pip install openai でインストールできます。

APIキーは、プログラムに直接書き込まず、環境変数に設定しておくのが安全・便利です。MacやLinuxでは、ターミナルに

export OPENAI_API_KEY="sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

と打ち込めば環境変数が設定されます。.bashrc 等に書き込んでおけばシェル起動時に設定されます。APIキーを書き込んだファイルは他人に見られないようにパーミッションを正しく設定しておきましょう。

自分の名前を知っているか聞いてみる

以下では InstructGPT から派生した text-davinci-003 というモデル(2022-11-28つまりChatGPTの2日前にリリースされた)を使います。APIの基本の使い方は簡単です:

import openai

prompt = "Haruhiko Okumura is"

res = openai.Completion.create(
    model="text-davinci-003",
    prompt=prompt,
    max_tokens=2048,
    temperature=0
)

print(res.choices[0].text)

次のような答えを出力してくれました:

a Japanese computer scientist and professor at the University of Tokyo. He is known for his research in the fields of computer networks, distributed systems, and computer security. He is the author of several books on computer networks and distributed systems, including the widely used textbook Computer Networks: A Systems Approach. He has also served as a consultant for several companies, including Microsoft, IBM, and NTT.

最初の6単語以外はまったく嘘です! OpenAIの言語モデルは自力でネット検索できません(WebGPT という研究はありますが提供されていません)。2021年のある時点までのネットで集めた文章で学習しているので、有名人なら覚えてくれている可能性があるのですが、私のことは知らなかったようです。また、仮に正しい知識を答えてくれても、ソース(URL)と紐づけられているわけではないので、根拠を聞いても答えられません(出典付きで答えてほしいなら Perplexity を使いましょう)。

max_tokens は返事の最大トークン数です。プロンプトのトークン数と合わせて、text-davinci-003 なら4097以下でないといけません。temperature は温度(0〜2、デフォルト1)です。上げるほど答えがランダムになります(想像力が上がります)。

Pythonをシェルから起動した場合、パッケージ側で環境変数のAPIキーを拾ってくれるはずですが、もしうまくいかなければ、import openai の後に

import os

openai.api_key = os.getenv("OPENAI_API_KEY")

のようなコードを入れるか、あるいは直接

openai.api_key = "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

のようにAPIキーを書き込みます(キーは漏れないように注意が必要です)。

英語の標語を作ってもらう

ホテルのトイレなどによく「トイレットペーパーの使い切りにご協力ください」と書いてあって、その英訳が意味不明なことがよくあります。そこで、text-davinci-003 に良い標語を考えてもらうことにしましょう。

import openai

prompt = """
### ホテルの部屋のトイレのトイレットペーパーを、新しいお客様が泊まるたびに取り替えていたのでは、資源が無駄になり、エコロジーの観点から望ましくないと考えます。そのため、新品でないトイレットペーパーを交換せず、資源節約のため最後まで使い切ってほしいと思っています。このことをお客様にご理解いただくためのなるべく短い標語を英語で書いてください。
"""

res = openai.Completion.create(
    model="text-davinci-003",
    prompt=prompt,
    max_tokens=1024,
    temperature=0.6,  # 少し創造性豊かにするために温度を上げてみる
    stop=["###"]
)

print(res.choices[0].text)

オプション stop は、AIが出力しない文字列のリストを指定します。ここでは質問のプロンプトを ### で始め、これを stop に設定して、AIが質問文まで生成してしまうことを避けています(最初は町野さんの command ai に倣って >>> にしていたのですが、PythonのプロンプトやJavaScriptの右シフトと被るので、変更しました)。AIの答えが1行だけになるようにするには、stop=["###", "\n"] のように改行を含めればいいでしょう。こういったテクニックは https://platform.openai.com のExamplesにいろいろ使われています。The Ultimate Guide to OpenAI's GPT-3 Language Model も参考になります。

さて、これを実行すると、

"Use it all - Save the Environment!"

という案を考えてくれました。なるほど!

戻り値 res はJSONオブジェクトです。中を見ると、トークン数などがわかります。

APIは記憶がありませんので、続けて質問する場合には、プロンプトにそれまでの会話を含ませる必要があります。質問と回答が区別できるように会話を記述しましょう。何度か質問を追加した後のプロンプトは、例えば次のようになります:

prompt = """
### ホテルの部屋のトイレのトイレットペーパーを、新しいお客様が泊まるたびに取り替えていたのでは、資源が無駄になり、エコロジーの観点から望ましくないと考えます。そのため、新品でないトイレットペーパーを交換せず、資源節約のため最後まで使い切ってほしいと思っています。このことをお客様にご理解いただくためのなるべく短い標語を英語で書いてください。

"Use it all - Save the Environment!"

### いいですね! ほかの案がもしあれば教えてください。

"Be Eco-friendly - Use Every Last Sheet!"

### シートではなくロールなのですが。

"Use Every Last Roll - Go Green!"

### Last Roll ではなく、ロールの最後の部分まで、という意味合いでお願いします。
"""

このプロンプトの答えは次のようになりました:

"Use Every Last Bit - Help the Environment!"

会話が続くとプロンプトはどんどん長くなりますが、プロンプトのトークン数と回答の max_tokens の合計は4097以下でないといけませんので、長くなってくれば、会話の最初の部分あるいは重要でない部分は削る必要があります。ChatGPTも最大トークン数は4000程度とのことです。