発注申請を対話で受け付けると、「前の発言を覚えること」と「どの内容を承認し、処理したかを残すこと」が同じ状態管理に見えます。しかし、数量の言い直しや通信切断が起きると、この二つの違いが表面化します。
この記事は、Difyで対話型の業務システムを設計するエンジニアに向けた設計例です。Chatflowには聞き取り、Workflowには確定した入力の処理、業務側のDBには承認と実行状態を持たせる構成を検討します。製品仕様は2026年10月4日に公式資料で確認しました。業務構成は設計案であり、Dify接続・DB連携・本番運用は未検証です。
ChatflowとWorkflowの違いは状態の寿命から見る
Difyの公式資料では、Workflowは単発のタスク、Chatflowは会話の各ターンで起動するアプリとして説明されています。ChatflowではLLMノードのメモリと、会話をまたいで保持・更新できる会話変数を使えます。Dify Key Concepts
| 観点 | Chatflow | Workflow |
|---|---|---|
| 自然な入力単位 | 会話の1ターン | 1回のタスク入力 |
| 持ち越す状態 | 同一会話の会話変数、設定したメモリ | 業務状態は外部から明示的に渡す設計にする |
| 本例の責務 | 品目・数量の聞き取り、訂正、確認表示 | 保存済み申請の処理、結果の整形 |
| 再実行の基準 | 次の発言で再び走る | 同じ申請・同じ版を処理する |
会話変数はVariable Assignerで更新でき、通常のWorkflow変数は実行単位の値です。ここから、会話変数は入力候補の保持に使い、業務上の確定記録は別に置くと判断します。これは製品の禁止事項ではなく、本例で採る責任分界です。Variable Assigner
なお、WorkflowでもHuman Inputノードで一時停止し、人の入力後に再開できます。「人に聞くなら必ずChatflow」という選び方はしません。継続的な自由対話が必要か、特定の実行を承認待ちにするのかで選びます。Human Input API Integration Flow
全部を一つのフローに載せる前に比較する
| 選択肢 | 採用しやすい条件 | 引き受ける制約 |
|---|---|---|
| Chatflowだけ | 聞き取りから下書き提示までで完結 | 次のターンで更新処理を再実行しない仕組みが必要 |
| Workflowだけ | 入力フォームで項目が揃う、定型タスク | 自由対話による不足項目の補完は別途必要 |
| Chatflow+Workflow+業務DB | 対話受付と承認後の処理を分け、履歴を残す | DB、認可、実行管理を保守する必要がある |
本例では三つ目を採ります。発言の訂正と承認後の実行を、同じ状態変更として扱いたくないからです。一方、FAQ回答や保存不要の文章生成なら、Chatflowだけで済む範囲を先に検討します。分離そのものを目的にしません。
採用する構成:聞き取りと確定処理の間に保存を置く
Chatflowの会話変数には、聞き取り途中の品目・数量と、保存後に返された申請IDを持たせます。申請DBには、所有者、入力内容、版、承認対象の版、処理状態を保存します。所有者と承認者は認証済みセッションから決定し、LLMが出した識別子を採用しません。
数量を訂正したら新しい版を保存し、以前の承認を使い回さない構成です。「はい」という発言から承認の意思を推定しても、その推定だけで書き込みを許可しません。認証済みの承認操作と保存済みの版が一致して初めて実行対象にします。
ここでのWorkflowは検証・整形などの処理を担当し、業務更新用の資格情報は実行サービスに集約します。フロー内のツールにも書き込み権限を渡すなら、そのAPI側で同じ認可・承認・重複防止を強制する必要があります。
実装の要点:LLMの候補をそのまま入力契約にしない
最初の境界は、抽出結果から保存可能な入力を作る部分です。次はPython標準機能だけで動く検証関数です。品目一覧は業務側から渡し、余分な項目は拒否します。数量上限100は説明用の業務ルールです。
def normalize_request(raw, allowed_items):
if not isinstance(raw, dict) or set(raw) != {"item_code", "quantity"}:
raise ValueError("invalid_fields")
item = raw["item_code"]
quantity = raw["quantity"]
if not isinstance(item, str) or item not in allowed_items:
raise ValueError("invalid_item")
# boolもintの派生型なので、Trueを数量1として通さない。
if type(quantity) is not int or not 1 <= quantity <= 100:
raise ValueError("invalid_quantity")
return {"item_code": item, "quantity": quantity}
assert normalize_request(
{"item_code": "PAPER-A4", "quantity": 2}, {"PAPER-A4"}
) == {"item_code": "PAPER-A4", "quantity": 2}
ローカルでこの関数を実行し、正常入力、数量の境界、空入力、未登録品目、文字列・真偽値の数量、余分な項目の拒否を確認しました。この確認は純粋な入力検証だけです。 認証、DBの競合、Dify上の実行、外部更新の成功を証明するものではありません。
Dify APIを呼ぶ際も、識別子を混ぜないことが重要です。ChatflowのPOST /chat-messagesは、返されたconversation_idを次のメッセージへ渡して会話を続けます。APIキーはサーバー側に置き、userは認証済み利用者から一貫して決定します。自由入力のuserを本人確認の代わりにしません。Send Chat Message
WorkflowのPOST /workflows/runには定義済みのinputsを渡し、返されたworkflow_run_idを業務の申請ID・版に関連付けます。会話ID、フロー実行ID、業務申請IDは用途が違います。 実行IDを取得できた場合は、実行詳細APIで状態と出力を照合できます。Run Workflow、Get Workflow Run Detail
失敗と中断を「もう一度実行」で処理しない
次の表は、業務側DBに持たせる独自の状態案です。Difyの実行ステータスとは別に管理します。
| 状態 | 意味 | 次の動作 |
|---|---|---|
pending_review |
検証済みだが未承認 | 対象の版を確認し、承認か差し戻し |
ready |
承認した版が現在の版と一致 | 実行権を原子的に取得 |
running |
実行権を取得済み | 同じ申請・版の並行実行を拒否 |
succeeded |
業務側の反映結果まで確認済み | 保存済み結果を返す |
failed |
反映されていないことを確認済み | 原因修正後、再実行条件を判定 |
unknown |
反映したかを確認できない | 照合へ進み、書き込みの再送を止める |
cancelled |
更新前に中断を確定 | 再開するなら新しい実行判断が必要 |
ready → runningはDBの条件付き更新で取得し、申請IDと版の組に一つだけ実行レコードを作ります。外部APIが冪等キーを受け付けるなら、この組から作る同じキーを再送時も使用します。相手側が対応していなければ、参照番号による照合や手動確認が必要です。ローカルの一意制約だけで、外部操作が一度きりになるとは保証できません。
画面の切断は取消しではありません。業務更新の直前にも、保存済みの取消状態と承認対象を再確認します。それでも送信後の中断では反映が済んでいる可能性があるため、結果が不明ならunknownへ移します。Difyの実行が成功していても、業務更新まで成功したと扱わないことがポイントです。
本番へ進めるための品質ゲートと監視
- 「数量を2から3へ訂正した後、古い版を承認する」操作を拒否する。
- 同じ承認を二つの処理が同時に取得しても、一方だけが実行へ進む。
- 別利用者の申請ID・会話IDを渡しても、所有者検証で拒否する。
- Workflow失敗時は業務更新へ進まず、利用者へ確認可能な状態を返す。
-
外部APIが反映後に応答を失った場合、
unknownとして照合へ送る。 - 更新前の取消しと更新後の取消しで、残る記録と案内が変わる。
これらは今後必要な結合・障害注入テストであり、今回実施済みではありません。ログには申請ID、版、許可された相関ID、Dify実行ID、処理段階、結果区分を残します。入力全文や資格情報を残す設計にはしません。承認待ちの滞留時間、結果不明の件数、重複拒否の件数を監視すれば、人が介入すべき場所が見えます。
コストでは、Chatflowの各ターンで重い処理をやり直す構成を避けます。不足項目の確認段階で発注後処理まで走らせず、承認済みの入力だけをWorkflowへ渡します。ただしフローを分けるだけでトークンが減るわけではありません。会話ターン数、送信履歴、Workflow再実行数、DB・運用費を合わせて比較します。削減率やROIは未計測です。
次は分離した境界を壊して確かめる
次の検証では、Difyのバージョンとフロー定義を固定し、訂正、二重承認、通信切断、外部反映後の応答欠落を再現します。最初の到達点は「受付と承認済み申請の保存」までとし、照合と重複防止を確認してから業務更新を接続する計画です。
この分離で狙う業務効果は、確認のし直しと二重処理の復旧を減らすことです。評価するなら、確認に要した時間と、結果不明を解消するまでの時間を導入前後で比較します。会話が成立するだけでなく、失敗後に何が確定し、誰が次の判断をするかまで説明できる設計を目指します。
参考リンク
- Dify Key Concepts
- Variable Assigner
- Human Input API Integration Flow
- Send Chat Message
- Run Workflow
- Get Workflow Run Detail
同様の仕組みの設計・構築・運用については相談可能。
この記事を書いた人✏️@YushiYamamoto
ITPRODX.com代表 / AIアーキテクト
Next.js / TypeScript / n8nを活用した自律型アーキテクチャ設計を専門としています。
日々の自動化の検証結果や、ビジネス側の視点(ROI等)に関するより深い考察は、以下の公式サイトおよびnoteで発信しています。
