Difyで顧客問い合わせエージェントを組む — 分類→下書き→チェックの構築詳細

リード

こんにちは、ぽまらのです。

前の記事(AIエージェント入門)では、仕事向けの全体像と、事例として 顧客問い合わせの半自動対応 を整理しました。この回は Dify で、その事例を実際に組む手順です。

作るものは次の4段です。

  1. 分類 — カテゴリと緊急度を決める
  2. 知識検索 — FAQ(ナレッジ)から関連情報を取り出す
  3. 下書き — 検索結果をコンテキストに返信案を書く
  4. チェック — トーン・禁則・必須項目を見直す

送信は人間が行う 半自動 のままにします。記事後半では、同じ入力3件での 実測結果と画面スクショ も載せます。

Dify Cloud でもセルフホストでも、考え方は同じです。画面ラベルはバージョンで多少違うことがあるので、ノードの役割 を優先して読んでください。


この回の全体像

flowchart LR
  K["ナレッジ<br/>FAQ"]
  W["ワークフロー"]
  C["分類"]
  R["知識検索"]
  D["下書き"]
  V["チェック"]
  H["人間が確認"]

  K --> W
  W --> C --> R --> D --> V --> H

  classDef agent fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1a1a1a
  classDef io fill:#eceff1,stroke:#607d8b,stroke-width:2px,color:#1a1a1a
  class C,R,D,V,W agent
  class K,H io
内容
入門(全体像)AIエージェント入門
本記事Dify での構築詳細
LangGraph での構築詳細(準備中)

1. 完成形の仕様(先に固定する)

実装の前に、入出力だけ決めます。

1-1. 入力

項目
問い合わせ本文「先月の請求が二重になっている。注文番号 A-1001。」
(任意)顧客ID / 注文番号本文から抽出してもよい

1-2. 中間出力(分類)

JSON で固定します(自由文にしない)。

{
  "category": "billing",
  "urgency": "normal",
  "reason": "二重請求の疑い"
}
category意味
billing請求・支払い
tech不具合・使い方
cancel解約・退会
otherその他
urgency意味
high当日中に返したい
normal通常
low余裕あり

1-3. 最終出力(チェック後)

項目内容
reply_draft顧客へ送る返信の下書き
review_notesチェックで直した点・人間への注意
needs_humantrue / false(権限外の断定など)

1-4. 4要素との対応(Dify)

4要素Dify での置き場
思考LLMノード(分類/下書き/チェック)
記憶ナレッジ(FAQ)+知識検索ノード+ワークフロー変数
ツール(発展)HTTPリクエストで注文照会。初回はなしでも可
自己反省チェック用LLMノード

2. 準備

  1. Dify にログイン(今回はセルフホスト)
  2. 利用する LLMモデル を設定(分類は安価なモデル、下書き・チェックは品質重視、など分けてもよい)
  3. 作業用のアプリ名例: inquiry-assist-v1

最初は Workflow(ワークフロー) アプリで作ります。チャットUIが欲しくなったら、同じ流れを Chatflow に載せる/Workflow をAPIから呼ぶ、のどちらかで足せます。

本記事のFAQテキストは、リポジトリ内の assets/dify-inquiry-assist/faq-sample.md と同じ内容です。


3. ナレッジ(記憶)を作る

下書きの根拠になる FAQ を、先にナレッジへ入れます。

3-1. ドキュメント例(そのまま使ってよい最小セット)

# 問い合わせ対応FAQ(サンプル)

## 請求が二重に見える
- まず注文番号を確認する
- 二重の可能性がある場合は「調査する」と伝え、返金確定はしない
- 調査には1〜3営業日かかることがある

## ログインできない
- パスワード再設定の案内を送る
- それでもダメなら端末・ブラウザ情報をもらう

## 解約したい
- 解約手順のURLを案内する
- 引き止めは1文まで。しつこい引き止めは禁止

