🦀

LLMによるDifyのDSLファイル(YAML)の自動生成について

2024/11/19に公開

1. はじめに

1.1. 目的

オープンソースのLLMアプリ開発プラットフォームであるDifyのDSLファイル(YAML)をLLMにより自動生成する方法について1手法を紹介します。

1.2. 読者対象と前提知識

  • DifyのDSLファイル(YAML)に興味がある方
  • LLMのワークフロー生成に興味がある方

2. DifyとDSLファイルの概要

2.1. Difyの概要

Difyは、処理の機能を持つブロックをつなげていき視覚的にプログラムを組み立てることができるオープンソースのLLMアプリ開発プラットフォームです。ノーコードでLLMアプリを開発できるのが特徴で、非エンジニアでもLLMアプリを開発できるためにX(旧Twitter)でも話題になっています。
Difyは、GUI上で作成したアプリケーションをDSLファイル(YAML)としてエクスポートできます。

2.2. DSLファイルとは

DSLは「Domain Specific Language」の略で、特定のドメイン(領域)に対して効率的に解決策を提供するために設計されたコンピュータ言語です。

2.3. DSLファイルの他の例

DSLファイルは他の分野でも使用されています。
例えば、構成管理ツールのAnsibleや、Teraaform, Docker Composeなどはインフラストラクチャを管理するためのDSLです。また、ビルドツールのGradleやMavenなどはビルドプロセスを管理するためのDSLです。

3. DifyのDSLファイルの特徴

3.1. DifyのDSLファイルの説明

Difyのマニュアル-アプリ作成には、以下のように記述されています。

Dify DSLは、Dify.AIが定めるAIアプリケーション開発のための標準ファイルフォーマット(YML)です。
この標準には、アプリケーションの基本情報、モデルのパラメータ、オーケストレーションの
設定などが含まれます。

実際に、DSLファイルを見てみると、以下のような内容が含まれています。

注意:画面上は「ブロック」と表現されていますが、YAMLファイルでは「ノード」と表現されています。

エクスポート時のDSLファイルの構成例:

# アプリケーションの基本情報
app:
  description: アプリケーションの説明
  kind: アプリケーションの種類
  version: 0.1.3
workflow:
  # 会話で使用する変数の定義
  conversation_variables:
    - name: 変数名
      description: 変数の説明
      type: 変数の型
      value: デフォルト値
  # 環境変数の定義
  environment_variables:
    - name: 環境変数名
      value: 環境変数の値
  # 機能の設定
  features:
    # ファイルアップロード、音声認識など
    # 各機能の有効/無効や詳細設定
  # ワークフローのグラフ定義
  graph:
    # ノード間の接続定義
    edges:
      - source: 開始ノード
        target: 終了ノード
        type: 接続タイプ
    # 処理ノードの定義
    nodes:
      - id: ノードID
        type: ノードタイプ
        data: ノードの設定データ
        position: ノードの表示位置や高さや幅など情報

DSLファイルには、機能の設定などワークフローに関わらない情報や、画面に表示するためのノードの表示情報(ノードの画面上のx,y座標や、ノードの高さや幅など)が含まれています。

3.2. DifyのDSLファイルの簡略化

上記DSLファイルの構造から、ワークフローのグラフ定義のみを抜き出したDSLファイルを作成します。また、nodesのposition情報も削除します。

簡略化後のDSLファイルの構成例:

app:
  description: アプリケーションの説明
  kind: アプリケーションの種類
  version: 0.1.3
workflow:
  # ワークフローのグラフ定義
  graph:
    # ノード間の接続定義
    edges:
      - source: 開始ノード
        target: 終了ノード
        type: 接続タイプ
    # 処理ノードの定義
    nodes:
      - id: ノードID
        type: ノードタイプ
        data: ノードの設定データ

3.3 DSLファイルの簡略化の手順

手順は以下の通りです。

手順

  1. 画面上で作成したワークフロローのDSLファイルをエクスポートします。
  2. 次に、LLMを使用して、ワークフローのグラフ定義のみを抜き出します。
    以下がプロンプトの例です。エクスポートしたDSLファイルを添付してください。

プロンプト:

添付したワークフローファイルはDifyのDSLファイルです。
画面向けの情報を削除して、シンプルにしてください
  1. LLMの出力を別のYAMLファイルに保存します。

上記手順で出力したYAMLファイルは、ワークフローのグラフ定義のみのDSLファイルとなります。
この状態で一度、新しいYAMLファイルをDifyにインポートして、ワークフローが正しく動作することを確認してください。

これだけで、簡略化でき、更にDifyにインポートして、ワークフローが正しく動作することを確認できたときは驚きました。LLMの言語の分析力と、DifyのDSLファイルの優れた設計が功を奏しています。

