openAIのGPTのAPIを利用する事で、
SPIRALに格納されているデータを組み込んだ自動回答が出来るチャットボットを構築する事が出来ます。
このチャットボットを構築すると以下のようなことが可能となります。
サポートデスクのチャット対応の自動化
社内用ナレッジ共有チャットボットの構築(新人教育に対するコスト低下等が見込めます)
通常のチャットボットですと、多岐に渡る会話を処理する事や自社のサービスや製品に対する内容を解答する事が難しいですが
GPTを利用する事でチャットボットとしての質を上げ、更にSPIRALとのAPI連携をする事で、
自社のサービス等の会社固有の情報を回答させられるようになります。
概要
GPTのAPIのfunction callingの機能を使います。
function callingとは自作の関数を呼び出す為に、
関数名や引数を含んだJSONオブジェクトをGPTに生成させる機能の事です。
ユーザがGPTに問い合わせた内容をGPTが解釈し、その内容に沿った内容を自動で呼び出せる為、
問い合わせ内容に応じたSPIRALのAPIを実行する事が可能となります。
今回はSPIRALのDB検索APIをGPTに呼び出せる様にする事で自社サービスや製品の情報を回答出来るようにする事を目指します。
※今回はGoogle Apps Script(以下GAS)上で作成する前提で進めさせていただきます。
今回はDBを検索してその結果を回答するサンプルとなりますが、
本記事のサンプルをカスタマイズすることで、
更に機能が拡充されたチャットボットを構築する事が可能となります。
チャットの内容次第で
「○○というDBにデータを登録して」といった指示や、
「○○にメールを送信して」といった指示に対して、
データ登録のAPIやメール配信のAPIを関数化する事でチャットベースでSPIRALを自由自在に活用する事が可能となります。
例えば「○○というDBにデータを登録して」といった具体的な指示ではなく、
お客様からの自社製品に関する利用金額に関するお問い合わせに限ったチャットのみ、
セールス担当用DBにデータを格納し、営業担当のスタッフにメール配信を行って通知を行う様にSPIRALの設定をしておく事で、
カスタマーサポートとセールス両方の機能を兼ね備えたチャットボットを構築する事が可能となります。
また自作関数の内容は自由である為、他のサービスのAPIと組み合わせると
更により充実した情報提供(当日の天気や近隣店舗の情報を返すAPI連携)
お問い合わせ→zoomの会議URLの自動発行
teamsやslackへの通知
等々で社内業務効率化を行う事も可能となります。チャット部分ソース
function doPost(e) {
var payload = JSON.parse(e.parameter.messages);
// Start chat session with a system message
payload.push({
'role': 'system',
'content': 'あなたは○○という製品のサポートデスクのユーザーサポート担当です。自社製品の質問が投げかけられるコトを想定して質問に回答してください。操作説明や製品の価格や特徴に関する質問が来た場合は○○の操作方法や製品に関する質問であると認識してください。技術的な質問に関しては原則回答を禁止し、function callingの機能を使ってください。答えらない場合「申し訳ございません、データ不足によりお答え出来ません。サポートデスクメールアドレスに直接お問い合わせください」とだけ回答してください。他の文言は一切禁止します。'
});
var url = 'https://api.openai.com/v1/chat/completions';
var options = {
method: 'POST',
headers: {
'Authorization': 'Bearer API-KEY',
'Content-Type': 'application/json'
},
payload: JSON.stringify({
'model': 'gpt-4-0613',
'messages': payload,
'function_call': 'auto',
'functions': [
{
name: "getSpiralSearch",
description: "○○に関する質問が行われた場合、○○独自の操作方法や仕様等をデータベースから検索する為の検索語句を確定し検索を行う。検索語句はOR検索に対応する為単語をスペース区切りにする",
parameters: {
type: "object",
properties: {
search: {
type: "string",
description: "検索語句",
},
},
required: ["search"],
},
},
],
})
};
var response = UrlFetchApp.fetch(url, options);
var responseJson = JSON.parse(response.getContentText());
const message = responseJson.choices[0].message;
const functionCall = message.function_call;
if (functionCall) {
var args = JSON.parse(functionCall.arguments || "{}");
// Assume that 'functions' is a predefined object that maps function names to their implementations
var functionRes = functions[functionCall.name](args.search);
// Prepare the messages for the second request
payload.push(message);
payload.push({
'role': "function",
'content': functionRes,
'name': functionCall.name,
});
// Make the second request
options.payload = JSON.stringify({
'model': 'gpt-4-0613',
'messages': payload,
});
response = UrlFetchApp.fetch(url, options);
responseJson = JSON.parse(response.getContentText());
return ContentService.createTextOutput(JSON.stringify(responseJson)).setMimeType(ContentService.MimeType.JSON);
}else{
return ContentService.createTextOutput(JSON.stringify(responseJson)).setMimeType(ContentService.MimeType.JSON);
}
}
関数部分ソース
// Define the functions object
var functions = {
getSpiralSearch: getSpiralSearch
};
function getSpiralSearch(search) {
//spiralV2のレコード一覧を取得するAPI
const base_url = "https://api.spiral-platform.com/v1/";
let url = base_url + "apps/{app}/dbs/{db}/records";
const apikey = "*********************************";
const headers = new Headers();
headers.append("Authorization", "Bearer " + apikey);
headers.append("Content-Type", "application/json");
headers.append("X-Spiral-App-Authority", "manage");
var searchWords = search.split(" ");
let query = "?fields=fieldTitle&limit=100&where=";
let conditions = [];
searchWords.forEach((word) => {
let encodedWord = encodeURIComponent(word);
conditions.push(`@fieldTitle LIKE '%${encodedWord}%'`);
});
query += conditions.join(" OR ");
url = url + query;
fetch(url, {
method: 'GET',
headers: headers,
})
.then(response => response.json())
.then(data => {
if (response.value.response.items.length === 0) {
return "データ不足なためお答え出来ません。";
}
let noteStr = data.value.data.items.map(item => item.note).join("");
noteStr = noteStr.substring(0, 6000);
return noteStr;
})
.catch((error) => {
console.error('Error:', error);
});
}
解説
※APIキー等の情報のお取り扱いにはご注意ください。
functionsに自作のSPIRALのAPIを設置した関数を設置した関数名を引き渡して
GPTにリクエストを行うとGPTが関数を使うべきと判断した場合に
function_callに使うべき関数名の値と引数がレスポンスとして返ってきます。
今回の場合はgetSpiralSearchとなります。
1回目のリクエストを行った後にレスポンスとして返ってきた関数名であるgetSpiralSearchを実行し
SPIRALのDBを検索します。
その値を再度GPTへリクエストして文章として生成させ最終的にユーザへチャットとして返答することでチャットボットとしての機能を実現しています。
descriptionの内容やsystemプロンプトの内容は適宜調整を行ってください。
また、関数ソースの内容は一例であり検索の条件や検索語句の調整は関数部分のソースを修正する事で調整が可能です。
この関数を複数増やす事が可能で、最大64種の関数をGPTに定義出来ます。
今回はDBの検索だけの紹介となりますが、SPIRALのAPIには様々な機能があるのでそれぞれのAPIに沿った機能の実装が可能です。