AIは「博識」だが、現実のニュースには疎い?
エンジニアの皆さんも、きっとこんな経験があるはずです。ChatGPTに今朝のビットコインの価格を聞いたり、Claudeにサーバーの死活監視を頼んだりしたときのこと。返ってくるのは、データが古いことへの丁寧な謝罪か、最悪の場合、AIがもっともらしく「捏造」した(ハルシネーション)全くデタラメな数字です。
実のところ、LLM(大規模言語モデル)はガラスケースの中に閉じ込められた天才の脳のようなものです。詩を書いたり高速でコードを書いたりすることはできますが、現実世界に触れるための「手足」がありません。AIは今日のハノイが晴れか雨かを知りませんし、売上レポートを取得するために自らデータベースにアクセスすることもできないのです。
多くのオートメーションプロジェクトを通じて、私はこれが最大の障壁であると感じてきました。ただチャットのやり取りをするだけでは、AIは単なる高級なおもちゃに過ぎず、真に頼れるパートナーにはなり得ません。
なぜAIにはこのような制限があるのか?
その根源は学習方法にあります。GPT-4やClaude 3.5 Sonnetのようなモデルは膨大なデータから学びますが、それはあくまで静的なデータです。トレーニングが終わった瞬間、彼らの知識は凍結され、AIは過去のことしか知らない「本の虫」になってしまいます。
一般的な解決策はRAG(プロンプトへのデータの流し込み)です。しかし、この方法ではトークン消費が跳ね上がり、AIは依然として自らアクションを実行することはできません。AIが自らAPIを叩いたり、DBのレコードを削除したり、メールを送信したりできるようにするには、周囲のツールを理解し制御するための仕組みが必要です。そこで輝くのがFunction Calling(またはTool Use)です。
解決策:AIをツールの操作者に変える
現在、OpenAIとAnthropicはどちらも、AIに対して関数(function)を定義して教える機能を提供しています。注意が必要なのは、AIが直接コードを実行するわけではないという点です。AIは実行すべき関数名と引数を含む JSONファイルを返し、実際に命令を実行するのは私たちのサーバー側になります。
1. OpenAI APIでの実装
OpenAIの場合、リクエストの中でtoolsリストを定義する必要があります。以下は、わずか1〜2秒の遅延でリアルタイムの天気を検索できるように統合した例です:
import openai
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "特定の都市の現在の天気を取得する",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "例: ハノイ"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["location"]
}
}
}
]
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "今日のハノイは雨が降っていますか?"}],
tools=tools,
tool_choice="auto"
)
テキストで回答する代わりに、GPTは関数 get_current_weather(location="ハノイ") の呼び出しを要求します。あなたは実際の天気APIからデータを取得してAIに差し戻すだけで、AIがユーザーへの最終的な回答をまとめてくれます。
2. Claude API (Anthropic)での実装
Claude側では、この概念は Tool Use と呼ばれます。構文は多少異なりますが、ロジックは同じです。Claude 3.5 Sonnetは引数の推論能力が非常に高く、データの取り違えが少ないため、現在非常に高く評価されています。
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
tools=[
{
"name": "query_database",
"description": "内部システムから注文情報を照会する",
"input_schema": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "注文ID(形式: #ITFZ-xxx)"}
},
"required": ["order_id"]
}
}
],
messages=[{"role": "user", "content": "注文番号 #ITFZ-123 のステータスを確認して"}]
)
Claude側では、この概念は Tool Use と呼ばれます。構文は多少異なりますが、ロジックは同じです。特に Claude API (Anthropic) を使用する場合、Claude 3.5 Sonnetは引数の推論能力が非常に高く、データの取り違えが少ないため、現在非常に高く評価されています。
実践のコツ:AIに関数呼び出しで「誤動作」させないために
Function Callingを使うこと自体は難しくありませんが、プロダクション環境で安定して動作させるのはまた別の話です。私がこれまでの経験から得た、3つの重要な教訓を共有します:
説明(Description)が鍵を握る
"get data" のような、いい加減な説明は絶対に書かないでください。AIはこの説明だけを頼に関数を選択します。*「お客様から配送状況を聞かれた際にこの関数を使用すること。入力はITFZで始まるコードである必要がある」*のように、詳細に記述しましょう。優れた説明文は、関数の誤呼び出し率を5%以下に抑えることができます。
常にツールからのエラーを処理する
もしAPIが404や500エラーを返した場合、そのエラーをそのままAIに投げないでください。*「エラー:注文が見つかりませんでした。お客様にコードを再確認するよう促してください」*のようにフォーマットし直しましょう。そうすることで、AIは無機質なシステムメッセージではなく、より人間味のある丁寧な回答をお客様に提供できるようになります。
セキュリティ最優先 (Security First)
絶対にAIに DROP TABLE のような破壊的なコマンドを勝手に実行させてはいけません。AIはプロンプトインジェクション攻撃を受ける可能性があり、それによって危険な関数を呼び出される恐れがあります。私は常に「AIはデータの**読み取り**のみ可能」という原則を適用しています。**書き込みや削除**といった操作は、管理者がダッシュボードで「承認」ボタンを押して初めて実行される仕組みにすべきです。
トークンコストの制御
定義した各ツールは、すべてのリクエストでトークンを消費します。50個ものツールを一度に詰め込むと、コストがかさむだけでなく、AIが混乱しやすくなります。私のコツは、ツールをグループごとに分類することです。金融に関する質問があった場合のみ、システムが金融用のツールセットをAIのコンテキストに読み込むように制御します。
これらの共有が、皆さんの AIアプリケーション開発 の助けになれば幸いです。Function Callingこそが、単なるチャットボットを真の仮想アシスタントへと進化させる架け橋なのです!

