【図解】Difyの変数を完全理解:会話変数・グローバル変数・変数代入ノードの使い方とハマりどころ

(最終更新日: 2025年11月27日)

Difyでチャットボットを作ったけれど、変数がどこで設定できて、どう保存・参照すればいいのか分からない…そんなモヤモヤはありませんか?

本記事は会話変数・グローバル変数・変数代入ノードを、手を動かしながら迷わず使えるように、やさしい言葉と図解で整理します。

どの画面で定義するか、ユーザー入力や会話履歴をどう保存するか、テンプレートからの呼び出し方まで、ひとつのシナリオに沿って順番に解説。

「値が入らない」「参照できない」「形式が合わない」などのハマりどころも、原因と直し方を具体例でカバーします。

読み終えるころには、自分のユースケースに合わせて変数設計を行い、ワークフローやチャットフローを安定して組める状態になれます。

内容は最新UIで検証済みで、実務にも直結します。

Difyの変数全体像:種類とスコープを最初にざっくり理解する

当セクションでは、Difyで扱う変数の種類とスコープ、読み書き可否の要点を最初に整理します。

なぜなら、どの情報をどこに保持し、いつ参照・更新するかの設計が、ワークフローの安定性と拡張性を大きく左右するからです。

  • Difyで扱う主な変数の種類と役割をざっくり整理
  • システム変数(sys.xxx):書き換え不可のメタデータとして理解する
  • 環境変数:APIキーやエンドポイントをワークフロー本体から切り離す
  • 会話変数:チャットごとの「状態」を保持するメインの入れ物
  • ノード出力・一時変数:データフロー上で「流れていく値」として捉える

Difyで扱う主な変数の種類と役割をざっくり整理

まず全体マップを掴むと、どこに何を置くかの判断が一気に迷わなくなります。

Difyの変数は「種類×スコープ×読み書き可否」の3軸で捉えると設計が安定します。

下表に主な変数の役割と参照範囲を一覧で示します。

表と合わせて図も確認し、頭の中で立体的なモデルを作っておくと後の実装がスムーズです。

この整理はDify公式ドキュメントに基づいています(参考: Variables | Dify)。

種類主な例スコープ読み書き代表的な用途
システム変数sys.app_id, sys.workflow_run_id, sys.user_id, sys.conversation_id, sys.queryアプリ全体(グローバル)読み取りのみ実行トレース、監査、セッション識別、条件分岐
環境変数env.API_BASE_URL, env.API_KEYアプリ全体(環境単位)読み取りのみ(UI設定)APIキー・URL・シークレットの安全な注入
会話変数conversation.user_profile, conversation.patient_data会話単位(conversation_idで永続)読み書き可(変数代入ノード)ユーザー状態や収集データの保持
ノード出力llm_1.output, http_1.body実行中パスのローカル読み取りのみ次ノードへの受け渡し
一時・ローカル変数テンプレートのforループ変数、コードノード内のローカルテンプレート/コードのブロック内読み書き可(ブロック内のみ)整形・一時計算・補助処理
Difyの主要変数の全体マップ。行に『システム変数/環境変数/会話変数/ノード出力/一時・ローカル変数』、列に『スコープ(グローバル/会話/ローカル)・読み書き(R/O・R/W)』を配置したサマリー図

システム変数(sys.xxx):書き換え不可のメタデータとして理解する

結論として、システム変数は「書き換え不可の全体共通IDと実行メタ」であり、まず最初に参照候補に挙げるべき土台です。

理由は、全ノードから同一の値で参照でき、監査やデバッグに不可欠なトレーサビリティを提供するからです。

例として、sys.workflow_run_idで失敗リクエストを一意に追跡し、sys.user_idやsys.conversation_idでCRMやログと紐付ける運用が定番です(参考: Variables | Dify)。

RAGではsys.conversation_idをドキュメントのキーにして、会話ごとの長期記憶をベクトル検索で取り出す設計が実務で機能します(関連記事: 【2025年版】Difyの「ナレッジ」完全ガイド)。

結果として、誰が・いつ・どのセッションかを扱う場面では、まずシステム変数で取得できないかを確認すると設計が簡潔になります。

環境変数:APIキーやエンドポイントをワークフロー本体から切り離す

結論は「機密と環境依存値は必ず環境変数へ」ですが、これは再現性とセキュリティを両立する最短ルートです。

理由は、ワークフロー定義から秘密情報を排除し、Dev/Stage/Prodの切り替えを設定値だけで完結できるからです。

具体的には、環境設定画面でSecret型のAPI_KEYやAPI_BASE_URLを定義し、HTTPノードやコードノードで{{ env.API_BASE_URL }}を参照します(出典: Environment Variables Explanation | Dify)。

以下のような画面イメージを参考に、URLと認証ヘッダーに環境変数を差し込むと、定義の再利用と安全な共有が容易になります。

Difyの環境変数設定画面の概念図。キー名、型(Secret)、値がマスクされているUI、説明欄付き
DifyのHTTPリクエストノードの概念図。URLに {{ env.API_BASE_URL }}、ヘッダーに Authorization: Bearer {{ env.API_KEY }} を参照している例

この方針はThe Twelve-Factor Appの「設定は環境変数で持つ」に沿っており、移植性と安全性を高めます(参考: The Twelve-Factor App: Config)。

機密管理の詳細や運用時の注意点は、あわせてこちらも参照ください(関連記事: 【2025年版】Difyのセキュリティ徹底解説)。

会話変数:チャットごとの「状態」を保持するメインの入れ物

