はじめに
OpenAI APIのfunction callingを使って、構造化されたダミーデータを生成してみました。
function callingによる構造化のよくある事例は、元になるテキストとデータ仕様を与えて、データ仕様に沿った情報を抽出する操作ですが、今回は、元になるテキストは与えず、データ仕様だけ与えて、そのデータ仕様に合致した構造化データをfunction callingで生成する、ということをやってみます。
以下のコードを実行してみたところ、指定した個数のダミーデータを得ることができました。
import openai
from openai_function_call import OpenAISchema
from typing import List
from pydantic import Field
import os
import dotenv
dotenv.load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
class UserDetails(OpenAISchema):
"""User Details"""
name: str = Field(..., description="User's name")
age: int = Field(..., description="User's age")
class Users(OpenAISchema):
"""Users"""
users: List[UserDetails] = Field(..., description="List of users")
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
functions=[Users.openai_schema],
messages=[
{"role": "system", "content": "与えられたスキーマに沿って架空の人物を5名、生成してください"}
],
function_call={"name": "Users"}
)
user_details = Users.from_response(completion)
print(user_details)
users=[UserDetails(name='John', age=25), UserDetails(name='Emily', age=30), UserDetails(name='Michael', age=35), UserDetails(name='Sophia', age=28), UserDetails(name='William', age=32)]
コード解説
ダミーのユーザーデータをChatGPTに生成させるタスクを想定します。
ユーザは名前と年齢の情報を持つとします。
function callingに渡すためのデータ構造の定義のために、openai_function_callを使います。データ構造の定義がpythonライクに直感的に書けるので便利です。
ライブラリをインストールします。
pip install openai-function-call python-dotenv
データ構造を定義します。
class UserDetails(OpenAISchema):
"""User Details"""
name: str = Field(..., description="User's name")
age: int = Field(..., description="User's age")
function callingを実行してみます。
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
functions=[UserDetails.openai_schema],
messages=[
{"role": "system", "content": "与えられたスキーマに沿って架空の人物を5名、生成してください"}
],
function_call={"name":"UserDetails"},
)
user_details = UserDetails.from_response(completion)
print(user_details)
name='Alice' age=25
25歳のAliceというユーザデータを構造化済みの状態で得ることができました。
しかし、1回のコールで1データしか得られないため、効率が悪いです。
そこで、UserDetailsのリストが得られるように、データ構造を修正します。修正というか、UserDetailsのリストを要素にもつ新たなクラスUsersを定義します。
class Users(OpenAISchema):
"""Users"""
users: List[UserDetails] = Field(..., description="List of users")
これをfunction callingに渡して、実行します。
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
functions=[Users.openai_schema],
messages=[
{"role": "system", "content": "与えられたスキーマに沿って架空の人物を5名、生成してください"}
],
function_call={"name": "Users"}
)
user_details = Users.from_response(completion)
print(user_details)
users=[UserDetails(name='John', age=25), UserDetails(name='Emily', age=30), UserDetails(name='Michael', age=35), UserDetails(name='Sophia', age=28), UserDetails(name='William', age=32)]
messagesで指定した個数(5個)のuser情報を1回のコールで得ることができました。
おわりに
function callingを使って、構造化されたダミーデータを直接生成することを試してみました。
function callingが情報抽出に使えること自体はよく知られています(参考1、参考2)が、元になるテキスト無しで構造化されたダミーデータを直接生成できるかどうかは、軽く調査した範囲では事例がなく、やってみる前はよくわかりませんでした。ちゃんと調べれば誰かは試していると思うのですが、自分で試したほうが早いので、やってみたところ、すんなり生成できることがわかりました。
ダミーデータ生成自体はChatGPTの有用な使い方の1つ(参考1、参考2)ですが、構造化のためのプロンプト工夫や後処理が面倒なことが多いため、今回の方法が有用なシーンはそこそこあるような気がします。
本記事がどなたかのお役に立てば嬉しいです。