✏️

OpenAIのFunction callingをつかって自然言語で関数を呼び出す

2023/06/15に公開

OpenAI APIの今回のアップデートでFunction callingがやってきました。

https://openai.com/blog/function-calling-and-other-api-updates

Function callingとは何であるか?

自然言語から関数呼び出しのデータをつくるものです。

たとえば以下のように自然言語から関数呼び出しのデータをつくることができます。

6月1日の8時にアニメを見る予定を追加
createTodo({ title: "アニメを見る", year: 2023, month: 6, date: 1, hour: 8, minute: 0 })

これによってSiriのようにユーザーからのお願いに答える(適切なシステムを呼び出し)サービスを、なんでも・だれでも作ることができるようになります。

Function callingとは何でないか?

  • ChatGPTの中でAPIの関数を呼び出す
    • ChatGPTの中でAPIの関数の呼び出しが行えるわけではありません

実装例

上のユースケースを実際に実装してみましょう。

基本の流れは公式ドキュメントの「Function calling example」が参考になります。
https://openai.com/blog/function-calling-and-other-api-updates

Completions API

import axios from "axios";

export const call = async ({
  apiKey,
  messages,
  functions,
}: {
  apiKey: string | null | undefined;
  messages: { role: string; content: string }[];
  functions: any[]; // TODO:
}) => {
  if (apiKey == null) {
    throw new Error("apiKey is required");
  }

  const data = await axios.post(
    "https://api.openai.com/v1/chat/completions",
    {
      model: "gpt-3.5-turbo-0613",
      messages,
      functions,
      temperature: 0,
    },
    {
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
    }
  );

  return data.data.choices[0]; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
};

Completions API 引数

6月1日の12時にアニメを見る予定を追加
{
  name: "createTodo",
  description: "Create a ToDo with schedule from a given text",
  parameters: {
    type: "object",
    properties: {
      year: {
        type: "number",
        description: "Schedule year, e.g. 2023",
      },
      month: {
        type: "number",
        description: "Schedule month, e.g. 6",
      },
      date: {
        type: "number",
        description: "Schedule date, e.g. 1",
      },
      hour: {
        type: "number",
        description: "Schedule hour, e.g. 8",
      },
      minute: {
        type: "number",
        description: "Schedule minute, e.g. 0",
      },
      title: {
        type: "string",
        description: "Todo title, e.g. watch the anime",
      },
    },
    required: ["title", "year", "month", "date", "hour", "minute"],
  },
},
const result = await call({
  apiKey: process.env.OPENAI_API_KEY,
  messages: [{ role: "user", content: `${data.message}` }],
  functions: [
    {
      name: "createTodo",
      description: "Create a ToDo with schedule from a given text",
      parameters: {
        type: "object",
        properties: {
          year: {
            type: "number",
            description: "Schedule year, e.g. 2023",
          },
          month: {
            type: "number",
            description: "Schedule month, e.g. 6",
          },
          date: {
            type: "number",
            description: "Schedule date, e.g. 1",
          },
          hour: {
            type: "number",
            description: "Schedule hour, e.g. 8",
          },
          minute: {
            type: "number",
            description: "Schedule minute, e.g. 0",
          },
          title: {
            type: "string",
            description: "Todo title, e.g. watch the anime",
          },
        },
        required: ["title", "year", "month", "date", "hour", "minute"],
      },
    },
  ],
});

呼び出し

{
  index: 0,
  message: {
    role: 'assistant',
    content: null,
    function_call: {
      name: 'createTodo',
      arguments: '{\n' +
        '  "year": 2023,\n' +
        '  "month": 6,\n' +
        '  "date": 1,\n' +
        '  "hour": 8,\n' +
        '  "minute": 0,\n' +
        '  "title": "アニメを見る"\n' +
        '}'
    }
  },
  finish_reason: 'function_call'
}
const args = JSON.parse(result.message.function_call.arguments);

const todo = await createTodo({ data: args });

さいごに

Function calling激熱ですね……!

Discussion