• HOME
  • 記事一覧
  • コード生成AIアプリのお問い合わせフォームをDifyで作ってみた – RAG構築編 –
  • DIFY

コード生成AIアプリのお問い合わせフォームをDifyで作ってみた – RAG構築編 –

Y.Kyohei
Y.Kyohei
コード生成AIアプリのお問い合わせフォームをDifyで作ってみた – RAG構築編 –

背景

前回の記事

コード生成AIアプリのお問い合わせフォームをDifyで作ってみた – 導入・実験編 – | 記事一覧 | エクシオ・デジタルソリューションズ株式会社

に続き、今回もDifyについて投稿します。

2025年の暮れ、コード自動生成や脆弱性診断ができる生成AIアプリを開発・リリースしました。

前回は、その生成AIアプリのお問い合わせチャットボットをDifyで作成しよう、というところまでを書きました。

前回示したゴールは以下の通りです。

  • ある程度の質問はAIが即時に返答する
  • 必要な問い合わせはチームへ通知できる形にする
  • ユーザー操作はできるだけ最小限にする

今回の記事では、このうち1つ目の

「ある程度の質問はAIが即時に返答する」

を、RAGの導入によって実現することを目指します。

そもそもRAGってなんぞや?

生成AIを使ったチャットボットを作ろうとすると、まずぶつかるのが、

「AIは賢そうに見えるけれど、こちらの社内情報や製品情報を最初から知っているわけではない」

という問題です。

たとえば今回のように、お問い合わせフォームの代わりになるチャットボットを作りたい場合、ユーザーからはこんな質問が飛んできます。

  • この機能は何ができますか?
  • 利用条件はどうなっていますか?
  • 料金や導入方法は?

こうした質問に対して、生成AIが毎回もっともらしく答えてくれたとしても、その答えが自社サービスの最新情報と合っているとは限りません。

ここで活躍するのが、RAG(Retrieval-Augmented Generation) です。

RAGをざっくり言うと、

「AIが回答を作る前に、関連する情報を探してきて、その情報を根拠に答える仕組み」

です。

普通の生成AIが「記憶や学習済み知識だけで答える」イメージだとすると、RAGは「回答する前にカンペを取りに行ってから答える」イメージに近いです。

これによって、社内ドキュメントやFAQ、製品資料などをもとに、より実務的な回答がしやすくなります。

今回の構成では、この「関連情報を探す」部分にベクトルDBを使います。

ベクトルDBは、文書を単なる文字列ではなく、意味の近さで検索できる形に変換して保存しておくデータベースです。

たとえばユーザーが「料金について知りたい」と質問したとき、資料側に「価格体系」「費用」「プラン一覧」といった表現で書かれていても、言葉が完全一致していなくても意味的に近い情報を引っ張ってこられるのが強みです。

流れとしてはかなりシンプルで、次のような形です。

  • あらかじめ製品情報やFAQをベクトルDBに登録しておく
  • ユーザーから質問が来たら、その内容に近い文書をベクトルDBから検索する
  • 検索で見つかった情報を参考資料としてAIに渡す
  • AIがその内容を踏まえて回答を生成する

つまりRAGは、生成AIをただ「会話できるAI」として使うのではなく、

「手元の情報を参照しながら答えられるAI」にする仕組み

と言えます。

DifyでRAG構築

では実際に構築してみます。

まずはデータソースを選択してアップロードします。

今回は、対象である生成AIアプリのユーザーマニュアルを選択しました。

「次へ」を押下すると、以下の画面「ナレッジベース」に移行します。

見慣れない単語もあるかと思いますが、重要なワードだけ説明していきます。

チャンク

チャンクは、登録する文章を小さく区切った単位のことです。

長い文章をそのまま丸ごと検索対象にするのではなく、ある程度の長さで分割しておくことで、質問に関係する部分だけを見つけやすくなります。

たとえばFAQや仕様書のような長文でも、内容ごとに分けておけば、AIが必要な部分を拾いやすくなります。

最大チャンク長

これは、1つのチャンクをどれくらいの長さまでにするかを決める設定です。

