皆さま、こんにちは。北の国の住人 やまぴです。
Qiitaに記事を核にはものすごーーーーーく久しぶりなので非常に緊張してます。
様々なデジタルツールを学んでから半年が過ぎまして・・自分でもあれこれと小さなツールを仕事用に、または完全に自分の趣味で作ったりしてます。
今回は「どうしてもこれを作りたい!」と思い、作成したアプリ(かな?)について書いてみたいと思います。
困ったら〇〇さんに聞け、でいいの?
現在、私はとある小売業にて商品部に関係するシステム担当(自社独自システム)をしております。
その中の一つに「リベート契約」に関するシステムがあります。
ここで「リベートって何?」と思われる方もいらっしゃると思うので、簡単に説明します。
📖 リベート:一定の売上を達成したときに取引先様から後で受け取るお金のこと
*契約で条件が決まっていて正しく管理することが大切
*売上・仕入に影響するため経理処理が必要
先ほど書いたシステムで、商品部のバイヤーやアシスタントさんがリベート契約を登録・契約書作成等の作業を行います。
このリベート契約のシステム含めリベート契約に関する質問を商品部から度々受けます。
はい、聞かれている人、ちょっと困った顔してますね?→私です💦
この状況の私の困りごとは2つあります。
①回答まで時間がかかること:過去の質問・回答履歴の蓄積不足・リベート契約関連の知識の分散
②業務の個人依存:担当者(私)しかわからない・対応できない(業務の属人化が起きている)
回答にも時間かかることがある 何より「私がいない時(いなくなった時)どーすんだい??」です。
この2点を解決するためにQ&Aチャットボット(Ver1)を作成しました。(なぜVer1なのかは後ほど)
Q&Aチャットボット(+管理者アプリ)
こちらが制作したQ&Aチャットボットアプリの動作画面です。
リベートに関する質問(文章ではなくキーワード)を入力すると、そのキーワードに対応する質問の回答が表示されるようにしています。
そして、質問を入力しても回答が出なかった場合(こちらはまた説明します)、その質問の回答を入力して、次に対応できるようにする管理者アプリも作りました。
その動作画面はこちらです。
*なお、動画はYoutubeにアップしてからリンクを埋め込んでます。
再生が終わってから、なんかいろいろ出てきますが、私が普段見てる動画の傾向を反映してますのでお気になさらず・・・💦
このチャットボットアプリ・管理者アプリは実際どのように繋がっているかというと
①アプリ作成に使用したツール
1.Power Apps チャットボットアプリ・管理者アプリの作成
2.SharePoint 質問回答リスト・未回答リストの作成
3.ChatGPT アプリ作成に当たってアイデア出し+お助けマン
4.PowerAutomate 未回答リストへ回答が保存されたらTeamsを起動
5.Teams 管理者へ未回答リストに回答が保存されたことを通知
ChatGPT君に助けてもらいつつ、作成していったわけですが、なぜPowerApps・SharePointを使おうと思ったのか?
→会社で使えるものにしたいから(できるだけ長く)です。というのも、会社はMicrosoftのソフト(今はMicrosoft365使用)を使っているためです.
本音を言えば、Difyを使って作りたかったのですが、会社では使用できない。
そして、Microsoft系でもCopilot Studioを使うとチャットボットが楽に(でもないが、たぶん)作成できる!AIも使える!のですが、現在社内でも限られた人しか使えません(しかも有料).
そこでChatGPT君に次のように相談してみました。
今、会社で使用しているシステムのマニュアルを使用したQ&Aのチャットボットを作ろうと考えているのですが、いくつか条件があるのです。
①できるだけMicrosoft系のツールを使用する
②Microsoft Copilot Studioを使いたいが、自分にはそのアクセス権がない。会社から許可を得られない場合、どのようなツールを使うと近いものができるだろうか(無料ならなお良い)
相談したところ、おすすめされたのがこの3つです。
1.Teams + Power Automate + SharePoint
→ Microsoft系で固められる、手軽で無料枠内でもOK(会社でMicrosoft365使用していて、使えるのは確認済み👌)
2.Power Appsで簡易Bot作成
→ Power Virtual Agents風のBotを作れる(ライセンス要確認)(こちらも会社PCで使えるのは確認済み👌)
3.Difyで試作し、将来Teamsに組み込む
→ 今すぐ試せて、後から応用可能
3については先ほど書いたように、現在は使うことができません。なので1か2で作成を考えることにしました。
更に、質問→回答だけではなく、質問→回答できない(表示されない)場合、あとで対応できるように記録に残し、その回答を作成・質問対応できる機能もつけたいなと考えました。
そして、決定した全体構成がこちら。
ということで、いざ!チャットボット(と管理者アプリ)作成開始!・・・
が。これがなかなかの手ごわさでした(ローコードって言いますが、文系人間の私にはめっちゃ大変だったぞおおおお!Difyで作りたかったぞお!!→しかし、自ら選んだのだから文句言えません)
②SharePointにFAQリスト/未回答リストを作成
まず、質問の回答のベースとなるFAQリストをSharePointに作成します。
(いわゆるチャットボットでいうところのナレッジの代替です)
リストの構成はこのようにしています。
| 内部列名 | 種類 | 説明 |
|---|---|---|
| Title | 単一行テキスト | 質問文(標準である列をそのまま利用) |
| Answer | 複数行テキスト | 回答本文 |
| Keywords | 単一行テキスト | 検索用キーワード(同義語などもカンマ区切りで) |
| Active | はい/いいえ | 回答の有効/無効管理 |
| Hits | 数値 | 参照された回数 |
| LastUsed | 日付と時刻 | 最後に使われた日時 |
| SectionUrl | ハイパーリンク | マニュアルのリンク(任意) |
キーワード(Keyword)は、同じ質問でも、人によって質問に使う言葉が違うこともあるため、関連する用語を複数入力しました。
こちらのFAQリストに載っていない質問が来た場合、一時登録しておく未回答リストも作成。
未回答リスト(Unansweredリスト)の構成はこのようになっています。
| 内部列名 | 種類 | 説明 |
|---|---|---|
| Title | 単一行テキスト | 質問文 |
| AskedBy | 単一行テキスト | 質問者(User().FullNameで自動取得) |
| AskedAt | 日付と時刻 | 質問された日時 |
| Status | 選択肢(Open / Answered) | 未処理 or 処理済み |
| LinkedFAQ | ハイパーリンク | FAQに昇格した場合のリンク(任意) |
③FAQチャットボットアプリを作る(PowerApps キャンバスアプリ)
①まず、Microsoft365アプリから、PowerAppsを選択します。
1.Power Apps ポータルにアクセス
2.「アプリ」→「キャンバスアプリ」(タブレットサイズ)を選択。
②SharePointと接続
1.「データ」アイコンをクリック
2.「データの追加」→「SharePoint」を選択
3.接続先のSharePointサイトURLを入力(リンクをコピペ)
4.作成済みのリスト FAQとUnanswered(未回答)を選択して接続
左側にFAQ・Unansweredが見えていればOKです。
(ここまでは、比較的スムーズに進んだのです。この先が大変でした・・・)
③UIを作る
1.ギャラリーを配置
・「挿入」→「ギャラリー」→「垂直ギャラリー」
・Itemsに以下を配置:「FAQ」→FAQリストの内容が一覧で表示される
2.入力欄と送信ボタンを配置(いずれも質問のために使用)
・TextInput(質問入力欄 名前:txtinput)
・Buttun(送信ボタン 名前:btnSend テキスト「送信」)
3.送信ボタン btnSendの「OnSelect」へ数式を貼り付ける
この数式は、質問を入力→回答を探して表示させるための数式になります。
その数式(コード)を貼り付けるのですが、(毎度おなじみ)エラー、エラー、またエラー。
何度もChatGPT君に聞いて、最終的に貼り付けたコードがこちらです。
txtSend Onselect数式コード
Set(varQ, Trim(txtInput.Text));
If(
Len(varQ) < 2,
Notify("2文字以上で検索してください。", NotificationType.Warning);
Reset(txtInput),
// 先頭一致でサーバー側プレフィルター(委任OK)
Clear(colPre);
Collect(colPre, Filter(FAQ, Active = true && StartsWith(Title, Left(varQ, 3))));
Collect(colPre, Filter(FAQ, Active = true && StartsWith(Keyword, Left(varQ, 3))));
// ローカルで “含む” 検索(厳密化)
ClearCollect(colHit, Filter(colPre, varQ in Title || varQ in Keyword));
// ヒット/未ヒット分岐
If(
CountRows(colHit) > 0,
// ── ヒット:回答セット&Hitsを+1 ──
Set(varAns, First(colHit));
Patch(
FAQ,
varAns,
{ Hits: Coalesce(varAns.Hits, 0) + 1 }
);
Notify("FAQから回答が見つかりました。", NotificationType.Success),
// ── 未ヒット:Unanswered に重複チェックして登録 ──
With(
{
openCount:
CountRows(
Filter(
Unanswered,
Title = varQ && Status.Value = "Open")
)
)
},
If(
openCount = 0,
Collect(
Unanswered,
{
Title: varQ,
Aksedby: User().FullName,
AskedAt: Now(),
Status: { Value: "Open" } // ← Status が選択肢列のとき
// テキスト列なら: Status: "Open"
}
);
Notify("見つかりませんでした → 未回答に追加しました。", NotificationType.Warning),
Notify("見つかりませんでしたが、未回答(Open)に既に登録済みです。", NotificationType.Information)
)
);
Set(varAns, Blank())
);
Reset(txtInput)
);
4. 回答ラベル(lbAnswer)の配置
・検索結果が見つかったときに、FAQの「Answer」列の内容を表示するラベル
①PowerAppsのキャンバスで、上メニュー→挿入>ラベルをクリック→「lbAnswer」と名前をつける
②ラベルに表示する式を設定・貼り付ける
lbAnswerの数式コード
// lblAnswer.Text
If(
CountRows(colHit) > 0,
First(colHit).Answer,
"該当する回答が見つかりませんでした。"
)
5.リンクボタンの配置
FAQリストにリンク(SectionURL)がある回答を表示した場合、そのリンク先に飛べるようにボタンを配置します。
①画面にボタンを1つ追加
・名前:btnOpen
・テキスト:”関連リンクを開く”
②ボタンを「ヒット時だけ表示」にする
→ボタンのVisibleにコードを設定
CountRows(colHit) > 0 && !IsBlank(First(colHit).SectionURL)
③クリックしたらリンクを開く
ボタンのOnSelectに下記を設定
Launch( First(colHit).SectionURL )
④URLがない場合には、無効化します(グレーアウト)
DiplayModeに下記を設定
If(
IsBlank(First(colHit).SectionURL),
DisplayMode.Disabled,
DisplayMode.Edit
)
Fill(背景色)にはこちらを設定(今はリンクありはネイビーに変えてます)
If(
IsBlank(First(colHit).SectionURL),
RGBA(200,200,200,1), // グレー(リンクなし)
RGBA(255,0,255,1) // マゼンダ(リンクあり)
)
Color(文字色)はこちらを設定してます。
If(
IsBlank(First(colHit).SectionURL),
RGBA(120,120,120,1), // 濃いグレー文字(リンクなし)
Color.White // 白文字(リンクあり)
)
いろいろありましたが、なんとか無事動作確認できてまずは一段落。「FAQチャットボット」と名前を付けて保存。
続いて、未回答リストの対応するための管理者アプリの作成に取り掛かります。
④管理者アプリの作成
このアプリの作成の流れは次のとおりです。
①新しいキャンバスアプリを作成
・PowerAppsを開き、「新しいアプリ」→「キャンバスアプリ」→「空のアプリ」を選択(今回もタブレットサイズ)
・「管理者アプリ」と名前を付けておく
②データソースの接続
・メニューから「データ」を選択
・SharePointリストから「Unanswered」「FAQ」を追加
→未回答リストから拾った質問を表示・FAQに昇格登録できるようになる
③画面構成(シンプルに2画面)
1.未回答一覧画面
・Gallary(垂直ギャラリー)を設置して、Unansweredのデータだけを表示
・Itemsプロパティに以下を設定(Openステータスのものだけ表示→つまりFAQリストにないもの)
With(
{ q: Trim(txtAdminSearch.Text) },
SortByColumns(
Filter(
Unanswered,
Status.Value = "Open" &&
(
IsBlank(q) ||
StartsWith(Title, q) ||
StartsWith(Askedby, q) // ← 1行テキスト列 Askedby
)
),
"AskedAt", // ← 内部名に合わせて修正(例: "AskedAt0")
SortOrder.Descending // ← ここを修正
)
)
そして出来上がったのがこちらです。(あまりにも殺風景な画面だったので、未回答の質問(キーワード)の頭に検索してるペンギンさんを加えてみました🐧🐧)
2.詳細画面を追加(質問昇格画面)
①メニューの「+挿入」ボタンのすぐ下にある「画面」メニューをクリック
②「新しい画面」を選択
③「空の画面」または「空白」を選択→「Screen2」という名前の新しい画面が追加
④画面の名前を変更(scrAdminDetail)
3.未回答一覧画面から昇格画面への移動設定
①未回答一覧画面を選択
②OnSelectに次のコードを入力
Set(varSelected, ThisItem);
Navigate(scrAdminDetail);
4.昇格画面にフォームを置く
①挿入>フォーム>編集フォームを選択 昇格画面(Screen2)に配置
②データソースに「Unanswered」を選択
③Itemプロパティに次を入力
varSelected
おお!なんか見えてきたぞ!(ゴール近いか?→いえいえ、まだまだでした)
ここで、ChatGPT君に確認したところ、「いいぞ!いいぞ!」と盛り上がり、説明を続けてくれたのは良かったのですが、昇格画面の名前がscrAdminDetailからscrPromoteに変わっていました。
「やったな、こいつは💦」
皆さん、AIにはこれがあるので気をつけましょう。もちろん、私は「名前変えたほういいですよね?」と確認、scrPromoteに変更しました(危ない危ない・・・)
で、改めて未回答一覧画面のOnSelectには画面名変更後のコードを入力
Set(varUnans, ThisItem);
Navigate(scrPromote, ScreenTransition.Cover)
5.昇格画面(scrPromote)の基本UIの設定
①未回答の中身を見せるフォームを1つ配置する:名前 frmUnans
②データソース=Unanswered
③Item=varQ
④フィールドは「Title / Askedby / AskedAt / Status」を追加(読み取り専用)
6.未回答の質問の入力欄を配置
①「挿入」→「テキスト」→「テキスト入力」を追加(名前 txtAnswer)
モード:複数行テキストを選択
*入力欄の大きさは見やすいように高さ(Heght)を調整する。
7.回答の保存ボタン(昇格)を画面に配置
保存ボタン:btnPromote
btnPromoteのOnSelectには次のコードを入力
// 1) 入力チェック
If(
IsBlank(varQ) || IsBlank(txtAnswer.Text),
Notify("質問が選択されていないか、回答が未入力です。", NotificationType.Warning);
Reset(txtAnswer);
Exit()
);
// 2) FAQ に新規登録 → 返ってきたレコードを newFAQ に保持
With(
{
newFAQ:
Patch(
FAQ,
Defaults(FAQ),
{
Title: varQ.Title, // 質問タイトルをFAQタイトルに
Answer: txtAnswer.Text, // 回答本文
SectionURL: Blank(), // 任意:不要ならBlank()でOK
Active: true, // 任意:Yes/No列
Hits: 0 // 任意:数値列
}
)
},
// 3) 未回答(選択アイテム)を Close にし、FAQ を参照でひも付け
Patch(
Unanswered,
varQ,
{
Status: { Value: "Close" }, // ← Choice列。「Close/ Open」の表記に合わせて
LinkedFAQ: { Id: newFAQ.ID, Value: newFAQ.Title } // ← Lookup列(単一)
}
);
// 4) 完了処理
Notify("FAQに登録し、未回答をCloseにしました。", NotificationType.Success);
Reset(txtAnswer);
ResetForm(frmUnans);
Set(varQ, Blank());
Navigate(scrUnans, ScreenTransition.Fade)
)
DisplayModeにはこちらを入力します。
If(
IsBlank(varQ) || IsBlank(Trim(txtAnswer.Text)),
DisplayMode.Disabled,
DisplayMode.Edit
)
とまあ、実は他にもいーろいろとエラーが発生しまくったのですが、そのたびChatGPT君にぶつけて、答えてもらって、また違って・・・を何度も繰り返し、最終的に問題なく動作できるようになりました。
⑤未回答リストの更新の通知機能の追加
PowerAppsのほうでアプリが完成しましたが、「未回答リスト新しく保存された質問の確認の機能はやはりほしい」と思い、PowerAutomate(クラウド版)+Teamsを使って、通知機能を作成しました。
手順は以下のとおりです。
*事前準備
・Teamsで「未回答通知」チャネルを作成しておく
1.新規フロー作成
①PowerAutomateを開く→「マイフロー」→「新しいフロー」→「自動化されたクラウドフロー」
②フロー名:未回答質問_Teams通知
③トリガー:SharePoint-アイテムが作成されたときを選択→「作成」
2.トリガー(SharePoint)の設定
・サイトのアドレス:FAQ/Unanswered のあるサイトを選択
・リスト名:Unanswered
3.Teamsに投稿(チャネル)
①「+ 新しいステップ」→ Microsoft Teams →「チャットまたはチャネルにメッセージを投稿」
②各項目を設定:
・投稿先:チャネルに投稿する
・チーム:通知先のチーム(例:FAQ運用)
・チャネル:作っておいた通知チャネル(例:📩未回答通知)
・メッセージ:下のテンプレをコピペ → 各URL部分だけ自社環境に合わせて
💬 **新しい質問が投稿されました(未回答)**
- **タイトル**: @{triggerOutputs()?['body/Title']}
- **登録者**: @{triggerOutputs()?['body/Askedby']}
- **登録日時**: @{triggerOutputs()?['body/AskedAt']}
🔗 SharePoint リストを開く: https://<SharePointサイトURL>/Lists/Unanswered/AllItems.aspx
無事、通知が来ました!
アプリへのフィードバックとこれからについて
このチャットボットを社内の方(リベート業務関連部署の担当者(商品部・総務部・財務経理部))数名に試用してもらい、フィードバックをお願いしたのですが、返してくれたのは2名だけでした(´;ω;`)
・・そうなんですよね。質問の入力の仕方も、返ってくる回答もまだまだ使いやすいものではないです。
「AIを使ったチャットボットだったら・・・FAQリストに一生懸命質問と回答を作成しておく必要ってないんだろうなあ・・」と感じました。
何より、作り手(私)がユーザー(実際リベート業務(契約書作成など)をされてる人)のニーズをまだわかりきっていないんだなあと強く反省しています。
とりあえず、今社内で使えるデジタルツールを使って、どんどんバージョンアップして、フィードバックをもらい理想の形に近づけていけたらと思います。
今のところでやろうと思う改善点は上の2点と考えてます。
まだまだ勉強しないといけませんが、職場での実践経験も積んで、チャットボット(Ver2)を完成したいです!
おまけ
実は、このアプリですが、今年のプロトアウトMVPイベントで賞をいただきました!
この時点ではまだ完成してはいなかったのですが・・
自分なりに頑張ったことを認めていただけたのかな?と嬉しく感じましたね。
これからも頑張るですぞ!
お読みいただき、ありがとうございました。

















