👻

(多分一番簡単な)OpenAI Function Calling のサンプルと解説

2025/03/05に公開

今日はOpenAIが提供しているFunction Callingという機能を試していきます。一応日本語で入手できる最も簡単なサンプルを目指しています。

Function Calling

ChatGPTはインターネット上で学習用データ収集ボットが収集可能な情報しかわかりません。このため、自社専用の情報(社内システムマニュアルやお客様とのサポート内容)などを踏まえた内容はわかりません。また学習時点以降の情報もわかりません。代表的なところでいえば、現在時刻や天気予報などの機能は備えていません。これを補完するのがFunction Callingです。図にすると以下の関係です。

まずは通常のChatBotのようにChatGPTは質問を受け付けます。その後ChatGPTが質問の内容を解釈し、即答できるようであれば自己の判断で回答を戻します。回答が不明の場合指定された外部関数を呼び出します。外部関数はさらに外部APIを呼び出すなどの処理を行いChatGPTへ回答を戻します。最後にChatGPTは得られた外部関数からのレスポンスを自然な言葉になおしてレスポンスを戻します。

つまり3Stepで動作します。

  1. ChatGPTによる外部関数呼び出しを行うかどうかの判断
  2. 外部関数呼び出し
  3. 外部関数レスポンスの自然言語化とユーザーへのレスポンス生成

ここで重要な点ですが、ChatGPTは外部関数を直接呼び出しません。 Function callingという名前で勘違いしがちですが、ChatGPTを呼び出す皆さんのプログラムにこういう内容で外部関数を呼び出してくれと依頼をする、といった形態をとります。
つまり図にするとこうなります。

このフローを頭に入れておけばFunction callingという名前の先入観にとらわれずサンプルが理解できると思います。
(我ながら絵心のなさに震えます。。。)

さっそくやってみる:サンプルコード

シンプルに時間を確認するサンプルを作成しました。当方TypeScriptがわからないのでJavaScriptです。すいません。

import { OpenAI } from "openai";
import dotenv from "dotenv";

dotenv.config();

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY, // .envファイルにAPIキーを設定
});

// Function 定義
const functions = [
  {
    name: "getCurrentTime",
    description: "現在の時刻を取得します",
    parameters: {
      type: "object",
      properties: {},
    },
  },
];

// Function 呼び出し処理
async function main() {
  const userMessage = "今の時間を教えて";

  const response = await openai.chat.completions.create({
    model: "gpt-4-turbo",
    messages: [{ role: "user", content: userMessage }],
    functions: functions,
    function_call: "auto", // 必要に応じて関数を呼び出す
  });

  const message = response.choices[0].message;
  
  if (message.function_call?.name === "getCurrentTime") {
    const result = getCurrentTime();
    console.log(result);
    
    // AIに関数の結果を渡して応答を得る
    const finalResponse = await openai.chat.completions.create({
      model: "gpt-4-turbo",
      messages: [
        { role: "user", content: userMessage },
        message, // AIの関数呼び出しリクエスト
        { role: "function", name: "getCurrentTime", content: result }, // 関数の実行結果
      ],
    });

    console.log("AIの回答:", finalResponse.choices[0].message.content);
  } else {
    console.log("AIの回答:", message.content);
  }
}

// シンプルな時間取得関数
function getCurrentTime() {
  return new Date().toLocaleString();
}

main();

実行すると以下の出力が戻ります。

2025/3/5 17:09:54
AIの回答: 今の時間は2025年3月5日17時09分です。

Step by Step

  const response = await openai.chat.completions.create({
    model: "gpt-4-turbo",
    messages: [{ role: "user", content: userMessage }],
    functions: functions,
    function_call: "auto", // 必要に応じて関数を呼び出す
  });

ここがポイントです。従来のChatGPTでは自分がわからない回答があったときは、無理やり答えを出すか、わからない、と回答するかの2択でした。この指定により外部関数を呼び出す、という判断が加わるようになりました。

    function_call: "auto", // 必要に応じて関数を呼び出す

特にこの行に注目です。autoというのは呼び出すかどうかをChatGPTに任せています。例えばnoneに設定した場合外部関数は呼び出さず以下の回答になります。

AIの回答: もちろんです。現在の時刻を確認してお伝えしますね。

responseは以下のような値がセットされます。

{
  "id": "chatcmpl-B7eJfkB2w4dmf5MAb2bzdAHf4wPDy",
  "object": "chat.completion",
  "created": 1741162971,
  "model": "gpt-4-turbo-2024-04-09",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "function_call": {
          "name": "getCurrentTime",
          "arguments": "{}"
        },
        "refusal": null
      },
      "logprobs": null,
      "finish_reason": "function_call"
    }
  ],
  "usage": {
    "prompt_tokens": 53,
    "completion_tokens": 11,
    "total_tokens": 64,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "service_tier": "default",
  "system_fingerprint": "fp_bf9cb2c77f"
}

finish_reason: 'function_call'となっている場合関数呼び出しを行います。
そのさい呼び出されるべき関数はfunctions: functions,で定義されている以下です。

        "function_call": {
          "name": "getCurrentTime",
          "arguments": "{}"
        },

関数本体は以下です。

const functions = [
  {
    name: "getCurrentTime",
    description: "現在の時刻を取得します",
    parameters: {
      type: "object",
      properties: {},
    },
  },
];
<snip>
function getCurrentTime() {
  return new Date().toLocaleString();
}

この関数は2025/3/5 17:15:00をレスポンスとして戻します。
最後にその文字列を受け取り以下の部分で回答を自然な言語にしています。

    const finalResponse = await openai.chat.completions.create({
      model: "gpt-4-turbo",
      messages: [
        { role: "user", content: userMessage },
        message, // AIの関数呼び出しリクエスト
        { role: "function", name: "getCurrentTime", content: result }, // 関数の実行結果
      ],
    });

どうでしょうか?まだややこしいですが少しでも皆さんの理解のお役に立てれば幸いです。

Discussion