AI APIをWebアプリに組み込むと、AIに文章を作らせるだけでは足りない場面が出てきます。注文状況を調べる、在庫を確認する、社内FAQを検索する、予約候補を取得する、顧客情報を確認する、といった処理では、AIが外部データやアプリ側の関数とつながる必要があります。
このときに使う考え方がFunction Callingです。Function Callingを使うと、AIに「どの関数を、どんな引数で呼ぶべきか」を選ばせ、実際の実行はアプリ側で行えます。
重要なのは、AIが勝手にサーバー処理を実行するわけではない点です。AIは関数呼び出しの提案を返します。アプリ側がその提案を検証し、許可された関数だけを実行し、結果をもう一度AIへ返します。この流れを理解すると、AIチャットを外部APIや業務システムにつなげやすくなります。
AIの返答をJSONとして固定するだけなら、先に Structured Outputsの使い方|JSON SchemaでAIの出力形式を固定する方法 を確認するとわかりやすいです。Function Callingはその先にある「AIにアプリ側の処理を選ばせる」ための記事です。JSON出力の基本は AIにJSONを出力させる方法 に分けています。
この記事の内容は、2026年7月9日時点のOpenAI API公式ドキュメントをもとにしています。Function Calling、Responses API、tool定義、モデル名、SDKの書き方は変わることがあるため、実装前には必ず公式ドキュメントも確認してください。
結論:Function CallingはAIに関数名と引数を選ばせ、実行はアプリ側で行う
Function Callingの基本は、次の5ステップです。
- アプリ側で、AIが呼べる関数一覧を定義する
- ユーザーの依頼と関数一覧をAIに渡す
- AIが呼び出す関数名と引数を返す
- アプリ側で引数を検証し、関数を実行する
- 関数の実行結果をAIへ返し、最終回答を作らせる
OpenAI公式ドキュメントでも、Function Callingはこのような複数ステップの会話として説明されています。モデルにtoolsを渡し、モデルがtool callを返し、アプリケーション側でコードを実行し、その結果をモデルに戻す流れです。
つまり、Function Callingは「AIに何でも実行させる機能」ではありません。正確には「AIに、許可された関数の中から使うものを選ばせる機能」です。
この違いはとても大事です。
| 誤解 | 正しい理解 |
|---|---|
| AIが直接DBやAPIを操作する | AIは関数名と引数を返し、実行はアプリ側が行う |
| AIが自由に関数を作れる | アプリ側が渡したtoolsの範囲内で選ばせる |
| 引数はそのまま信用できる | 実行前に型、権限、値の妥当性を検証する |
| 関数実行後は完了 | 結果をAIに戻し、ユーザー向けの最終回答を作る |
この設計にすると、AIチャットから外部API、DB、検索処理、メール下書き、管理画面操作などにつなげられます。ただし、強い権限を持つ処理ほど、人間確認や権限制御を厚くする必要があります。
Function Callingで作るもの
この記事では、ユーザーが注文状況を質問したときに、AIが get_order_status という関数を選び、注文番号を引数として渡す例を作ります。
ユーザーの入力は次のようなものです。
注文番号 A-1024 の配送状況を教えてください。
AIには、次の関数を使えると教えます。
get_order_status({
order_id: "A-1024"
})
アプリ側では、この関数を実行して注文状況を取得します。ここではサンプルなので固定データを返しますが、実務ではDB検索、外部API、社内システムへの問い合わせなどに置き換えます。
最終的には、AIがユーザーに次のような自然文で返します。
注文番号 A-1024 は現在発送済みです。到着予定日は7月12日です。
このように、Function Callingでは「AIが外部情報を直接知っている」ように見えますが、実際にはアプリ側の関数を通して情報を取得しています。AIは、関数を選ぶ判断と、結果をユーザー向けに説明する役割を担当します。
前提環境を確認する
この記事のコード例は、考え方を示すための最小例です。実際のSDKバージョン、モデル名、レスポンス形式は、利用時点の公式ドキュメントに合わせてください。
前提は次のとおりです。
- サーバー側のJavaScriptからOpenAI APIを呼び出す
- APIキーは環境変数などで管理する
- ブラウザから直接OpenAI APIを呼ばない
- AIが呼べる関数はアプリ側で明示的に定義する
- 関数の実行前に引数と権限を検証する
AI APIをブラウザから直接呼ぶと、APIキー漏洩や不正利用のリスクがあります。クライアントとサーバーの役割は、クライアントサーバーシステムとは も参考になります。
また、Function Callingは外部処理とつながるため、安全設計が重要です。AI利用時の情報漏洩や誤回答対策は、生成AIの安全な使い方|情報漏洩・著作権・間違いを防ぐチェックリスト も確認してください。
toolsで関数を定義する
Function Callingでは、AIに渡す関数一覧を tools として定義します。
今回の get_order_status は、注文番号を受け取り、配送状況を返す関数です。
const tools = [
{
type: "function",
name: "get_order_status",
description:
"注文番号をもとに、注文の現在ステータスと到着予定日を取得します。",
parameters: {
type: "object",
properties: {
order_id: {
type: "string",
description: "注文番号。例: A-1024",
},
},
required: ["order_id"],
additionalProperties: false,
},
strict: true,
},
];
関数定義では、主に次の項目を指定します。
| 項目 | 意味 |
|---|---|
type |
関数ツールの場合は function |
name |
AIが選ぶ関数名 |
description |
いつ使う関数かをAIに伝える説明 |
parameters |
引数のJSON Schema |
strict |
引数をスキーマに沿わせるための設定 |
OpenAI公式ドキュメントでは、関数の引数はJSON Schemaで定義し、strict: true を使う例が示されています。これはStructured Outputsと同じく、引数の形を安定させるための考え方です。
ただし、引数の形がスキーマに合っていることと、その引数で本当に処理してよいことは別です。たとえば注文番号の形式が正しくても、そのユーザーがその注文を見る権限を持っているとは限りません。権限チェックは必ずアプリ側で行います。
アプリ側の関数を用意する
次に、実際に実行する関数を用意します。
function getOrderStatus({ order_id }) {
const orders = {
"A-1024": {
status: "shipped",
estimated_delivery: "2026-07-12",
},
"B-2048": {
status: "processing",
estimated_delivery: null,
},
};
const order = orders[order_id];
if (!order) {
return {
found: false,
message: "注文が見つかりませんでした。",
};
}
return {
found: true,
order_id,
status: order.status,
estimated_delivery: order.estimated_delivery,
};
}
ここでは固定データを使っていますが、実務では次のような処理に置き換えます。
- DBから注文情報を検索する
- ECシステムのAPIを呼ぶ
- 配送会社APIから追跡情報を取得する
- 社内FAQやチケット管理システムを検索する
- 権限チェック後に管理画面用データを返す
この関数は、AIが直接実行するものではありません。AIが返した function_call を受けて、アプリ側が明示的に呼び出します。
最小コードを書く
Responses APIでFunction Callingを使う最小例は、次のような流れになります。
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const tools = [
{
type: "function",
name: "get_order_status",
description:
"注文番号をもとに、注文の現在ステータスと到着予定日を取得します。",
parameters: {
type: "object",
properties: {
order_id: {
type: "string",
description: "注文番号。例: A-1024",
},
},
required: ["order_id"],
additionalProperties: false,
},
strict: true,
},
];
function getOrderStatus({ order_id }) {
const orders = {
"A-1024": {
status: "shipped",
estimated_delivery: "2026-07-12",
},
};
const order = orders[order_id];
if (!order) {
return { found: false };
}
return {
found: true,
order_id,
status: order.status,
estimated_delivery: order.estimated_delivery,
};
}
let input = [
{
role: "user",
content: "注文番号 A-1024 の配送状況を教えてください。",
},
];
let response = await openai.responses.create({
model: "gpt-5.5",
instructions:
"注文状況を確認する必要がある場合は、利用可能な関数を使ってください。",
input,
tools,
});
input.push(...response.output);
for (const item of response.output) {
if (item.type !== "function_call") continue;
if (item.name !== "get_order_status") {
throw new Error(`Unknown function: ${item.name}`);
}
const args = JSON.parse(item.arguments);
const result = getOrderStatus(args);
input.push({
type: "function_call_output",
call_id: item.call_id,
output: JSON.stringify(result),
});
}
response = await openai.responses.create({
model: "gpt-5.5",
instructions:
"関数の実行結果をもとに、ユーザーに短くわかりやすく回答してください。",
input,
tools,
});
console.log(response.output_text);
このコードでは、1回目のAPI呼び出しでAIに関数を選ばせています。AIが function_call を返したら、アプリ側で関数を実行し、その結果を function_call_output として input に追加します。
その後、2回目のAPI呼び出しで、関数の結果をもとにユーザー向けの最終回答を生成します。
モデル名は、公式ドキュメント上の例に合わせて gpt-5.5 としています。ただし、利用できるモデルや推奨モデルは変わるため、実装時点の公式ドキュメントとアカウントの利用可能モデルを確認してください。
処理の流れを分解する
Function Callingの実装で混乱しやすいのは、1回のAPI呼び出しで全部終わるわけではない点です。
もう少し細かく分けると、次のようになります。
- アプリ側がtoolsを定義する
- ユーザー入力とtoolsをモデルに渡す
- モデルが
function_callを返す - アプリ側が
item.nameを確認する - アプリ側が
item.argumentsをJSONとしてパースする - アプリ側が引数と権限を検証する
- アプリ側が許可された関数だけを実行する
- 実行結果を
function_call_outputとしてモデルに返す - モデルが最終回答を作る
このうち、特に重要なのは4から7です。AIが返した関数名や引数を、そのまま実行してはいけません。
たとえば、次のようなチェックを入れます。
function validateOrderStatusArgs(args) {
if (!args || typeof args !== "object") {
throw new Error("Invalid arguments");
}
if (typeof args.order_id !== "string") {
throw new Error("order_id must be a string");
}
if (!/^[A-Z]-[0-9]{4}$/.test(args.order_id)) {
throw new Error("Invalid order_id format");
}
return args;
}
Function Callingの引数はJSON Schemaである程度制御できますが、アプリ側の検証は別に必要です。注文番号の形式、ログインユーザーの権限、利用回数、危険な操作かどうかは、アプリ側が責任を持って確認します。
複数の関数を渡すときの考え方
Function Callingでは、複数の関数をtoolsとして渡せます。たとえば、注文状況確認、配送先変更、キャンセル可否確認を渡すこともできます。
ただし、最初から多くの関数を渡すと、AIがどれを使うべきか迷いやすくなります。実務では、まず小さな関数セットから始めるのがおすすめです。
関数を増やすときは、次のように役割を分けます。
| 関数 | 役割 | 注意点 |
|---|---|---|
get_order_status |
注文状況を読む | 読み取り専用なので比較的扱いやすい |
check_cancel_available |
キャンセル可否を確認する | 実行ではなく判定だけにする |
create_support_ticket |
問い合わせチケットを作る | 作成前に確認画面を挟む |
cancel_order |
注文をキャンセルする | AI判断だけで実行しない |
読み取り専用の関数と、状態を変更する関数は分けて考えます。最初は読み取り専用から始め、メール送信、決済、削除、キャンセルなどの副作用がある処理は、人間確認や確認UIを挟むのが安全です。
tool_choiceで関数の使い方を制御する
デフォルトでは、モデルは関数を使うかどうか、どの関数を使うかを判断します。OpenAI公式ドキュメントでは、tool_choice を使って挙動を制御できることが説明されています。
代表的な使い分けは次のとおりです。
| 設定 | 意味 | 使いどころ |
|---|---|---|
auto |
モデルに使うかどうかを任せる | 通常のチャット |
required |
1つ以上の関数呼び出しを求める | 必ず外部データを確認したい処理 |
none |
関数を使わせない | 通常回答だけにしたいターン |
| 特定関数を指定 | 呼ぶ関数を固定する | UI上で操作が確定している処理 |
また、モデルが複数の関数呼び出しを1回のターンで返すこともあります。並列実行を避けたい場合は、parallel_tool_calls を false にする設計も検討します。
最初の実装では、関数を1つだけ渡し、必要なら parallel_tool_calls: false にして、流れを単純に保つとデバッグしやすいです。
Structured Outputsとの違い
Function CallingとStructured Outputsは、どちらもJSON Schemaに関係するため混同しやすいです。
違いは目的です。
| 機能 | 目的 | 例 |
|---|---|---|
| Structured Outputs | AIの返答そのものを決まったJSONにする | 問い合わせ分類、レビュー判定、構成案生成 |
| Function Calling | AIに呼ぶ関数と引数を選ばせる | 注文検索、在庫確認、予約候補取得 |
たとえば、「問い合わせ文をカテゴリ分類してJSONで返す」ならStructured Outputsが向いています。一方、「問い合わせ内容に応じて注文検索APIを呼ぶ」ならFunction Callingが向いています。
整理すると、次のように考えます。
- 返答の形を固定したいならStructured Outputs
- 外部データを取得したいならFunction Calling
- 関数の引数を安定させたいならFunction Calling内のstrict schema
- 複数の手順を継続的に進めたいならAIエージェントやワークフロー設計
AIアプリ全体の中でどこに位置づけるかは、AIとは?エンジニアがWeb開発で押さえるべき基本 や AIエージェントとは?できること・仕組み・使い方をわかりやすく解説 ともつながります。
よくあるエラーと原因
Function Callingでつまずきやすいポイントを整理します。
| 症状 | 原因 | 見直す場所 |
|---|---|---|
| 関数が呼ばれない | descriptionが曖昧、ユーザー依頼が関数の用途と合っていない | toolsのdescription、instructions、tool_choice |
| 違う関数が選ばれる | 関数の役割が近すぎる | 関数分割、名前、description |
| argumentsのJSON.parseで失敗する | 想定外の出力や未対応レスポンスを処理していない | strict、レスポンス分岐、エラーハンドリング |
| 関数結果を返しても最終回答が変 | function_call_outputの形式やcall_idが間違っている | inputへの追加順、call_id、outputの文字列化 |
| 同時に複数の関数が呼ばれる | 並列tool callが有効になっている | parallel_tool_calls |
| 危険な処理まで実行されそうになる | 副作用のある関数を直接実行している | 確認画面、権限、allowlist、実行前チェック |
特に多いのは、AIが返した引数をそのまま実行してしまうケースです。Function Callingの引数は、ユーザー入力とAI判断が混ざったものとして扱います。信頼済みデータではありません。
安全にするなら、次のように関数名のallowlistを作ります。
const functionMap = {
get_order_status: getOrderStatus,
};
function executeFunctionCall(item) {
const fn = functionMap[item.name];
if (!fn) {
throw new Error(`Function is not allowed: ${item.name}`);
}
const args = JSON.parse(item.arguments);
const validatedArgs = validateOrderStatusArgs(args);
return fn(validatedArgs);
}
このように、AIが返した文字列をそのままコマンド実行やSQLに流さない設計が大切です。
セキュリティ・料金・運用の注意点
Function Callingは便利ですが、外部処理とつながるため、通常の文章生成より注意点が増えます。
まず、関数には権限レベルをつけて考えます。
| レベル | 例 | 扱い |
|---|---|---|
| 読み取り | 注文状況確認、FAQ検索、在庫確認 | 権限チェック後に実行しやすい |
| 作成 | チケット作成、下書き保存 | 確認画面やログを挟む |
| 更新 | 住所変更、ステータス変更 | ユーザー確認と権限チェックを必須にする |
| 削除・送信・決済 | 注文キャンセル、メール送信、支払い処理 | AI判断だけで実行しない |
次に、料金と遅延です。Function Callingでは、1回目のモデル呼び出し、関数実行、2回目のモデル呼び出しが発生します。外部APIも呼ぶ場合、AI APIと外部APIの両方の料金やレート制限を考える必要があります。
運用では、最低限次をログに残すと原因調査がしやすくなります。
- ユーザー入力
- モデルが選んだ関数名
- 検証後の引数
- 関数実行結果の要約
- 失敗理由
- 最終回答
- モデル名とプロンプトバージョン
ただし、個人情報や機密情報をそのままログに残すと別のリスクになります。何を保存し、何をマスクするかを先に決めておきます。
実務で使うときの設計パターン
実務では、Function Callingをいきなり大きな自動化に使うより、小さな読み取り処理から始めるのが安全です。
おすすめの順番は次のとおりです。
- FAQ検索や注文状況確認のような読み取り専用関数から始める
- 関数名と引数をログで確認する
- AIの選択が安定しているかテストする
- 作成系の処理は確認画面を挟む
- 更新・削除・送信系は人間確認を必須にする
Function Callingを使うと、AIチャットの中でアプリ機能を呼び出せます。しかし、アプリ側の設計としては、通常のAPI設計と同じように、入力検証、権限、ログ、エラー処理、レート制限が必要です。
また、Function Callingが増えてくると、関数をどう整理するかが課題になります。関数が数個ならコード内のtools定義で十分ですが、数十個になると、ツール検索、Agent SDK、MCP、ワークフロー管理などを検討する段階に入ります。
この記事ではそこまで深掘りせず、まずOpenAI APIでFunction Callingを最小構成で理解することをゴールにしています。
まとめ
Function Callingは、AIに呼び出す関数名と引数を選ばせ、実行はアプリ側で行うための仕組みです。AIが外部APIやDBを直接操作するのではなく、アプリ側が許可した関数だけを、検証したうえで実行します。
基本の流れは次のとおりです。
- toolsで関数名、説明、引数スキーマを定義する
- ユーザー入力とtoolsをモデルに渡す
- モデルが
function_callを返す - アプリ側で関数名と引数を検証する
- 許可された関数だけを実行する
- 結果を
function_call_outputとしてモデルへ戻す - モデルがユーザー向けの最終回答を作る
Structured Outputsが「返答の形を固定する機能」なら、Function Callingは「外部処理につなげる機能」です。どちらもAIアプリ開発では重要ですが、役割は違います。
次に進むなら、Tool Calling、MCP、AIエージェント設計へ広げると、AIが外部ツールや複数ステップの処理を扱う仕組みがより具体的に見えてきます。