要点は、会話変数が「セッション継続の記憶領域」であり、チャット体験の一貫性を支えるということです。

理由は、同一conversation_id内で値が永続化され、前回入力の再利用や分岐判断に確実に使えるからです。

具体例として、ユーザー名や会員ランクに加え、オブジェクトや配列で問診票やカートのような複雑データも保持できます。

医療問診ボットならpatient_dataに{name, age, symptoms[]}を蓄積し、最後に必要項目だけを推論ノードへ渡すとノイズが大幅に減ります。

値の更新は変数代入ノードが基本で、履歴全文依存から状態ベース設計へ移行できます(参考: Dify v0.7.0: Conversation Variables)。

結論として、長く使う情報は会話変数へ早めに集約し、LLMには必要最小限の構造化データを渡すのが定石です。

ノード出力・一時変数:データフロー上で「流れていく値」として捉える

結論は、ノード出力は「今だけ使う値」、会話変数は「長く持つ値」と切り分けて設計することです。

理由は、各ノードの出力やテンプレート内のローカル変数は実行パスに閉じており、再利用性と寿命が短いからです。

例としては「ユーザー入力 → LLM出力 → 変数代入ノードで会話変数へコピー → テンプレートで整形」という流れが実務の基本線です。

ユーザー入力→LLMノード出力→変数代入ノード→会話変数→テンプレートノード出力 という一連のデータフローを示す図

詳しいノード設計やパス分岐は、こちらも合わせて確認してください(関連記事: 【2025年版】Dify Workflow完全ガイド)。

最終的に、短命な値は流し、長命な値は貯めるというシンプルな原則が混乱を防ぎます。

どの画面で変数を定義する?DifyのUI別・変数設定の場所ガイド

当セクションでは、Difyのどの画面でどの種類の変数を定義・参照・更新するのかを、UIごとに整理して解説します。

理由は、変数の設定場所を取り違えると参照エラーやセキュリティ事故につながり、ワークフローの再利用性や保守性が大きく損なわれるからです。

  • アプリ/ワークフロー設定画面:環境変数・初期値などの「土台」を準備
  • チャットフローキャンバス:会話変数と変数代入ノードを中心に設計
  • ワークフロー型アプリのキャンバス:ノード出力の連結とテンプレートからの参照
  • テンプレート/LLMプロンプト編集画面:{{ }} で変数を差し込む場所

アプリ/ワークフロー設定画面:環境変数・初期値などの「土台」を準備

結論として、最初に開くべきは「アプリ設定/ワークフロー設定」で、ここで環境変数や入力パラメータ、共有初期値といった土台を定義します。

理由は、機密値とロジックを分離し、環境ごとの差し替えや再デプロイを安全かつ素早く行えるからです。

たとえば①APIキーやエンドポイントURLなどの環境変数、②外部APIから受け取る入力スキーマ、③営業時間やブランド名のような全体初期値をここで定義しておくと、すべてのノードから共通参照できます。

Secret型の環境変数はUI上でマスクされエクスポート定義にも平文で含まれないため、ガバナンス面でも安心です(出典: Environment Variables Explanation | Dify)。

設定後はキャンバスで参照パスを入力するだけで使い回せるため、HTTPノードやテンプレートの切替が最小限で済みます。

まず「設定」で土台を固めることで、後続の設計・運用が劇的に安定します。

Difyのアプリ設定画面。左サイドバーのSettingsを開き、Environment/VariablesタブでAPIキー(Secret型)、API_BASE_URL、共有初期値などを定義しているスクリーンショットの概念図。マスク表示や型が示され、右側にサンプル参照パスの注釈付き。

チャットフローキャンバス:会話変数と変数代入ノードを中心に設計

結論は、チャットフローでは「会話変数」と「変数代入ノード」をセットで使い、ユーザー発話や抽出結果を構造化して蓄える設計が要です。

理由は、履歴全文に依存せず必要な状態だけを明示保存でき、コストと精度の両面で有利になるからです。

実務ではユーザー入力直後やLLM抽出直後に変数代入ノードを置き、conversation.user_name や conversation.preferences のように書き込みます。

右サイドの「変数」パネルで定義済みの会話変数と型を確認しながら進めると、型不一致や名前のミスを防げます(参考: Variables | Dify)。

なお、会話変数はセッション内で永続化されるため、再訪時のパーソナライズにも有効です(参考: Dify v0.7.0 Blog)。

都度抽出→即保存→次ノードで再利用、というリズムを徹底すると、壊れにくい会話体験になります。

チャットフローキャンバス右側の「変数」パネルの概念図。conversation.user_name(String)、conversation.preferences(Object)などが一覧表示され、直近の変数代入ノードからの更新がハイライトされている。矢印でノードと変数の関係を示す注釈付き。

ワークフロー型アプリのキャンバス:ノード出力の連結とテンプレートからの参照

結論として、ワークフロー型では各ノードの出力を変数として次ノードへつなぎ、テンプレートで {{ node_x.output }} のように参照するのが基本線です。

理由は、対話中心ではない処理系であっても、データフローを明示すれば再利用性とデバッグ性が高まるためです。

具体的には、HTTPレスポンスやDBクエリ、LLMの応答をテンプレートや条件分岐から参照し、必要に応じて会話変数やストレージへ書き出して後続で使います。

このときJinja2の条件分岐やループで整形できるため、無駄なLLM呼び出しを減らせます(参考: Template | Dify)。

基本的な変数の考え方はチャットフローと同一なので、まずはチャットフローで感覚を掴み、次にワークフロー型へ展開すると学習効率が高いです。