筆者は、LLMとしてAnthropic社のClaude-3.5-sonnetを使用していますが、上記プロンプトでの出力は、再現性があります。
ChatGPTやGeminiなどのLLMでも同様の処理が可能かは試していません。

3.4 DifyのDSLファイルに対する考察(感想)

筆者は、10年近く前にRPA(Robotic Process Automation)の自動化ツールを業務として開発を行ったり、他社製品のRPAのPoC/デモなどを行っていました。
その当時は、JSON/YAMLが発明される前で、画面で作成したワークフローを出力する際には、XMLファイルがメジャーなファイルフォーマットでした。
XMLファイルは、XSLファイルというスキーマファイルを使って、データの構造を定義し、データ構造の中身をチェックすることができました。逆に言うと、データ構造を省略して記述してしまうと、インポートすることができませんでした。
当然、画面上のノードの表示情報を削ると、インポートしても表示されないという問題がありました。

今回のDifyのDSLファイルは、画面上のノードの表示情報を削除しても、インポートが可能で画面に表示されるという点で、非常に優れていると感じました。
(想像ですが、Difyの内部では、ワークフローのグラフ・ノードの定義と、表示情報を別管理しているのかもしれません)

4. LLMによるDSLファイルの自動生成

3章で紹介した簡易化後のDSLファイルを、LLMにより自動生成する方法について紹介します。

これはノードの表示情報を削除できるというのが非常に大きく寄与しています。もし表示情報を削除できなかった場合、LLMで表示情報を計算する必要があり、困難だったと思います。

4.1 Dify ワークフロージェネレーターの紹介

筆者は、GitHubの以下のリポジトリでDifyのDSLファイルを自動生成するプロンプトを公開しています。
DifyWorkFlowGenerator

DifyWorkFlowGenerator

※ Dify.ai公式ではなく、筆者個人の成果物ですのでご注意ください。

4.2 Difyワークフロージェネレータの機能

ワークフローの目的/必要な入力情報/期待する出力形式/制約条件を自然言語で記述して、LLMにDSLファイルを出力させることができます。

以下の例は、2つのRAGを使い分けながら、回答するチャットボットのDSLファイルを生成した例です。

ワークフロージェネレータ

出力されたDSLファイルをDifyにインポートすると以下のようなワークフローが表示されます。

ワークフロー

上記のように自然言語でDifyのワークフローを生成できるのが特徴です。

4.3 Difyワークフロージェネレータのプロンプトの紹介

Difyワークフロージェネレータのプロンプトは、以下の構造で記述します。

プロンプトの構造:

purompt:
    メタデータ:
        タイトル: Difyワークフロー生成プロンプト
        バージョン: 1.0.0
        用途: ワークフローファイルの生成
    入力要件:
        ワークフローの目的/必要な入力情報/期待する出力形式/制約条件
    ワークフローの構造:
        app: モード(workflow)とバージョン情報
        workflow.graph: 実際のワークフロー定義
        edges: ノード間の接続関係
        nodes: 各処理ノードの定義
    ノードタイプの説明:
        Start Node: ワークフローの開始点、入力の受け付け
            :
        LLM Node: 言語モデルを使用した処理
        End Node: 処理結果の出力
    各ノードの構造:
        id: ユニークな識別子
        type: ノードの種類
        data: ノード固有の設定
        title: ノードのタイトル
        その他の設定項目

上記のように一般的に使われる自然言語のプロンプトではなく、YAML形式のプロンプトを使用しています。
YAML形式にすることによるメリット/デメリットは以下のように感じてます。

YAML形式のプロンプトにするメリット/デメリット

メリット デメリット
プロンプトの構造が明確になる 自然言語で記述するよりも長くになる
曖昧性がなくなる LLMが気を利かしてくれなくなる
機能追加時にLLM側が真似しやすい -

特に3点目の機能追加時にLLM側が真似しやすいというのが大きいです。

プロンプトを作る際には、CursorにDifyの画面のソースコードのノードの定義部分と、ノードが利用されているDSLファイルをRAGとして渡した上で、xxノードを追加するように指示して、プロンプトを作成しています。この時にYAML形式で構造化されていると、LLMの出力が他のノードを真似してくれるので、統一したフォーマットでプロンプトを作成することができています。

4.4 制限事項

以下のノードには現在未対応です。

  • イテレーションノード : (理由) 構造が複雑でプロンプト化できていない。
  • 変数代入ノード: (理由) ユースケースが正しく理解できていない
  • リスト処理:(理由) ユースケースが正しく理解できていない
  • ツールノード全般:(理由) 単純にまだ手を付けてない。

4.5 まとめ

DifyのDSLファイルの構造から、LLMによるDSLファイルの自動生成を行う方法について紹介しました。
皆様の業務の効率化や、自動化に貢献できれば幸いです。

4.6 関連リンク

Dify.aiの皆様、素敵なOSSを提供していただきありがとうございます。

Discussion