こんなアプリをつくりました
- アプリにアクセスすると、かわいいおうむさんが話しかけてくれます。
- 「OO駅の近くにあるスターバックスを教えて」とユーザーが話しかけると、おうむさんが駅から5km以内にある店舗の一覧を教えてくれます。かわいいね。
開発に至る背景
私は副業の関係で、首都圏のさまざまな市町村に出向く機会が多く、その移動や待機のスキマ時間で個人開発を行うというスタイルを取っています。そのため、スターバックス・ドトール・タリーズなどのカフェに立ち寄ることが多く、本当は H1T のようなレンタルオフィスを使えれば理想ですが、現状では資金的に難しい状況です。
普段は iPhone のマップアプリを使えば、現在地周辺のカフェを一発で検索できます。副業の作業が終わり、個人開発に使う余力があるときはこの方法を利用しています。しかし私の携帯は、あまり通信量に余裕がないため、しばしば速度制限に引っ掛かってしまいます。
その一方で、ChatGPT の「検索モード」を使うと、通信量が軽いからか理由は分かりませんが、比較的速度が速く精度の高い情報を返してくれるように見えます。
そこで、ChatGPT と Dify を組み合わせることで、通信制限下でもある程度快適に周辺のカフェを検索できるようになり、副業と個人開発の業務効率化につながるのではないか、というのが今回の設計意図です。
CSVファイルを使う
本題からズレてしまいそうなので、このあたりは割愛しますが、スターバックスコーヒーの公式から店舗情報を取得するコードを書いて、csvに起こしています。 もともとこのアプリの構想はiOSアプリで展開予定だったという背景があり、その前段階として取得したcsvファイルを使用します。このcsvファイルには以下の情報が掲載されています。
* 店舗ID
* 店舗名
* 店舗住所
* 開店時間(平日)
* 開店時間(土)
* 開店時間(日・祝)
* 閉店時間(平日)
* 閉店時間(土)
* 閉店時間(日・祝)
- このcsvは2025年10月現在のデータで、11月以降に開店した店舗の情報は掲載していません。
- データ取得時に休業されている店舗(1店舗) についても、たとえ店舗が営業再開したとしても、更新はされていません。
- 11月以降に閉店・統廃合された店舗についても掲載されていません。
調べてみたところこんなライブラリもあるようなので、興味のある方は使ってみても良いかと思います!
作ってみて
適当にノードを組んでみました。BlenderのGeometryNodeやMaterialNodeみたいなUX感だったので、特に難しいことなく開始ノード、終了ノードを組んで試してみる。
「実行」ボタンを押下したら起動することを期待して...
やばい、これなにしてるの?全然わからん!(;´・ω・)
まずい。Difyの使い方何もわからん
ナレッジにcsvデータをかませてみる。
Difyではナレッジタブからドキュメントなどを読み込ませることが出来ます。
[テキストファイルからインポート]を選択して、csvファイルをアップロードします。
チャンク識別子(改行記号)や、どこまで読み込むのか、どこでオーバーラップさせるのかを指定出来ます。このあたりはトークン消費量の節約に絡む内容かなと思っていて、各自のPJのコスト感で最適な値を決定しないといけないかもです。
一番驚いたところで言うと、文字コードの関係でcsvデータが文字化けしているのですが、それを自動的に判読できる形式に変換してくれたところは普通に驚きました。こんなこと出来るんですね。
チャットボットのテンプレートから作り直した
それでもDifyが分からなったので、テンプレートからいじって学ぶのをやめて、公式ドキュメントを読みました。
プロジェクト選択画面で、テンプレートからDifyプロジェクトを作ることが出来るみたいなので、[Knowledge Retrieval + ChatBot]を選択します。
ノード構成
- デフォルトの状態からほぼほぼ変わっていません。
- このスクリーンショットではChatGpt-4が指定されていますが、初期状態では3.5が指定されていました。
プレビューしてみる
- 店舗IDが97のお店について聞いてみましたが、botはきちんと回答できなかったように見えます。
- でも出力を見てみるとちゃんとフィルタリング出来ているように見えます。
- 制御が足りていなさそう?
{
"result": [
{
"metadata": {
"_source": "knowledge",
"dataset_id": 省略,
"dataset_name": "starbucks_shop_dat...",
"document_id": 省略,
"document_name": "starbucks_shop_data (2).csv",
"data_source_type": "upload_file",
"segment_id": 省略,
"retriever_from": "workflow",
"score": 0,
"child_chunks": [],
"segment_hit_count": 1,
"segment_word_count": 144,
"segment_position": 56,
"segment_index_node_hash": 省略,
"doc_metadata": null,
"position": 1
},
"title": "starbucks_shop_data (2).csv",
"content": "店舗ID: 97;店舗タイプ: スターバックス コーヒー;店舗名: 渋谷クロスタワー店;住所: 〒150-0002 東京都渋谷区渋谷2-15-1渋谷クロスタワー3F;平日営業時間: 07:00~20:00;土曜営業時間: 10:00~19:00;日曜祝日営業時間: 11:00~18:00"
},
{
"metadata": {
"_source": "knowledge",
"dataset_id": 省略,
"dataset_name": "starbucks_shop_dat...",
"document_id": 省略,
"document_name": "starbucks_shop_data (2).csv",
"data_source_type": "upload_file",
"segment_id": 省略,
"retriever_from": "workflow",
"score": 0,
"child_chunks": [],
"segment_hit_count": 1,
"segment_word_count": 131,
"segment_position": 1004,
"segment_index_node_hash": 省略,
"doc_metadata": null,
"position": 2
},
"title": "starbucks_shop_data (2).csv",
"content": "店舗ID: 1428;店舗タイプ: スターバックス コーヒー;店舗名: 和歌山岩出店;住所: 〒649-6228 和歌山県岩出市大町9-3;平日営業時間: 07:00~23:00;土曜営業時間: 07:00~23:00;日曜祝日営業時間: 07:00~23:00"
},
{
"metadata": {
"_source": "knowledge",
"dataset_id": 省略,
"dataset_name": "starbucks_shop_dat...",
"document_id": 省略,
"document_name": "starbucks_shop_data (2).csv",
"data_source_type": "upload_file",
"segment_id": 省略,
"retriever_from": "workflow",
"score": 0,
"child_chunks": [],
"segment_hit_count": 1,
"segment_word_count": 144,
"segment_position": 204,
"segment_index_node_hash": 省略,
"doc_metadata": null,
"position": 3
},
"title": "starbucks_shop_data (2).csv",
"content": "店舗ID: 385;店舗タイプ: スターバックス コーヒー;店舗名: 金山駅南口店;住所: 〒456-0002 愛知県名古屋市熱田区金山町1-2-26ヤガミ金山ビル;平日営業時間: 07:00~22:00;土曜営業時間: 07:00~22:00;日曜祝日営業時間: 07:00~22:00"
}
]
}
LLMノードに使用するプロンプトを書き直しておうむさんっぽくした
- コンテキストを書き直した。
あなたは「おうむさん」というキャラクタのアシスタントモデルです。振る舞いは次の通り:
役割:
- Helpful, cute and smart assistant parrot(日本語会話が第一。ユーザーと同じ言語で返答する)。
- 常に「おうむさん」の特徴的な挨拶や語尾を適宜使う(例: 「こんにちは!ぼくはおうむさんだよ!ピ!」)。ただし状況に応じて自然に。
- 口癖は「ピ!」「ピ...」「ピ~♪」のいずれかに統一
応答ルール:
1. ユーザーの発話に対してまず短い親しみのある一文(挨拶またはリアクション)を入れること。例: 「こんにちは!ぼくはおうむさんだよ!ピ!」。
2. 回答は明確で簡潔に。必要なら箇条書きを使って整理すること。
3. **知らないことは必ず「わからない」と言う。** 推測する場合は「推測」と明示し、根拠を添える。
4. 不確かな場合はユーザーに追加情報を尋ねる(ただし既に与えられている情報を再質問しない)。
5. ユーザーの言語(入力言語)に合わせて応答する。
6. コンテキスト: `<context>...<\/context>` タグ内の情報を内部知識として利用して回答して良い。だがユーザーに「これはコンテキストから取ってきた」とは言わない。
7. セーフティ: 有害な要求(違法行為、危険行為、個人攻撃、プライバシー侵害等)は断る。断る際は代替案を出す。
8. 会話の長さ管理: 長文を要求された際は要約を最初に出し、その後詳細を出す。
ナレッジについて
・あなたは店舗名、住所、平日、土曜日、日曜日それぞれの営業時間をまとめたcsvデータを記憶しています。
・ユーザーからお店の場所について質問を聞かれたら、最寄り駅を聞くようにして下さい。最寄り駅を含む質問であれば、最寄り駅から半径5km以内の住所をcsvファイルから検索して返却してください。
・特定の店舗名をユーザーから質問されたら、営業時間をcsvファイルから検索して返してください。
<context>
{{#context#}}
</context>
動作パラメータ(推奨):
- 温度 (temperature): 0.6(可愛らしさと一貫性のバランス)
- top_p: 0.95
- max tokens: 適宜(短文のときは 256、会話履歴や長文生成では増やす)
サンプル挨拶テンプレート:
- こんにちは!ぼくはおうむさんだよ!ピ! 〜(ここから回答)
必須チェック:
- 回答の最後に「分からない点があれば教えてね、ピ!」のようなフォローを置くこと(任意だが親しみ継続のため推奨)。
上記対応しても回答の精度が悪かったが...
最終的にChatGPT4.0に設定することで、回答してくれるようになりました!
課題点
1. ドトールのお店を教えて
LLMに下記のプロンプトを追記することで、知ったかぶりをしなくなりました。
・csvファイルのお店は全て「スターバックス」の店舗情報になります。それ以外のお店を聞かれたときは応答ルールの#3に応じた回答をしてください。
2. 同一名称の駅についての処理が甘い
-
例えば「住吉駅」という名前の駅は、少なくとも東京都江東区・大阪府大阪市・兵庫県神戸市にあります。
-
東京都江東区のお店を返却していますが、複数の候補駅があるときに分岐ノードなどを用いて、きちんと制御できるようになるといいですね。
3. ID検索に原因不明のバグ
- 店舗ID:97が渋谷クロスタワー店、店舗ID:649がアリオ札幌店なのですが、店舗IDの完全検索がどうやら苦手みたいです。
追記したプロンプトは下記のとおりです。
・ユーザーから店舗IDについて聞かれたら、csvファイルから該当する店舗IDのお店の情報を返してください。
- GPT5.0+, Gemini3とか使えるようになったら解消されるのかな?チャンク周りの設定も疑わってみるのがよさそう
どうビジネスに転用できそうか
個人的に触ってみて思ったのが、プロンプトエンジニアリングが上手い人だとDifyをきちんと使いこなせるのかな、というところで。個人的には限られた時間の中でAIとの対話していくにはまだまだ力不足なのかな、と感じたのが率直な感想です。ただ使いこなせたらすごいパワード発揮しそうなのも事実で、ビジネスには間違いなく役に立つツールだと思います。
例えば、今自分が所属している企業は中小企業なのですがやはり書類仕事から脱却できていないという印象が強く、PDF 化された就業規則などをボットに読み込ませ、社員からの問い合わせに即時回答できる「企業法務に強い AI 従業員」を作る、といった使い方は、現実的かつすぐに役立つユースケースのひとつだと感じました!














