業務自動化 · AI連携

n8nとDifyを連携させる — AIが判断する業務自動化ワークフローの設計と実装

「Difyで社内FAQボットを作ったが、社員に使ってもらえない」——よくある話だ。DifyのチャットURLを共有しても、日常的に使うTeamsやSlackから離れてもらうのは思ったよりも高いハードルになる。

n8nと組み合わせると、この問題が消える。社員はいつも通りTeamsに質問を投稿するだけで、n8nがその投稿をDify APIに転送し、AIが生成した回答をスレッドに自動返信する。「AIを使っている感」を意識させないことが、定着率を上げるコツだ。

この記事の検証環境
n8n バージョン
2.25.6(Docker セルフホスト)
Dify
セルフホスト(Docker)
推奨通知先
Slack Incoming Webhook
難易度
★★★ n8n・Docker の基礎知識が必要
n8n.io クラウド版を使う場合は Docker 固有の注意事項(後述)は不要です。手順の本筋は同じです。

なぜn8n×Difyなのか

n8nはワークフロー自動化ツール、DifyはRAG・LLMアプリの構築プラットフォームだ。それぞれ単体でも強力だが、組み合わせると「AIが文脈を読んで自動対応する」フローが作れる。

⚙️
n8n単体
定型的な転送・通知

「メールが来たらSlackに転送」「定時にスプレッドシートを更新」など、ルールが決まっている処理は得意。ただし、テキストの意味を読んで判断する能力はない。

弱点:「この問い合わせは誰の担当か」を判断できない
🤖
Dify単体
AI質問応答

社内ドキュメントをRAGで検索し、自然言語の質問に回答するのが得意。チャット画面をURLで共有できる。ただし、自ら外部サービスに通知を送る機能はない。

弱点:社員に「別のURLを開いてもらう」必要がある
n8n × Dify
AIが判断する自動化

n8nがトリガーと配送を担当、DifyがAI判断を担当。社員はTeamsやSlackなどいつものツールで質問するだけで、AIが自動回答・自動振り分けを実行する。

強み:既存ツールの使い勝手を変えずにAIを注入できる

準備するもの

この記事では以下が稼働済みの前提で進める。

  • n8n — セルフホスト(Docker)または n8n.io クラウドのどちらでも可
  • Dify チャットボットアプリ — Cloud(cloud.dify.ai)またはセルフホスト。アプリ種別は「チャットボット」を選ぶこと
  • Difyのナレッジベース — FAQ対象の社内ドキュメントを登録済みであること(シナリオAに必要)
  • 通知先 Webhook URL(オプション) — Slack を使う場合は Incoming Webhook URL(無料・簡単)。Teams は後述の注意を参照。検証フェーズは通知なしでもOK
✅ この記事の進め方(推奨)
  • Phase 1(必須・約15分) — Webhook → Dify の 2ノード で動作確認。curl で叩いて Dify の回答が返ってくれば成功
  • Phase 2(オプション) — Slack / Teams 通知ノードを追加。Phase 1 が動いてから着手すること
動かない状態のまま通知ノードを追加すると、エラーの原因切り分けが格段に難しくなります。必ず Phase 1 から始めてください。

🐝 Difyのアプリ種別について この記事で使うAPIはチャットボット(チャット型)アプリのエンドポイントです。Dify管理画面でアプリを作成するとき「チャットボット」を選んでください。エージェント型・ワークフロー型は別のエンドポイントを使うため設定が異なります。


Dify APIキーの取得と確認

APIキーの発行

  1. Dify管理画面でチャットボットアプリを開く
  2. 左サイドバー「APIアクセス」をクリック
  3. 「APIキー」セクションで「APIキーを作成
  4. 生成されたキー(app-xxxxxxxxxxxxxxxxxx 形式)をコピーして保管
🐝 Cloud vs セルフホストでベースURLが異なる

curlで疎通確認

n8nの設定前にAPIが正常に動作するか確認しておく。以下のコマンドを実行し、answer フィールドにAIの回答が返ってくれば疎通成功だ。