データは「ノード出力→参照→必要なら保存」の直線で考えると、設計が一気にクリアになります。

【2025年版】Dify Workflow完全ガイド もあわせて参照すると、全体像の理解が深まります。

テンプレート/LLMプロンプト編集画面:{{ }} で変数を差し込む場所

結論は、変数を「読む」主戦場はテンプレートノードとLLMプロンプト編集画面で、{{ }} による差し込みが基本です。

理由は、Jinja2構文で条件分岐やループ、フィルタが使えるため、余計な加工ノードを増やさずに出力を整えられるからです。

たとえば {{ conversation.user_name }}、{{ sys.query }}、{{ http_1.body.result }} のようにスコープに応じて参照し、右側の「変数挿入」UIからクリック挿入すればタイプミスも防げます(参考: Template | Dify)。

最小例は次のとおりで、条件分岐とループをまとめて確認できます。

{% if conversation.user_name %}Hello, {{ conversation.user_name }}!{% else %}Hello!{% endif %}
{% for item in http_1.body.items %}- {{ item.title }}{% endfor %}

なお、複雑な入れ子の動的参照は制約があるため、必要に応じてフロー制御や前段整形で回避します(参考: Variable Parsing Issue · GitHub)。

「参照はプロンプト/テンプレートで一元化」する意識が、保守性と品質の両立に直結します。

LLMプロンプト編集画面の概念図。右側に変数候補リストが並び、conversation.user_name、sys.query、http_1.body.result などをクリックで挿入できる様子を注釈で示す。

【2025年最新】Difyの使い方・機能・料金 も参考にすると、画面遷移や基本操作の不安が解消します。

会話変数の基本と実践:ユーザー入力を保存・再利用する一連の流れ

当セクションでは、Difyの会話変数にユーザー入力を保存し再利用する一連の流れを、設計の勘所と具体例で解説します。

なぜなら、会話変数を正しく設計できるかどうかが、精度・コスト・拡張性のすべてを左右するからです。

  • 会話変数のスコープとライフサイクル:どこまで残り、いつ消えるのか
  • 変数代入ノードで会話変数に値を書き込む基本パターン
  • 書き込みモード(上書き/追加/クリア)の違いと使いどころ
  • ケーススタディ:医療問診ボットのpatient_dataを会話変数で管理

会話変数のスコープとライフサイクル:どこまで残り、いつ消えるのか

結論として、会話変数は同一のconversation_idに紐づいて永続し、設計で明示的にクリアしない限り次のターンや再訪でも参照可能です。

この仕様はセッションの一貫性を保ち、必要な最低限の文脈だけを安定的に渡すために存在します。

例えば最初のターンで取得した名前をconversation.user_profile.nameに入れておけば、その後の全ノードから{{ conversation.user_profile.name }}として利用できます。

一方でタスク完了後に値が残ると誤作動の原因になるため、ワークフロー末尾でClearして初期化する設計を推奨します。

下図のタイムラインは会話開始からリセットまでの各時点で、conversation変数がどう変わるかを可視化したものです。

会話開始→数ターン→タスク完了→リセットの時間軸に沿って、conversation.user_profileやpatient_dataなどのキーが生成・更新・クリアされていく推移を示すタイムライン図

詳細仕様は公式ドキュメントの変数リファレンスに基づきます(参考: Variables | Dify)。

変数代入ノードで会話変数に値を書き込む基本パターン

最小構成は「入力の選択」「出力先の指定」「モードの選択」の3点だけで、Variable Assignerノードから会話変数へ確実に書き込めます。

理由は、Assignerがフロー内で唯一の正式な書き込み手段として設計され、スコープと型を安全に管理するからです。

典型例として、直近のユーザー発話sys.queryをconversation.user_profile.nameに保存すれば、次ターン以降で名寄せや敬称付与のロジックに再利用できます。

LLMの出力をJSONで受け、その中からnameやageだけを取り出して会話変数に格納するパターンも安定します。

設計の全体像はワークフロー解説と合わせて確認すると理解が早まります(参考: 【2025年版】Dify Workflow完全ガイド)。

下図はAssignerの入力元・出力先・モードの設定例を示したものです(参考: Dify v0.7.0: Enhancing LLM Memory…)。

Variable Assignerノードの設定例。Inputにsys.query、Outputにconversation.user_profile.name、ModeにOverwriteを選択したUIワイヤリング図

書き込みモード(上書き/追加/クリア)の違いと使いどころ

結論は「単一値は上書き、履歴やリストは追加、完了時はクリア」を基本に使い分けると破綻しません。

なぜなら、値の性質に合わないモードを選ぶと配列が壊れたり、不要な残存値で誤判定が起きたりするからです。

例えば症状の蓄積はconversation.patient_data.symptomsにAppendで追記し、会員ランクの更新はconversation.user_profile.tierをOverwriteで置換します。

タスク完了時にconversation.current_caseのみClearし、conversation.historyは保持するように分離設計すると運用が楽になります。

下のbefore/afterは各モードの挙動を最小例で示します。

# Overwrite(上書き)
# before: {"tier": "silver"}
# op: Overwrite tier := "gold"
# after:  {"tier": "gold"}

# Append(追加)
# before: {"symptoms": ["fever"]}
# op: Append symptoms += "sore throat"
# after:  {"symptoms": ["fever", "sore throat"]}

# Clear(クリア)
# before: {"current_case": {"id": "A-123", "status": "done"}}
# op: Clear current_case
# after:  {"current_case": {}}
Overwrite・Append・Clearの3モードについて、会話変数のJSONが操作前後でどう変化するかを並列で示す図

