補助金RAGチャットボットの
全体像
Next.js 16 + Dify Workflow(セルフホスト)+ Cohere Rerank v3.5 + Claude Sonnet 4.6 による 補助金 RAG チャットボットのシステム構成・検索設計・ヒアリング UX 実装・ガードレール設計の詳細を、 エンジニアリング視点で解説します。
全体アーキテクチャ
ブラウザから Dify Workflow(セルフホスト)、外部 LLM/API までのリクエストの流れを視覚化。
LP / Chat UI
- / (LP)
- /chat (チャット本体)
- 段階的ヒアリングUI
- 補助金カード・比較表
API Routes
- /api/chat (Dify プロキシ)
- /api/export (HTML出力)
- SSE ストリーミング転送
- APIキー秘匿
ガードレール
- 出典バッジ
- 信頼度インジケーター
- 免責表示
- “情報なし”明示
段階的ヒアリング
- 6 項目 (業種 / 従業員数 /
- 投資予定 / 所在地 /
- 会社URL / 課題)
- conversation_variables で状態管理
確認ゲート (ADR-014)
- ヒアリング完了→確認ターン
- 次ユーザー発話で
- マッチング起動
- ガチャ誘導文を排除
マッチング生成
- Knowledge Base 検索
- Cohere Rerank
- subsidy-cards JSON 出力
- (ADR-015 構造化出力)
- subsidy-master 3,178 件
- (jGrants API 全件)
- subsidy-detail 公募要領 3 件
- subsidy-cases 2,286 件
- 全 KB に Cohere Rerank v3.5
- FireCrawl API
- 会社 URL → 企業プロファイル生成
- ヒアリング完了後 1 回のみ
- Dify から直接呼び出し
- Claude Sonnet 4.6
- (Dify 経由で呼び出し)
- システムプロンプトで
- ガードレール制御
※ Dify は Xserver VPS にセルフホストしており、ユーザー入力・社内資料・企業プロファイルはBeyonZ管理下のサーバを通り、外部の汎用 LLM サービスの学習データには使われない。Cohere Rerank も Dify からサーバ間で呼び出すため、ブラウザに API キーは露出しない。
2 段階検索 — ベクトル検索 + Cohere Rerank
関連度の高い補助金を確実に上位に持ち上げるため、ベクトル検索の結果をリランカーで並べ直す 2 段階構成。
ステージ 1 — ベクトル検索
クエリと業務語(業種・従業員数・課題)を埋め込みに変換し、3 つの KB それぞれにベクトル検索を実行。意味的に近い候補を広めに 20 件ずつ取得する。
- 対象
- Knowledge Base 3 種(補助金 3,178 / 公募要領 3 / 採択事例 2,286)
- top-K
- 20 件 / KB
- 埋め込み
- Dify 既定モデル(OpenAI text-embedding-3-large 等)
- 閾値
- min score なし(次段の Rerank で篩い直す)
ステージ 2 — Cohere Rerank v3.5
クエリと候補のペアを Cohere Rerank に投げ、関連度スコアで並べ直す。ベクトル検索だけでは「業務語クエリ ↔ 公募要領テキスト」の語彙差を吸収しきれないため、ここで篩い直す。
- 対象
- ステージ 1 の合計 60 件
- top-K
- 5 件(マッチング用)
- モデル
- rerank-v3.5(多言語対応・日本語精度向上)
- 閾値
- relevance_score を Dify に渡し、上位 5 件を採用
なぜ Rerank が必要か
ベクトル検索は「埋め込み空間で近い」候補を返すが、補助金マッチングのクエリは業務語(「製造業 / 従業員30名 / 設備投資」)であるのに対し、公募要領テキストは行政・法律用語で書かれている。語彙差が大きいため、ベクトル検索だけでは「本命の補助金が 8 位 / ノイズが 1〜3 位」のような順位崩れが起こりやすい。 Cohere Rerank はクエリと候補の文脈的関連度を直接スコアリングするため、ベクトル検索の取りこぼしと順位崩れを補正できる。
段階的ヒアリングのステートマシン
6 項目のヒアリングを Dify Workflow の conversation_variables で状態管理。ユーザー側は対話だが、内部は決定論的なステートマシンになっている。
ヒアリング 6 項目と変数
industryemployeesinvestmentprefecturecompany_urlconcernヒアリング完了 → 「確認ゲート」(ADR-014)でユーザーに6項目+クロール後のプロファイルを確認させ、次の発話を起点にマッチング起動。1 ターンに詰め込まずに「確認 → 実行」の 2 ターンに分け、生成 LLM の「少々お待ちください」系のガチャ誘導文を構造的に封じている。
ヒアリング項目・遷移条件は要件に合わせて差し替え可能。Demo A は補助金マッチング向けに 6 項目で組んでいるが、社内 FAQ や商品問い合わせのフロントエンドとしても同じステートマシンが使える。
なぜ Dify を選んだのか
Mastra・LangChain・LangGraph も同等以上のことはできる。それでも Demo A は Dify に振り切った。その判断軸を 4 点で。
GUI でワークフローが完成する
段階的ヒアリング → 確認ゲート → クロール → マッチング → 構造化出力という多段の Workflow を、ノードを線でつなぐだけで組める。コードファースト層が必要な細部だけを Code ノードで補う設計に絞れる。
LangChain / LangGraph はコードでつなぐ。ノード数が増えると差分レビューが重くなる。
横展開が「差し替え」で済む
本デモを社内 FAQ/契約書照会/問い合わせ対応に横展開する場合、Knowledge Base を差し替えてシステムプロンプトを書き換えるだけで完結。コードベース側の改修は最小で、案件ごとの初期構築が短い。
コードファースト層は実装の自由度が高い反面、横展開時の改修範囲が広い。Demo A 級の RAG なら Dify の制約内で十分。
運用引き継ぎがしやすい
クライアント側に Workflow を譲渡しても、GUI で動作を追えるので「中身が分からないブラックボックス」にならない。プロンプトの微調整は非エンジニアでも触れるレベル。
コードファースト層を譲渡すると、引き継ぎ先に同じスキルセットのエンジニアが必要。
状態管理を GUI に閉じ込められる
conversation_variables による状態管理を Dify 側に閉じ込めることで、Next.js 側のコードに状態を持たない。クライアント/サーバの状態同期バグが構造的に起きない設計にできる。
コード側に状態を持つと、SSE 中断・再接続・再送のたびに状態同期の罠が増える。
※ BeyonZ は Demo B(Mastra)・Demo C(LangGraph)でコードファースト層も扱う。案件の性質——「GUI で完結すべきか/コードで作り込むべきか」——から逆算して、最適な層を選ぶ前提でデモを分けている。
セキュリティとガードレール
「動く」ことと「事故を起こさない」ことは別。AIを業務に持ち込むときの安全装置を 3 層で設計している。
プロンプトインジェクション対策
ユーザー入力を Workflow のシステムプロンプトと明確に分離し、Knowledge Base にない情報の捏造を構造的に防ぐ。
- システムプロンプトで「KBに無い情報は『情報がありません』と返す」を明示・繰り返し
- ユーザー発話は Variable Reference 経由でテンプレに差し込み、命令文として解釈させない
- Workflow ノードの分岐は決定論的(変数の empty / not empty)で、LLM 判断に依存しない
ガードレール多層化
「動作する」ではなく「事故を起こさない」を担保するために、出力にも複数の安全装置を組み合わせる。
- 回答に出典バッジ(参照元・ページ番号)を必ず付与
- 信頼度インジケーター(高 / 中 / 低)で確度を可視化
- 免責表示(最終判断は専門家へ)をフロントで常時提示(F-04)
- 締切済み補助金を鮮度フィルタで除外し、誤誘導を防ぐ
PII / データ統制
業務データを外部の汎用 LLM サービスに学習データとして渡さない経路設計。
- Dify は BeyonZ 管理下の Xserver VPS にセルフホスト
- クライアント要件があれば AWS / GCP / Azure 上のセルフホストへ移植可能
- 企業 URL クロールは FireCrawl 直接呼び出しで、BeyonZ サーバを通過しない経路に
- ユーザー入力・社内資料は LLM の学習データには使われない(Anthropic API の規約に準拠)