Claude CodeでDifyワークフローを構築してみた|CSVからグラフ自動生成に挑戦(エージェントノード → ECharts方式へ)
「Difyのワークフロー、GUIでノードを1つずつつないで変数を設定して…って、地味に時間かかるんだよな」と思ったことはありませんか?
本記事では、AnthropicのClaude Codeを使ってDify v1.13のワークフローを構築した過程を、成功も失敗も包み隠さずお伝えします。最初はエージェントノード+matplotlibでグラフ生成に挑戦し、サンドボックス制約で壁にぶつかり、最終的にECharts方式のコードノードで解決するまでの一部始終です。
この記事でわかること
- Claude Codeを使ったDifyワークフローYAML自動生成の手順と効果
- Dify v1.13エージェントノードのDSL構造と、Claude Codeの学習データにない新機能への対処法
- インポート後に発生するバグの具体例と修正方法
- エージェントノードがサンドボックス制約にどう適応するかの実験結果
- サンドボックス制約を回避するECharts方式への転換と、その劇的なパフォーマンス改善
前提条件
- Dify v1.13以降(セルフホスト環境)
- Claude Code(Anthropic API キーが必要)
- ターミナル操作の基本知識
今回試したこと
IoTセンサーデータの可視化を想定し、以下のワークフローをClaude Codeで構築してみました。
| 項目 | 内容 |
|---|---|
| ワークフロー名 | IoTセンサーデータ グラフ自動生成 |
| Difyバージョン | v1.13(セルフホスト環境) |
| ノード数 | 4ノード |
| アプローチ | Step 1〜4:エージェントノード+matplotlib → Step 5:ECharts方式に転換 |
最初に構築したワークフローの処理フローは以下の通りです。

ノード数は4つとシンプルですが、エージェントノードの内部では「データの特徴を把握→適切なグラフ種別を選択→matplotlibコードを作成→実行→結果を返す」という複数ステップが自律的に実行されます。
Claude Codeに任せたこと・任せられなかったこと
先に結論をお見せします。
| 工程 | Claude Code | 人間 |
|---|---|---|
| ワークフロー構造設計 | ◎ 自動 | — |
| YAML(DSL)生成 | ◎ 自動 | — |
| Codeノードのロジック実装 | ◎ 自動 | レビュー |
| エージェントノードのプロンプト設計 | ◎ 自動 | レビュー |
| Difyへのインポート | — | 手動(GUI) |
| エージェントノードのツール設定 | △ YAML生成 | GUI上で要調整 |
| インポート後の設定確認 | — | 手動(変数名・パラメータ目視確認) |
| テスト実行 | — | 確認・判断 |
| バグ原因特定・修正 | ◎ 自動 | — |
| YAML再生成 | ◎ 自動 | 再インポート |
| ECharts方式への設計転換 | ◎ 自動 | 方針決定 |
| API経由の動作検証 | ◎ 自動 | APIキー発行 |
ポイントは、「全自動」ではなく「協業」 だということ。特にエージェントノードはDify v1.13の新機能であるため、Claude Codeの学習データに含まれていないDSL構造があり、従来のノードより人間の介入が必要な場面がありました。一方で、サンドボックス制約に直面した後の設計方針の転換(ECharts方式への移行)とコード実装はClaude Codeが主導し、API経由の動作検証まで自動で完了しました。
Step 1:仕様からYAMLを一発生成
最初に驚いたのがここです。Claude Codeに「IoTセンサーのCSVデータ(温度・湿度・気圧)を入力したら、エージェントノードがmatplotlibでグラフを自動生成するDifyワークフローを作って」と伝えたところ、Dify DSL(v0.6.0)準拠のYAMLファイルを1回のやり取りで生成してくれました。
自動で組み上がった構造は以下の通りです。
- 開始ノード: CSVデータのテキスト貼り付け(paragraph型、最大50,000文字)と分析指示のテキスト入力
- Codeノード: Python標準ライブラリ(, )を使ったCSV解析。カラム名・行数・基本統計量を抽出し、エージェントが分析しやすいテキスト形式に変換
- エージェントノード: Function Calling戦略でコード実行ツールを呼び出し、matplotlibグラフを生成
- 終了ノード: 分析結果テキストを出力
ノード間の変数バインディング(例:CSV解析結果をエージェントの に埋め込む )や、Codeノードの入出力定義まで、すべてYAML内に正しく記述されていました。
GUIで同じ作業をやると、ノード追加→変数設定→プロンプト入力→接続線を引く…で30分〜1時間はかかります。Claude Codeなら数分です。
Step 2:エージェントノード特有の壁――DSLリバースエンジニアリング
ここからが今回の本題です。Claude Codeが生成したYAMLをDifyにインポートしたところ、エージェントノードの設定でエラーが発生しました。
壁①: が不明
エージェントノードのDSLには、使用するエージェント戦略プラグインの一意識別子()が必要です。これはDify環境ごとにインストールされたプラグインのハッシュ値を含むため、Claude Codeが事前に知ることができない値です。
壁②:エージェントノードのDSL構造
Difyのエージェントノードに関して、、(ツール設定、最大イテレーション数など)の正確なDSL構造がClaude Codeの学習データに含まれていませんでした。
解決策:リバースエンジニアリング
そこで取ったアプローチが 「手動構築→エクスポート→Claude Codeに学習させる」 というリバースエンジニアリングです。
- Dify UIでエージェントノードを手動で設定(モデル選択、ツール追加、プロンプト入力)
- ワークフロー全体をDSLエクスポート
- エクスポートしたYAMLからエージェントノードの正確なDSL構造を抽出
- その構造をClaude Codeに渡して、完全なYAMLを再生成

