こんにちは。ファンリピートの鳴海です。
今回はOpenAIの一つの機能であるFunction callingにセットするBubble Backend APIでも叩くことは可能なのか調査してみました。
Function callingとは
ユーザーから入力された文章から事前にセットした関数を実行するか、そのまま生成するか判断してくれるOpenAI APIの機能となります。
Function callingとは

OpenAI APIのレスポンスが外部関数の呼び出しを検知し、教えてくれる仕組みです。
この機能のおかげで、OpenAIと外部のシステムとの連携をミスなく、かつ正確に行うことが可能になります。具体的には、自然言語でリクエストを投げると内部で関数が実行され、正確な計算や処理が行われるという流れです。
中身を理解する

Function callingを使って実装するとなると、やや難しいかもしれません。
処理は大きく3段階に分かれており、それぞれの段階でAIが質問に必要な関数を選び、引数を作成し、最終的に関数の結果も入力に加えて質問に回答します。これにより、Function callingは関数を適切に実行し、適切な結果を提供してくれます。
結局何ができるようになった?
Function callingの導入により、開発者はAIから返された自然言語の文章から必要な要素を抽出する作業が簡略化されました。
それまで正規表現などを駆使して要素の抽出を行う方法から、関数に直接引数として要素を渡す形に変更が可能になりました。これにより、開発の効率化やシステムの信頼性向上が期待されるため、システム開発において大きなメリットがあります。
Bubble Backendとは
Backend Workflowとは

Bubbleのサーバー側で実行されるワークフローのことです。
通常、Bubbleのワークフローはクライアント側で実行されますが、Backend Workflowはサーバー側で実行される点が異なります。機能としてはAPI作成、スケジュール処理、再帰処理(1日後、1週間後…)などがあげられます。
メリット
主なメリットとして、日時を指定した処理が可能であり、一括処理によって動作が早く、外部サービスとAPIエンドポイントとして連携できます。
例えば、定期的なメール送信やデータベースの変更に対するワークフローの組み立てなど、様々な用途で利用できます。
バックエンドワークフローの呼び出し方
非同期処理と同期処理の2種類が存在します。
非同期処理は、長い時間がかかる処理と同時に他の処理を実行でき、Bubbleでは通常のワークフローをスケジュールすることで実装可能です。
一方、同期処理は、処理が順番に実行され、必要なデータが同期的に返される方式です。これにより、連続したアクションで応答を使用できます。
これらについて以下の記事でも詳しく説明していますので、よければご覧ください。



結果
Bubble APIでもFunction callingの呼び出しは可能!
ユーザー一覧を教えてくださいと尋ねてみます。
USERTEXT=ユーザー一覧を教えてください。 node index.js

ユーザー情報が取得できていることがわかります。
次に全く関係がないたこ焼きについて聞いてみます。
USERTEXT=たこ焼きとはなんですか? node index.js

この通り別々で判定していることがわかります。
API作成方法
APIはBubble Backendの方で作成していきます。
尚、BubbleでAPIを作成する場合はPersonalプラン以上となりまして、無料プランでは作成できない点はご注意ください。
Backend及びAPIを有効化
Settingタブ>APIタブを開き、有効化します。

データ設計
データ設計は以下の通りです。

ユーザー情報

関数作成
Backendページを開き、New API…から新しく作成します。

以下の通りで設定します。
- 関数名はget_users
- APIは公開
- 認証なし(APIキーによる認証を無効化)
- プライバシールールを無視

次にユーザーのリストを返却すればいいので、Dataからretun data…を選択します。

Do a search for usersで、返却するようにします。

これでAPIを呼び出せるようになりました。
呼び出し
nodeJSを使って、今回呼び出すようにしました。コードは以下の通りです。
“コード”
const OpenAI = require("openai");
const openai = new OpenAI({
apiKey: "OpenAIのAPIキー",
});
const prompt = {
role: "user",
content: process.env.USERTEXT, //ターミナルから実行時に命令を入力して受ける
};
const getUsers = async () => {
const url = `ワークフローAPIのURL/get_users`;
try {
const response = await fetch(url);
const data = await response.json();
console.log(data.response.users);
return data;
} catch (error) {
console.error(
"There was a problem with the fetch operation:",
error.message
);
}
};
const functions = {
getUsers,
};
const main = async () => {
const gptOptions = {
model: "gpt-4-0613",
messages: [prompt],
function_call: "auto",
functions: [
{
name: "getUsers",
description: "ユーザー一覧を取得",
parameters: {
type: "object",
properties: {
name: {
type: "string",
description: "ユーザーの名前",
},
age: {
type: "number",
description: "ユーザーの年齢",
},
name: {
type: "string",
description: "ユーザーのメールアドレス",
},
},
},
},
],
};
const completion = await openai.chat.completions.create(gptOptions);
const message = completion.choices[0].message;
console.log(completion.choices[0]);
let responseMessage = "";
if (completion.choices[0].finish_reason === "function_call") {
const functionCall = message?.function_call;
const functionRes = await functions[functionCall.name]();
responseMessage = JSON.stringify(functionRes.response.users, null, 2);
} else {
responseMessage = message?.content;
}
console.log(responseMessage);
};
main();
※getUsersのurlにはBubble workflow urlを入れるようにしてください。
※apiKeyにはOpenAIのキーを入れるようにしてください。
コードの処理内容
上から説明していきます。
OpenAIのライブラリの読み込み
function calling、チャット生成のためにOpenAIのライブラリがインポートされ、apiKeyにセットされた認証情報で他の関数で読み込みを可能にしています。
プロンプトの設定
プロンプトはユーザーからの入力を受け取ります。入力文自体はターミナルから実行するときにテキストに入力し、セットされるようになっています。
getUsers関数とmain関数
getUsers関数はBubbleで作成したAPI URLからユーザーの情報を非同期にフェッチします。取得した情報を格納して、返却します。
OpenAIのAPIにクエリを送信し、受け取った結果に基づいてさまざまな操作(関数呼び出しやメッセージ生成など)ができます。特に、gptOptionsオブジェクトがOpenAIのAPIに送信されるパラメータを定義し、APIからの応答を処理して適切なアクションを実行します
まとめ
本日はFunction calling, bubble APIでも使用できるのか調査してみました。所感としてはかなり便利な機能だなと思いました。もし今後openAIを活用したプロダクトが参入することになった場合、Bubbleで実装→function callingで自由に呼び出しという形で実現できるので、今後が楽しみだなと思いました。