はじめに
DifyにはHuman Inputという、ワークフローの途中で処理を一時停止し、人間の入力や判断を挟み込めるノードがあります。
LLMが生成した内容をそのまま後続処理に流すのではなく、「一度人間の目を通す」というステップを組み込めるため、業務利用を考えると欠かせない機能の1つです。
今回は、Human Inputノードの機能を紹介しつつ、実際に簡単なサンプルアプリを作って動かしてみます。
Human Inputノードとは
Human Inputノードは、ワークフローの任意のポイントで処理を止め、受け取り手にリクエストフォームを提示します。
受け取り手はフォームの内容を確認し、入力や選択を行った上で、あらかじめ定義されたアクションボタンを押すことでワークフローの続きを進められます。
Dify公式ドキュメントによると、設定項目は大きく4つに分かれています。
配信方法(Delivery Method)
フォームをどの経路で届けるかを選べます。
- Web app: Difyのウェブアプリのエンドユーザーにフォームを表示する方法です。Triggerで起動したワークフローでは使えません。
- Email: ワークスペースメンバーや外部メールアドレス宛にリクエストリンクをメール送信する方法です。リンクを知っていればDifyアカウントがなくても回答できます。
どちらの方法でも、最初の回答があった時点でリクエストはクローズされます。
フォーム内容(Form Content)
フォームにはMarkdownで見出しやリスト、太字などを使って情報を整形できるほか、ワークフロー変数を埋め込んで動的な内容(LLMの生成結果やアップロード済みファイルなど)を表示できます。
Web app配信の場合、変数を参照するだけでフォームに値が表示されるため、Human Inputノードの手前にAnswerノードを挟む必要がありません。
入力を受け取るフィールドは以下の種類があります。
| フィールドタイプ | 概要 |
|---|---|
| Paragraph | テキスト入力。空欄始まりでも、変数や固定文字列で事前入力しておくことも可能 |
| Select | 選択式。選択肢を手動定義するか、配列変数を参照して選択肢にできる |
| Single File / File List | ファイルアップロード |
Paragraph以外(Select、Single File、File List)は必須項目扱いで、すべて入力し終えるまでアクションボタンが押せない仕様になっています。
回答後は、フォームの内容がすべて値で埋まった状態が__rendered_contentという変数として後続ノードから参照できます。
ユーザーアクション(User Action)
受け取り手が押せる決定ボタンを定義します。ボタンごとに異なる実行パスへ分岐させられるのがポイントで、例えば「承認」ボタンなら公開処理へ、「差し戻し」ボタンならLLMでの再生成処理へ、といった分岐が組めます。
ボタンにはそれぞれ表示タイトルとアクションIDがあり、押されたボタンのIDは__action_id、タイトルは__action_valueとして後続に渡されます。
タイムアウト戦略(Timeout Strategy)
リクエストを開いたままにしておく時間を設定できます(デフォルトは3日)。時間内に誰も回答しなかった場合は、タイムアウト用の分岐にワークフローが進みます。タイムアウト分岐を繋いでいない場合は、そのままワークフローが終了します。
サンプルアプリの全体構成
今回は、じゃんけんをテーマにしたシンプルなチャットフローアプリを作りました。全体の流れは以下の通りです。
スタート → LLM(1回目の回答) → Human Input → LLM2(追加入力を踏まえた回答) → 回答2
└(タイムアウト)→ 回答
- ユーザが最初のメッセージ(例:じゃんけんの手について)を送ると、LLMノードが1回目の回答を生成します。
- Human Inputノードが、その回答を表示しつつ、追加の質問を受け付けるフォームを提示します。
- ユーザが追加の質問を入力してアクションボタンを押すと、1回目の回答と追加質問の両方を踏まえてLLM2が最終回答を生成します。
- タイムアウトした場合は、そのまま1回目の回答を最終回答として返します。
構築手順
1. スタートノード
特に入力変数は設定せず、シンプルにユーザのメッセージ(sys.query)を後続に渡すだけの構成にしています。
2. LLMノード(1回目)
システムプロンプトは空にして、ユーザプロンプトに{{#sys.query#}}をそのまま渡すシンプルな構成です。ここでは、ユーザの最初の質問に対する素の回答を生成させます。
3. Human Inputノード
- 配信方法: Web app
-
フォーム内容:
{{#llm.text#}}(1回目のLLM回答)を表示した上で、区切り線を挟み、add_queryという名前のParagraphフィールドを配置。ユーザはここに追加の質問を入力します。 - アクションボタン: 「Button Text 1」というボタンを1つだけ設定
- タイムアウト: 3日
4. 分岐の接続
- Human Inputノードのタイムアウト用ハンドル(
__timeout)を、直接「回答」ノードに接続し、1回目のLLM回答をそのまま返すようにしています。 - アクションボタン(
action_1)側のハンドルを、2つ目のLLMノード(LLM2)に接続します。
5. LLMノード(2回目)
ユーザプロンプトに、以下の3つの情報をまとめて渡しています。
# ユーザの入力
{{#sys.query#}}
# ユーザの1回目の入力に対するLLMの回答内容
{{#llm.text#}}
# 追加のユーザ入力
{{#1787458462546.add_query#}}
ここでポイントなのが、Human Inputノードで定義したフィールド(add_query)を参照する際は、フィールド名だけでなく{{#(Human InputノードのノードID).add_query#}}という形式でノードIDを指定する必要がある点です。他のノードのように単純な変数名だけでは参照できないので、初めて使う際は少し戸惑うかもしれません。
6. 回答ノード
- 「回答」ノード: タイムアウト時に
{{#llm.text#}}を返す - 「回答2」ノード: 通常フロー完了時に
{{#1787458852025.text#}}(LLM2の出力)を返す
実際に動かしてみる
1回目のチャット
ユーザ:
じゃんけんでチョキとパーを出すと
あえて主語や状況を曖昧にした質問を投げてみました。
LLMなので毎回同じ回答が返ってくるとは限りませんが、今回試した際は以下のような回答が得られました
質問文が曖昧だったため、LLMが2つの解釈を提示してくれる形になりました。
ここでHuman Inputノードが登場し、「どちらの意味だったのか」をユーザに追加で確認できるフォームが表示されます。
Human Inputフォームの表示
1回目の回答がそのままフォームに表示され、その下に追加質問を入力するテキストエリアが出てきます。
2回目の入力
追加質問欄に、1回目の回答の中から知りたかった方の選択肢を指定する形で入力してボタンを押しました。
2人で勝負した場合(勝敗の判定)
最終回答
LLM2が、1回目の回答内容と追加質問を踏まえて、じゃんけんの勝敗を判定した回答を返します。
このように、1回目のLLM回答が曖昧・多義的だった場合でも、Human Inputを挟むことでユーザの意図を確認してから最終回答を生成できる、という一連の流れが実演できました。
つまずいたポイント
-
フィールド変数の参照方法: 前述の通り、Human Inputノードのフィールドは
{{#ノードID.フィールド名#}}という形式で参照する必要があります。他のノードの出力変数と参照ルールが異なるため注意が必要です。 -
フォーム内のMarkdown表示:
{{#llm.text#}}のような変数をフォーム内に埋め込むと、LLMの出力がそのままMarkdownとしてレンダリングされます。長文の回答を確認してもらう用途では、Paragraphフィールド単体より見やすく表示できました。 - タイムアウトの検証: デフォルトのタイムアウトは3日のため、動作確認時は一時的に短い時間(数分など)に変更してテストすると効率的です。
まとめ
Human Inputノードを使うことで、AIの出力を人間が確認・修正・承認してから次の処理に進めるフローを、ノーコードに近い形で組めることが分かりました。
今回はじゃんけんという単純な題材でしたが、実務では例えば「AIが下書きした問い合わせ回答をサポート担当者が確認し、そのまま送信するか、修正指示を出して再生成させるか」といったカスタマーサポート業務にもそのまま応用できそうな機能だと感じました。






