AIエージェントと関数呼び出し:LLMのためのツール構築
リアルタイムデータの取得、計算、外部APIとの連携が必要なAIエージェントを構築しているとします。しかし、LLMのテキスト生成と実際のコード実行の間のギャップをどう埋めればよいでしょうか?その答えが関数呼び出し(ツール利用とも呼ばれます)です。これにより、LLMは特定のアクションを要求し、あなたのコードがそれを実行できます。このガイドでは、AIエージェントのための関数呼び出しの設計、実装、デバッグ方法を順を追って説明します。
関数呼び出しとは?
関数呼び出しは、LLMがあなたが定義した関数を呼び出すための構造化されたリクエストを出力できる仕組みです。モデルは自由なテキストを生成する代わりに、関数名と引数を含むJSONオブジェクトを返します。その後、アプリケーションが関数を実行し、結果をモデルにフィードバックします。これにより、エージェントはテキスト生成を超えたアクション(データベースへの問い合わせ、メール送信、API呼び出しなど)を実行できます。
OpenAI、Anthropic、Googleなどの主要なLLMプロバイダーは関数呼び出しをサポートしています。基本的な考え方は一貫しています:利用可能なツールを記述し、モデルがいつ使用するかを決定し、あなたが実行を処理します。
LLMのためのツール設計
信頼性の高いエージェントの動作には、よく設計されたツールが不可欠です。以下の原則に従ってください:
- 明確な名前と説明: 説明的な関数名と詳細な説明を使用します。LLMはこれらに基づいて適切なツールを選択します。
- シンプルなパラメータ: パラメータは最小限に抑え、標準的な型(string、number、boolean、array、object)を使用します。可能な限り複雑なネスト構造は避けます。
- 冪等性: 可能な限り、ツールを冪等(再試行しても安全)に設計し、障害を適切に処理します。
- エラー処理: 情報量のあるエラーメッセージを返し、LLMがアプローチを調整できるようにします。
例:天気ツール
OpenAIのAPIでよく使用されるJSONスキーマ形式でのシンプルなツール定義を以下に示します:
{
"name": "get_weather",
"description": "Get the current weather for a given city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city name, e.g., San Francisco"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["city"]
}
}
関数呼び出しの実装:ステップバイステップ
OpenAIのAPIを使用して最小限のエージェントループを構築しましょう(このパターンは他のプロバイダーにも適用できます)。
1. ツールの定義
ツールスキーマのリストと、関数名から実際のPython関数へのマッピングを作成します。
import json
import openai
# Tool schemas
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}
}
]
# Actual functions
def get_weather(city: str, unit: str = "celsius") -> dict:
# In reality, call a weather API
return {"city": city, "temperature": 22, "unit": unit, "condition": "sunny"}
# Map names to functions
function_map = {
"get_weather": get_weather
}
2. エージェントループの作成
エージェントループは、LLMにメッセージを送信し、ツール呼び出しをチェックし、それらを実行し、モデルが最終的な回答を返すまで繰り返します。
def run_agent(user_message: str):
messages = [{"role": "user", "content": user_message}]
while True:
response = openai.ChatCompletion.create(
model="gpt-4",
messages=messages,
tools=tools,
tool_choice="auto"
)
message = response.choices[0].message
messages.append(message)
# If no tool calls, return the content
if not message.get("tool_calls"):
return message["content"]
# Execute each tool call
for tool_call in message.tool_calls:
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
if function_name in function_map:
result = function_map[function_name](**arguments)
else:
result = {"error": f"Unknown function: {function_name}"}
# Append tool result to messages
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
このループは、LLMがツール呼び出しなしの応答を生成するまで続きます。これは、十分な情報を得たことを示します。
3. エラーとエッジケースの処理
実際のエージェントは以下を処理する必要があります:
- 無効な引数: 引数の解析や関数呼び出し時の例外をキャッチします。
- 未知のツール: LLMが自己修正できるようにエラーメッセージを返します。
- タイムアウト: 外部API呼び出しにタイムアウトを設定し、ハングを防ぎます。
- レート制限: 指数バックオフを用いた再試行を実装します。
信頼性の高いエージェントのためのベストプラクティス
- ツール数を制限する: ツールが多すぎるとモデルが混乱します。関連する関数をグループ化するか、ルーターを使用します。
- 入力を検証する: 実行前にすべての引数をサニタイズして検証します。
- すべてをログに記録する: デバッグと監査のためにツール呼び出しと結果をログに記録します。
- 多様なプロンプトでテストする: さまざまなシナリオでエージェントが適切なツールを選択することを確認します。
- フォールバックを提供する: ツールが失敗した場合、エージェントは代替手段を試すか、明確化を求めるべきです。
関数呼び出しサポートの比較
| プロバイダー | 機能名 | フォーマット |
|---|---|---|
| OpenAI | Function Calling | JSON Schema |
| Anthropic | Tool Use | JSON Schema |
| Function Calling | OpenAPI Schema |
高度なパターン
エージェントが成長するにつれて、以下のパターンを検討してください:
- 並列ツール呼び出し: 一部のモデルは複数のツールを一度に要求できます。速度のために並行して実行します。
- Human-in-the-loop: 機密性の高いアクション(例:送金)では、実行前に人間の承認を要求します。
- メモリ: 会話履歴とツール結果を保存し、長いセッションでコンテキストを提供します。
- ツールルーティング: 軽量な分類器を使用して、メインのLLMを呼び出す前に関連するツールを選択します。
関数呼び出しのデバッグ
問題が発生した場合は、以下を確認してください:
- ツールの説明は明確で曖昧さがないか?
- パラメータ名と型は正しいか?
- モデルは適切なツールを選択するのに十分なコンテキストを持っているか?
- ツール結果を正しく処理しているか(例:JSONシリアライゼーション)?
ログを使用して、完全なメッセージ履歴とツール呼び出しをキャプチャします。多くの場合、問題は期待される引数と実際の引数の不一致です。
FAQ
関数呼び出しとツール利用の違いは何ですか?
これらは同じ概念を指します。OpenAIは「関数呼び出し」と呼び、Anthropicは「ツール利用」と呼びます。どちらもLLMが外部関数の実行を要求できるようにします。
オープンソースモデルで関数呼び出しを使用できますか?
はい、Llama 3.1のようないくつかのオープンソースモデルは関数呼び出しをサポートしており、LangChainのようなフレームワークが抽象化を提供しています。ただし、サポートは異なり、微調整や特定のプロンプト形式が必要になる場合があります。
LLMが危険な関数を呼び出すのを防ぐにはどうすればよいですか?
危険な関数を直接公開しないでください。許可リストを使用し、入力を検証し、権限チェックを実装します。機密性の高い操作では、実行前に人間の確認を要求します。
独自のAIエージェントを構築する準備はできましたか?まずはシンプルなツールを定義し、エージェントループをテストしてみてください。その他の開発者ツールについては、ツール呼び出しのペイロードをデバッグするためのJSON Formatterをご覧ください。