長すぎると不要な情報まで含みやすくなり、短すぎると文脈が切れやすくなります。

そのため、ある程度まとまりを保ちつつ、細かく検索できる長さにしておくのがポイントです。

オーバーラップ

オーバーラップは、前後のチャンクで少し内容を重ねる設定です。

文章をきれいに区切れるとは限らないので、境目で文脈が途切れないようにするために使います。

たとえば、ある説明文の途中でチャンクが分かれてしまっても、少し重複があれば、重要な文脈を取りこぼしにくくなります。

ベクトル検索

ベクトル検索は、ユーザーの質問と意味的に近い文章を探す検索方法です。

たとえ表現が少し違っていても、内容が近ければ候補として拾いやすいのが特徴です。

お問い合わせ対応のように、言い回しが毎回変わるケースと相性が良いです。

Top K

Top Kは、検索結果として上位いくつのチャンクを取り出すかを決める値です。

大きくしすぎると関係ない情報も混ざりやすく、小さすぎると必要な情報を取り逃すことがあります。

まずは少なめから試して調整するのが分かりやすいです。

スコア閾値

これは、どれくらい関連性が高いチャンクだけを採用するかの基準です。

値を高くすると厳選され、低くすると広めに拾う動きになります。

精度と取りこぼしのバランスを見るための設定と考えると分かりやすいです。

チャンク長やオーバーラップの値は、今回はまずデフォルト設定のまま試しました。

というのも、最初の段階で細かく値をいじりすぎると、逆にどの設定が効いているのか分かりづらくなるためです。

今回ナレッジ化したのはユーザーマニュアルで、文章中心の比較的扱いやすいデータだったこともあり、まずはDifyの標準的な設定でどの程度回答できるかを確認する方針にしました。

実際に試してみると、大きく文脈が切れることもなく、検索結果にも大きな違和感はなかったため、今回はこの設定を採用しています。

実際にノードをつないでみる

ナレッジベースを用意したら、次は実際にノードをつないで回答の流れを作っていきます。

今回の構成はシンプルで、LLMで検索クエリを作成 → 知識検索 → LLMで最終回答を生成 という流れにしました。

ここで意識したのは、ユーザーの質問文をそのままナレッジ検索に使わないことです。

ユーザーの質問は自然文なので、検索にそのままかけると、言い回しの揺れや不要な表現が混ざってしまうことがあります。

そこで今回は、知識検索の前に一度LLMを挟み、「検索に向いたワード」に整形してからナレッジベースを検索するようにしました。

実際に知識検索の前段で使ったプロンプトは以下のようなものです。

「{{#sys.query#}}はユーザーの質問です。

この質問からマニュアルの入ったナレッジデータベースに検索をかけに行くときのクエリとして適切なワードを出力してください。」

このノードの役割は、ユーザーの質問に対していきなり答えることではなく、

検索でヒットしやすい形に言い換えることです。

その後、知識検索ノードで関連情報を取得し、最後のLLMノードで回答を生成します。

知識検索の後段では、以下のようなプロンプトを使いました。

「コンテキストにナレッジデータベースからの返値{{#context#}}があるので、それをもとにユーザーからの質問に答えてください」

つまり、最後のLLMには自由に答えさせるのではなく、

取得したコンテキストを根拠に回答させる という形にしています。

この流れにすることで、単なる生成AIの受け答えではなく、ナレッジベースを参照した回答に寄せやすくなります。

実際に動かしてみる

今回は上記画像のような質問をしてみました。

すると、先ほどベクトルDB化したマニュアルから関連する情報を抽出して答えてくれました。

最後に

構築に手間がかかりそうなRAGやベクトルDBも、Difyを使うことで比較的簡単に試すことができました。

このような、既存アプリの仕様をAIが参照しながら回答する仕組みは、DXやアプリ運用の視点から見ても有用性が高いと感じています。

お問い合わせ対応の効率化はもちろん、ユーザーが必要な情報に素早くたどり着けるという意味でも、相性の良いアプローチでした。

DifyはRAGを試す入口としても扱いやすいので、興味のある方はぜひ触ってみてください。

新着記事一覧へ