仕様の要点は公式解説を参照してください(参考: Variables | Dify)。

ケーススタディ:医療問診ボットのpatient_dataを会話変数で管理

要点は、patient_dataを「インテリジェントなフォーム」として育て、最終判断ノードへノイズのない構造化データだけを渡すことです。

この設計にすると、長い会話ログを毎回送らずに済み、コストと誤読を同時に抑えられます。

具体的には1ターン目で名前と年齢を抽出してpatient_data.nameとpatient_data.ageに保存し、2ターン目で症状をpatient_data.symptomsへAppendします。

最後にpatient_data全体を診療科推論LLMへ入力し、挨拶や雑談などの不要文脈を除外します。

下図は簡易フローとpatient_dataのJSONイメージです。

医療問診ボットのフロー図(質問ノード→LLM抽出→Variable Assigner→推論LLM)と、patient_dataのJSON例{name, age, symptoms[]}を併記

ヘルスケア領域の導入観点は事例まとめも参考になります(参考: 【2025年最新】医療AI事例大全Dify v0.7.0: Enhancing LLM Memory…)。

ユーザー入力や会話履歴を変数に保存し、後続ノードで活用するレシピ

当セクションでは、Difyでユーザー入力や会話履歴を「会話変数」に保存し、後続ノードで再利用するための実践レシピを説明します。

これは、LLMのステートレス性を補って文脈を安定供給し、コストと精度を同時に最適化するために重要だからです。

  • パターン1:ユーザーの直近の問い(sys.query)をそのまま保持する
  • パターン2:LLMで抽出した情報を会話変数に構造化して保存する
  • パターン3:会話の中で累積するリスト(選択履歴・操作履歴など)を作る
  • パターン4:会話変数をRAGや外部APIのパラメータとして使う

パターン1:ユーザーの直近の問い(sys.query)をそのまま保持する

最短の安定化手段は、sys.query を変数代入ノードで conversation.last_question に書き込み、次のLLMやテンプレートから明示参照することです。

こうしておくと「前の質問」を確実に呼び出せるため、履歴全量に依存せずに意図の取り違えを防げます(参考: Variables | Dify)。

実装はシンプルで、チャット受信直後に変数代入ノードを挿み、conversation.last_question = {{ sys.query }} を設定します。

全体像は次のようなイメージです。

sys.query から 変数代入ノードで conversation.last_question に保存し、回答テンプレートで参照する簡易フロー図

テンプレートやLLMのプロンプトでは {{ conversation.last_question }} を差し込んで自然な追記や補足ができます。

変数代入ノード:
  conversation.last_question = {{ sys.query }}

テンプレート/LLMプロンプト例:
「前の質問: {{ conversation.last_question }}」を参照して回答してください。

パターン2:LLMで抽出した情報を会話変数に構造化して保存する

要点は、LLMにJSON形式でキー情報を抽出させ、そのオブジェクトを会話変数へ保存して以降の処理を確実化することです。

理由は、構造化データにしておくとJinja2での参照やHTTPリクエストBodyの生成が安定し、外部連携の失敗を減らせるからです。

例えば「ご希望のプランと人数、実施日を教えてください」に対し、次のスキーマで返すようLLMに指示します。

{
  "plan": "",
  "guest_count": 0,
  "date": ""
}

出力を変数代入ノードで conversation.booking に保存すれば、後段で {{ conversation.booking.plan }} や {{ conversation.booking.date }} を安全に参照できます。

ワークフロー構築の全体像は【2025年版】Dify Workflow完全ガイドを併読すると設計の勘所が掴みやすいです。

LLMプロンプトでJSONスキーマを指定し、変数代入ノードで conversation.booking に保存する設定例の図

パターン3:会話の中で累積するリスト(選択履歴・操作履歴など)を作る

結論は、配列型の会話変数を用意し、変数代入ノードのAppendモードで履歴を蓄積することです。

こうすると選択や操作が重なる場面でも、時系列の足跡を失わずに「これまで」を正確に見渡せます。

例えば conversation.selected_topics を空配列で初期化し、選択のたびに {“topic”:”SEO”,”timestamp”:…} のようなオブジェクトを追加します。

前後の状態は次のように把握できます。

Append前後のJSON比較。空配列に {topic, timestamp} オブジェクトが追加され、履歴が伸びていく様子の図

// Before
conversation.selected_topics = []

// After (Append)
conversation.selected_topics = [
  {"topic":"SEO","timestamp":"2025-07-01T12:34:56Z"}
]

この履歴をLLMに渡せば「ダイジェスト生成」や「未選択トピックの提案」が精度高く行えます(参考: Variables | Dify)。

パターン4:会話変数をRAGや外部APIのパラメータとして使う

ポイントは、会話変数で保持したプロフィールや意図をRAGノードのクエリやHTTPリクエストのBodyに差し込み、検索と連携を文脈最適化することです。

理由は、「質問文だけ」で探すよりも、業種や役割といった属性を結合したほうが関連度の高いドキュメント取得や精密なAPI動作が期待できるからです。

例えば conversation.user_industry をRAGのクエリ「{{ conversation.user_industry }} + {{ conversation.last_question }}」に組み込みます。

HTTPノードではJSON Bodyに会話変数を安全に埋め込み、CRMや予約システムに正しい属性を渡します。

RAG設計の詳しい流れは【ノーコードでOK】Dify×RAG完全ガイドや、ナレッジ運用は【2025年版】Difyの「ナレッジ」完全ガイドが役立ちます。

以下のようにRAGクエリへ差し込むイメージを持つと設計が安定します。

