- 技術 💻
Difyの使い方|ワークフローの作り方とノード一覧
Dify は、LLM を使うアプリを画面上で「ノード(処理の箱)」をつないで作るツールです。 1回の入力を処理して結果を返すなら「ワークフロー」、会話を続けるなら「チャットフロー」を選び、開始ノードから順に LLM・知識検索・条件分岐などをつなぎます。作ったアプリは、DSL(YAML ファイル)で書き出せ、API から呼べます。
| アプリの種類 | DSL の mode |
最後に置くノード | API |
|---|---|---|---|
| ワークフロー | workflow |
出力(Output。以前の「終了」) | POST /v1/workflows/run |
| チャットフロー | advanced-chat |
回答(Answer) | POST /v1/chat-messages |
| やりたいこと | 見出し |
|---|---|
| どのノードを使うか決めたい | ノード一覧と使いどころ |
| 問い合わせ対応の bot を作りたい | 作例:問い合わせの一次対応 |
| YAML で受け渡し・レビューしたい | DSL(YAML)の書き方 |
| 自分のシステムから呼びたい | API から呼ぶ |
| 自社のサーバーで動かしたい | Docker Compose で立てる |
確認環境:Dify 1.17.1(2026年9月10日のリリース。GitHub のリリース一覧で「Latest」の版)のソースを git clone して確かめました。ノードの種類はソースの定義(Dify が使うワークフロー実行ライブラリ graphon 0.7.0 の BuiltinNodeTypes と、Dify 側のトリガー・知識検索の定義)で、DSL の版と読み込みの判定は api/services/app_dsl_service.py・api/services/dsl_version.py で、作例の DSL は graphon 0.7.0 のノードの定義クラス(Pydantic)と DSL 読み込み関数で検証しました。API のリクエストの項目と SSE のイベントの種類は api/controllers/service_api・api/core/app/entities/task_entities.py で、送るコードは Dify の応答の形を返す擬似サーバー(手元の小さな HTTP サーバー)に向けて Python 3.11.15・requests 2.34.2 で確かめました。Docker Compose の構成と既定値は docker/ のファイルで、必要なスペックと手順は docs.dify.ai で確かめました。Dify を起動してモデルを動かすことはしていません(確認日 2026年10月13日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Difyの使い方|ワークフローの作り方とノード一覧」
Dify のワークフローとは
ワークフローは「入力 → いくつかの処理 → 出力」を図で組む機能です。 プロンプト1つでは足りない処理(分類してから別々に答える、資料を検索してから答える、外部 API を呼ぶ)を、ノードの組み合わせで作れます。
| 比べる点 | ワークフロー | チャットフロー |
|---|---|---|
| 向く用途 | 1回で終わる処理(要約・分類・データ変換・定期実行) | 会話を続ける bot(問い合わせ対応・社内ヘルプ) |
| 入力 | 開始ノードで決めた変数 | ユーザーの発言(sys.query)と、開始ノードの変数 |
| 結果の返し方 | 出力ノードの変数をまとめて返す | 回答ノードの文を返す(途中で何度でも置ける) |
| 会話の記憶 | 無い | LLM ノードのメモリ・会話変数 |
| 定期実行・Webhook | トリガーで起動できる | - |
関連記事「AIエージェントとは|仕組みとワークフローとの違い・作り方入門」で、決まった手順の「ワークフロー」と、手順をモデルが決める「エージェント」の違いを扱っています。
ワークフローの作り方(手順)
- アプリを作る:スタジオで「最初から作成」を選び、種類(ワークフロー/チャットフロー)を選ぶ
- モデルを使えるようにする:設定の「モデルプロバイダー」で、OpenAI などのプラグインを入れ、API キーを登録する
- 開始ノードに入力を決める:ワークフローなら
textなどの変数を足す。チャットフローはsys.query(ユーザーの発言)が最初からある - ノードを足してつなぐ:ノードの右の「+」から次のノードを選ぶ。前のノードの出力は
{{#ノードID.変数名#}}で参照する - 出口を置く:ワークフローは出力ノード、チャットフローは回答ノード
- 試す:右上の「実行」(チャットフローは「プレビュー」)で動かし、各ノードの入力・出力・かかった時間を確かめる
- 公開する:「公開する」を押すと、Web アプリと API から使える。API キーは「API アクセス」で作る
変数の参照のしかた
| 書き方 | 中身 |
|---|---|
{{#ノードID.変数名#}} |
前のノードの出力。例:{{#llm.text#}} |
{{#sys.query#}} |
チャットフローのユーザーの発言 |
{{#sys.files#}} |
ユーザーが添付したファイル |
{{#env.名前#}} |
環境変数(API キーなどの定数) |
{{#conversation.名前#}} |
会話変数(チャットフローで会話のあいだ持つ値) |
{{#context#}} |
LLM ノードの「コンテキスト」に入れた知識検索の結果 |
ノード設定の入力欄では、/ を打つと変数を選べます。ソースの定義では、sys・env・conversation は決まった名前空間です(ドキュメントの画面の説明では、ユーザーの発言が userinput.query と表示される箇所があります)。
ノード一覧と使いどころ
Dify 1.17.1 のソースで決まっているノードの種類は、次のとおりです。 「DSL の type」は YAML の data.type に書く値です。
入口と出口
| ノード(画面) | DSL の type | 使いどころ |
|---|---|---|
| 開始(User Input) | start |
入力の変数(文字・段落・選択・数値・ファイル)を決める |
| 出力(Output。以前は End) | end |
ワークフローの結果を返す。チャットフローでは使えない |
| 回答(Answer) | answer |
チャットフローで返答の文を返す。途中にも置ける |
| スケジュールトリガー | trigger-schedule |
決まった時刻にワークフローを起動 |
| Webhook トリガー | trigger-webhook |
外部からの HTTP で起動 |
| インテグレーショントリガー | trigger-plugin |
プラグインのイベントで起動 |
ドキュメントによると、出力ノードは以前「End」という名前で、今は必須ではありません。複数置くと、実行された全部の出力ノードの変数が1つにまとめられ、名前が重なると後から来た値で上書きされます。
LLM と知識
| ノード | DSL の type | 使いどころ |
|---|---|---|
| LLM | llm |
文章の生成・要約・判断。コンテキスト・メモリ・構造化出力・画像の入力を設定できる |
| 知識検索(Knowledge Retrieval) | knowledge-retrieval |
ナレッジ(登録した文書)から関係する部分を探す。出力は result |
| 質問分類器(Question Classifier) | question-classifier |
入力を LLM でクラスに分け、クラスごとに分岐する |
| パラメータ抽出(Parameter Extractor) | parameter-extractor |
文から日付・金額・名前などを取り出して変数にする |
| エージェント(Agent) | agent |
推論とツールの呼び出しをくり返して作業させる |
| 人の入力(Human Input) | human-input |
途中で止めて、人の確認・入力を待つ |
分岐とくり返し
| ノード | DSL の type | 使いどころ |
|---|---|---|
| 条件分岐(IF/ELSE) | if-else |
文字を含む・等しい・空などの条件で分ける |
| イテレーション(Iteration) | iteration |
配列の要素ごとに同じ処理をする(中の始まりは iteration-start) |
| ループ(Loop) | loop |
条件を満たすまでくり返す(loop-start・loop-end) |
| 変数集約(Variable Aggregator) | variable-aggregator |
分かれた枝の結果を1つの変数にまとめる |
データの加工と外部連携
| ノード | DSL の type | 使いどころ |
|---|---|---|
| コード(Code) | code |
Python か JavaScript で加工する。main() が dict を返す |
| テンプレート(Template) | template-transform |
Jinja2 で文を組み立てる |
| 文書抽出(Document Extractor) | document-extractor |
アップロードされた PDF・Word などから文字を取り出す |
| リスト操作(List Operator) | list-operator |
配列の絞り込み・並べ替え・先頭 N 件 |
| 変数代入(Variable Assigner) | assigner |
会話変数に値を書き込む(チャットフロー) |
| HTTP リクエスト | http-request |
外部の API を呼ぶ |
| ツール | tool |
プラグインのツール(検索・Slack など)や、他のワークフローを呼ぶ |
ソースには、このほか RAG パイプライン用の datasource・knowledge-index と、以前の DSL を読むための variable-assigner(変数集約の以前の type)があります。
ノードの選び方の目安
| したいこと | 向くノード | 理由 |
|---|---|---|
| 「障害・質問・要望」に分ける | 質問分類器 | 分岐の出口がクラスごとにでき、条件を書かなくてよい |
| 「件名に【至急】を含む」で分ける | 条件分岐 | LLM を呼ばないので速く、結果が毎回同じ |
| 文から値を取り出して次のノードで使う | パラメータ抽出 | 型つきの変数になる |
| 文字の整形・計算・JSON の加工 | コード | LLM より速く、結果が毎回同じ |
| 決まった形の文を組み立てる | テンプレート | コードより手軽 |
| 複数の文書を1件ずつ要約する | イテレーション | 配列を受けて要素ごとに処理する |
| 分岐した結果を後ろで1本にする | 変数集約 | どの枝を通っても同じ変数名で受け取れる |
作例:問い合わせの一次対応(チャットフロー)
問い合わせを3つに分け、使い方の質問はナレッジを根拠に答え、不具合は状況を聞き取り、その他は窓口を案内する bot です。
開始 ─→ 質問分類器 ─┬─ ① 使い方の質問 ─→ 知識検索 ─→ LLM(回答) ─→ 回答
├─ ② 不具合の報告 ─→ LLM(聞き取り) ─→ 回答
└─ ③ その他 ─→ 回答(窓口の案内文)
各ノードの設定
| ノード | 設定 | 値 |
|---|---|---|
| 質問分類器 | 入力変数 | sys.query |
| 質問分類器 | クラス | ①製品の使い方・設定方法の質問 ②不具合・エラーの報告 ③料金・契約・その他 |
| 質問分類器 | 指示 | 迷ったら「料金・契約・その他」に分類する |
| 知識検索 | ナレッジ | 製品マニュアルを登録したナレッジ |
| 知識検索 | Top K | 4 |
| LLM(回答) | コンテキスト | 知識検索の result |
| LLM(回答) | temperature | 0.2(答えのぶれを小さく) |
| LLM(聞き取り) | メモリ | 有効(直近10件)。聞き取りを何往復か続けるため |
ドキュメントでは、質問分類器のクラスの説明文は LLM が分岐を選ぶときに読む部分で、重なりそうなクラスには「〜を除く」のような境目を書くと分けやすくなる、とあります。迷う入力の扱いは「指示」欄に書きます。
LLM(回答)のシステムプロンプト
あなたは製品サポートの担当です。次の資料だけを根拠に、手順を番号付きで答えます。
資料に無いことは「担当者から折り返します」と答えます。
<資料>
{{#context#}}
</資料>
{{#context#}} は、コンテキストに知識検索の result を入れたときだけ中身が入ります。 コンテキストを設定し忘れると、資料の無いプロンプトになります。資料に無いことを答えさせない書き方は、関連記事「ハルシネーション対策のプロンプト集|根拠と出典を求める書き方」で扱っています。
LLM(聞き取り)のシステムプロンプト
あなたは不具合受付の担当です。原因は推測で断定しません。
発生日時・操作の手順・エラーの文・使っている環境のうち、まだ聞いていないものを最大3つ質問します。
聞き取った内容を記録したいときは、変数代入ノードで会話変数に書き込むか、HTTP リクエストノードでチケットの API に送ります。
DSL(YAML)の書き方
DSL は、Dify のアプリを YAML で表したファイルです。 スタジオの「DSL をエクスポート」で書き出し、「DSL ファイルをインポート」で読み込めます。Git で管理する、別の環境へ移す、レビューする、といった用途に使えます。
上の作例の DSL
app:
description: 問い合わせを分類し、使い方はナレッジで回答、不具合は聞き取り、その他は窓口を案内する
icon: 🤖
icon_background: '#FFEAD5'
mode: advanced-chat
name: 問い合わせ一次対応
use_icon_as_answer_icon: false
dependencies: []
kind: app
version: 0.7.0
workflow:
conversation_variables: []
environment_variables: []
features: {}
graph:
edges:
- {id: start-classifier, source: start, sourceHandle: source, target: classifier, targetHandle: target}
- {id: classifier-1-retrieval, source: classifier, sourceHandle: '1', target: retrieval, targetHandle: target}
- {id: classifier-2-llm_bug, source: classifier, sourceHandle: '2', target: llm_bug, targetHandle: target}
- {id: classifier-3-answer_other, source: classifier, sourceHandle: '3', target: answer_other, targetHandle: target}
- {id: retrieval-llm_howto, source: retrieval, sourceHandle: source, target: llm_howto, targetHandle: target}
- {id: llm_howto-answer_howto, source: llm_howto, sourceHandle: source, target: answer_howto, targetHandle: target}
- {id: llm_bug-answer_bug, source: llm_bug, sourceHandle: source, target: answer_bug, targetHandle: target}
nodes:
- id: start
type: custom
position: {x: 80, y: 280}
data:
type: start
title: 開始
desc: ''
variables: []
- id: classifier
type: custom
position: {x: 380, y: 280}
data:
type: question-classifier
title: 質問分類器
desc: ''
query_variable_selector: [sys, query]
model:
provider: langgenius/openai/openai
name: gpt-6-luna
mode: chat
completion_params:
temperature: 0
classes:
- id: '1'
name: 製品の使い方・設定方法の質問
- id: '2'
name: 不具合・エラーの報告
- id: '3'
name: 料金・契約・その他
instruction: 迷ったら「料金・契約・その他」に分類する
- id: retrieval
type: custom
position: {x: 680, y: 120}
data:
type: knowledge-retrieval
title: 知識検索
desc: ''
query_variable_selector: [sys, query]
dataset_ids: [ここにナレッジのID]
retrieval_mode: multiple
multiple_retrieval_config:
top_k: 4
score_threshold: null
reranking_enable: false
- id: llm_howto
type: custom
position: {x: 980, y: 120}
data:
type: llm
title: 回答を作る
desc: ''
model:
provider: langgenius/openai/openai
name: gpt-6-luna
mode: chat
completion_params:
temperature: 0.2
context:
enabled: true
variable_selector: [retrieval, result]
prompt_template:
- role: system
text: |-
あなたは製品サポートの担当です。次の資料だけを根拠に、手順を番号付きで答えます。
資料に無いことは「担当者から折り返します」と答えます。
<資料>
{{#context#}}
</資料>
- role: user
text: '{{#sys.query#}}'
vision:
enabled: false
- id: answer_howto
type: custom
position: {x: 1280, y: 120}
data:
type: answer
title: 回答(使い方)
desc: ''
answer: '{{#llm_howto.text#}}'
variables: []
- id: llm_bug
type: custom
position: {x: 680, y: 300}
data:
type: llm
title: 聞き取り
desc: ''
model:
provider: langgenius/openai/openai
name: gpt-6-luna
mode: chat
completion_params:
temperature: 0.2
context:
enabled: false
variable_selector: []
memory:
window:
enabled: true
size: 10
query_prompt_template: '{{#sys.query#}}'
prompt_template:
- role: system
text: |-
あなたは不具合受付の担当です。原因は推測で断定しません。
発生日時・操作の手順・エラーの文・使っている環境のうち、まだ聞いていないものを最大3つ質問します。
vision:
enabled: false
- id: answer_bug
type: custom
position: {x: 980, y: 300}
data:
type: answer
title: 回答(不具合)
desc: ''
answer: '{{#llm_bug.text#}}'
variables: []
- id: answer_other
type: custom
position: {x: 680, y: 480}
data:
type: answer
title: 回答(その他)
desc: ''
answer: 料金・契約のお問い合わせは、営業窓口(平日10時〜17時)で承ります。
variables: []
dataset_ids は、自分の環境のナレッジの ID に置き換えます(エクスポートした DSL では、ナレッジの ID は暗号化された値で書き出されます)。モデルの provider は、モデルプロバイダーのプラグインの名前(例:langgenius/openai/openai)です。インポート先に同じプラグインが入っていないと、そのモデルは使えません。
この DSL を検証した結果
| 確かめたこと | 結果 |
|---|---|
開始・質問分類器・LLM×2・回答×3 の data を graphon 0.7.0 のノードの定義クラスで読む |
全部エラーなし |
知識検索の data を Dify 1.17.1 の KnowledgeRetrievalNodeData で読む |
エラーなし(retrieval_mode='multiple'・top_k=4) |
graphon の DSL 読み込み関数 inspect() |
種類は app。知識検索は graphon 単体では扱えないため「unsupported」 |
知識検索を除いた形で inspect() |
loadable |
エッジの source を存在しないノードにする |
Graph edge references an unknown node. |
DSL の書き方の要点
| 項目 | 内容(ソースで確認) |
|---|---|
version |
1.17.1 が書き出す DSL の版は 0.7.0(api/constants/dsl_version.py) |
kind |
app |
app.mode |
workflow・advanced-chat(チャットフロー)など |
workflow.graph.nodes |
ノードの配列。id と data.type が必須。position は画面の位置 |
workflow.graph.edges |
線の配列。source・target にノードの id |
sourceHandle |
普通は source。質問分類器はクラスの id、条件分岐は true・false やケースの id |
| 変数の参照 | value_selector: [ノードID, 変数名] か、文の中の {{#ノードID.変数名#}} |
dependencies |
使うプラグイン(モデル・ツール)。インポート時に足りないものを案内する |
質問分類器の枝は、sourceHandle にクラスの id を書きます。 ソースでも、分類の結果のクラスの id を、次に進むエッジの sourceHandle として使っていました。
版が違う DSL を読み込んだときの扱い
インポート時の判定は check_version_compatibility() で次のとおりでした(今の版は 0.7.0)。
読み込む DSL の version |
結果 |
|---|---|
| 0.7.0(同じ) | 完了 |
| 0.7.0 より新しい(例:0.8.0) | 保留(確認を求める) |
| メジャー番号が小さい | 保留 |
| マイナー番号が小さい(例:0.3.1・0.6.0) | 完了。ただし警告つき |
| 版として読めない文字 | 失敗 |
Dify のテストに入っている DSL の見本は version: 0.3.1 のものが20件ありました。以前の版で書き出した DSL も、警告つきで読み込まれる扱いです。YAML の書き方そのものは、関連記事「Python設定ファイルの読み込み|ini・TOML・YAML・JSON比較」でも扱っています。
API から呼ぶ
公開したアプリは、アプリごとの API キー(app- で始まる)で呼びます。 キーはアプリの「API アクセス」で作り、Authorization: Bearer app-... ヘッダで送ります。セルフホストでは、nginx が /v1 を API のコンテナ(api:5001)へ渡す設定でした。
| アプリ | エンドポイント | 必須の項目 |
|---|---|---|
| チャットフロー・チャット | POST /v1/chat-messages |
inputs・query・user |
| ワークフロー | POST /v1/workflows/run |
inputs・user |
| 止める | POST /v1/chat-messages/{task_id}/stop・/v1/workflows/tasks/{task_id}/stop |
user |
Python のコード(requests)
import json, os
import requests
BASE_URL = os.environ.get("DIFY_BASE_URL", "http://localhost/v1") # API アクセス画面の URL
API_KEY = os.environ["DIFY_API_KEY"] # app-...
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def chat(query: str, user: str, conversation_id: str = "", inputs: dict | None = None) -> dict:
"""チャットフローに1回聞く(blocking)"""
r = requests.post(
f"{BASE_URL}/chat-messages",
headers=HEADERS,
json={
"inputs": inputs or {},
"query": query,
"response_mode": "blocking",
"conversation_id": conversation_id, # 空なら新しい会話
"user": user, # 必須。利用者を区別する文字列
},
timeout=120,
)
r.raise_for_status()
return r.json()
def chat_stream(query: str, user: str, conversation_id: str = ""):
"""チャットフローに聞き、SSE を1イベントずつ返す(streaming)"""
with requests.post(
f"{BASE_URL}/chat-messages",
headers=HEADERS,
json={"inputs": {}, "query": query, "response_mode": "streaming",
"conversation_id": conversation_id, "user": user},
stream=True,
timeout=(10, 300),
) as r:
r.raise_for_status()
for raw in r.iter_lines(): # bytes で受ける
line = raw.decode("utf-8") # charset が無くても UTF-8 で読む
if line.startswith("data: "):
yield json.loads(line[len("data: "):])
def run_workflow(inputs: dict, user: str) -> dict:
"""ワークフローを実行する(blocking)"""
r = requests.post(
f"{BASE_URL}/workflows/run",
headers=HEADERS,
json={"inputs": inputs, "response_mode": "blocking", "user": user},
timeout=120,
)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
res = chat("パスワードの変え方は?", user="user-001")
print(res["answer"], res["conversation_id"])
answer = ""
for ev in chat_stream("パスワードの変え方は?", user="user-001",
conversation_id=res["conversation_id"]):
if ev["event"] == "message":
answer += ev["answer"]
elif ev["event"] == "message_end":
print("usage:", ev["metadata"].get("usage"))
elif ev["event"] == "error":
raise RuntimeError(ev.get("message"))
print(answer)
wf = run_workflow({"text": "VPNにつながりません"}, user="user-001")
print(wf["data"]["status"], wf["data"]["outputs"])
擬似サーバーで受けた、送られた中身です。
POST /v1/chat-messages
Authorization: Bearer app-test123
Content-Type: application/json
{"inputs": {}, "query": "パスワードの変え方は?", "response_mode": "blocking", "conversation_id": "", "user": "user-001"}
POST /v1/chat-messages
{"inputs": {}, "query": "パスワードの変え方は?", "response_mode": "streaming", "conversation_id": "8f0c6d2e-1b7a-4c1e-9a55-3f2b1d0e4c11", "user": "user-001"}
POST /v1/workflows/run
{"inputs": {"text": "VPNにつながりません"}, "response_mode": "blocking", "user": "user-001"}
SSE を iter_lines(decode_unicode=True) で読むと、文字化けすることがあります。 擬似サーバーが Content-Type: text/event-stream だけを返したとき(charset なし)、requests は ISO-8859-1 として読み、日本語が 1. è¨å®... のように化けました。上のコードのように bytes で受けて decode("utf-8") すると、正しく読めました。
リクエストの項目(ソースの定義)
| 項目 | 内容 |
|---|---|
inputs |
開始ノードの変数。必須(無ければ {}) |
query |
ユーザーの発言(chat-messages で必須) |
response_mode |
blocking か streaming。省くと blocking(新しいエージェントのアプリを除く) |
user |
利用者を区別する文字列。無いと Arg user must be provided. |
conversation_id |
会話を続けるときに前の返答の値を入れる。空なら新しい会話。UUID の形でないとエラー |
files |
画像・文書など。ローカルのファイルは先にアップロードして upload_file_id を使う |
auto_generate_name |
会話のタイトルを自動で作るか(既定 true) |
workflow_id |
公開済みの特定の版を実行する(チャットフロー) |
blocking の応答(チャットフロー)は、event・task_id・id・message_id・conversation_id・mode・answer・metadata・created_at を持つ JSON です。ワークフローの blocking の応答は、task_id・workflow_run_id と、data(status・outputs・error・elapsed_time・total_tokens・total_steps など)です。OpenAPI の定義には「Dify Cloud ではタイムアウトまでに返らないと接続が切れることがある」との注意があり、streaming が推奨とされています。
SSE のイベントの種類(ソースの StreamEvent)
SSE は data: {JSON} の行と空行のくり返しで、接続を保つための event: ping も届きます(ソースの convert_to_event_stream)。
| イベント | 中身・使いどころ | 主に出るアプリ |
|---|---|---|
message |
回答の断片(answer)。つなげると全文 |
チャット・チャットフロー |
message_end |
回答の終わり。metadata に使用量や引用 |
チャット・チャットフロー |
message_replace |
回答の差し替え(内容の審査で置き換えたときなど) | チャット・チャットフロー |
message_file |
回答に付いたファイル | チャット・チャットフロー |
text_chunk |
ワークフローの出力の断片(data.text) |
ワークフロー |
workflow_started・workflow_finished |
実行の始まりと終わり。終わりの data.outputs に結果 |
両方 |
workflow_paused |
人の入力などで一時停止 | 両方 |
node_started・node_finished・node_retry |
ノードごとの始まり・終わり・再試行 | 両方 |
iteration_started・iteration_next・iteration_completed |
イテレーションの進み | 両方 |
loop_started・loop_next・loop_completed |
ループの進み | 両方 |
agent_thought・agent_message・agent_log |
エージェントの考えと途中経過 | エージェント |
reasoning_chunk |
推論の断片(推論を分けて出す設定のとき) | 両方 |
human_input_required・human_input_form_filled・human_input_form_timeout |
人の入力の待ち・入力済み・時間切れ | 両方 |
tts_message・tts_message_end |
読み上げの音声 | 両方 |
error |
エラー。ストリームの途中で届く | 全部 |
ping |
接続を保つ(event: ping の行) |
全部 |
チャットフローの回答は message、ワークフローの出力は text_chunk で届きます。 ワークフローの最終結果は workflow_finished の data.outputs で受け取ります。ストリームの読み方は、関連記事「Pythonのrequestsの使い方|タイムアウト・エラー処理・再試行まで」でも扱っています。
エラーの応答(chat-messages のドキュメント文字列)
| HTTP | code |
意味 |
|---|---|---|
| 400 | app_unavailable |
アプリが使えない・設定の不足 |
| 400 | not_chat_app |
アプリの種類とエンドポイントが合わない(ワークフローに chat-messages を送ったなど) |
| 400 | provider_not_initialize |
モデルプロバイダーの API キーが無い |
| 400 | provider_quota_exceeded |
モデルプロバイダーの利用枠を使い切った |
| 400 | completion_request_error |
文章の生成に失敗した |
| 404 | not_found |
会話が無い(conversation_id の間違い) |
| 429 | too_many_requests |
このアプリへの同時のリクエストが多すぎる |
| 429 | rate_limit_error |
Dify Cloud のワークフロー実行の枠に達した |
認証のヘッダが Bearer で始まらないと、Authorization header must be provided and start with 'Bearer' になります(ソースの wraps.py)。429 への備えは、関連記事「LLM APIの429・529エラー対処|リトライ実装とエラー一覧」で扱っています。キーの置き場所は、関連記事「.envの使い方と注意点|APIキーを安全に管理する方法」で扱っています。
Docker Compose で自分のサーバーに立てる
セルフホスト版は、リポジトリの docker/ にある docker-compose.yaml で起動します。
必要なスペック(ドキュメント)
| 項目 | 値 |
|---|---|
| CPU | 2コア以上 |
| メモリ | 4GiB 以上 |
| Linux | Docker 19.03 以上、Docker Compose 2.24.0 以上 |
| macOS | Docker Desktop。仮想マシンに 2 vCPU・8GiB 程度を割り当てる |
| Windows | WSL 2 と Docker Desktop。ソースは Linux 側のファイルシステムに置く |
起動の手順
git clone --branch 1.17.1 https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
docker compose up -d
docker compose ps # init_permissions が Exited なのは正常
ブラウザで http://サーバーのIP/install を開き、管理者のアカウントを作ります。2回目からは / でログインします。.env.example では SECRET_KEY が空で、コメントに「空なら、ストレージのディレクトリに永続のキーを自動で作る」とありました。
起動するコンテナ(1.17.1 の docker-compose.yaml)
| 役割 | サービス | イメージ |
|---|---|---|
| API・画面 | api・api_websocket・web |
langgenius/dify-api:1.17.1・langgenius/dify-web:1.17.1 |
| 非同期の処理 | worker・worker_beat |
langgenius/dify-api:1.17.1 |
| プラグイン | plugin_daemon |
langgenius/dify-plugin-daemon:0.6.10-local |
| コードの実行 | sandbox・local_sandbox |
langgenius/dify-sandbox:0.2.15 など |
| エージェント | agent_backend・agent_ssrf_proxy |
langgenius/dify-agent-backend:1.17.1 など |
| DB・キャッシュ | db_postgres・redis |
postgres:15-alpine・redis:6-alpine |
| ベクトル DB | weaviate(既定) |
VECTOR_STORE で qdrant・pgvector なども選べる |
| 入口・外への通信 | nginx・ssrf_proxy |
nginx・squid |
.env.example の COMPOSE_PROFILES は ${VECTOR_STORE:-weaviate},${DB_TYPE:-postgresql},collaboration で、ベクトル DB と DB の種類に合わせて起動するコンテナが変わります。Compose の基本は、関連記事「Docker Composeの使い方|compose.yamlの書き方と開発環境の作り方」で扱っています。ベクトル DB を PostgreSQL にまとめたいときは、関連記事「pgvectorの使い方|PostgreSQLでベクトル検索をコピペで構築」も参考になります。
1.17.1 で変わった点(リリースノート)
- 同梱の Weaviate を使うセルフホストでは、1.17.1 を起動する前に Weaviate を 1.27.0 から 1.39.2 へ段階的に上げる手順が必要
- 1.17.0 で、タイムアウトの既定が 1200 秒から 3600 秒に延びた
- 1.17.0 で、環境変数
EDITIONがDEPLOYMENT_EDITIONに変わり、ENTERPRISE_ENABLEDは無くなった
アップグレードの前に、新しい .env.example と自分の .env を比べます(ドキュメントの案内)。
設計の前に知っておく上限値(1.17.1 の既定値)
| 環境変数 | 既定値 | 意味 |
|---|---|---|
WORKFLOW_MAX_EXECUTION_STEPS |
500 | 1回の実行で動かすノードの最大数 |
WORKFLOW_MAX_EXECUTION_TIME |
3600 | 1回の実行の最大秒数 |
WORKFLOW_CALL_MAX_DEPTH |
5 | ワークフローから呼ぶワークフローの深さ |
APP_MAX_EXECUTION_TIME |
3600 | アプリの実行の最大秒数 |
MAX_ITERATIONS_NUM |
99 | イテレーションの最大回数 |
LOOP_NODE_MAX_COUNT |
100 | ループの最大回数 |
MAX_VARIABLE_SIZE |
204800 | 変数1つの最大バイト数 |
CODE_MAX_STRING_LENGTH |
400000 | コードノードが返す文字の最大長 |
CODE_MAX_STRING_ARRAY_LENGTH・CODE_MAX_OBJECT_ARRAY_LENGTH |
30 | コードノードが返す配列の最大長 |
CODE_MAX_NUMBER_ARRAY_LENGTH |
1000 | 数値の配列の最大長 |
CODE_MAX_DEPTH |
5 | コードノードが返すオブジェクトの深さ |
SANDBOX_WORKER_TIMEOUT |
15 | コードの実行の最大秒数 |
HTTP_REQUEST_NODE_MAX_TEXT_SIZE |
1048576 | HTTP リクエストノードで扱う文字データの最大バイト数 |
UPLOAD_FILE_SIZE_LIMIT |
15 | アップロードの上限(MB) |
値は docker/envs/core-services/ の *.env.example にあります。コードノードで31件以上の文字列の配列を返すと上限に当たります。 件数の多いデータは、JSON の文字列にして返すか、上限を上げます。ドキュメントでは、コードノードのサンドボックスはファイルやシステムコマンドを使えず、外への通信は SSRF プロキシ経由とされています。
よくある質問
Q. ワークフローとチャットフローは、あとで変えられますか。
A. DSL の mode が違い、置けるノード(出力と回答)も違います。作り直すつもりで選びます。会話の記憶が要るならチャットフローです。
Q. Dify Cloud とセルフホストの違いは?
A. Cloud はサーバーの用意が要らず、セルフホストは自社のネットワークにデータを置けます。セルフホストでは、上の上限値を .env で変えられます。
Q. ローカル LLM を使えますか。
A. モデルプロバイダーのプラグインに Ollama などがあります。Ollama 自体は関連記事「Ollamaの使い方|ローカルLLMのコマンド一覧とAPIの呼び方」で扱っています。Docker の中の Dify から、ホストの Ollama へは localhost ではつながらない点に注意します。
Q. LangChain との使い分けは? A. Dify は画面で組み、そのまま Web アプリと API になります。LangChain は Python のコードで組みます。画面で業務の人と一緒に直したいなら Dify、細かい制御やテストをコードで持ちたいなら LangChain、という分け方ができます。LangChain は関連記事「LangChain入門|PythonでLLMアプリを作る基本とコピペ集」で扱っています。
Q. ナレッジの精度が上がりません。 A. 文書の分け方・Top K・スコアのしきい値・リランクで変わります。考え方は関連記事「RAGの精度改善の方法一覧|原因の切り分けと評価指標の計算」で扱っています。
まとめ
- 1回で終わる処理は ワークフロー(
workflow・出力ノード)、会話は チャットフロー(advanced-chat・回答ノード) - 前のノードの値は
{{#ノードID.変数名#}}、ユーザーの発言は{{#sys.query#}} - 分類は 質問分類器(LLM)か 条件分岐(ルール)。分岐を戻すのは 変数集約
- DSL は
version: 0.7.0(1.17.1)。質問分類器の枝はsourceHandleにクラスの id - API は
/v1/chat-messages(query・user必須) と/v1/workflows/run。SSE は bytes で受けて UTF-8 で読む - セルフホストは 2コア・4GiB 以上、
cp .env.example .env→docker compose up -d→/install - 上限(500 ステップ・コードの配列 30 件・コード 15 秒など)を設計の前に確かめる
参考・出典
確認日はいずれも 2026年10月13日です。
- GitHub「langgenius/dify」Releases:https://github.com/langgenius/dify/releases
- GitHub「langgenius/dify」1.17.1 のソース:https://github.com/langgenius/dify/tree/1.17.1
- Dify ドキュメント「Deploy with Docker Compose」:https://docs.dify.ai/en/self-host/quick-start/docker-compose
- Dify ドキュメント「Environment Variables」:https://docs.dify.ai/en/self-host/deploy/configuration/environments
- Dify ドキュメント「LLM」:https://docs.dify.ai/en/use-dify/nodes/llm
- Dify ドキュメント「Question Classifier」:https://docs.dify.ai/en/self-host/use-dify/nodes/question-classifier
- Dify ドキュメント「Knowledge Retrieval」:https://docs.dify.ai/en/self-host/use-dify/nodes/knowledge-retrieval
- Dify ドキュメント「Output」:https://docs.dify.ai/en/self-host/use-dify/nodes/output
- Dify ドキュメント「Code」:https://docs.dify.ai/en/self-host/use-dify/nodes/code
- Dify API リファレンス(OpenAPI):https://docs.dify.ai/en/api-reference/openapi_service.json
- PyPI「graphon」:https://pypi.org/project/graphon/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Difyの使い方|ワークフローの作り方とノード一覧」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。