はじめに:なぜLAN内RAGの「ナレッジ登録」は定着しないのか?
Difyを使ってLAN内FAQやナレッジ検索用のRAG(Retrieval-Augmented Generation)ボットを作ったことのある方なら、必ずこの壁にぶつかったことがあるはずです。
「エンジニアは便利だと思って作ったのに、現場の利用者が誰もPDFやマニュアルを追加してくれない」
理由は極めてシンプルです。
現場の業務担当者にとって、「Webブラウザを開いて、Difyにログインして、該当のナレッジベースを選んで、ファイルアップロードダイアログを開いて、ファイルをドラッグ&ドロップして、チャンク設定を確認して保存ボタンを押す」 という工程は、面倒くさすぎて絶対に定着しないからです。
現場で日常的に行われている唯一の行為は、「複合機で紙の書類をスキャンして、いつもの共有フォルダ(Samba / NAS)にポイッと保存すること」 だけです。
そこで、「共有フォルダにPDFが放り込まれた瞬間、裏側のPythonが検知してDifyのナレッジAPIに自動登録し、完了したら処理済みフォルダへ移動させる全自動パイプライン」 を構築しました。
現場の作業フローは1ミリも変えずに、LAN内AIが勝手に最新ナレッジを学習し続けます。
1. 実装のキモ:Python watchdog による共有フォルダ監視
ファイルシステムのイベント検知には、Pythonの定番ライブラリ watchdog を使用します。
ネットワーク共有(Samba)特有の注意点として、「巨大なスキャンPDFのネットワーク書き込み中にスクリプトが反応して壊れたファイルをアップロードしてしまう」 のを防ぐため、検知後に短い待機時間を設けています。
💻 コア実装・設定スニペット(抜粋)
# コア実装ロジック(要点抜粋)
import os
import time
import requests
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
DIFY_API_URL = os.getenv("DIFY_API_URL", "http://localhost/v1")
DIFY_DATASET_API_KEY = os.getenv("DIFY_DATASET_API_KEY", "dataset-xxxxxxxxxxxx")
DATASET_ID = os.getenv("DATASET_ID", "your-dataset-uuid")
SAMBA_WATCH_DIR = os.getenv("SAMBA_WATCH_DIR", "/mnt/samba/knowledge")
PROCESSED_DIR = os.path.join(SAMBA_WATCH_DIR, "processed")
class SambaToDifyHandler(FileSystemEventHandler):
def on_created(self, event):
# ディレクトリ作成イベントは無視
if event.is_directory:
return
file_path = event.src_path
# 処理済みフォルダ内のファイルは無視
if "processed" in file_path:
return
print(f"[+] New file detected: {file_path}")
# 複合機からの書き込み完了を確実に待つ(ネットワークバッファ対策)
time.sleep(2)
# Difyへのアップロード実行
self.upload_to_dify(file_path)
def upload_to_dify(self, file_path):
url = f"{DIFY_API_URL}/datasets/{DATASET_ID}/document/create_by_file"
headers = {
"Authorization": f"Bearer {DIFY_DATASET_API_KEY}"
}
filename = os.path.basename(file_path)
print(f"[*] Uploading {filename} to Dify Dataset {DATASET_ID}...")
try:
with open(file_path, "rb") as f:
files = {
"file": (filename, f, "application/pdf")
}
# Difyの高品質インデックス・自動チャンク化ルールを指定
data = {
"data": '{"indexing_technique": "high_quality", "process_rule": {"mode": "automatic"}}'
}
response = requests.post(url, headers=headers, files=files, data=data, timeout=60)
if response.status_code == 200:
print(f"[SUCCESS] Successfully uploaded {filename} to Dify.")
self.move_to_processed(file_path, filename)
else:
print(f"[ERROR] Failed to upload {filename}. Status: {response.status_code}, Msg: {response.text}")
except Exception as e:
print(f"[ERROR] Exception processing {filename}: {str(e)}")
def move_to_processed(self, file_path, filename):
os.makedirs(PROCESSED_DIR, exist_ok=True)
dest_path = os.path.join(PROCESSED_DIR, filename)
os.rename(file_path, dest_path)
print(f"[+] Moved {filename} -> {dest_path}")
2. メインループの起動スクリプト
デーモンとして常駐させ、フォルダ内を監視し続けます。
3. Docker Compose で超軽量にコンテナ常駐化
監視スクリプト自体は、わずか数十MBのメモリしか消費しないため、軽量なPython Alpineコンテナで常駐させます。
4. 現場での導入効果
この仕組みを導入した結果、以下の劇的な変化が起きました。
-
学習ナレッジ数が10倍に急増:
「AIに教えるためにファイルをアップロードする」という意識は現場にはありません。「いつものフォルダに伝票や仕様書のスキャンを置くだけ」なので、無意識に最新情報が集まるようになりました。 -
LAN内問い合わせの激減:
現場の作業員が「去年の型番の仕様書どこだっけ?」と探す代わりに、Difyのチャットボットに聞くだけで数秒で答えが返ってくるようになりました。
まとめ:DXの成否は「現場の既存習慣に乗っかれるか」で決まる
どれほど優れたAIエンジンを導入しても、現場の人間に「新しいWeb画面の操作」を強制した瞬間にDXは失敗します。
- 現場の行動: 複合機のスキャンボタンを押して共有フォルダに保存するだけ(従来通り)
- システムの裏側: Pythonが勝手に吸い上げてDify APIへ登録する(完全自動)
この「ゼロタッチ・インテグレーション」こそが、リアルな現場でAIを活用・定着させるための最大の秘訣です。LAN内RAGの運用に悩んでいる方は、ぜひ試してみてください!
📚 さらに詳しいアーキテクチャ設計・パラメータ表・トラブルシューティング
最後までお読みいただきありがとうございます!
本記事が少しでも「役に立った」「あとで試したい」と感じていただけましたら、ぜひQiitaの 「いいね(♡)」 と 「ストック」、および アカウントのフォロー をいただけると今後の検証・執筆の大きな励みになります!
また、本記事のさらに踏み込んだ 「深層アーキテクチャ解説」「主要パラメータの技術的根拠」「現場アンチパターン・トラブルシューティング対応表」 は、以下のGitHub技術リファレンスにて公開しています。
👉 【第12弾 詳細技術リファレンス (QIITA_ARTICLE_DETAIL_12.md)】
⭐ 全14層・200パターンの自立型インフラ&オンプレAIリファレンス集(おじさんの武器庫)を順次公開中です。ぜひGitHubリポジトリへの Star (★) と X (@OjisanTechnical) のフォローもお願いいたします!
👉 GitHub リポジトリ: ojisantech/ojisan-arsenal
💡 【検証環境・個人研究(PoC)に関する注記】
本記事は、筆者個人の自宅検証環境(ホームラボ/仮想環境)において、公開情報およびOSS(オープンソースソフトウェア)を用いて独自に構築・検証した個人研究(PoC)の記録です。特定の企業・団体の実環境や業務上の非公開情報とは一切関係ありません。