RAGノードのクエリ欄に {{ conversation.user_industry }} を差し込み、ユーザー属性+質問で検索する設定図

テンプレート(Jinja2)で変数を参照・整形する:{{ }}の実践入門

当セクションでは、Difyのテンプレートノードで使うJinja2の基本から、会話変数の差し込み、条件分岐・ループ、運用設計の勘所までを実践的に解説します。

理由は、Jinja2で最終整形を担保することでLLMの出力ばらつきを抑え、コストと品質を両立できるからです。

  • 最低限覚えておきたいJinja2の基本構文
  • 会話変数を回答テンプレートに差し込む実用例
  • 条件分岐とループ:VIP向け文言やリスト表示をテンプレート側で制御
  • テンプレートでやり過ぎない:複雑な変換は専用ノードやLLMに任せる

最低限覚えておきたいJinja2の基本構文

まずは「変数展開・if・for・フィルター」の4点を押さえれば、Difyのテンプレート整形は8割方カバーできます。

Difyのテンプレートノードや一部プロンプト入力ではJinja2が使えるため、最小限の構文で安定した出力設計が可能です。

下のミニチートシートをブックマークしておくと、日常の整形タスクが格段に速くなります。

目的構文/例備考
変数を挿入{{” {{ variable }} “}}None対策に default を併用可
条件分岐{% if condition %}…{% endif %}elif/elseも使用可
繰り返し{% for item in list %}…{% endfor %}loop.index などの変数あり
文字列整形{{” {{ text | replace(‘\n’,’
‘) }} “}}
pipeで複数フィルター連結可
デフォルト値{{” {{ variable | default(‘N/A’) }} “}}未定義・空値対策の基本

HTMLの改行変換や空値対策は現場で最も出番が多いテクニックです。

{{ text | replace('\n', '<br>') }}
{{ user_name | default('お客様') }} 様

Jinja2はテンプレートノードの公式機能としてサポートされているので、まずは最低限の文法に慣れることから始めると良いです(参考: Template | Dify)。

会話変数を回答テンプレートに差し込む実用例

聞き取った情報をそのままテンプレートに差し込むだけで、応答は丁寧かつ一貫した品質になります。

理由は、文章構成を毎回LLMに委ねず、固定の体裁に会話変数を流し込むことで、トーンと情報欠落のばらつきを抑えられるからです。

例えば「お名前」「商品カテゴリ」「希望対応方法」を会話変数に保持している場合は、次のように書けば即戦力として機能します。

{{" {{ conversation.user_name }} "}} 様

お問い合わせありがとうございます。{{" {{ conversation.category }} "}} についてのご相談を {{" {{ conversation.contact_channel }} "}} で承ります。
Difyテンプレートノードの編集画面(左)と、会話変数を展開した出力結果(右)の比較図。左は {{ conversation.user_name }} などのJinja2が並び、右は和文の最終メッセージが整形されている。

この設計はプロンプトの自由度を保ちつつ、接客文面の骨格はテンプレートで固定化するアプローチで、運用時の安定感が高いです。

ワークフロー全体の作り方は、まずテンプレートに入れる変数を決め、その値を前段ノードで確実に埋める流れが基本です(参考手順: 【2025年版】Dify Workflow完全ガイド)。

条件分岐とループ:VIP向け文言やリスト表示をテンプレート側で制御

VIP判定や箇条書きの整形は、Jinja2のif/forでテンプレートに寄せると管理が楽になります。

理由は、軽いロジックをLLMに任せると出力の言い回しが揺れやすく、保守時に追跡しづらくなるからです。

以下はVIP向けの特別文言と、推薦リストを箇条書きに整形する例です。

{% if conversation.user.is_vip %}
・VIP様限定のサポート窓口をご案内します。
{% endif %}

おすすめ候補:
{% for rec in conversation.recommendations %}
- {{ rec.title }}({{ rec.reason }})
{% endfor %}
左にJinja2テンプレートのif/forコード、右にVIP向け一文と箇条書きがレンダリングされた結果を並べた図。

テンプレートで体裁を決めておけば、推薦項目の増減やフラグ条件が変わっても、表現の統一を簡単に維持できます。

テンプレートでやり過ぎない:複雑な変換は専用ノードやLLMに任せる

Jinja2は「最終整形の道具」と割り切り、重い変換や複雑ロジックはノードやLLMに委譲するのが長期運用の正解です。

理由は、テンプレートにロジックを詰め込みすぎると全体像が見えにくくなり、非エンジニアの保守が困難になるからです。

たとえばJSONのパースや大規模な文字列加工は、コードノードや専用の処理ノードで整形してからテンプレートに渡すと見通しが良くなります。

LLMノード→データ処理ノード→テンプレートノードの責務分離アーキテクチャ。矢印でデータが流れ、最後にJinja2で最終整形する模式図。

チーム開発では「データはどこで作るか、表示はどこで整えるか」を役割分担として明文化しておくと、障害調査や仕様変更が素早く進みます。

体系的に学びたい方は、プロンプトやテンプレート設計の基礎をオンラインで学べる講座の活用も効率的です(例: DMM 生成AI CAMP)。

よくある変数エラーとデバッグのコツ:値が入らない・参照できない・型が違う

当セクションでは、Difyで発生しやすい変数エラーの代表例と、現場で使えるデバッグのコツを解説します。

