TECH BLOG

エルカミーの技術ブログです

Difyでうまくいかないときに役立つ!体系的デバッグ手法

はじめに


Difyでワークフローやチャットフローを作成したのに、「思うように動いてくれない」という経験をしたことはないでしょうか。エラーログが出てくれていればどこを直せばいいかわかるので修正しやすいですが、エラーログが出ていないのにうまくいかないときはどこを修正すればいいかわからないですよね。今回は、「Difyでうまくいかなかったときのデバッグ手法」を一つのワークフローを例にとって体系的にまとめていきます。これを読めばどのようにデバッグを行えばいいかわかるようになります。

💡
デバッグとは

コンピュータープログラムやソフトウェアに含まれる誤り(バグ)を見つけ出し、それを取り除いて正しく動作するように修正する作業

この記事の対象者

  • あまりプログラミング経験がない方(非エンジニア)
  • Difyでこれから本格的なアプリ開発をしていこうと思っている方
  • Difyで何回か簡単なアプリ開発をしたことがある方

デバッグの大まかな流れ


まず、ワークフローを構築したあとから実際にアプリを実行するまでの流れを以下に示します。

image block

以上のように段階的にデバッグを行うことで、どこを修正すればよいか効率的に特定できます。それぞれの段階においてどのようなユースケースで、具体的にどのようにデバッグをしていくのか以下に説明していきます。

デバッグの具体的な流れ


このセクションから具体的なデバッグの進め方を説明していきます。下記のブログで紹介したワークフローをユースケースとして使用します。

【Difyで作るシリーズ10】スライドを自動作成する

  • ワークフローの全体像

    Gamma API を活用して、ユーザの入力内容に合わせてスライドを自動作成する

    image block

このワークフローにエラーや望みどおりでない出力が発生したケースを想定して、トラブルシューティングの形でデバッグ手法を紹介していきます。

1. チェックリストに問題がないか確認する

まずはテスト実行前に「チェックリスト」を確認してワークフローに構成や設定の問題がないか確認します。

  1. チェックリスト」を確認し、ノード間の接続ミスや必須パラメータの欠落などの問題がないかをチェックします。
    下図を確認するとエラーが出ていることがわかるので修正します。今回は「HTTPリクエスト(Short_Ver)」ノードがどのノードにもつながっておらず孤立していることが原因です。
    image block
  2. ノードの接続が完了し、「チェックリスト」をもう一度確認するとエラーが消えていることがわかりました。下図のようにチェックリストにエラーが出ていないことが確認できたら次の「『実行』からワークフローをテスト実行する」に移ります。
    image block
2. 「実行」からワークフローをテスト実行する

アプリの更新を公開する前に、正常にワークフローが動いているかをテスト実行します。画面上部にある「実行」から、実際に入力を与えた際にエラーや望みどおりでない出力にならないかを確認するためにテスト実行をします。

image block
チャットフローでは「実行」ではなく「プレビュー」と表示されます。

このテスト実行の結果によって、以下のようにデバッグ手法を使い分けます。

エラー/出力結果 デバッグ手法 デバッグの概要
a ワークフロー処理中にエラーが起きて、ワークフローが止まる 単一ステップデバッグ
(ノード実行・実行追跡)
ワークフロー内の特定のノードを独立してテスト実行する。エラーが起きたノードのみでテスト実行することで最小単位でデバッグできる。
b ワークフローは正常に処理されるが、望んだ出力結果が得られない(ノード間でデータフローのエラーが起きている可能性がある) 段階的実行 ノード間のデータフロー(変数の受け渡しなど)を確認する。相互に依存する複数のノード(「HTTPリクエスト」ノードと「コード」ノード)をテストするのに適しており、開発者が複雑なワークフローアプリケーション内でエラーを素早く特定するのに役立つ。

それぞれのケースについて、テスト実行をした結果から実際にデバッグする方法を紹介します。

2-a 単一ステップデバッグ

テスト実行では、エラーが起きた段階でワークフローが止まるため、エラーが発生するノードを特定できます。今回のケースでは「GenerationID取得(コード)」ノードでエラーが起きています。

image block

このノードを選択し、画面左上に表示されている、「実行追跡」を確認してみます。

💡
実行追跡とは

Difyのデバッグ機能の一つで、各ノードで入力と出力の結果を確認できます。

image block

このノードの設定を確認すると、取得している変数は「generationId」なのに対し、出力変数の設定は「generationid」になっているのが原因でした。

image block

該当部分を修正し、再テストをしてみます。

ここでポイントとなるのが「実行」で全体のフローを確認する前に、ノードデバッグによって対象ブロックのみをテストするということです。

