📚

【Dify】ナレッジパイプライン調査レポート3/3 - Excelデータの自動選別とQAナレッジ化

に公開

はじめに

LLMアプリケーション開発プラットフォーム「Dify」では、ver.1.9.0で「ナレッジパイプライン」が登場しました。本記事は、この新機能に関する技術テーマを深掘りするシリーズの第3回です。

今回のテーマは多くの企業がデータ管理ツールとして利用している「Excel」のナレッジ化です。

社内FAQリストなどをExcelで管理する際、「公開用」「下書き」といったステータス管理は日常業務の一部です。しかし、このデータをRAGで活用しようとすると、「公開用の行だけを抽出する」といったフィルタリング処理が必要です。

本記事では、このExcel上のフィルタリング作業からQA形式のナレッジとして格納するまでをDifyのナレッジパイプラインで自動化するアプローチを解説します。

Excelビジュアルイメージ
▲従来の手作業によるプロセス(左)と、本記事で紹介する自動化パイプライン(右)。


従来の課題:Excel活用のボトルネックは「手作業による前処理」

ExcelやCSVをRAGナレッジとして活用する際の課題は、必要なデータだけを選び出し、Difyが求める形式に変換する手間でした。

例えば、以下のようなFAQリストがあったとします。

id category question answer remark 公開可否
1 アカウント パスワードを忘れました。 再発行手続きが必要です...
2 PC PCが起動しません。 電源ケーブルを確認してください... PC管理番号が必要
3 ネットワーク VPNに接続できません。 設定マニュアルを参照してください...
4 アカウント 新規アカウントを発行したい。 (現在申請フローを準備中) ×

従来のQAナレッジ作成プロセスでは、「公開可否」の列でフィルタをかけ、対象行のquestion列とanswer列をコピーし、新しいシートに貼り直し、そのデータを格納する作業が必要でした。元ファイルが更新されるたびにこの作業が発生するため、ナレッジを最新に保つには一定の工数がかかります。


検証の概要

検証内容

「ナレッジパイプライン」を使い、特定の条件を満たす行だけをExcelファイルから自動で抽出し、QA形式のナレッジとして格納できるか検証します。

検証環境

本検証の環境は以下の通りです。

環境 Difyバージョン
Community版 1.9.1
SaaS版 1.9.1

検証手順

本検証は、「①データ準備」「②ナレッジパイプラインの構築」「③チャットボットでの効果検証」の3ステップで実施します。

手順1: データの準備

まず、ナレッジの元となるファイルを用意します。今回は、社内FAQリストを想定した、以下のようなExcelファイルを準備しました。このファイルは、「ナレッジに格納するか」という列を使いナレッジに格納すべき行を判断しています。
データの画像
▲使用したデータの画像

手順2: ナレッジパイプラインでナレッジを格納

次に、Difyの「ナレッジ」メニューから、「ナレッジパイプラインから作成」→「空白のナレッジパイプライン」を選択し、以下のノードを接続してパイプラインを構築します。
ナレッジパイプライン
▲パイプラインの全体像

  1. File: 手順1で準備したExcelファイルをアップロードするソースノード。
  2. Dify Extractor: アップロードされたファイル全体をMarkdownテーブル形式のテキストとして抽出するノード。
  3. コード(Python): 前のノードから受け取ったMarkdownテーブルに対し、Pythonコードで以下の処理を実行するノード。
    • フィルタリング: 「ナレッジに格納するか」列が「〇」の行だけを抽出。
    • 列の選択と再構成: 抽出した行から、「id」「question」「answer」の3つの列だけを取り出し、新しいMarkdownテーブルを作成

コードノードからの出力例

| id | question | answer |
| --- | --- | --- |
| 1 | 有給休暇の申請方法について教えてください。 | 勤怠管理システム... |
| 2 | PCが起動しなくなりました。 | まずは電源... |
| 5 | 新しいソフトウェアをインストールしたい。 | 業務で必要な情報システム... |
... (「〇」の行が続く) ...
コードはこちら
import io
import csv

def main(args) -> dict:
    """
    Difyのコードノードで、Markdown形式のテーブルテキストから特定の条件に合う行を抽出し、
    id, question, answerの3列を持つMarkdown形式の表を生成します。
    """
    markdown_text = ""
    # 1. 入力からMarkdownテキストを取得
    if isinstance(args, dict):
        markdown_text = args.get("text", "")
    elif isinstance(args, str):
        markdown_text = args

    if not markdown_text:
        return {"result": "入力テキストが空です。"}
    
    # | を含む行(テーブルの行)のみを抽出
    table_lines = [line for line in markdown_text.strip().split('\\n') if '|' in line]
    
    if len(table_lines) < 2:
        return {"result": "有効なテーブルデータが見つかりませんでした。"}

    # 2. ヘッダーを解析して必要な列のインデックスを取得
    header_line = table_lines[0]
    headers = [h.strip() for h in header_line.split('|')][1:-1]
    
    try:
        id_col_index = headers.index("id")
        question_col_index = headers.index("question")
        answer_col_index = headers.index("answer")
        filter_col_index = headers.index("ナレッジに格納するか")
    except ValueError as e:
        return {"result": f"エラー: 必要な列が見つかりません。 ({e})"}

    # 3. 出力用の新しいMarkdown表のヘッダーを作成
    output_lines = [
        "| id | question | answer |",
        "| --- | --- | --- |"
    ]
    
    # 4. データを一行ずつ処理
    # ヘッダー行と区切り線行を除外
    data_lines = table_lines[2:]
    
    for line in data_lines:
        columns = [c.strip() for c in line.split('|')][1:-1]
        
        if len(columns) <= filter_col_index:
            continue
            
        # 5. 「ナレッジに格納するか」列が'〇'の行のみを抽出
        if columns[filter_col_index] == "〇":
            # 必要な列のデータを取得
            id_val = columns[id_col_index]
            question_val = columns[question_col_index]
            answer_val = columns[answer_col_index]
            
            # answer内の改行文字を<br>に置換
            answer_val_formatted = answer_val.replace('\\n', '<br>')
            
            # Markdown表の一行として追加
            output_lines.append(f"| {id_val} | {question_val} | {answer_val_formatted} |")

    # 6. すべての行を結合して最終的なMarkdownテキストを生成
    final_output = "\\n".join(output_lines)
    
    return {"result": final_output}
  1. Markdown to CSV file: 3.コードノードが生成したMarkdownテーブルからCSV形式(カンマ区切り形式)のファイルを作成するノード。

