OpenAI Python SDK v1.0がめちゃくちゃ使いやすくなってた
ハイライト
- インスタンス化されたクライアントの利用を推奨するようになった
- Async/Azure専用のクライアントが追加された
- レスポンス(出力)がPydantic Modelになった
- リクエストパラメータ(入力)がTypedDictになった
インスタンス化されたクライアントの利用を推奨するようになった
これまではopenai
モジュールに定義されていたopenai.ChatCompletion.create
関数をよんでいたところがインスタンス化されたOpenAI
オブジェクトのchat.completions.createメソッドを呼ぶ仕様になりました。
これまで
import json
import openai
completion = openai.ChatCompletion.create(model='curie')
print(completion['choices'][0]['text'])
print(completion.get('usage'))
print(json.dumps(completion, indent=2))
これから
from openai import OpenAI
client = OpenAI(
api_key=os.environ['OPENAI_API_KEY'], # デフォルト値なので省略してよい
omitted)
completion = client.chat.completions.create(model='curie')
print(completion.choices[0].text)
print(dict(completion).get('usage'))
print(completion.model_dump_json(indent=2))
これがどううれしいかというと、これまで環境変数の読み込みのタイミングはopenaiモジュールに隠された内部実装でした。ユーザーはopenai.ChatCompletion.createを呼ぶ前に環境変数を設定する必要があります。新実装ではOpenAI()を呼ぶタイミングで環境変数がセットされているか、任意の文字列を入力することでこの目的を達成できます。
Async/Azure専用のクライアントが追加された
この新しいクライアントは
- Asyncか否か
- Azureか否か
で全部で4バージョン(OpenAI, AsyncOpenAI, AzureOpenAI, AsyncAzureOpenAI)あります。
AsyncClientが登場したことでopenai
モジュールに定義されたopenai.ChatCompletion.acreate
関数は利用できなくなりました。また間違えやすかったエンドポイント周りの設定ミスが明示的にクライアントが分かれたことでわかりやすくなりましたね。
client = AsyncAzureOpenAI(
api_key = os.getenv("AZURE_OPENAI_API_KEY"),
api_version = "2023-12-01-preview",
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
)
response = await client.chat.completions.create(model="gpt-35-turbo", messages=[{"role": "user", "content": "Hello world"}])
※そもそもOpenAIのリクエストを非同期並列でリクエストできるって知っていましたか?詳しく書いている素敵な記事を見つけたのでぜひご覧ください。
レスポンス(出力)がPydantic Modelになった
最近のPythonコミュニティはType Safeなソースコードが大好きです。余談ですがOpenAIはWhisperをリリースしたときもType Safeなクリーンなコードを公開しています。Whisperではdataclassが使われていましたがOpenAI SDK v1.0からはPydanticを採用しdataclassよりもさらにクリーンでJSONへの変換が容易になっています。
これまで
import json
import openai
completion = openai.Completion.create(model='curie')
print(completion['choices'][0]['text']) # 汚いstrリテラルでのアクセス
print(completion.get('usage'))
print(json.dumps(completion, indent=2))
これから
from openai import OpenAI
client = OpenAI()
completion = client.completions.create(model='curie')
print(completion.choices[0].text) # クリーンなドットアクセスでvscodeもニッコリ
print(dict(completion).get('usage'))
print(completion.model_dump_json(indent=2))
リクエストパラメータ(入力)がTypedDictになった
入力に渡していたちょっとめんどくさい辞書のリストがTypedDictになりました。キーやバリューの許容値がLiteralで制限されているのでかなり厳しくエラーをチェックしてくれます。
from openai import OpenAI
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "ssystem",
"content": "You are a helpful assistant.",
}, # TypedDictがsystemを要求しているので、ssystemはエラーになる
{
"role": "user",
"contant": "What is human life expectancy in the United States?", # contantはエラーになる
},
],
)
response = completion.choices
当然の疑問としては出力がPydanticModelなんだから入力もPydanticModelに統一したほうがいいんじゃないの?ってところですよね。そこはver0からの破壊的な変更を嫌ったのでしょうか。でもTypedDictで十分エディターの恩恵を得られるので、超ナイスアップデートですね!
まとめ
OpenAIのソースコードめちゃ綺麗になりましたね。もともとOpenAIってすごい研究者を集めてはいるものの研究としての新規性というより、既存の研究を大規模にスケールさせるエンジニアリングで著名な成果を残している印象です。リリースから数カ月たって今更解説記事書いちゃいましたが、よかったらいいねおしていただけるととてもとても励みになります。
Discussion
OpenAI Python SDK v1.0 からは Stainless という SDK 自動生成のフレームワークが利用されているようです。
(Pull request テンプレートに自動生成ということが言及されている)
Stainless になったことでこの記事の言及の通り素晴らしい API になっていて驚いています ✨
いつも良質な記事ありがとうございます!
Stainless知りませんでした。なぜこれまでだれも作らなかったのかと思わされるような素敵なツールですね。
awsのboto3のような自動実装系のライブラリはみんなこうした仕組みでクリーンに再実装されて欲しいです!