curl -X POST https://api.dify.ai/v1/chat-messages \
  -H "Authorization: Bearer app-あなたのAPIキー" \
  -H "Content-Type: application/json" \
  -d '{"inputs":{},"query":"有給休暇の申請方法を教えてください","response_mode":"blocking","conversation_id":"","user":"test-user"}'

正常なレスポンス例:

{
  "answer": "有給休暇の申請は、社内ポータルの「各種申請」から...",
  "conversation_id": "abc-123",
  "message_id": "msg-456"
}

n8n HTTP Requestの基本設定

n8nでDifyを呼び出す共通設定を押さえておく。すべてのシナリオでこの設定が基本になる。

① 認証情報の登録(一度だけ)

  1. n8n画面右上の設定 → Credentials → 「Add Credential」
  2. タイプ: Header Auth
  3. Name(ヘッダー名): Authorization
  4. Value: Bearer app-あなたのAPIキーBearer のあとに半角スペースが必要)
  5. 保存名を Dify API Key などに設定して保存

② HTTP Requestノードの設定値

設定項目
MethodPOST
URLhttps://api.dify.ai/v1/chat-messages(セルフホストは自サーバーURL)
AuthenticationGeneric Credential Type → Header Auth → 先ほど登録した認証情報
Send HeadersON → Content-Type: application/json を追加
Send BodyJSON(下記テンプレート参照)

③ リクエストボディのテンプレート

response_mode は必ず blocking にすること(streamingはn8nでサポートされていない)。query には前ノードの変数を差し込む。