Markdown to CSV fileからの出力例

id,question,answer
1,"有給休暇の申請方法について教えてください。","勤怠管理システム..."
2,"PCが起動しなくなりました。","まずは電源..."
5,"新しいソフトウェアをインストールしたい。","業務で必要な情報システム..."
...
実際のMarkdown to CSV fileノード出力

実際には作成したファイルのURLが出力されています

{
  "text": "",
  "files": [
    {
      ...//実際にはファイルに関する様々な内部情報がURL以外にも記載されています
      "url": "https://xxxxxxdify.net/files/tools/391c9304-995a-43d4-8f0d-ae71d00f1b54.csv?timestamp=1760688128&nonce=17cef288eb661cb344d8b1988fc7c627&sign=IcWXf7BJBn955CmHzIs1LH6k7FRrXI2emWNON5odzSo="
    }
  ],
  "json": [
    {
      "data": []
    }
  ]
}
  1. QA Chunk: 4.Markdown to CSV fileで作成されたCSVファイルを受け取り、指定された列を「質問」と「回答」として解釈し、QA形式のチャンクを生成するノード。 今回は、CSVの2列目をquestion、3列目をanswerとして指定します。

QA Chunkからの出力例

{
...
  "result": {
    "qa_chunks": [
      {
        "answer": "勤怠管理システム...",
        "question": "有給休暇の申請方法について教えてください。"
      },
      {
        "answer": "まずは電源...",
        "question": "PCが起動しなくなりました。"
      },
        ...
    ]
...
QA Chunk設定画面

QA Chunk設定画面

  1. 知識ベース: 完成したQAチャンクを格納するノード。

手順3: チャットボットで効果を検証

最後に、作成したナレッジをチャットボットに接続して、正しい回答が得られるかを検証します。

  1. Difyでチャットボット(Chatflow)を新規作成します。
  2. 「知識取得」ノードを追加し、手順2で作成したナレッジを選択します。
  3. 開始ノード、知識取得ノード、LLMノード、回答ノードを接続すれば、検証用のRAGチャットボットの完成です。
LLMについて

本チャットフローの目的は、作成したナレッジを用いて正確な回答を生成できるか検証することです。そのため、プロンプトは検証に特化した、以下の通りシンプルな構成にしています。

SYSTEM

{{#sys.query#}}に対して、社内FAQの該当箇所を利用して回答を作成してください。

USER

{{#sys.query#}}:ユーザーの質問
{{#context#}}:ユーザーの質問に関連する社内FAQ文書の該当箇所

チャットボットのフロー図
▲構築されたチャットボットのフロー全体像

会話例2
▲構築したRAGチャットボットによる回答例


検証結果

結論として、パイプラインはExcelのフィルタリングとデータ整形を自動化し、アップロードするだけで意図したQAナレッジを完成させることができました。

ナレッジベースを確認すると、Excel上で「〇」が付いていた行だけが、QAペアとして格納されていることがわかります。

元データとQAチャンク
▲元データと格納されたQAチャンク(必要なQ&Aのみが抽出されている)

このナレッジを利用したチャットボットは、的確な回答を返しました。

会話例2
▲構築したRAGチャットボットによる回答例1(ID1)

▲構築したRAGチャットボットによる回答例2(ID5)


技術的なQ&A

Q1. どこまで自動化できる?

A1. パイプラインを構築すれば、その後の分割ロジックを自動化できます。

一度パイプラインを組めば、ExcelまたはCSVファイルをアップロードするだけで、QA形式のナレッジとして格納するまでを自動化できます。 元のExcelの更新も、ファイルを再アップロードするだけでナレッジに反映されます。

Q2. 精度は?

A2. コードノードに記述する処理ロジック(スクリプト)に依存します。

コードでの処理なので入力データの形式が要件通りであれば精度は高く、同じデータでも結果が異なるというケースは発生しません。

Q3. Pythonが書けないとダメ?

A3. LLMでも代替可能ですが、精度の観点からコードノードの利用がおすすめです。

Excelの場合データ量が膨大で、LLMに処理をさせると精度が低く指示通りにナレッジ化できない恐れがあります。
そういったケースではコードを使ったルールベースの処理の方が精度が安定します。

どんな場面で活躍する?

  • 製品マスタ管理 🛠️
    • 概要:「現行品」「販売終了品」といったフラグを持つ製品リストから、「現行品」の「製品名」と「スペック」だけを抽出してナレッジ化。
    • 効果:ExcelやDifyについて詳しくない人でも製品マスタ管理シートをアップロードするだけでナレッジ更新が可能になる。

まとめ

今回の検証を通じ、DifyのナレッジパイプラインがExcelデータの前処理ツールとして機能することが分かりました。

  • Excelフィルタ処理の自動化: コードノードを使えば、特定の条件に基づくデータの抽出など、手間のかかる作業を自動化できます。
  • QAチャンクノードの活用: 新しいQA Chunkノードは、整形されたCSVデータからQAペアを正確に生成するための有力な手段です。
UPGRADE tech blog

Discussion