SmartStageで、タイムラインでのやりとりをもとに生成AIによってFAQを自動生成する方法をご案内します。
目次
完成イメージ
概要
SmartStageのデータを利用してFAQを生成します。
これにより、これまで手間がかかっていたFAQ作成の工数を大幅に削減できます。
また、FAQデータベースに登録されたFAQは、ホーム画面からAI検索機能(セマンティック検索)で検索可能です。
AIについて
生成AIを活用したFAQ自動生成機能は、問い合わせ内容と対応履歴(タイムライン)からFAQ文章を自動生成する機能です。
生成AIによるFAQ生成例:
Q. Node.jsを自身の環境にインストールしようとしたら、管理者権限を求められました。対策をご教示いただけますでしょうか?
A. 管理者権限が必要な場合、情報システム部門にPCを持参し、管理者権限を一時的に付与してもらう必要があります。インストールが完了したら、再度情報システム部門で管理者権限を削除してもらう手順となります。管理者権限の付与・削除の際には、OSのサインインし直しが必要です。
事前準備
SmartStageのAPIトークンの発行
SmartStage APIを呼び出すには、認証用のAPIトークンの発行が必要です。
APIトークンの発行については、以下の記事を参照してください。
生成AIのエンドポイントとAPIキー
生成AIを起動させるには、認証用のエンドポイントとAPIキーの発行が必要です。
生成AIのエンドポイントとAPIキーの発行については、弊社にお問い合わせください。(※お客様自身の生成AI環境をご利用の場合はお客様自身でご確認いただきますようお願いいたします。)
画面項目の追加
FAQデータベースに登録するデータを管理するため、以下の画面項目を追加します。
※画面項目名は運用に合わせて変更可能です。
生成AIを適用するデータストアに、生成AIの結果を管理するための画面項目を追加します。
設定箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「項目設定」>「項目リスト(+ボタン)」の順にクリックしてください。
項目名に画面項目の名称、項目の型に適切な画面項目型を設定し、「保存」をクリックしてください。
上記にならい、以下の項目を追加してください。
- 「FAQタイトル」(テキスト型)
- 「FAQ質問」(複数行テキスト型)
- 「FAQ回答」(複数行テキスト型)
- 「FAQ補足情報」(複数行テキスト型)
ワークスペースIDの取得
サンプルスクリプトのワークスペースIDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
- SmartStageの管理者ページであることを確認します。
- 右上にある歯車アイコン > ワークスペース設定の順にクリックします。
ここで確認できるワークスペースIDがお客様のワークスペースIDです。
データストアIDの取得
サンプルスクリプトのデータストアIDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「基本設定」の順にクリックしてください。
ここで確認できるデータストアIDがお客様のデータストアIDです。
アクションIDの取得
サンプルスクリプトのアクションIDをお客様自身の値に置き換えるため、SmartStage의 管理メニューからIDを取得します。
確認箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「データ操作設定」の順にクリックしてください。
ここで確認できる「内容を更新する」のアクションIDがお客様のアクションIDです。
画面項目IDの取得
サンプルスクリプトの登録対象画面項目IDをお客様自身の値に置き換えるため、SmartStageの管理メニューからIDを取得します。
確認箇所:
SmartStageの管理者ページであることを確認し、「プロセス設定」>対象プロセス>「項目設定」>「項目リスト」の対象画面項目名の順にクリックしてください。
ここで確認できる項目IDが登録対象画面項目IDです。
上記にならい、以下の項目を同様に確認してください。
- 「FAQタイトル」
- 「FAQ質問」
- 「FAQ回答」
- 「FAQ補足情報」
サンプルスクリプトの修正と配置
サンプルスクリプトを、お好みのテキストエディタ(例:VSCode)にペーストしてください。
以下の各項目を、先ほど取得したID等に書き換えます。
-
生成AIのエンドポイントの設定:定数
CHATGPT_API_ENDPOINT -
ワークスペースIDの設定:定数
SS_WORKSPACE_ID -
データストアIDの設定:定数
SS_DATASTORE_ID_CHATGPT_P -
アクションIDの設定:定数
SS_CHATGPT_P_UPDATE -
画面項目IDの設定:定数
SS_FIELD_ID_XXXXXX
動作確認
サンプルスクリプトの配置
アクションスクリプト設定から「FAQを生成し登録判断をする」を選択し、ポストスクリプトに修正したサンプルスクリプトを配置します。
テスト実行
サンプルスクリプトを配置したら、「テスト実行」をクリックしてください。設定したポストスクリプトのJavaScriptが実行されます。
注意事項
- アクションスクリプトの実行によりFAQが生成されることを確認しやすくするため、事前にテストデータとなるタイムラインにデータを蓄積しておくことを推奨します。
- テストデータ(テスト実行するタスク)は、「アクション実行時に渡されるデータ」に表示されているタスクが対象となります。
サンプルスクリプト
タイムラインの内容を生成AIのプロンプトに投入し、FAQを生成するサンプルスクリプトです。
// --- 定数定義 ---
// SmartStage API のエンドポイント
const SMARTSTAGE_EXTERNAL_API_BASE_URL = "https://api.smart-stage.io"; // SmartStage外部公開APIベースURL
// SmartStage 環境固有のID
const SMARTSTAGE_WORKSPACE_ID = "<ワークスペースID>";
const SMARTSTAGE_CHATGPT_PROCESS_UPDATE_ACTION_ID = "<「内容を更新する」アクションID>";
// SmartStage データストアID
const SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID = "<データストアID>"; //プロセスID
// SmartStage 項目ID
const SMARTSTAGE_FIELD_ID_TITLE = "<画面項目ID>";
const SMARTSTAGE_FIELD_ID_CHATGPT_QUESTION = "<画面項目ID>"; //ChatGPT 生成結果「質問」
const SMARTSTAGE_FIELD_ID_CHATGPT_ANSWER = "<画面項目ID>"; //ChatGPT 生成結果「回答」
const SMARTSTAGE_FIELD_ID_CHATGPT_EXPLANATION = "<画面項目ID>"; //ChatGPT 生成結果「補足情報」
const SMARTSTAGE_FIELD_ID_CHATGPT_PROCESS = "<画面項目ID>";//ChatGPT 生成結果「生成AIからのコメント」
const SMARTSTAGE_FIELD_ID_INQUIRY_CONTENT = "<画面項目ID>"; // 問い合わせ内容を管理する画面項目ID
const SMARTSTAGE_FIELD_ID_RESPONSE_CONTENT = "<画面項目ID>"; // 回答内容を管理する画面項目ID
const SMARTSTAGE_API_REQUEST_OPTIONS = {
headers: {
Authorization: 'Bearer {SS_API_TOKEN}',
'Content-Type': 'application/json',
},
timeout: 50000,
};
const CHATGPT_API_REQUEST_OPTIONS = {
headers: {
'api-key': '{CHATGPT_API_KEY}',
'Content-Type': 'application/json',
},
timeout: 50000,
};
// `item` オブジェクトは環境変数として提供されるため、ここでは定義しません。
// 実行環境が `item` オブジェクトをグローバルスコープまたは適切な形で提供することを前提とします。
/**
* ChatGPTに送信するリクエストの生成とFAQ生成
* @param {object} currentItemData - SmartStageの項目データ
* @returns {Promise<string>} ChatGPTから生成されたFAQのJSON文字列
*/
const systemPrompt = `ユーザからの質問に対する回答集のQAを作るために、step by stepで考えてください。
ステップ1:まず、応答履歴を要約して整理してください。
ステップ2:前のステップの結果を使用して、QA形式で質問内容、回答、必要に応じて追加説明の文章を作ってください。
ステップ3:作成した文章に矛盾点がある場合は、ステップ1戻ることも大切です。
ステップ4:作成した文章を、与えられた条件とJSON形式に沿って、JSON形式のみを出力してください。
#条件
・与えられた情報以外は使わない。
・マークダウンは使わない。
・個人情報は含めない。
・固有番号は含めない。
・IPアドレスは一部を”xxx”に置き換える。
・あいさつ文は含めない。
#JSON形式
{
"faq": [
{
"question": "質問内容",
"answer": "回答内容",
"explanation": "必要に応じた追加説明",
"process":"質問からどのような課題があり、それをどのように理解して文章を作成したかの理由"
}
]
}`;
const generateFaqFromChatGpt = async (currentItemData) => {
// 質問と回答のデータを取得
logger.log("currentItemData.fields[SMARTSTAGE_FIELD_ID_INQUIRY_CONTENT]" + currentItemData.fields[SMARTSTAGE_FIELD_ID_INQUIRY_CONTENT]);
const rawInquiryContent = String(currentItemData.fields[SMARTSTAGE_FIELD_ID_INQUIRY_CONTENT]); // 問い合わせ内容
const formattedInquiryContent = rawInquiryContent.replace(/\r?\n/g, "\\n"); // ChatGPTへのプロンプトで改行をエスケープ
const rawResponseContent = String(currentItemData.fields[SMARTSTAGE_FIELD_ID_RESPONSE_CONTENT]); // 回答内容
const formattedResponseContent = rawResponseContent.replace(/\r?\n/g, "\\n"); // ChatGPTへのプロンプトで改行をエスケープ
// Timelineデータを取得
// item オブジェクトは環境変数として提供されることを前提とします。
logger.log("SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID" + SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID);
const smartStageTimelineData = await fetchTimelineRecords(item.itemId, SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID);
const formattedTimelineString = JSON.stringify(smartStageTimelineData).replace(/\r?\n/g, "\\n"); // ChatGPTへのプロンプトで改行をエスケープ
logger.log("formattedTimelineString" + formattedTimelineString);
const chatGptPromptContent = `
#質問:
${formattedInquiryContent}
#回答:
${formattedResponseContent}
#応答履歴:
${formattedTimelineString}
`;
const chatGptRequestPayload = {
"messages": [{ role: "system", content: systemPrompt },
{ role: "user", content: chatGptPromptContent }],
"max_completion_tokens": 4000,
"temperature": 1,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0,
"model": "o4-mini"
};
try {
const chatGptApiResponse = await axios({
url: '{CHATGPT_API_ENDPOINT}',
method: 'post',
data: chatGptRequestPayload,
...CHATGPT_API_REQUEST_OPTIONS,
}).catch((e) => {
logger.error(`ChatGPTでエラー:エラー情報: ${JSON.stringify(e)}`);
throw false;
});
logger.info(chatGptApiResponse);
const generatedFaqMessage = chatGptApiResponse.data.choices[0].message.content;
const finalFaqOutput = generatedFaqMessage;
return finalFaqOutput;
} catch (error) {
logger.error("エラーが発生しました:", error);
throw error; // エラーを再スローして呼び出し元で処理できるようにする
}
};
/**
* SmartStageのタイムラインデータを取得する
* @param {string} targetItemId - タイムラインを取得するアイテムのID
* @param {string} datastoreId - アイテムが属するデータストアのID
* @returns {Promise<object>} タイムラインデータ
*/
const fetchTimelineRecords = async (targetItemId, datastoreId) => {
logger.log("取得データ" + targetItemId +datastoreId)
const timelineResponse = await axios(`${SMARTSTAGE_EXTERNAL_API_BASE_URL}/items/${targetItemId}/timelines?datastoreid=${datastoreId}`, SMARTSTAGE_API_REQUEST_OPTIONS)
.catch(
(error) => {
logger.error(`アイテムタイムライン取得に失敗しました。 エラー情報: ${JSON.stringify(error)}`);
throw error; // エラーを再スロー
}
);
return timelineResponse.data;
};
/**
* レコードを更新する
* @param {string} workspaceId ワークスペースID
* @param {string} targetItemId アイテムID
* @param {string} faqUpdateDataString - 更新するFAQデータを含むJSON文字列
* @returns {Promise<object>} 更新APIのレスポンス
* @throws {Error} 更新処理に失敗した場合
*/
const updateSmartStageTicket = async (workspaceId, targetItemId, faqUpdateDataString) => {
let parsedFaqUpdateData;
try {
parsedFaqUpdateData = JSON.parse(faqUpdateDataString);
} catch (error) {
logger.error(`JSONパースエラー: ${error.message}`);
throw new Error("更新データが不正なJSON形式です。");
}
const faqEntry = parsedFaqUpdateData.faq && parsedFaqUpdateData.faq[0];
if (!faqEntry) {
logger.error("FAQデータが期待される形式ではありません。");
throw new Error("更新データにFAQ情報が含まれていません。");
}
const requestPayload = {
comment: `ChatGPTにより更新しました。`,
fields: {
// item.title は環境変数として提供されることを前提とします。
[SMARTSTAGE_FIELD_ID_TITLE]: item.title,
[SMARTSTAGE_FIELD_ID_CHATGPT_QUESTION]: faqEntry.question,
[SMARTSTAGE_FIELD_ID_CHATGPT_ANSWER]: faqEntry.answer,
[SMARTSTAGE_FIELD_ID_CHATGPT_EXPLANATION]: faqEntry.explanation,
[SMARTSTAGE_FIELD_ID_CHATGPT_PROCESS]: faqEntry.process
},
datastoreId: SMARTSTAGE_CHATGPT_PROCESS_DATASTORE_ID,
workspaceId: workspaceId,
};
const updateApiResponse = await axios({
method: 'post',
url: `${SMARTSTAGE_EXTERNAL_API_BASE_URL}/items/${targetItemId}/actions/${SMARTSTAGE_CHATGPT_PROCESS_UPDATE_ACTION_ID}/update?name=false`,
data: requestPayload,
...SMARTSTAGE_API_REQUEST_OPTIONS,
}).catch((error) => {
logger.error(`更新が失敗しました。 エラー情報: ${JSON.stringify(error)}`);
throw error;
});
return updateApiResponse.data;
};
/**
* メイン処理
*/
const main = async () => {
try {
// ChatGPTでFAQを生成する
logger.info("ChatGPTによるFAQ生成を開始します。"); // 開始ログ
const generatedFaqResult = await generateFaqFromChatGpt(item);
logger.info("ChatGPTによるFAQ生成が完了しました。"); // 完了ログ
logger.info(generatedFaqResult);
// 生成されたFAQでチケットを更新する
logger.info("SmartStageチケットの更新を開始します。"); // 開始ログ
const ticketUpdateResult = await updateSmartStageTicket(SMARTSTAGE_WORKSPACE_ID, item.itemId, generatedFaqResult);
logger.info("メイン処理完了: チケットが正常に更新されました。"); // 最終完了ログ
} catch (error) {
logger.error("メイン処理でエラーが発生しました:", error.message);
// 必要に応じて、ここでエラー通知などの追加処理を行う
}
};
// メイン処理の実行
main();FAQへ自動連携する場合は、以下の記事も参照してください。
何かお困りのことはございますか?まずはヘルプセンターを検索してみましょう!
その他ご不明な点があれば、サポートチームにお問い合わせください。
コメント
0件のコメント
サインインしてコメントを残してください。