{
  "inputs": {},
  "query": "={{ $json.body.question }}",
  "response_mode": "blocking",
  "conversation_id": "",
  "user": "={{ $json.body.user_id || 'anonymous' }}"
}
🐝 式の書き方:$json.body.question になる理由
  • n8n の Webhook ノードは、POSTで受け取ったJSONボディを $json.body.フィールド名 に格納する(直接 $json.フィールド名 ではない)
  • “Body Content Type: JSON / Specify Body: Using JSON” モードでは、式の先頭に = が必要(例: ="{{ $json.body.question }}"
  • || ‘anonymous’ はフォールバック値。データがない場合に Dify API が user 必須エラーを返すのを防ぐ

④ レスポンスの取り出し方

HTTP Requestノードの次のノードで {{ $json.answer }} を参照するとAIの回答テキストが取得できる。


シナリオA:FAQ自動返答

最もシンプルで即効性が高い構成だ。Webhookでリクエストを受け取り、Difyで回答を生成してTeamsに返信する。

フロー構成
📥 Webhook受信🤖 Dify API呼び出し📤 Slack / Teams投稿(省略可)

Step 1 — ワークフローの作成とWebhookノードの設定

① ワークフローJSONをインポートする(推奨)

配布しているJSONファイルをn8nに読み込むと、ノード構成が自動で揃います。

  1. ツールページ から n8n-dify-faq-v1.json をダウンロード
  2. n8n の画面で「Create workflow」ボタンをクリック(新規ワークフローが開く)
  3. 画面右上の「(三点メニュー)」をクリック
  4. メニューから「Import from file…」を選択

🐝 「Import from file」がグレーアウトして選べない場合 画面上部に「Editor」「Executions」「Evaluations」のタブがある場合、「Editor」タブをクリックしてから「…」メニューを開いてください。Executionsタブを開いているとインポートが無効になります。

② 手動でゼロから作る場合

  1. n8n で「Create workflow」→ 「+ Add first step」→ 検索欄に「Webhook」と入力して選択
  2. Webhook ノードの設定 — HTTP Method: POST / Path: dify-faq(任意) / Respond: When Last Node Finishes
  3. 次に「+」ボタンで HTTP Request ノードを追加 → 前節(n8n HTTP Requestの基本設定)の設定値を入力

③ Webhookをテストモードで待機させる

  1. Webhook ノードをクリックして開く
  2. Listen for test event」ボタンをクリック → ノードが待機状態(リスニング中)になる
  3. この状態のまま次の curl を実行する(待機は一定時間でタイムアウトするので素早く実行)
curl -X POST https://your-n8n/webhook-test/dify-faq \
  -H "Content-Type: application/json" \
  -d '{"question":"有給休暇の申請方法は?","user_id":"tanaka"}'
🐝 Docker セルフホスト環境でのURL
  • n8nをインストールしたサーバー上のターミナルから実行する場合: http://localhost:5678/webhook-test/dify-faq(Cloudflareなどのトンネルを経由しない直接アクセス)
  • 外部・別PCから実行する場合: https://your-n8n.example.com/webhook-test/dify-faq(ドメイン名に置き換え)
  • Cloudflare Access で保護されている場合: 外部からのcurlはアクセス認証に弾かれます。サーバー自身から localhost:5678 で叩くのが確実です

✅ Phase 1 の成功確認 curl の返り値に “answer”: “…” が含まれていれば、Webhook → Dify の2ノード連携は完成です。この時点でいったん止めて動作を確認しましょう。通知ノード(Phase 2)は次のステップで追加します。

Step 2 — HTTP Requestノード(Dify呼び出し)

前節(n8n HTTP Requestの基本設定)と同じ設定でDify APIを呼び出す。“Body Content Type: JSON / Specify Body: Using JSON” を選び、以下を入力する。

{
  "inputs": {},
  "query": "={{ $json.body.question }}",
  "response_mode": "blocking",
  "conversation_id": "",
  "user": "={{ $json.body.user_id || 'anonymous' }}"
}
🐝 式が効かない・エラーになる場合のチェックリスト
  • =[object Object] の先頭に = が入っているか確認(忘れると文字列として送信される)
  • Dify API から “Arg user must be provided” エラー → user フィールドが空になっている。|| ‘anonymous’ フォールバックを確認
  • 接続エラー → URLが正しいか確認(セルフホストの場合、n8nコンテナから見たDifyのURLを使う。詳細は後述のトラブルシュートを参照)

Step 3 — 通知ノードの設定

⚠️ Teams通知の現状(2026年7月時点) Teams の旧「Incoming Webhook(コネクタ)」は Microsoft により 2026年5月18〜22日に廃止完了。現在は使用不可(既存の Webhook URL も動作停止)。後継の Workflows(Power Automate)経由の HTTP トリガーは PREMIUMライセンス必須 で設定も複雑。まず Slack または「通知なし」で動作確認することを強く推奨。

選択肢 ①:Slack に通知する(推奨・無料)

  1. Slack の App管理画面 → 「Create New App」→「From scratch」
  2. 「Incoming Webhooks」を ON → 「Add New Webhook to Workspace」→ 通知先チャンネルを選択
  3. 発行された https://hooks.slack.com/services/ をコピー
  4. n8n に 2つ目の HTTP Request ノードを追加(認証: なし)
  5. Method: POST / URL: コピーしたSlack Webhook URL
{
  "text": "*Q:* {{ $('Webhook').item.json.body.question }}\n\n*A:* {{ $json.answer }}"
}

選択肢 ②:通知ノードを省いて Webhook レスポンスで返す(検証用・最速)

通知先がない検証フェーズでは Step 3 を省略できる。Webhook ノードの Response Mode を「Last Node」にしておけば、Dify API ノードの出力(answerフィールド)がそのまま HTTP レスポンスとして返ってくる。

# curl の返り値に Dify の回答が含まれる(2ノード構成でも動く)
curl -X POST http://localhost:5678/webhook-test/dify-faq \
  -H "Content-Type: application/json" \
  -d '{"question":"有給休暇の申請方法は?","user_id":"tanaka"}'

🐝 Teams に通知したい場合 旧コネクタ方式(Incoming Webhook)は 2026年5月に廃止済みで現在使用不可。Teams へ通知したい場合、現実的な選択肢は Power Automate Premium(プレミアムプラン必須) のみ:Workflows アプリ → 「HTTP 要求の受信時」トリガーを作成 → 生成された URL を n8n の通知ノードに設定。Microsoft 365 E3/E5 環境では Power Automate Premium が付帯するケースがある。まずライセンスを確認すること。

🐝 関連ツール

n8n × Dify FAQ自動返答ワークフロー

シナリオAのn8nワークフローをそのままインポートできるJSONファイル。Webhook → Dify API → Slack/Teams通知の3ノード構成。DifyのAPIキーと通知先Webhook URLを差し替えるだけで動作します(Slack推奨)。

n8n JSONWebhookTeams対応

シナリオB:死活監視 + AI通知文の自動生成

定期的にサーバーの死活確認を行い、ダウンを検知したらDifyが過去の障害対応手順書を参照して通知文を自動生成する。情シスが深夜に慌てて通知を書く手間がなくなる。

フロー構成
⏰ 5分ごと🌐 HTTP Ping🔀 IF(ダウン判定)🤖 Dify(通知文生成)📤 Teams投稿

Step 1 — Schedule Trigger

「Schedule Trigger」ノードを追加 → Mode: Every X Minutes → Interval: 5

Step 2 — HTTP Requestノード(サーバーPing)

監視対象のURLにGETリクエストを送る。ノードの「On Error」設定を「Continue(Error Output)」にしておくことが重要——失敗してもフローを止めない。

設定項目
MethodGET
URL監視対象のURL(例: https://your-internal-app.com/health
On ErrorContinue(Error Output)
Timeout10000(10秒)

Step 3 — IFノード(ダウン判定)

HTTPステータスコードが200以外、またはエラーが発生した場合に「True」ブランチへ進む。IFノードの条件は2つ設定し、「OR」でどちらか一方が真のときに発火させる。

条件設定値
条件1statusCode is not equal to 200
条件2error is not empty
組み合わせOR(どちらか一方が真)

Step 4 — Dify(通知文生成)

Trueブランチ(ダウン検知時)のみDifyを呼び出す。ナレッジベースに過去の障害対応手順書を登録しておくと、より具体的な通知文が生成される。

{
  "inputs": {},
  "query": "【障害発生】サービスがダウンしています。影響範囲の推定と、エンドユーザー向けの暫定案内文を日本語で作成してください。",
  "response_mode": "blocking",
  "conversation_id": "",
  "user": "monitoring-bot"
}

🐝 連続通知を防ぐには ダウンが続く限り5分ごとに同じ通知が飛んでしまう。n8nの「Static Data」ノードや外部KVストアを使って「直前の状態(UP/DOWN)」を記録し、状態が変化したときだけ通知する設計にするとノイズを減らせる。


シナリオC:問い合わせの自動分類と担当者振り分け

フォームやメールで受け付けた問い合わせをDifyに分類させ、カテゴリに応じてn8nが担当者チャンネルへ自動通知する。受付件数が増えるほど効果が大きいシナリオだ。

フロー構成
📥 フォーム受信🤖 Dify(分類+JSON返却)🔧 JSONパース🔀 Switch(担当者別)📤 Teams各チャンネルへ

Step 1 — Difyへの分類依頼プロンプト

「JSON形式のみで返してほしい」と明示することが重要だ。フリーテキストで返ってくると後続のパース処理が壊れる。Difyのシステムプロンプトにも「JSONのみ出力」と追記しておくと安定する。

問い合わせ内容を分類し、JSONのみで回答してください。説明文は不要です。

問い合わせ: ={{ $('Webhook').item.json.body.message }}

出力形式(必ずこのJSONのみ):
{"category":"pc_trouble|network|account|other","urgency":"high|medium|low","summary":"30文字以内の要約"}

Step 2 — Codeノードでレスポンスをパース

DifyのLLMがMarkdownのコードブロックで囲んで返すことがある(例: json ... )。Codeノードで除去してからパースする。

// n8n Codeノード(JavaScript)
const answer = $input.item.json.answer;
// コードブロック記号を除去して純粋なJSONを取り出す
const cleaned = answer
  .replace(/```json\n?/g, '')
  .replace(/```/g, '')
  .trim();
const parsed = JSON.parse(cleaned);
return [{ json: parsed }];

Step 3 — Switchノードで担当者チャンネルに振り分け

category値urgency送信先
pc_troublehigh → 🔴Teams「PCトラブル対応」チャンネル
networkmedium → 🟡Teams「ネットワーク対応」チャンネル
accountlow → 🟢Teams「アカウント管理」チャンネル
otherTeams「情シス全般」チャンネル

トラブルシュート

① 401 Unauthorized — APIキー認証エラー

原因:Header Authの Value フィールドの書き方が間違っている。

対処:値は Bearer app-xxxxxxxxBearer のあとに半角スペース、そしてAPIキー)の形式にする。curlで疎通確認してから設定すると確実。

② answerが空または「この質問には答えられません」と返ってくる

原因:Difyのナレッジベースに該当情報がない、またはチャンク分割が適切でない。

対処:Dify管理画面「デバッグ・プレビュー」で同じ質問を投げて動作確認する。プレビューで回答が返ってくれば問題はAPIの設定側、返ってこなければナレッジベース側の問題。

③ Codeノードで JSON.parse がエラーになる(シナリオC)

原因:DifyのLLMがJSON以外の説明文を混ぜて返すことがある(「以下がJSON形式の回答です:」など)。

対処:Difyのシステムプロンプトに「回答はJSONのみ出力してください。前置き・説明文は一切不要」と追記するのが最も効果的。それでも起きる場合はDifyのプロバイダーをClaude 3.5などの指示追従性が高いモデルに変更する。

④ streaming モードにしたらn8nでエラーになる

原因:n8nのHTTP Requestノードは Server-Sent Events(ストリーミング)を正式サポートしていない。

対処:リクエストボディの response_mode は必ず blocking にすること。blockingモードはDifyが回答を全部生成してから一括でレスポンスを返すため、n8nで正常に受け取れる。

⑤ 「The service refused the connection」— Dockerセルフホスト環境での接続エラー

原因:n8nをDockerで動かしている場合、HTTP RequestノードのURLに localhost127.0.0.1 を使うとn8nコンテナ自身を指してしまい、別コンテナのDifyに繋がらない。

対処:以下のいずれかに変更する。

ホストIPは ip addr show(Linux)または ipconfig(Windows)で確認できる。

⑥ 「Bad request: Arg user must be provided」— userフィールドが空

原因:Dify APIは user フィールドが空文字または未指定だとエラーを返す。手動テスト(Webhookからのデータなし)時に発生しやすい。

対処:ボディの user フィールドにフォールバック値を設定する: ="{{ $json.body.user_id || 'anonymous' }}"。これにより入力データが空でも ‘anonymous’ が使われる。


まとめ

n8n × Dify 連携の核心は「既存ツールの使い勝手を変えずにAIの判断を注入する」ことだ。社員はTeamsやSlackをいつも通り使い、裏でn8nがDify APIを呼び出してAIが処理する。

即日稼働
シナリオA — FAQ返答

Webhook → Dify → Slack/Teams の3ノード構成。Difyのナレッジベースさえ整っていれば半日で稼働できる。情シスへの問い合わせ数削減に直結する。

運用負荷削減
シナリオB — 死活監視

障害通知の文章作成を自動化し、深夜対応の精神的コストを下げる。ナレッジベースに手順書を入れるほど通知の質が上がる。

長期的な効果大
シナリオC — 自動分類

問い合わせ件数が増えるほど効果が大きい。担当者割り当てのミスも防げる。Difyの判断精度をナレッジベースで育てていくことが鍵。

✅ まず試すならシナリオAから ダウンロードできるn8nワークフローJSONをインポートし、DifyのAPIキーを設定するだけで動作確認できます。通知先は Slack Incoming Webhook URL を推奨(Teams は後述の注意あり)。
ツールページでダウンロード →