💡
ノードデバッグとは

ワークフローの中でエラーが起きてしまったノードに対して、修正後そのノード単体で再テストするデバッグ機能。そのノードに対する入力を設定することでその入力に対して望んだ出力がされているか、処理にエラーがないかを確認することができます。

全体のフローを再テストせず最小単位でデバッグをすることによって、以下のようなメリットがあります。

  • 時間の短縮(「ループ」ノードなど処理に時間がかかるものがフロー内にある場合)
  • API利用料の節約(「LLM」・「ツール」ノードを呼び出さなくてよいため)
  • HTTPリクエストで不要なリクエストを飛ばさずにすむ(レートリミットやリクエスト制限がかかる可能性があるため)

画面右上にある「このステップだけ実行」を選択することでノードデバッグできます。実際にデバッグした結果、正しく出力されていることが確認できました。

image block
image block

このとき、入力を設定せずにノード単体で再テストできます。これは「変数インスペクタ」によってノードの入力と出力がキャッシュに一時保存されているためです。

💡
変数インスペクタ(変数検査)とは

ワークフローを実行後に各ノードの入力パラメータと出力結果を自動的にキャッシュ(一時保存)する機能。開発者がワークフロー全体のデータフローにおける問題を素早く特定し、検証するのに役立ちます。

今回のケースでは、1回目のテスト実行によって変数インスペクタに「コード」ノードの入力である変数「変数集約器/output」が一時保存されていたため、そのデータが再テストに使用されていました。

image block

また、変数インスペクタは直前の実行に対する入力と出力を確認するのに役立つだけではなく、格納されている入力変数の内容を変更することによって、同様の方法で異なる入力に対するノードデバッグができます。

image block

単一ステップデバッグが完了し、エラーが起きていたノードの修正が完了したら再び「実行」を選択し全体のフローをテスト実行します。

2-b 段階的デバッグ

「単一ステップデバッグ」では、テスト実行時にエラー起きたノードを特定し、デバッグできました。しかし、ワークフローの処理でエラーが起きなかったとしても、ノード間のデータフローのエラーによって望みどおりの出力結果が得られないことがあります。また、エラーが起きていたとしても、そのノードが直接的な原因でない可能性もあります。このような場合に役立つデバッグ手法が「段階的デバッグ」です。

このような不具合が起きてしまう原因として以下のようなことが考えられます。

  • データ形式の不一致(例:想定の入力のデータ型は「String」であるのに対し、実際は「Number」であった。)
  • 変数の設定ミス(例:誤った入力変数を選択していた。)
  • JSONデータの解析失敗(例:「JSON Parse」でのフィルターのミス)
  • 変数パスの参照エラー

このようなエラーの場合、テスト実行では問題なくフローが進みます。そのため、エラーが発生するノードを特定できず、単一ステップデバッグができません。「段階的デバッグ」では、問題のノードを特定・修正することが可能です。

先ほど使用したワークフローに対してテスト実行すると「generationID取得(コード)」ノードにエラーが発生します。ノードの実行履歴を確認してみると、そもそも入力が空になっていました。

image block

このノードでの処理が正常であることを確認するため、「変数インスペクタ(変数検査)」から入力変数を編集してノードデバッグをしてみたところ、「generationId」が正しく出力されていることが確認できました。つまり、別のノードがエラーの原因となっていることがわかります。

image block
image block

次にエラーが起きているノードを特定します。変数インスペクタで前回の実行による各ノードの出力を確認してみたところ、「HTTPリクエスト(Short_Ver)」ノードの出力変数「body」に何も格納されていないことがわかりました。

image block

「HTTPリクエスト(Short_Ver)」ノードに移動し、「実行履歴」を確認すると出力内容の状態変数「status_code」の出力が「401(APIの認証設定ミス)」になっていることが判明しました。

💡
status_codeとは

HTTPリクエストの処理結果を表す3桁の数字。リクエストがうまくいった場合は「201(処理成功)」と表示され、何かしらの不具合が起きた場合はエラーコードが出力されるため、どのようなエラーが起きたか大まかにわかります。