なぜなら、変数はワークフローの神経系であり、設計や記法の僅かな齟齬が全体の不具合に波及しやすいからです(基本設計は【2025年版】Dify Workflow完全ガイドも併せて参照ください)。

  • ケース1:変数に値が入らない/nullになるときのチェックポイント
  • ケース2:テンプレート/プロンプトで変数が展開されない・文字列のまま出る
  • ケース3:HTTPリクエストのJSONボディで型がおかしくなりAPIがエラー
  • ケース4:会話変数が意図せず上書き/持ち越されてしまう

ケース1:変数に値が入らない/nullになるときのチェックポイント

結論は、「前ノードの出力→対象ノードの入力→通過した分岐」を順に追う一点突破の切り分けが最速です。

多くの原因は、入力元が空、変数名や階層のミス、分岐外配置による未実行の三つに集約されます。

デバッグ画面で対象ノードの入力値を確認し、どのパスが実行されたかを必ずトレースします。

Difyのデバッグ画面の例:あるノードの入力が空(null)で赤枠強調、前ノード出力は値あり、分岐パス表示

本番環境では sys.workflow_run_id を使って該当実行を特定し、前段ノードが成功しているかをログで確かめると効率的です(参考: Variables | Dify)。

この三点チェックで null の根本原因は高確率で特定できます。

ケース2:テンプレート/プロンプトで変数が展開されない・文字列のまま出る

展開されないときは「Jinja2の構文」と「変数のスコープ」が噛み合っていない可能性が高いです。

