OpenAI function callingの機能比較を実装-2 複数関数をcall(ChatCompletionとAssistants)
先回に続いて、複数関数をcallする仕様にしました。
function 1 : 誕生日から今日までの日数を算出する
function 2: 名言を取得する
名言をランダムに取得するAPIは、以下を使わせていただきました。
ありがとうございます。
先回の記事
コードと実行結果(途中経過付き)は、google colabのnotebookで共有します。(このように共有するの初めてなので、おかしな点があれば、コメントで教えていただけると大変ありがたいです)
他の人に説明する仕様になっていませんこと、お断りしておきます。
それぞれのコードと実行結果だけ、以下に記載します。
(import類とapi keyの設定は省略)
ChatCompletion
def get_meigen(num):
try:
# APIのエンドポイント
url = f"https://meigen.doodlenote.net/api/json.php?c={num}"
# APIリクエストを送信
response = requests.get(url)
# レスポンスの内容をJSON形式で取得
data = response.json()
return data
except ValueError:
return "名言は取得できませんでした"
def get_meigen(num):
try:
# APIのエンドポイント
url = f"https://meigen.doodlenote.net/api/json.php?c={num}"
# APIリクエストを送信
response = requests.get(url)
# レスポンスの内容をJSON形式で取得
data = response.json()
# 名言リストを文字列に変換
meigen_list = []
for item in data:
meigen_list.append(f"「{item['meigen']}」 - {item['auther']}")
# リストを改行区切りの文字列に変換して返す
return "\n".join(meigen_list)
except ValueError:
return "名言は取得できませんでした"
# 上記の2つの関数の説明を変数toolsに入れる
tools = [
{
"type": "function",
"function": {
"name": "cal_you_lived",
"description": "ユーザーが入力した誕生日から数えて今日は何日目かを計算して、日数を返す",
"parameters": {
"type": "object",
"properties": {
"birthday ": {
"type": "string",
"description": "ユーザーの生年月日。format:yyyy-mm-dd. e.g. 2001-11-10 ",
},
},
"required": ["birthday"],
},
},
},
{
"type": "function",
"function": {
"name": "get_meigen",
"description": "api経由で名言をnumの数だけ取得する",
"parameters": {
"type": "object",
"properties": {
"num": {
"type": "string",
"description": "名言の数 最大数は10。 e.g. 3 ",
},
},
"required": ["num"],
},
},
}
]
# messageを保存するlistの初期化
messages = []
# gptに問い合わせる。二つの関数がcallされる
message = "私の誕生日は、昭和41年10月10日です。"
messages = [
{'role':'system', 'content':
"ユーザが入力した誕生日から数えて、今日が何日目かを計算してください ¥n\
同時に、api経由で名言3つ取得してください ¥n"},
{"role": "user", "content": message}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
tool_choice="auto",
)
# 1回目の問い合わせ回答を変数に入れる
response_message = response.choices[0].message
# 問い合わせ回答をmessagesに追加
messages.append(response_message)
# callする関数を変数に入れて実行
tool_calls = response_message.tool_calls
if tool_calls:
available_functions = {
"cal_you_lived": cal_you_lived,
"get_meigen": get_meigen,
}
for tool_call in tool_calls:
# tool_callsにあるfunctionを実行する準備
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
# 関数を引数とともに実行
if function_name == "cal_you_lived":
function_response = function_to_call(
birthday=function_args.get("birthday"),
)
elif function_name == "get_meigen":
function_response = function_to_call(
num=function_args.get("num"),
)
# 呼び出して実行した関数の情報と引数をmessagesに追加
messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
}
)
# 2回目の問い合わせでお祝いしてもらう
message = {'role':'user','content':'あなたは、ユーザーが今日生まれてから何日目であることを、ぴったりな名言を1つ引用してお祝い文を作って、祝福してください'}
messages.append(message)
second_response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
)
# 問い合わせの結果の印字
print(second_response.choices[0].message.content)
assistans(関数の定義類は省略)
# assistantsの作成
assistant = client.beta.assistants.create(
name="birthday_calculator",
instructions="古今東西の名言を引用して祝福するプロのコピーライダーです。ユーザーを幸せな気持ちにします",
model="gpt-4o-mini",
# ツールの定義
tools = tools
)
# threadの作成
thread = client.beta.threads.create()
# messageの作成
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="assistant",
content="ユーザが入力した誕生日から数えて、今日が何日目かを計算してください。同時に、api経由で名言3つ取得してください。"
)
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content="私の誕生日は、昭和41年11月11日です。3つの名言の中からお祝いにピッタリな明言を1つ引用して、今日まで生きてきた私を祝福してください。"
)
# assistantを実行する
run = client.beta.threads.runs.create_and_poll(
thread_id=thread.id,
assistant_id=assistant.id,
)
if run.status == 'completed':
messages = client.beta.threads.messages.list(
thread_id=thread.id
)
print(messages)
else:
print("\n")
# print(run.status)
# 関数実行結果のリスト
tool_outputs = []
available_functions = {
"cal_you_lived": cal_you_lived,
"get_meigen": get_meigen,
}
for tool in run.required_action.submit_tool_outputs.tool_calls:
# tool_callsにあるfunctionを実行する準備
function_name = tool.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool.function.arguments)
# 関数を引数とともに実行
if function_name == "cal_you_lived":
function_response = function_to_call(
birthday=function_args.get("birthday"),
)
elif function_name == "get_meigen":
function_response = function_to_call(
num=function_args.get("num"),
)
tool_outputs.append({
"tool_call_id": tool.id,
"output": function_response,
})
# tool_outputsを使って2回目のrunを実行し、問い合わせ結果を印字
if tool_outputs:
try:
run = client.beta.threads.runs.submit_tool_outputs_and_poll(
thread_id=thread.id,
run_id=run.id,
tool_outputs=tool_outputs
)
# print("Tool outputs submitted successfully.")
except Exception as e:
print("Failed to submit tool outputs:", e)
else:
print("No tool outputs to submit.")
if run.status == 'completed':
messages = client.beta.threads.messages.list(
thread_id=thread.id
)
print(messages.data[0].content[0].text.value)
else:
print(run.status)
最後に
これ、いい感じのデザインにして、音声つけたり、お祝いテキストを元にAIで作曲した音楽を後ろで流したりするスマホアプリにしたら、面白いと思います。(私は毎日使いたい)
今の私には、これを実装まで持っていく力がないので、興味のある方は、ぜひ実装してみてください。
実装したら、教えてくださいね。