エラーコードリストとその対処法(参考)
クライアントエラー
HTTPコード ステータス 意味 主な原因と対処法
400 Bad Request 不正なリクエスト APIがリクエストの形式を理解できませんでした。
(例) ・必須パラメータの不足
・JSON形式の構文エラー
[対処法] APIの仕様書を確認し、パラメータやBodyの形式が正しいか確認してください。
401 Unauthorized 認証エラー APIキーや認証トークンが無効、または設定されていません。
[対処法] Credential(資格情報)欄で正しいAPIキーが設定されているか、有効期限が切れていないか確認してください。
403 Forbidden アクセス拒否 認証は成功しましたが、リソースへのアクセス権がありません。
(例) ・APIキーの権限不足
・IPアドレス制限
[対処法] APIキーに適切な権限が付与されているか、アクセス元IPが許可されているかなどを確認してください。
404 Not Found リソース未検出 指定したURLのエンドポイントが存在しません。
[対処法] APIのURLが正しいか(タイポやバージョンの指定ミスがないか)を確認してください。
429 Too Many Requests リクエスト過多 短時間にAPIを呼び出しすぎて、レート制限(利用上限)に達しました。
[対処法] APIの利用規約を確認し、リクエストの間隔を空けるなどの調整を行ってください。

サーバーエラー
HTTPコード ステータス 意味 主な原因と対処法
500 Internal Server Error サーバー内部エラー APIサーバー側で予期せぬエラーが発生しました。
[対処法] API提供者の障害情報を確認し、時間をおいて再度試行してください。
502 Bad Gateway 不正なゲートウェイ サーバーが上流サーバーから無効なレスポンスを受け取りました。
[対処法] サーバー側のネットワーク問題の可能性があります。時間をおいて再試行してください。
503 Service Unavailable サービス利用不可 サーバーが一時的に過負荷、またはメンテナンス中です。
[対処法] API提供者のメンテナンス情報を確認し、復旧を待ってください。
504 Gateway Timeout ゲートウェイタイムアウト サーバーが上流サーバーから時間内に応答を得られませんでした。
[対処法] サーバー側の処理に時間がかかっている可能性があります。時間をおいて再試行してください。
image block

ノードの設定に移動し、設定を確認するとAPIが「認証なし」になっていました。API認証がされていなかったことでAPI呼び出しに失敗していたことがエラーの原因でした。

image block

APIキーを適切に設定し「ノードデバッグ」をすることでノードが正常に処理されていることが確認できました(「status_code」が「201(処理成功)」となりました)。

image block

エラーの原因と思われるノードを特定し、ノードデバッグによって修正が完了したため「実行」によって再テストを行い、フロー全体にエラーがあるか再確認します。

⚠️
今回のフローには「IF/ELSE」ノードが存在しているため、入力を変えてテスト実行をすることでそれぞれの条件分岐に対してエラーがないことを確認する必要があります。
image block

Tips(応用例)


このセクションでは、基本的なデバッグ手法に加えて、知っておくとデバッグが効率的に進むようなものを紹介します。

よくエラーの原因となるノード

Difyのワークフローにはそもそもエラーの原因になりやすいノードがいくつかあります。公式文書によると以下4つのノードがエラーの原因となる可能性が高いようです。

  • コード
  • HTTPリクエスト
  • LLM
  • ツール

特に「HTTPリクエスト」ノードはリクエストにエラーが起こっても問題なくテスト実行が進んでしまうため、デバッグ時には「status_code」を確認する必要があります。それぞれのノードの詳細な情報やエラー処理に関しては、公式文書を参照してください。

エラーの原因がわからないときの最終手段

今回紹介したようなデバッグ手法をすべて試してみても原因がわからない場合には、「DSLをエクスポート」することで生成AIチャットに相談することができます。

💡
DSL(Domain-Specific Language)とは

Dify内のアプリをエクスポートするときに出力されるファイル形式です。このファイルをエクスポートすることでアプリの内容を保持することができ、インポートすることでアプリの内容を複製することができます。

生成AIに相談する手順は以下のとおりです。

  1. エラーが起きているアプリ(ワークフロー)の画面に移動し、アプリ右下にあるボタンから「DSLをエクスポートする」を選択します。
    image block

    また、生成AIにシークレットをもらさないようにするため、エクスポートする際「シークレット値を含む」のチェックボックスを外してからDSLをエクスポートしましょう。

    image block
  2. DSLがYAML形式でダウンロードされるため、そのファイルを生成AIとのチャット欄に添付したうえで、ワークフローのエラーの原因を聞いてみると、エラーの原因について思考し、出力をしてくれます。
    image block

おわりに


今回は、Difyのワークフロー構築でエラーが発生した際の、体系的なデバッグ手法をシナリオ形式で解説しました。

本編で紹介した手法の応用として、コードブロック実行時のエラー処理(例外処理)なども、Difyの機能を活用して実装することが可能です。

この記事が、皆さんのDifyでのフロー構築をよりスムーズに進めるための一助となれば幸いです。

参考