はじめに
GPT APIのFunction Calling機能を使うことで、ChatGPTが外部のAPIを自動的に呼び出して、リアルタイムの情報を取得したり、複雑なタスクを実行できるようになります。
本記事では、天気情報APIやデータベース操作など、実際のユースケースを通してFunction Callingの実装方法を詳しく解説します。初心者の方でも理解できるよう、段階的に実装していきます。
Function Callingとは
Function CallingはOpenAIが提供する機能で、GPTモデルが適切な関数を選択して実行することができます。これにより以下のようなことが可能になります:
- リアルタイムの天気情報や株価の取得
- データベースへのクエリ実行
- 外部サービスとの連携(メール送信、カレンダー操作など)
- 計算や変換処理の自動実行
基本的な実装
まず、シンプルな計算機能を実装してFunction Callingの仕組みを理解しましょう。
import openai
import json
# OpenAI APIキーの設定
client = openai.OpenAI(api_key="your-api-key")
# 関数の定義
def calculate(operation, a, b):
"""計算を実行する関数"""
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
elif operation == "divide":
return a / b if b != 0 else "Error: Division by zero"
else:
return "Error: Unknown operation"
# 使用可能な関数をGPTに伝えるためのスキーマ定義
tools = [
{
"type": "function",
"function": {
"name": "calculate",
"description": "四則演算を実行します",
"parameters": {
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": ["add", "subtract", "multiply", "divide"],
"description": "実行する演算の種類"
},
"a": {
"type": "number",
"description": "最初の数値"
},
"b": {
"type": "number",
"description": "2番目の数値"
}
},
"required": ["operation", "a", "b"]
}
}
}
]
# GPTとの対話を実行
def chat_with_function_calling(user_message):
messages = [
{"role": "user", "content": user_message}
]
# 最初のAPIコール
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
tools=tools,
tool_choice="auto" # GPTが自動的に関数を選択
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
# 関数が呼び出された場合の処理
if tool_calls:
messages.append(response_message)
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 関数を実行
if function_name == "calculate":
result = calculate(
function_args["operation"],
function_args["a"],
function_args["b"]
)
# 関数の実行結果をメッセージに追加
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": str(result)
})
# 関数の結果を含めて再度APIを呼び出し
second_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages
)
return second_response.choices[0].message.content
return response_message.content
# 使用例
result = chat_with_function_calling("125かける37は何ですか?")
print(result) # 出力: 125 × 37 = 4,625です。
実践的な応用例:天気情報取得システム
次に、より実用的な例として天気情報を取得するシステムを実装してみましょう。
import requests
import json
from datetime import datetime
# 天気情報を取得する関数
def get_weather(city):
"""指定した都市の天気情報を取得"""
# OpenWeatherMap APIを使用(実際にはAPIキーが必要)
api_key = "your-weather-api-key"
base_url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": city,
"appid": api_key,
"units": "metric", # 摂氏温度
"lang": "ja" # 日本語
}
try:
response = requests.get(base_url, params=params)
data = response.json()
if response.status_code == 200:
return {
"city": data["name"],
"temperature": data["main"]["temp"],
"feels_like": data["main"]["feels_like"],
"humidity": data["main"]["humidity"],
"description": data["weather"][0]["description"],
"status": "success"
}
else:
return {"status": "error", "message": "都市が見つかりませんでした"}
except Exception as e:
return {"status": "error", "message": f"API呼び出しエラー: {str(e)}"}
# データベースから履歴を取得する関数(模擬実装)
def get_weather_history(city, days=7):
"""過去の天気履歴を取得(実際の実装ではデータベースを使用)"""
# 模擬データ
return {
"city": city,
"period": f"過去{days}日間",
"average_temp": 22.5,
"status": "success"
}
# Function Calling用のツール定義
weather_tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "指定した都市の現在の天気情報を取得します",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "天気を調べたい都市名"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "get_weather_history",
"description": "指定した都市の過去の天気履歴を取得します",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "履歴を調べたい都市名"
},
"days": {
"type": "integer",
"description": "取得する日数(デフォルト: 7日)",
"default": 7
}
},
"required": ["city"]
}
}
}
]
# 天気アシスタントのメイン処理
def weather_assistant(user_message):
"""天気情報を提供するアシスタント"""
messages = [
{
"role": "system",
"content": "あなたは天気情報を提供するアシスタントです。ユーザーの質問に応じて適切な関数を呼び出し、親しみやすい形で天気情報を提供してください。"
},
{"role": "user", "content": user_message}
]
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
tools=weather_tools,
tool_choice="auto"
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
if tool_calls:
messages.append(response_message)
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 関数を実行
if function_name == "get_weather":
result = get_weather(function_args["city"])
elif function_name == "get_weather_history":
result = get_weather_history(
function_args["city"],
function_args.get("days", 7)
)
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": json.dumps(result, ensure_ascii=False)
})
# 結果を含めて再度APIを呼び出し
final_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages
)
return final_response.choices[0].message.content
return response_message.content
# 使用例
print(weather_assistant("東京の今の天気はどうですか?"))
print(weather_assistant("大阪の過去5日間の天気履歴を教えて"))
エラーハンドリングとベストプラクティス
Function Callingを本格的に運用する際は、以下の点に注意が必要です:
エラーハンドリング
- API呼び出し失敗: 外部APIが利用できない場合の代替処理
- パラメータ検証: GPTが不正なパラメータを渡す可能性への対応
- タイムアウト処理: 長時間実行される処理の制限
セキュリティ対策
- 関数の実行権限制限: 危険な操作を実行する関数の制限
- 入力値のサニタイゼーション: SQLインジェクションなどの攻撃への対策
- レート制限: API呼び出し回数の制限
パフォーマンス最適化
- キャッシュの活用: 同じ情報への重複リクエスト防止
- 非同期処理: 複数の関数を並列実行
- 結果の圧縮: 大きなデータを扱う場合の最適化
コスト管理と運用のポイント
Function Callingを使用する際は、通常のGPT APIよりもトークン使用量が増加する傾向があります。以下の点を考慮して運用しましょう:
- 関数定義の簡潔化: 不要な説明を削除してトークンを節約
- 結果のフィルタリング: 必要な情報のみをGPTに返す
- モデルの選択: gpt-3.5-turboとgpt-4の適切な使い分け
- ログ記録: 実行状況の監視と分析
まとめ
GPT APIのFunction Callingは、単なるチャットボットを超えた高度なAIアシスタントを構築するための強力な機能です。適切に実装すれば、以下のようなメリットが得られます:
- リアルタイムデータの活用による正確な情報提供
- 複雑な業務プロセスの自動化
- ユーザーエクスペリエンスの大幅な向上
一方で、セキュリティやコスト管理への配慮も重要です。本記事で紹介した実装パターンを参考に、自分のプロジェクトに適した形でFunction Callingを活用してみてください。
次のステップとして、より複雑な業務アプリケーションへの組み込みや、複数の関数を連鎖的に実行するワークフローの構築にも挑戦してみることをお勧めします。