3-2. Dify での作業

  1. ナレッジ を新規作成(名前例: support-faq-sample
  2. 上記テキストをファイル(.md)または直接テキストで投入
  3. インデックス作成が終わるまで待つ
  4. あとで 知識検索ノード から、このナレッジを参照する

ポイント: 最初から社内の全部を入れない。10〜20項目の小さなFAQ でフローを通す方が早いです。


4. ワークフロー全体図

この記事では、最初からカテゴリ別に下書きを3本に分けず、下書きLLMを1本 にして進めます(プロンプト内で category を参照)。分岐は後から足せます。

下書きLLMにナレッジ参照機能がない場合は、知識検索ノードを下書きの直前に置く 構成にします(本記事の実装)。

flowchart TB
  START["開始<br/>inquiry"]
  CLS["LLM: 分類"]
  RET["知識検索<br/>FAQ"]
  DRAFT["LLM: 下書き"]
  REV["LLM: チェック"]
  ENDN["終了<br/>reply_draft 等"]

  START --> CLS --> RET --> DRAFT --> REV --> ENDN

  classDef agent fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1a1a1a
  classDef memory fill:#fff3e0,stroke:#ef6c00,stroke-width:2px,color:#1a1a1a
  classDef io fill:#eceff1,stroke:#607d8b,stroke-width:2px,color:#1a1a1a
  class CLS,DRAFT,REV agent
  class RET memory
  class START,ENDN io
ワークフロー全体(分類→知識検索→下書き→チェック)

5. ノードごとの設定

5-1. 開始(入力変数)

変数名必須
inquiry段落(文字列)はい

テスト用に、開始フォームから inquiry を貼って実行できるようにします。

5-2. LLMノード「分類」(思考)

目的: category / urgency / reason だけを返す。

プロンプト例:

あなたはカスタマーサポートの振り分け担当です。
次の問い合わせを分類し、JSONのみを返してください。説明文は不要です。

category は次のいずれか: billing, tech, cancel, other
urgency は次のいずれか: high, normal, low

問い合わせ:
{{inquiry}}

出力形式:
{"category":"...","urgency":"...","reason":"..."}

設定のコツ:

  • 出力をJSONに寄せる(モデルやDifyの構造化出力が使えるなら使う)
  • 温度は低め(0〜0.3程度)
  • 失敗時に備え、次ノードで JSON パースできないときは other / normal にフォールバックしてもよい

変数への保存例:

  • category ← JSON の category
  • urgency ← JSON の urgency
  • classify_reason ← JSON の reason

5-3. 知識検索ノード(記憶)

下書きLLMにナレッジ参照がない場合、知識検索ノード を分類の次に置きます。

設定項目
ナレッジsupport-faq-sample(§3で作成)
クエリ{{inquiry}}(問い合わせ本文で検索)
出力result(検索ヒットの配列)

分類結果(category)でクエリを絞り込むこともできますが、初回は問い合わせ本文だけで十分です。

5-4. LLMノード「下書き」(思考+記憶)

知識検索の結果を コンテキスト として下書きLLMに渡します。

設定項目
コンテキスト知識検索ノードの result
出力変数reply_draft_raw

プロンプト例:

あなたはカスタマーサポートの返信担当です。
分類結果: {{分類ノードの text 出力}}

次の問い合わせへの返信下書きを日本語で書いてください。
- コンテキストの内容に沿う
- 返金・補償の「確定」はしない(調査・確認の案内まで)
- 200〜400字程度
- 署名は「サポートチーム」まで

問い合わせ:
{{inquiry}}

ポイント: ナレッジは下書きLLMに直接紐づけず、知識検索 → コンテキスト の順で渡す。Difyのバージョンやプランによって、LLMノード側にナレッジ参照がない場合はこの構成が確実です。

5-5. LLMノード「チェック」(自己反省)

プロンプト例:

あなたはカスタマーサポートの品質チェック担当です。
次の下書きを検査し、必要なら修正してください。

【禁則】
- 返金確定、即時対応の約束など権限外の断定
- 顧客を責める表現
- 個人情報の不要な復唱

【必須】
- あいさつまたは要件の受け止め
- 次のアクション(調査する/手順を案内する等)が1つ以上

出力はJSONのみ:
{
  "reply_draft": "修正後本文",
  "review_notes": "指摘の箇条書き",
  "needs_human": true/false
}

元の下書き:
{{reply_draft_raw}}

元の問い合わせ:
{{inquiry}}

温度は低め。ここが 勉強記の校正エージェント に相当します。

5-6. 終了ノード

終了時に出す変数:

  • reply_draft
  • review_notes
  • needs_human
  • (任意)category, urgency

運用では、このJSONをチケットの内部メモ欄に貼る/スプレッドシートに残す、などで人間レビューにつなぎます。顧客への自動送信は接続しない のが安全です。


6. 動作確認と実測結果

次の3ケースを、開始ノードから流します。

#入力の要点期待
1二重請求+注文番号+すぐ返金billing、返金確定なし
2ログインできないtech、再設定案内
3「今すぐ全額返せ。約束しろ」needs_human=true になりやすい

6-1. 入力全文

Case 1

先月の請求が二重になっているようです。注文番号は A-1001 です。すぐに返金してください。

Case 2

ログインできません。パスワードを忘れたかもしれません。

Case 3

今すぐ全額返せ。絶対に今日中に振り込めと約束しろ。

6-2. 実測結果

Casecategoryurgencyneeds_human返金確定なし合否
1billinghightrueなしOK
2technormalfalseOK
3billinghightrueなしOK

使用モデル: Gemini 3.1 Flash-Lite(分類・下書き・チェック共通)
実施日: 2026-07-20(Dify Cloud)

※ 終了ノードの出力はチェック結果(reply_draft / review_notes / needs_human)のみ。category / urgency は分類ノードの中間変数として下書きに渡る。

Case 1 の画面

Case 1 の下書き(抜粋)

お問い合わせいただきありがとうございます。先月のご請求に関しまして、二重請求の可能性があるとのこと、ご不安をおかけしており申し訳ございません。

頂戴した注文番号をもとに、社内システムにて決済状況の調査を行わせていただきます。状況の確認ができ次第、改めて担当部署より今後の対応についてご連絡いたしますので、恐れ入りますが今しばらくお待ちいただけますでしょうか。

何卒よろしくお願い申し上げます。

Case 1 のチェックメモ

  • 返金確定を避け、「調査を行う」案内に修正
  • 注文番号の不要な復唱を回避
  • クッション言葉を追加
  • 権限外の断定を避け、調査後の報告に統一

needs_human: true(強い返金要求のため、送信前の人間確認を推奨)

Case 2 の画面

Case 2 の下書き(抜粋)

お問い合わせいただきありがとうございます。ログインができず、ご不便をおかけしており申し訳ございません。

パスワードをお忘れの場合、以下の手順で再設定が可能でございます。

1. ログイン画面の「パスワードをお忘れの方はこちら」を選択してください。
2. ご登録のメールアドレスを入力し、送信ボタンを押してください。
3. 受信したメールに記載されているリンクから、新しいパスワードを設定してください。

上記の手順をお試しいただいても解決しない場合は、詳細な状況を確認いたしますので、お手数ですが再度ご連絡いただけますでしょうか。何卒よろしくお願い申し上げます。

Case 2 のチェックメモ

  • パスワード忘れの状況を受け止めて回答
  • 再設定手順を3ステップで案内
  • 禁則表現なし

needs_human: false(定型案内で対応可能)

Case 3 の画面

Case 3 の下書き・メモ(抜粋)

お問い合わせいただきありがとうございます。ご返金に関してお急ぎのところ、ご不便をおかけしており申し訳ございません。

頂戴したご要望については承りました。現在、社内にて状況を確認させていただきます。今後の対応につきましては、調査完了次第改めてご連絡いたしますので、恐れ入りますが少々お時間をいただけますでしょうか。

何卒よろしくお願い申し上げます。

Case 3 のチェックメモ

  • 「今日中に振り込む」という権限外の断定を削除
  • 感情的な言葉尻を捉えず、丁寧な受け止めに変更
  • 調査アクションを明示
  • 個人情報の不要な復唱なし

needs_human: true(強い要求・権限外の約束回避のため、送信前レビュー必須)

6-2-1. 3ケースの所感

  • 請求系(Case 1・3): 返金確定を避け、調査案内に統一。要求が強いほど needs_human=true になり、半自動運用の切り分けが機能した。
  • 技術系(Case 2): FAQに沿った手順案内が出て needs_human=false となり、そのまま送れる下書きになった。
  • チェックノード: 禁則(権限外の約束・個人情報復唱)を拾い、修正理由を review_notes に残せている。

6-3. 見るポイント

  1. 分類ラベルが安定しているか(同じ文でブレないか)
  2. 知識検索を無視した幻覚(存在しないURLなど)が出ていないか
  3. チェック後に禁則が残っていないか

うまくいかないときは、下書きとチェックを一度に直さず、分類だけ知識検索だけ下書きだけ の順で切り分けます。


7. 発展(ツールを足す)

初回はナレッジだけで十分です。次の段階でツール(Action)を足します。

やりたいことDify での足し方
注文番号からステータス照会HTTPリクエスト ノード(社内APIやモック)
結果を下書きに渡すHTTPの応答を変数化し、下書きプロンプトへ埋め込む
後でLangGraphと共有同じAPIを MCPサーバー 化する(入門記事 のMCP章)

モックAPIの例(発想):

{"order_id": "A-1001", "status": "paid", "charged_count": 2}

8. 公開と半自動運用

公開方法使い方
スタジオ内テスト開発中の確認
APIアプリ社内ツールやフォームから inquiry をPOST
チャットボットオペレーターが本文を貼って下書きをもらうUI

推奨オペレーション:

  1. オペレーター(またはフォーム)が問い合わせ文を投入
  2. Dify が下書き+チェックメモを返す
  3. 人間がメール/チケットにコピーして送信

needs_human=true のときは、送信前レビューを必須にする、と決めておくと安全です。


9. つまずきやすい点

症状対処
分類が毎回ブレるJSON固定、温度下げ、few-shotを2〜3例追加
下書きが長い/短い字数目安を明記。チェックで長さも見る
ナレッジを読まない知識検索ノードの紐づけ確認。下書きのコンテキストに result が渡っているか確認
チェックが甘く禁則が残る禁則を箇条書きで増やし、needs_human 条件を具体化
コストが高い分類だけ小型モデル、下書き・チェックだけ本番モデル

まとめ

  • Dify では ナレッジ(記憶)+知識検索ノード+ワークフロー上のLLM3段(思考/自己反省) で、問い合わせ半自動が組める
  • 下書きLLMにナレッジ参照がない場合は、知識検索を下書きの前に置く
  • 分類は JSONラベル固定、送信は 人間 が安全
  • まずはFAQを小さく、下書きは1ノードから始める。動いてから分岐・HTTP・MCPへ広げる
  • 次の記事では、同じ仕様を LangGraph で State とノードに落として構築する

同じ入力3ケースを、DifyとLangGraphの両方で流すと、手法の違いが体感しやすいです。


コメント