この「リバースエンジニアリング」パターンは、今後Difyに新しいノードタイプが追加されるたびに使える汎用的なテクニックです。
Step 3:バグ修正――インポート後に潜む落とし穴
リバースエンジニアリングで正確なDSL構造を反映したYAMLを生成し、Difyにインポート。一見すべて成功に見えましたが、テスト実行前の確認で複数のバグが見つかりました。
バグ①:終了ノードの出力変数名が空になる
インポート後、終了ノードを開くと出力変数の フィールドが空欄になっていました。YAML上では と記述されているのに、DifyのUIには反映されていません。
これはDifyのDSLインポート処理の挙動によるもので、Claude Codeでは対処できない問題です。GUI上で手動で と入力する必要がありました。
バグ②: のデフォルト値
エージェントノードの最大イテレーション数()が意図した値になっていませんでした。エージェントがコード実行→エラー→リトライのサイクルを回すには十分な回数が必要です。今回は5回に設定しました。
これらのバグは、Claude Codeが生成したYAMLの記述自体は正しかったものの、Difyのインポート処理で一部の値が正しく反映されないというケースです。「YAMLを生成して終わり」ではなく、インポート後にGUI上で設定値を目視確認するステップが重要だと痛感しました。
Tips:セルフホスト環境のサンドボックス設定Difyのサンドボックスでmatplotlibやpandasを使いたい場合、 への追記とコンテナ再起動()が必要です。ただし、この方法はインフラへのアクセス権が必要であり、Cloud版では使えません。次のステップで、この制約に正面からぶつかることになります。
Step 4:テスト実行――エージェントは何をしたのか?
バグ修正後、IoTセンサーデータ(温度・湿度・気圧、2デバイス×2日分・16行)のCSVでテストを行いました。分析指示は「温度と湿度の時系列推移を、デバイスごとに色分けした折れ線グラフで表示して」です。
実行結果
ワークフロー全体は約18秒で完了し、4ノードすべてが正常終了(緑チェック)しました。
| 指標 | 値 |
|---|---|
| 総実行時間 | 約18秒 |
| トークン消費量 | 4,558トークン |
| エージェントノード単体 | 14.8秒 |
| 使用モデル | GPT-4o(Function Calling戦略) |

エージェントの挙動を追跡する
Difyの実行追跡ログを見ると、エージェントの思考プロセスが詳細にわかります。エージェントノード(14.8秒、4,558トークン)では、まずmatplotlibを使ったグラフ描画コードを生成し、Code Interpreterツールを呼び出しました。しかし、サンドボックスにmatplotlibがインストールされていないため、コード実行でエラーが返されました。
matplotlibが使えないことを理解したエージェントは、テキストベースのデータ分析にフォールバック。sensor_Aの方が常に高めの温度を示していること、sensor_Bの方が湿度が高い傾向にあること、気圧は安定していることなど、データの傾向を的確に捉えた分析結果をテキストで出力しました。

