Markdownコンバーターでファイルの保存場所が取得できない、出力変数が使えない?

結論から言うと、現在のあなたの使い方(LLMに##タイトル付きのMarkdownを出力させ、Markdownコンバーターが##で自動的にシートを分割することを期待する)はDifyでは動作が保証されません。Markdownコンバーターには現在、##が必ずExcelのワークシート名になるという「公式に定められた」ルールがありません。

言い換えれば、

  • MarkdownテーブルをExcelに変換することはできます。
  • しかし、「複数シート + シート命名ロジック」は現在、比較的「ブラックボックス」であり、外部に文書化されたり、設定可能な機能ではありません。そのため、「Markdownは問題なさそうに見えるのに、##でシートが分割されない」という現象は、現在の実装状況に合致しています。

以下に、どのように対処できるかについていくつか説明します。


1. 現在の挙動の理解

あなたが貼り付けた構造と合わせて:

{
  "text": "## XXX\n\n| 列1 | 列2 |\n| --- | --- |\n| ... | ... |"
}

あなたの期待は:

  • ## XXX → ExcelにXXXという名前のシートが出現する
  • ## YYY → 別のシートが新規作成される

しかし、現在のMarkdownコンバーターは、むしろ次のような挙動をします:

  • Markdown全体を一つのドキュメントとして扱います。
  • 「タイトル階層 → シート」ではなく、「テーブルそのもの」に重点を置いています。

そのため、よくある現象は次のとおりです:

  • 1つのシートしか生成されない可能性があります。
  • または、##内のテキストではなく、デフォルトのシート名(例:Sheet1)が使用されます。

これはあなたのMarkdownの記述が間違っているのではなく、現在の製品設計において##が「シートの境界 + シート名」の正式なプロトコルとして扱われていないためです。


2. 「タイトルごとにシートを分割する」を実現するための検討可能なアプローチ

もし「##でシートを分割する」という強い要件がある場合、Markdownコンバーターのデフォルトルールを迂回し、「コードノード + Excelライブラリ」を使用して、目的の構造を明示的に複数シートとして書き出すことを検討できます。

アプローチ A:LLMが構造化JSONを出力し、その後コードでExcelを生成する

  1. LLMノードでは、Markdownを直接出力させるのではなく、構造化JSONを出力させます。例えば:

    {
      "sheets": [
        {
          "name": "SheetA",
          "table": [
            ["列1", "列2"],
            ["a1", "a2"],
            ["b1", "b2"]
          ]
        },
        {
          "name": "SheetB",
          "table": [
            ["列1", "列2"],
            ["x1", "x2"]
          ]
        }
      ]
    }
    
  2. コードノード(Pythonを推奨)でこのJSONを解析し、openpyxlpandasなどのライブラリを使って自分でExcelを作成します。複数テーブル、複数シートを完全に制御できます。

    疑似コード例:

    import io
    from openpyxl import Workbook
    import json
    
    data = json.loads(inputs["llm"]["text"])  # LLMの出力が上記のJSONであると仮定
    
    wb = Workbook()
    # デフォルトシートを削除
    default_ws = wb.active
    wb.remove(default_ws)
    
    for sheet in data["sheets"]:
        ws = wb.create_sheet(title=sheet["name"][:31])  # Excelシート名は最大31文字
        for row in sheet["table"]:
            ws.append(row)
    
    # メモリに保存し、後続のノードにファイルとして返す
    buffer = io.BytesIO()
    wb.save(buffer)
    buffer.seek(0)
    
    outputs["excel_file"] = {
        "type": "document",
        "filename": "result.xlsx",
        "content": buffer.read()
    }
    
  3. その後、このexcel_fileを通常のファイルとしてユーザーにダウンロードさせたり、別のノードに渡したりすることができます。

利点:

  • Markdownコンバーターの内部ルールに全く依存しません。
  • シート名、シート数、各シートの内容をすべて自分で制御できます。
  • LLMのタスクもより明確になります。「構造化計画」のみを担当し、Excelの詳細は担当しません。

アプローチ B:LLMに引き続きMarkdownを出力させ、コードで分割してからExcelを書き出す

もし現在のLLMプロンプトがMarkdown出力に固定されており、Markdownの可読性を好むのであれば、次のようにできます:

  1. LLMに引き続き同様の構造を要求します:

    ## SheetA
    
    | 列1 | 列2 |
    | --- | --- |
    | a1  | a2  |
    | b1  | b2  |
    
    ## SheetB
    
    | 列1 | 列2 |
    | --- | --- |
    | x1  | x2  |
    
  2. ダウンストリームにコードノードを追加し、2つのことを行います:

    • 正規表現 / Markdown解析ライブラリを使用して、テキストを##タイトルごとにブロックに分割します。
    • 各ブロック内の最初のテーブルを二次元配列として抽出し、その後上記と同様の方法でExcelの複数シートを書き出します。

    例えば、シンプルな正規表現のアプローチ(疑似コード):

    import re
    
    md = inputs["llm"]["text"]
    
    # 各シートのブロックに分割
    blocks = re.split(r'^##\s+', md, flags=re.MULTILINE)
    # blocks[0]は##より前の内容である可能性があり、無視できます
    sheet_blocks = blocks[1:]
    
    sheets = []
    for block in sheet_blocks:
        # 最初の行から改行前までがシート名
        lines = block.splitlines()
        sheet_name = lines[0].strip()
        sheet_body = "\n".join(lines[1:])
    
        # さらにsheet_bodyから最初のMarkdownテーブルを二次元配列として解析
        # (自分でパーサーを書くことも、既存のライブラリを使うことも可能)
        table = parse_markdown_table(sheet_body)
    
        sheets.append({"name": sheet_name, "table": table})
    
    # その後、上記のopenpyxlの書き込みロジックを再利用
    
  3. 最終的には、Markdownコンバーターが自動的にシートを推測するのではなく、このコードノードがExcelを生成します。


3. もしMarkdownコンバーターに依存し続ける必要がある場合はどうするか?

現在入手可能な情報では、次のような「保証された」ドキュメントはありません:

  • #####などの見出しとシート間のマッピングルール
  • または「タイトルごとにシートを分割する」を有効にするための何らかのスイッチ

したがって:

  • たとえ現在、試行錯誤の結果「見出しごとにシートを分割できるらしい」という書き方を見つけたとしても、それは実装の詳細である可能性があり、将来のバージョンで安定するとは限りません。
  • 本番環境では、未文書化の挙動に依存することを避けるため、上記の「LLM + コードによるExcel自作」の方法を推奨します。

4. 実践的なアドバイス(最小限の変更バージョン)

既存のワークフローで、大幅な変更をしたくない場合は、次のように微調整できます:

  1. アップストリームLLM:

    • 引き続き「##付きのMarkdown」を出力させます。

    • ただし、プロンプト内でモデルに同時にJSONを出力する構造を保証させるように追加します。例えば:

      先给我 Markdown 展示,方便阅读;
      然后再给我一个 JSON 代码块,结构为:
      ```json
      { "sheets": [ { "name": "...",
                      "table": [["表头1","表头2"],["...","..."]] } ] }
      
      
      
  2. ダウンストリームにコードノードを新規追加:

    • JSONの部分だけを読み込み、Markdownの部分は無視します。
    • JSON → 複数シートExcelのロジックでファイルを生成します。
    • Markdownコンバーターを使ってExcelに変換することはもうしません。

これにより:

  • 人間がチャット履歴を見る際は依然として洗練されたMarkdownです。
  • マシンがExcelに落とし込む際は、「構造化 + 制御可能」なパスを辿ります。

まとめ

  • あなたが現在直面している問題の本質は、Markdownコンバーターに「## → Excelシート」という信頼できる、外部に公開されたルールがないため、期待するような方法で複数シートを作成しないということです。
  • シート名と構造を安定して制御したい場合は、次のアプローチを推奨します:
    • 「LLMが構造化JSONを出力 → コードノードがExcelを生成」;または
    • 「LLMが##付きのMarkdownを出力 → コードノードが##で分割 → 自分でExcelを書き出す」。
  • これにより、内部の未文書化された実装の詳細に依存する必要がなくなり、将来のバージョンアップグレードもより安全になります。

もしよろしければ、現在のLLMの完全な出力例(匿名化後)を少し貼り付けていただければ、その出力を複数シートのExcelに変換するための対応するコードノードの例を直接作成できます。