🌞

OpenAIのFunctionCallingをTypeScriptなしでNode.jsで使ってみる

2023/06/24に公開

環境

  • node.js v18.16.0
  • OpenAIのモデル gpt-3.5-turbo-0613

さっそくコード

const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

functions = {
  get_current_weather : ({location, offsetDay, unit}) => {
    // console.log(args);
    // const location = args.location;
    // const offsetDay = args.offsetDay;
    // const unit = args.unit;

    // .. 実際に天気APIなど使ったり

    weather_info = {
        "location": location,
        "temperature": "-10",
        "unit": unit,
        "offsetDay": offsetDay,
        "forecast": ["晴れ"],
    }
    return JSON.stringify(weather_info);
  }
}
async function main() {
  const prompt = {role: "user", content: "昨日の浪江の天気を教えて"};
  const response1 = await openai.createChatCompletion({
    model: "gpt-3.5-turbo-0613",
    messages: [prompt],
    functions: [
      {
        name: "get_current_weather",
        description: "与えられた場所の天気の情報を返す",
        parameters: {
          type: "object",
          properties: {
            location: {
              type: "string",
              description: "天気を知りたい場所の県や市の名前 例)愛知県名古屋市"
            },
            offsetDay: {
              type: "number",
              description: "天気を知りたい今日の日付からの差分の日付。例えば、昨日の天気を知りたい場合は-1"
            },
            unit: {
              type: "string",
              enum: ["celsius", "fahrenheit"]
            }
          },
          required: ["location", "offsetDay"]
        }
      }
    ]
  });
  const message = response1.data.choices[0].message;
  // console.log(message);

  // 関数を実行すると判断
  const functionCall = message?.function_call;
  if(functionCall) {
    const args = JSON.parse(functionCall.arguments || "{}");
    const funcResponse = functions[functionCall.name](args);

    const response2 = await openai.createChatCompletion(
      {
        model: 'gpt-3.5-turbo-0613',
        messages: [prompt, message, {
          role: 'function',
          content: funcResponse,
          name: functionCall.name
        }]
      }
    );
    const message2 = response2.data.choices[0].message;
    console.log(message2);
  }
  
}
main();

参考サイト

工夫した点

まず実装上の仕様として、

  • 実行したい関数の名前の文字列で来る
    • 関数名の文字列からその関数を実行する
    • この点はjs的に簡単にできそう!
  • 引数はjson形式の文字列で来る
    • オブジェクトを引数にわたすしかない
    • 自分的にこの点が今回学んだところ
functions[functionCall.name](args);

  get_current_weather : (args) => {
    console.log(args);
    const location = args.location;
    const offsetDay = args.offsetDay;
    const unit = args.unit;

引数がオブジェクトなら、オブジェクトで受け取ってconstに展開していくのが、あんましスマートじゃないと感じてちょっと調査したところ

functions[functionCall.name](args);

  get_current_weather : ({location, offsetDay, unit}) => {

引数をこんな感じで書くことで、展開する手間がはぶけた!

ただ、functions内にわたすparametersの中身と同じになるはずなので、ここらへんを共通化しつつ、うまく引数受取るのもできたらいいなと思ってます

ちなみに...

参考サイトからoffsetDayを付け加えてみた。
今週の天気教えてってやるとoffsetDayは0
今日は土曜なので、-6,-5,-4...って7回functionsが実行される感じだとおもろいなっておもた

細かい試行錯誤はこちらに

https://www.youtube.com/live/DBq8Wbs5BYc?feature=share

Discussion