正直な評価
今回のテストではグラフ画像の生成には至りませんでした。サンドボックスにmatplotlibが入っていなかったためです。
注目すべきはエージェントの適応力です。コード実行が失敗しても、エージェントはパニックせず、利用可能な手段でタスクを完遂しようとしました。しかし、「グラフを作って」と依頼しているのにテキスト分析が返ってくるのでは、ワークフローとしては不十分です。
にmatplotlibを追記してサンドボックスを再起動すれば解決はできます。しかしそれでは、Cloud版やインフラ権限のない環境では使えないワークフローになってしまいます。
もっと根本的な解決策はないのか? ――この問いが、次のステップにつながります。
Step 5:ECharts方式への転換――サンドボックス制約を根本解決
なぜEChartsなのか?
ここでClaude Codeに「matplotlibを使わずに、Difyのコードノードだけでグラフを生成する方法はないか?」と相談しました。Claude Codeが提示した選択肢は3つです。
| 方法 | 外部ライブラリ | LLMトークン | セルフホスト版 | Cloud版 |
|---|---|---|---|---|
| EChartsコードノード | 不要 | 不要 | ○ | ○ |
| ChartGen AIプラグイン | 不要 | 必要 | ○ | ○ |
| QuickChart.io API連携 | 不要 | 不要 | ○ | ○(外部API依存) |
Difyのチャット出力は ブロックをネイティブにレンダリングできます。つまり、コードノードでPython標準ライブラリ(, )だけを使ってEChartsのJSON設定を生成すれば、matplotlibもLLMも外部APIも一切不要でインタラクティブなグラフが表示できるのです。
ワークフローの再設計
Claude Codeに方針を伝えたところ、既存のYAMLを修正してエージェントノードをコードノードに置き換えた新しいワークフローを生成してくれました。

エージェントノードがコードノードに変わっただけで、ワークフロー全体の構造(4ノード)は維持しています。大きな違いは以下の通りです。
| 項目 | 旧:エージェントノード | 新:EChartsコードノード |
|---|---|---|
| グラフ描画方式 | matplotlib(サンドボックス依存) | ECharts JSON(標準ライブラリのみ) |
| LLMトークン消費 | 4,558トークン/回 | 0 |
| 環境依存値 | が必要 | 不要 |
| Cloud版対応 | 不可(matplotlib未インストール) | 可 |
EChartsコードノードの実装
Claude Codeが生成したコードの主な機能を紹介します。
1. 列の自動分類
CSVのカラムを数値列(グラフのY軸候補)とテキスト列(X軸やグループ化候補)に自動分類します。
2. グループ列・X軸列の自動検出
、 などのキーワードからグループ化列を、、 などから時系列軸を自動検出します。IoTセンサーデータのように「デバイスごとに色分けしたい」ケースに対応しています。
3. 分析指示からの対象列の絞り込み
ここで一つバグが見つかりました。「温度と湿度の時系列推移を折れ線グラフで表示して」という日本語の指示に対して、CSVの列名は 、、 と英語です。最初のバージョンでは日本語の指示と英語の列名がマッチせず、全列が表示されてしまいました。
Claude Codeに指摘したところ、日本語→英語の列名マッピング辞書を追加して修正してくれました。
これにより、「温度と湿度」と日本語で指示すれば と 列だけがグラフ化され、 は除外されるようになりました。
4. グラフタイプの自動判定
分析指示に含まれるキーワードからグラフタイプを判定します。
- 「折れ線」「line」→ 折れ線グラフ
- 「棒」「bar」→ 棒グラフ
- 「円」「pie」→ 円グラフ
- 「散布」「scatter」→ 散布図
- キーワードなし → デフォルトで折れ線グラフ
テスト実行と結果
DifyにインポートしたワークフローのAPIキーを発行し、Claude Codeが直接APIを叩いて動作検証を行いました。
結果は以下の通りです。
| 指標 | エージェントノード版 | ECharts版 | 改善 |
|---|---|---|---|
| ステータス | succeeded(テキストにフォールバック) | succeeded(グラフ生成成功) | ○ |
| 総実行時間 | 約18秒 | 約2秒 | 9倍高速 |
| トークン消費量 | 4,558トークン | 0トークン | 100%削減 |
| グラフ出力 | なし(テキスト分析のみ) | EChartsインタラクティブグラフ | ○ |