{{ conversation.user_name }} のつもりが古い記法 {{#conversation.user_name#}} を混在させるなどの記述差異は、文字列のまま出力される主因になります。

また、変数名を動的に組み立てるようなネスト参照は現状サポート外で、期待どおりに評価されません。

正しい例と誤りの例は次のとおりです。

# 誤り(旧記法混在の例)
{{#conversation.user_name#}}

# 正しい(Jinja2)
{{ conversation.user_name }}

動的参照が必要なら、LLMに参照すべきキーを選ばせてIf分岐に渡す設計に置き換えるのが安全です(参考: Template | Dify、参考: Variable Parsing when in LLM Prompts · Issue #12241)。

ケース3:HTTPリクエストのJSONボディで型がおかしくなりAPIがエラー

JSONは「文字列連結で作らず」、テンプレートノードやコードノードで必ずJSONセーフに整形してから送るべきです。

余計な改行や二重クォートが混ざるとInvalid JSONになり、配列やオブジェクトの会話変数は特に壊れやすいです。

壊れたJSONと正しいJSONを比較します。

// 壊れたJSON(Invalid)
{
  "name": "{{ user_name }}\n",
  "items": "{{ conversation.items }}"  // 本来は配列だが文字列化されている
}
# 正しい(Jinja2で安全にシリアライズ)
{
  "name": {{ user_name | tojson }},
  "items": {{ conversation.items | tojson }}
}
壊れたJSONと正しいJSONの対比、左に赤い×付きで余計な改行と二重引用符、右に緑のチェックで正しいキーと値、Content-Type: application/jsonの注記

オブジェクトや配列をそのままボディに入れたい場合は tojson などで明示的にエスケープし、必要に応じて一度文字列化してから送るワークアラウンドを検討します(参考: Support for Inserting Object Variables in HTTP Request Body · Issue #20282、参考: Template | Dify)。

ケース4:会話変数が意図せず上書き/持ち越されてしまう

命名のネームスペース化と節目での一括クリアを「設計として癖づける」ことが最も効果的です。

同じキーを再利用したり、完了時にClearせずに次のシナリオへ進むと、意図しない値が残ります。

具体策は次の三つです。

  • シナリオごとにプレフィックスを付ける(例: lead_*, booking_*)。
  • フェーズの切れ目でClearノードをまとめて実行する。
  • 「ログ用」と「現在処理中」の変数を分離する(例: history_* と current_*)。
目的推奨命名例クリアタイミング
問い合わせ進行中の状態current_stage, booking_stepシナリオ完了時にClear
永続ログ・監査history_actions[]基本は保持、運用方針でローテーション
ユーザー固有属性profile_*プロファイル更新時のみ上書き

長期セッションでは会話開始時と終了時の2箇所にClearを明示配置し、フロー全体を見通せる位置に置くと事故が減ります(参考: Variables | Dify、実装の流れは 【2025年版】Dify Workflow完全ガイドを参照)。

設計段階で命名規則とクリア戦略を決めておくことで、持ち越しバグは大幅に抑制できます。

実践シナリオ:問い合わせ対応チャットボットをDifyの変数で組んでみる

当セクションでは、問い合わせ対応チャットボットを例に、会話変数・テンプレート・RAG・環境変数を連携して設計する具体手順を解説します。

なぜなら、変数を軸に設計することで、LLM任せの曖昧さを避け、業務に耐える一貫性と再現性を実現できるからです。

  • シナリオ概要:ユーザー情報を聞きながら最適な回答を返すチャットボット
  • ステップ1:ユーザー情報をヒアリングし会話変数に保存
  • ステップ2:問い合わせ内容をRAG+会話変数で文脈検索
  • ステップ3:テンプレートでパーソナライズされた最終回答を生成
  • 発展編:環境変数・外部API・料金プランを組み合わせた本番運用イメージ

シナリオ概要:ユーザー情報を聞きながら最適な回答を返すチャットボット

結論として、会話変数とRAGを組み合わせれば「人に合わせて最適な答え」を再現性高く返すチャットボットをDifyだけで構築できます。

理由は、名前・会社名・業種・問い合わせカテゴリを会話変数で構造化し、以降のノードで確定値として参照できるからです。

具体的には「開始→プロフィール取得→カテゴリ質問→RAG→回答テンプレート→終了」という流れで、conversation.user_profile.name/company/industry や conversation.inquiry.category を使います(参考: Variables | Dify)。

下図のような最小構成にすると、後段のテンプレートや検索条件にブレが出ず、運用時のデバッグも容易になります。

Difyキャンバス全体図:開始→名前質問→変数代入→会社名質問→変数代入→業種質問→変数代入→カテゴリ質問→テンプレートで検索クエリ組立→ナレッジ検索(業種別FAQ)→回答テンプレート→終了。変数は conversation.user_profile.name/company/industry と conversation.inquiry.category を明示し、各ノード間の矢印に参照関係を注記。

設計の基本はワークフロー指向で、ノードの入出力を見える化することです。詳しい設計パターンは 【2025年版】Dify Workflow完全ガイド も参考になります。

ステップ1:ユーザー情報をヒアリングし会話変数に保存

結論は、最初の数ターンで「お名前」「会社名」「業種」を聞き取り、直後に変数代入ノードで conversation.user_profile に確実に書き込むことです。

理由は、各値をその場で確定させると後続ノードが {{ conversation.user_profile.xxx }} を安定参照でき、スロット欠落や誤抽出の連鎖を防げるからです。

例として、LLMで以下のJSONを抽出し、変数代入ノードで上書き保存します。

{
  "name": "山田太郎",
  "company": "サンプル株式会社",
  "industry": "SaaS"
}

キャンバスでは「質問→ユーザー回答(sys.query)→変数代入」のミニパターンを3回繰り返します。

Difyミニパターン図:質問ノード→ユーザー回答(sys.query)→変数代入ノードで conversation.user_profile.name に保存、次に同様に company、industry を順番に保存。各代入は上書きモードで、右側に更新後の変数プレビューを表示。

このパターンにより、以降のノードはプロンプトやHTTPボディにそのまま変数展開できるようになります(参考: Variables | DifyInput variables cannot be updated #7846)。

操作の全体像は Difyの使い方・機能・料金を徹底解説 の基本編も参照してください。

ステップ2:問い合わせ内容をRAG+会話変数で文脈検索

結論は、検索クエリを「sys.query+業種」の複合にして、同じ質問でも業種固有のFAQがヒットするように調整することです。

理由は、業種文脈を前置するだけで検索空間のノイズが減り、少ないトークンで関連文書に到達しやすくなるからです。

テンプレートノードで次のように組み立て、RAGノードへ渡します。

【検索条件】{{ conversation.user_profile.industry }} のお客様からの質問:{{ sys.query }}
テンプレート→RAG接続図:テンプレートで『業種 のお客様からの質問:sys.query』を生成→ナレッジ検索ノードへ。ナレッジは『業種別FAQ(SaaS/製造/医療)』のフォルダ構成で、クエリに含まれる industry で該当ドキュメントが優先ヒット。

ナレッジ構成のコツやRAG精度の伸ばし方は 【ノーコードでOK】Dify×RAG完全ガイドDifyの「ナレッジ」完全ガイド を参照すると設計が早くなります。

テンプレートによるクエリ整形は公式ドキュメントの構文に従うと安全です(参考: Template | DifyVariables | Dify)。

ステップ3:テンプレートでパーソナライズされた最終回答を生成

結論は、RAG結果と会話変数をテンプレートで合成し、冒頭の呼びかけや業種別の注意点を差し込んで「あなた専用の回答」を作ることです。

理由は、名前や会社名の明示が安心感を高め、業種固有の留意点が不要な往復を減らすからです。

Jinja2の条件分岐を使えば、特定業種だけに文言を出し分けられます。

山田様({{ conversation.user_profile.company }})
以下が回答です:
{{ rag.output }}
{% if conversation.user_profile.industry == '医療' %}
・医療機関向けの個人情報取り扱い手順を遵守してください。
{% endif %}
回答の比較図:左=汎用『ご質問ありがとうございます。以下が回答です。』、右=個別『山田様(サンプル株式会社)、以下が回答です:… 医療向けの追記事項…』。差分として name/company/industry による文脈強化を可視化。

テンプレートの構文とフィルタは公式仕様に従うと安定します(参考: Template | Dify)。

テンプレート設計の考え方は プロンプトエンジニアリング入門 も参考になります。

発展編:環境変数・外部API・料金プランを組み合わせた本番運用イメージ

結論は、機密は環境変数で管理し、HTTPノードからCRM等に連携しつつ、プラン制限を前提にスケール設計を行うことです。

理由は、Secret型でAPIキーを守りつつ環境切替を安全化でき、RAG多用フローは無料枠のレートや容量にすぐ届くためです(参考: Plans & Pricing – DifyEnvironment Variables Explanation | Dify)。

例としてHTTPボディに会話変数と環境変数を混在させます。

{
  "contact": {
    "name": "{{ conversation.user_profile.name }}",
    "company": "{{ conversation.user_profile.company }}",
    "industry": "{{ conversation.user_profile.industry }}",
    "question": "{{ sys.query }}"
  },
  "source": "dify-supportbot",
  "api_key": "{{ env.CRM_API_KEY }}"
}

まずは無料枠で組み上げ、手応えが出たら Difyの料金プランを徹底比較 を参考に有料へ切り替える計画が現実的です。

社内のスキルトランスファーには体系的な学習も有効ですので、必要に応じて DMM 生成AI CAMP などの活用も検討すると効果が高まります。

これからDifyの変数設計を学ぶ人へのロードマップと他記事への導線

当セクションでは、Difyの変数設計をこれから学ぶ人に向けて、最短で理解を深める学習ロードマップと役立つ関連記事への導線を提示します。

変数はワークフローの神経系であり、学ぶ順番を誤ると混乱しやすいため、段階的に進めるための道筋を明確化する狙いがあります。

  • 学習ステップ1:会話変数+変数代入ノード+テンプレートの3点セットをマスター
  • 学習ステップ2:環境変数・RAG・外部APIとの連携に広げる
  • 学習ステップ3:エラー事例から逆算して設計パターンを洗練させる
  • Dify以外のAIワークフロー/チャットボットツールとの比較観点

以下の図で全体像を俯瞰できます。

Dify変数設計の3ステップ学習ロードマップ。Step1: 会話変数・変数代入ノード・Jinja2テンプレート、Step2: 環境変数・RAGノード・HTTPリクエスト、Step3: 型不一致やJSONエラーなどのデバッグを経て本番品質に仕上げる流れを矢印で示す図

学習ステップ1:会話変数+変数代入ノード+テンプレートの3点セットをマスター

最初は「会話変数に状態を保存→変数代入ノードで更新→テンプレートやLLMから参照」の3点セットに絞って身につけるのが最短ルートです。

理由は、この組み合わせだけで多くの業務シナリオが再現でき、Difyの記憶設計の核心を体感できるからです。

例えば会話変数にユーザー属性を保持し、テンプレートで {{ conversation.user_profile.name }} を差し込めば、確実に個別化できます(参考: Variables | Dify、参考: Template | Dify)。

この記事のサンプルフローをそのまま複製し、変数名やキーを自分の業務用語に置き換えると理解が一気に進みます。

たとえばテンプレートでは次のように参照できます。

{{ conversation.order.items | length }} 件のご注文を確認しました。

この3点が固まれば、次の応用ステップにも安全に進めます。

関連ガイドも併読すると効率的です(例:Difyの使い方・機能・料金ガイドDify Workflow完全ガイド)。

学習ステップ2:環境変数・RAG・外部APIとの連携に広げる

次の一歩は、環境変数で機密と設定を分離しつつ、会話変数をRAGやHTTPリクエストのパラメータに渡す設計へ拡張することです。

そうすることで、セキュアかつ再利用可能なフローになり、社内ナレッジ検索やSaaS自動連携が実務レベルで回り始めます。

具体的には、API_BASE_URLやAPI_KEYをSecretとして環境変数に置き、RAGノードは conversation.topic を検索クエリに、HTTPノードは conversation.payload をJSON Bodyに渡します(参考: Environment Variables Explanation | Dify)。

構成イメージは次の図がわかりやすいです。

Difyワークフローの構成図。左に環境変数(API_BASE_URL, API_KEY Secret)、中央に会話変数、右にRAGノードとHTTPリクエストノード。会話変数がパラメータとして両ノードへ渡り、環境変数はHTTP先や認証に適用される様子をロックアイコン付きで示す

手順は本サイトのRAG構築手順とワークフロー入門が役に立ちます(Dify×RAG完全ガイドDifyの「ナレッジ」完全ガイドDifyのセキュリティ解説)。

外部APIの呼び出し構造を理解したい場合は、API実装の基礎としてこちらもおすすめです(OpenAI APIをPythonで完全解説)。

学習ステップ3:エラー事例から逆算して設計パターンを洗練させる

ある程度動くようになったら、あえて失敗を再現してデバッグの型を体験的に身につけるのが近道です。

この演習で最も学びが大きいのは、値の上書きミス、型不一致、そしてHTTP BodyのJSON破損です。

実プロジェクトでは、数値を文字列で送って外部APIに400を返され、デバッグログで会話変数の型を確認し、テンプレートでJSONエスケープ後に解決したことがありました。

再現テストでは、変数代入ノード直後にログを確認し、どの分岐で値がnullや意図しない型に変わったかを特定すると修復が速くなります。

詳細な事例や既知の制約は以下のスレッドが参考になります。

この訓練を踏めば、本番運用でのMTTRが短縮し、設計パターンが一段上の堅牢性に到達します。

Dify以外のAIワークフロー/チャットボットツールとの比較観点

比較の軸は「変数の扱いやすさ」「テンプレートエンジンの有無」「RAGやツール連携の統合度」を外さないことです。

理由は、ここが整っていないと、複雑化した後に運用コストやバグ頻度が跳ね上がるからです。

Difyは会話変数とJinja2テンプレート、RAGやHTTPノードを一枚のキャンバスで統合でき、非エンジニアでも短期間で実務フローに到達しやすい特長があります(参考: Variables | Dify、参考: Template | Dify)。

他ツールを検討する際は、「自分の業務に必要な変数機能があるか」を要件表に落とし、上記3軸で採点すると見極めが容易になります。

全体比較の視点は次の記事も参考になります(ノーコードAIアプリ開発の完全比較AIエージェント市場徹底比較)。

体系的に学習を進めたい場合は、オンライン講座で基礎〜実践を短期で固めるのも有効です(例:DMM 生成AI CAMPAidemy)。

まとめ:Difyの変数を武器に、次の一歩へ

変数の種類とスコープ、設定場所、Jinja2活用、会話変数+代入ノードによる状態管理を要点整理。

典型エラーの回避とデバッグ、コスト設計の勘所も押さえました。今日から設計の精度と速度は変えられます。

まずはこの記事のサンプルを基に「会話変数+変数代入ノード+テンプレート」だけでミニボットを1つ作り、必要に応じてRAGやAPI連携を足しましょう。

プラン確認はDify公式サイト、深掘りは生成AI 最速仕事術DMM 生成AI CAMPで前進を。