Closed4

OpenAI ChatCompletion APIのJSON modeを試してみる

kun432kun432

OpenAI Python SDKの場合。

!pip install openai
Successfully installed ... openai-1.1.1
from google.colab import userdata
import os

os.environ["OPENAI_API_KEY"] = userdata.get('OPENAI_API_KEY')

ポイントは2つ

  • response_format={"type":"json_object"}を指定する
  • プロンプトに"json"という文字列を含める
from openai import OpenAI
from pprint import pprint
import json

model = "gpt-4-1106-preview"  # or "gpt-3.5-turbo-1106"

messages = [
    {"role": "system", "content": "あなたは詩的なアシスタントで、複雑なプログラミングのコンセプトをクリエイティブなセンスで説明することに長けている。"},
    {"role": "user", "content": "プログラミングにおける再帰の概念を説明する詩を作ってください。日本語で。JSONで出力してください。"}
]

client = OpenAI()

res = client.chat.completions.create(
    model=model,
    messages=messages,
    response_format={"type":"json_object"}
)

print(res.json(indent=2, ensure_ascii=False))

レスポンス

{
  "id": "chatcmpl-8IEsbrPQWCZ3Cv9u3r3gAX2bHmKPC",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "{\n  \"詩\": [\n    \"再帰の世界へようこそ、永遠の螺旋階段を登ろう\",\n    \"関数は呼び、自身を見つめ、無限の鏡のように反射する\",\n    \"一歩ずつ問題を削り、シンプルな核心まで落とし込む\",\n    \"小さな問いに答えて、大きな謎を解き明かす旅の途中で\",\n    \"根底に達し、答えが見えたら振り返る、\",\n    \"元の道へと戻るための、過去への扉を閉じる\",\n    \"条件が鍵、終わりを告げる合図、完結を意味する\",\n    \"見渡せば、作り上げたひとつの完璧な塔\",\n    \"再帰で描くプログラムの美、エレガントな解の舞\"\n  ]\n}",
        "role": "assistant",
        "function_call": null,
        "tool_calls": null
      }
    }
  ],
  "created": 1699357793,
  "model": "gpt-4-1106-preview",
  "object": "chat.completion",
  "system_fingerprint": "fp_a24b4d720c",
  "usage": {
    "completion_tokens": 283,
    "prompt_tokens": 114,
    "total_tokens": 397
  }
}

choices[0].message.contentを取り出してみるとこう。

print(res.choices[0].message.content)
{
  "詩": [
    "再帰の世界へようこそ、永遠の螺旋階段を登ろう",
    "関数は呼び、自身を見つめ、無限の鏡のように反射する",
    "一歩ずつ問題を削り、シンプルな核心まで落とし込む",
    "小さな問いに答えて、大きな謎を解き明かす旅の途中で",
    "根底に達し、答えが見えたら振り返る、",
    "元の道へと戻るための、過去への扉を閉じる",
    "条件が鍵、終わりを告げる合図、完結を意味する",
    "見渡せば、作り上げたひとつの完璧な塔",
    "再帰で描くプログラムの美、エレガントな解の舞"
  ]
}

ドキュメントにもある注意

  • JSONモードを使用するには、システムメッセージがモデルにJSONを生成するように指示しなければならない。忘れないように、システムメッセージに "JSON"という文字列がない場合、APIはエラーを投げる。
  • finish_reasonlengthの場合、モデルが返すメッセージは部分的なものになるかもしれない。これを防ぐには、レスポンスをパースする前にfinish_reasonをチェックする。
  • JSONモードは、出力が特定のスキーマにマッチすることを保証しないが、有効でエラーなくパースされることだけは保証する。

"JSON"という文字列を含まない場合は以下のようなエラーになる。

BadRequestError: Error code: 400 - {'error': {'message': "'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.", 'type': 'invalid_request_error', 'param': 'messages', 'code': None}}
kun432kun432

JSONモードは、出力が特定のスキーマにマッチすることを保証しないが、有効でエラーなくパースされることだけは保証する。

とある。100%保証はされないのかもだけど、以下のようにプロンプトで定義してあげれば、スキーマ通りに出力してくれる。

from openai import OpenAI
from pprint import pprint
import json

model = "gpt-3.5-turbo-1106"
#model = "gpt-4-1106-preview"

user_prompt = """
プログラミングにおける再帰の概念を説明する詩を作ってください。日本語で。出力は以下のようなJSONで出力してください。

{
    "title": <詩のタイトル>,
    "author": <詩の作者>,
    "text": [
        <詩の本文。行ごとに配列の要素に分ける。>
    }
}
"""

messages = [
    {"role": "system", "content": "あなたは詩的なアシスタントで、複雑なプログラミングのコンセプトをクリエイティブなセンスで説明することに長けている。"},
    {"role": "user", "content": user_prompt}
]

client = OpenAI()

res = client.chat.completions.create(
    model=model,
    messages=messages,
    temperature=0,
    response_format={"type":"json_object"}
)

json_obj = json.loads(res.choices[0].message.content)
print(json_obj)

結果(見やすいように改行入れた)。gpt-3.5-turbo-1106で10回ぐらい試したけど、一応JSONフォーマットは破綻しなかった模様。

{
    "title": "再帰の詩",
    "author": "AIアシスタント",
    "text": [
        "木々の枝が繋がり合い",
        "遠くまで広がる森を作る",
        "再帰の魔法がそれを紡ぎ出す",
        "自分自身を呼び出し、続ける",
        "問題を小さな部分に分け",
        "それぞれを解き明かす手法",
        "再帰の詩がプログラミングの世界に",
        "美しいパターンを編み出す"
    ]
}
このスクラップは6ヶ月前にクローズされました