出力されたECharts JSONには、、、、 の4系列が含まれ、 は正しく除外されていました。Difyのチャット画面では、これがインタラクティブなグラフとしてレンダリングされます(ズーム操作やツールチップ対応)。
学びと所感:Claude Code × Dify開発で得た教訓
教訓①:新機能のDSLは「リバースエンジニアリング」で対応する
Claude Codeの学習データには、Difyの最新機能(v1.13のエージェントノードなど)のDSL構造が含まれていません。しかし、「手動構築→エクスポート→Claude Codeに学習させる」というパターンを使えば、新しいノードタイプでもClaude Codeに正確なYAMLを生成させることが可能です。Difyは今後もアップデートが続くため、このリバースエンジニアリング・パターンは汎用的に使えるテクニックです。
教訓②:制約にぶつかったら「代替設計」をClaude Codeに相談する
最初のエージェントノード+matplotlib方式はサンドボックス制約で行き詰まりました。ここで重要だったのは、「matplotlibをインストールする」という力技ではなく、「そもそもmatplotlibを使わない方法はないか」とClaude Codeに相談したことです。
Claude Codeは複数の代替案(ECharts、ChartGenプラグイン、QuickChart.io)を提示し、それぞれのメリット・デメリットを整理してくれました。最終的にECharts方式を選択したことで、実行時間は9倍高速、トークン消費ゼロ、環境依存なしという大幅な改善を実現しています。
制約は「設計を見直す好機」 です。Claude Codeは「言われた通りに実装する」だけでなく、「もっと良い方法を提案する」パートナーとしても機能します。
教訓③:エージェントノードは「銀の弾丸」ではない
エージェントノードはLLMが自律的にツールを呼び出す強力な機能ですが、今回の検証では以下の課題が明らかになりました。
- サンドボックス制約: 使えるライブラリが限られており、matplotlibのような外部ライブラリは追加設定が必要
- コスト: LLMを呼び出すため、毎回トークンを消費する(今回は4,558トークン/回)
- 速度: LLMの推論+コード実行で約15秒かかる
- 環境依存: など、環境固有の値がDSLに必要
一方、コードノードで完結できる処理なら、LLMトークン消費ゼロ、実行速度は数秒、環境依存もなくなります。エージェントノードの真価は「何をすべきか事前に決められないタスク」にあります。今回のようにグラフの生成ロジックを固定できるケースでは、コードノードの方が適切でした。
教訓④:Claude CodeはAPI経由の検証まで自動化できる
今回、DifyのバックエンドAPIキーをClaude Codeに渡したところ、curlコマンドでワークフローを実行し、レスポンスを解析して問題点(列フィルタリングのバグ)を特定、修正、再テストまでを自動で回してくれました。GUI操作が必要な部分はDifyへのインポートとAPIキー発行だけで、それ以外のサイクルはすべてClaude Codeが主導しています。
まとめ
Claude Code × Difyの組み合わせは、ワークフロー開発の全サイクルで威力を発揮します。特に「仕様からYAMLを一発生成」「Codeノードのロジック実装」「DSL構造の解析と再生成」「制約に対する代替設計の提案」「API経由の自動検証」の5点は、手動開発と比較して体感で5〜10倍の速度差がありました。
今回の検証で最も印象的だったのは、「エージェントノード+matplotlib」から「コードノード+ECharts」への設計転換です。
| 指標 | エージェントノード版 | ECharts版 |
|---|---|---|
| 実行時間 | 約18秒 | 約2秒 |
| トークン消費 | 4,558トークン | 0 |
| 環境依存 | あり(matplotlib、plugin_unique_identifier) | なし |
| Cloud版対応 | 不可 | 可 |
| グラフ出力 | 失敗(テキストにフォールバック) | 成功(インタラクティブ) |
Claude Codeは「万能な自動化ツール」ではなく、「優秀なペアプログラマー」として捉えるのが正確です。テスト実行やGUI上の設定確認は人間が担い、YAML生成・分析・修正・代替案の提案をClaude Codeに任せる。この「協業モデル」を設計できるかどうかが、AI活用プロジェクトの成否を分けるポイントだと感じました。