しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure OpenAI Service に追加された Content filters (Preview) の実行結果を取得する

少し前から Azure OpenAI Service に Content filters (Preview) が追加されたからなのか、たまに Chat Completion を使っていると以下のようなメッセージが返ってくることがあります。

メッセージ内容から Content filters に引っかかっていることは一発でわかるのですが、何が原因で引っかかったのかは分からないので Chat Playground 上では対処が結構難しいです。

とはいえ、Content filters で弾かれる内容は以下のドキュメントにもあるように 4 項目に対してなので、そこから想像は付くのですが確証がない状態です。

せめて 4 項目のうちどれに引っかかって、どういった表現に問題があったのかもデバッグ中には教えてもらいたいものですが、残念ながら Chat Playground にはそういう機能はありません。

更に現時点では Content filters のカスタマイズでも、これ以上フィルタを緩くする方向には設定できないので、プロンプト側でフィルタに引っかからないように出力を制御するしかありません。

Content filters の実行結果は Chat Playground では確認出来なくても、REST API を直接叩けば取れるだろと思って Postman を使って適当に叩いてみたところ、以下のような情報量がほぼゼロのレスポンスしか返ってきて来なかったので若干絶望しました。

絶対に取れる方法が用意されていると思っていたので調べたところ、以下のドキュメントが見つかりました。適切に API Version を設定すれば、問題なく Content filters の結果は返ってくるようです。

今回サンプル URL を Chat Playground から取得したので、Content filters に対応していない API Version が指定されていましたが 2023-06-01-preview を指定すると、以下のように詳細な情報が返ってくるようになりました。このスクリーンショットでは応答についての結果が含まれていますが、実際にはプロンプトに対しての結果も返ってきています。

Content filters の結果が返ってくることが分かれば、後は SDK 経由で結果が取れるかの確認ですが、残念ながら C# 向けの SDK では現時点では古い API Version 向けに生成されていたので、詳細な情報を取得することは出来ませんでした。

しかし最近の Azure SDK は全て AutoRest を使った OpenAPI 定義からの自動生成となっているので、暫くすると 2023-06-01-preview に対応したバージョンがリリースされると思います。

他の言語の SDK で対応していることを期待して調べてみると、Azure SDK for Python のリポジトリに Content filters 周りのテストコードが存在していることに気が付きました。

Python SDK ではレスポンスの型を定義しておらず、割と自由に参照できるようになっていたので API Version だけ対応したものを指定してやれば、特に問題なく扱えることが分かりました。

Azure SDK for Python のリポジトリにテストコードはありましたが、SDK の実体は OpenAI が提供しているものなので、利用を開始する際には以下のリポジトリを確認しておきます。

適当に Codespaces を立ち上げて Python 環境を作成し、その上で Content filters の応答を取得するサンプルコードを書いてみました。このサンプルコードの肝は前述した通り openai.api_version2023-06-01-preview を指定している部分です。

import openai

openai.api_type = "azure"
openai.api_key = "..."
openai.api_base = "https://***.openai.azure.com/"
openai.api_version = "2023-06-01-preview"

# create a chat completion
completion = openai.ChatCompletion.create(deployment_id="gpt-4", model="gpt-4", messages=[{"role": "user", "content": "Hello world"}])

# print the completion
print(completion.choices[0].message.content)

# print content filter results
print(completion.choices[0].content_filter_results)
#print(completion.prompt_annotations[0].content_filter_results)

このサンプルコードを実行すると、以下のように応答に対する Content filters の実行結果が出力されます。コメントアウトしている行を戻すと、プロンプトに対する結果も表示されます。

これで Content filters のどの項目に引っかかって、応答がフィルタリングされてしまったのかを把握することが可能となりました。開発中だけは応答のどの部分に問題があったのかも教えてほしくはありますが、最低限の情報は取れているので対応は出来そうです。