TLDR
parallel_tool_calls = false
を指定する
解説
ChatGPT APIのFunction Calling機能を使うと、jsonで定義したデータ構造でレスポンスを返却してくれるので、プログラム上の後段の処理に繋げるのに便利です。
2024年8月のアップデートで、このデータ構造を厳格に守るように命令するパラメータ"strict"が登場し、Function Callingがより使いやすくなりました。(逆に言うと、それまではデータ構造を指定してもそれをChatGPTが守るかどうかはベストエフォートだったため、プロンプト上でもデータ構造に誘導するような文言の工夫が必要でした。)
When crafting function calls you need to think about what information the AI has at that moment in time, what are the function names like? Informative? would it be clear to the AI what the function does and when it should use it? Imagine the AI is a new employee and you need to explain to it everything it needs to complete the task.
ところが、この新しいパラメータstrictにtrueを指定しても、返却値が定義通りにならないことがあります。その理由のひとつとして、パラメータ"parallel_tool_calls"がデフォルトでtrueになっていることで、こちらが定義したデータ構造をChatGPTが勝手に分割して解釈し、アウトプットを複数のオブジェクトとして返却する場合があります。
ドキュメントを読む限り、parallel_tool_callsパラメータは、ユーザーが複数関数を定義してAPIを呼び出したときにアウトプットを分割させる役割のように読めるので、単一関数の定義の場合の挙動はおかしいように思いますが、とにかくこれのデフォルト値が望ましい結果を得られない原因となっているようです。
When the model outputs multiple function calls via parallel function calling, model outputs may not match strict schemas supplied in tools.
これを回避するためにこちらでparallel_tool_callsをfalseにしておく必要があります。ドキュメントのサンプルに挿入位置が載っていないようなので例示しておきます。
response = client.chat.completions.create(
model='gpt-4o-2024-08-06',
messages=messages,
tools=tools,
parallel_tool_calls=False,
)