はじめに
こんにちは!今回は、ノーコードでAIアプリを開発できるオープンソースプラットフォームDifyを使って、
RAGを構築し、Pythonから呼び出す方法をご紹介します。
Difyは、専門的なプログラミングの知識がなくても、
誰でもAIを簡単に活用したアプリケーションを作成できるツールです。
ビジネスや個人プロジェクトで生成AIを取り入れたい方にとって、最適な選択肢となるでしょう。
この記事では、Difyを使ってRAGを構築する手順を詳しく解説し、
さらにPythonからそのワークフローを呼び出す方法についても説明します。
初心者の方でも理解しやすいように、ステップバイステップで進めていきますので、
ぜひ最後までお付き合いください。
DifyとRAGとは?
どちらも有名な名前なのでよく聞くとは思いますが、今一度簡単に説明します。
Difyは、2024年の春頃から注目され始めたノーコードでAIアプリを開発できるオープンソースプラットフォームです。
専門的なプログラミングの知識がなくても、誰でも生成AIを活用したアプリケーションを作ることができ、初心者でも手軽に操作できるよう設計されています。
ビジネスや個人プロジェクトで生成AIを取り入れたい人に最適な選択肢となります。Difyの公式サイトで「始める」を選択し、ログインしてすぐに利用できる点も魅力的です。
※Dify公式サイトのスクリーンショット画像
今回はこのDifyを使って簡単にRAGを作ります。RAGとは、*Retrieval-Augmented Generation(検索拡張生成)*の略で、 *LLM(大規模言語モデル)*によるテキスト生成を行う際に、外部のデータベースを検索する機能を組み合わせることで、出力の精度を向上させる技術のことです。
今回使用するLLMのモデルは、Gemma3の12Bです。特にモデルの指定はありませんので、
好きなLLMをご使用ください。
Web版のDifyであればChatGPT 4が使用できますし、GoogleのAPIを使えばGeminiも使用できますので、簡単にRAGを作りたい方はそれらをご利用ください。
モデルの設定はモデルプロバイダーより設定が可能です。
※Difyのスクリーンショット画像
Difyのワークフローで生成AIアプリを構築する
まずは「最初から作成」を選択し、「ワークフロー」に名前とアイコンをつけて作成します。
※Difyのスクリーンショット画像
作成すると「開始」のノードがありますので、変数を作りましょう。 入力フィールドの+(プラス)を選んで好きな変数名とラベル名をつけます。 RAGであれば「短文」で十分ですが、入力したいものに合わせて入力フィールドを決めてください。
※Difyのスクリーンショット画像
変数名やラベル名は好きな名前で構いませんが、ラベル名を工夫するとアプリ化したときに見栄えが良くなるのでおすすめです。
※Difyのスクリーンショット画像
では、LLMを呼び出して簡単な出力を行えるアプリを作ります。開始ノードの+(プラス)を選択して「LLM」を呼び出してください。
※Difyのスクリーンショット画像
LLMの設定はデフォルトでも十分な出力が得られますが、
LLMの出力が変わらないようにしたい方はTemperatureとTop Pを0に設定することで、
同じ入力と同じプロンプトであれば出力が変化しないようになります。
コンテキストには先ほど開始ノードで作成した変数を選び、
「メッセージを追加」を選択、USERにコンテキストを反映させてください。
ローカルのLLMはSYSTEMで指示をしないと様々な言語で話し始めるので、「日本語」で話すように指示しています。
※Difyのスクリーンショット画像
LLMノードの設定が完了したら終了ノードをつけてLLMの出力を確認します。 「出力変数」はLLMノードの出力を選択してください。最後に3つのノードが線で結ばれていれば完了です。
※Difyのスクリーンショット画像
右上の「実行」を選択して任意の文字を入力し、「実行を開始」で実行しましょう。
私は「こんにちは!」と入力したところ、「こんにちは!」と出力されました。
Googleの生成AIはニコニコした顔文字がよく出力されるので可愛いですよね。
※Difyのスクリーンショット画像
このようにDifyを使うことで簡単に生成AIを使ったアプリの作成ができます。プロンプトでLLMに役割を指定すると、自分好みの生成AIアプリが簡単に作れますので、ぜひお試しください。
RAGを構築する
では、引き続きDifyでRAGを作ります。
今回は以下のデータを外部情報として使用します。以降では外部情報のことをナレッジと呼びます。
石破茂(いしば しげる)
在任期間: 2024年11月11日 -
生年月日: 1957年2月4日
出身地: 鳥取県
主な経歴: 自由民主党(LDP)の総裁。防衛大臣(2007-2008年)、農林水産大臣(2008-2009年)などを歴任。地方創生や安全保障政策に注力しています。
岸田文雄(きしだ ふみお)
在任期間: 2021年10月4日 - 2024年11月11日
生年月日: 1957年7月29日
出身地: 広島県
主な経歴: 自由民主党(LDP)の総裁。外務大臣(2012-2017年)として日米同盟の強化やTPP交渉に尽力。内閣総理大臣としては新型コロナウイルス対策や経済政策に取り組みました。
菅義偉(すが よしひで)
在任期間: 2020年9月16日 - 2021年10月4日
生年月日: 1948年12月6日
出身地: 秋田県
主な経歴: 自由民主党(LDP)の総裁。内閣官房長官(2012-2020年)として安倍政権を支え、携帯電話料金の引き下げや観光政策の推進に尽力。内閣総理大臣としては新型コロナウイルス対策やデジタル庁の設立に取り組みました。
安倍晋三(あべ しんぞう)
在任期間: 2012年12月26日 - 2020年9月16日
生年月日: 1954年9月21日
出身地: 山口県
主な経歴: 自由民主党(LDP)の総裁。内閣総理大臣としては、アベノミクスと呼ばれる経済政策を推進し、日米同盟の強化や憲法改正の議論を進めました。健康上の理由で辞任。
野田佳彦(のだ よしひこ)
在任期間: 2011年9月2日 - 2012年12月26日
生年月日: 1957年5月20日
出身地: 千葉県
主な経歴: 民主党(DPJ)の総裁。財務大臣(2010-2011年)として財政再建に取り組み、内閣総理大臣としては東日本大震災からの復興や消費税増税を推進しました。
試しに、ナレッジを使用する前のLLMに今の日本の総理大臣を答えてもらいます。
「2024年11月11日に就任した日本内閣総理大臣の名前は?」とかなり具体的に聞いてみましょう。
ChatGPTでは正解を出すかもしれませんが、ローカルのLLMでは答えることができませんでした。
※Difyのスクリーンショット画像
これを踏まえてナレッジを登録していきます。
Difyの「スタジオ」の隣にある「ナレッジ」から登録します。迷うところはないかと思いますので、 表示されたとおりに進めてください。 ナレッジの設定は、基本的にDifyのデフォルト設定ですが、 埋め込みモデルを使用せずに「経済的」の設定にしています。 埋め込みモデルを使用したRAGもDifyでは行えますが、 今回は「簡単にRAGを作る」ことを目的にしていますので、 埋め込みモデルを使用せずに作ってみます。 「保存して処理」を選択でナレッジを登録します。
※Difyのスクリーンショット画像
それでは、このナレッジをワークフローから呼び出します。開始とLLMノードの間の線にカーソルを合わせると 「+」が表示されるので、ここから「知識取得」を選びます。
※Difyのスクリーンショット画像
クエリ変数に開始ノードで作成した変数、ナレッジに先ほど登録したデータを選択します。
※Difyのスクリーンショット画像
LLMのプロンプトもナレッジのデータを読み込むように変更します。 コンテキストを知識取得とし、開始ノードで作成した変数も読み込むようにします。 Markdown形式で記述するとLLMに認知させやすくできます。 また、LLMは指示してあげないと自由に推論をはじめてしまい、 結果的にハルシネーションにつながることがあるので、 プロンプトで「入力データの中にないものは出力しないでください」と指定することをオススメします。
※Difyのスクリーンショット画像
では、先ほどの検索をもう一度行ってみます。
※Difyのスクリーンショット画像
無事にローカルLLMでもナレッジのデータから情報を取得することができました。 このようにDifyでは簡単にRAGを構築することができます。
ここで、作成したRAGの精度を正直にお伝えします。
こちらのRAGの精度は、正直に言うと結構悪い印象です。これはモデルではなくDify側に原因があります。
Difyでは、ナレッジから文章を取得する部分で埋め込みモデルを使用しない場合、
キーワード検索を行っているのですが、的確にキーワードを入力してあげないと取得してくれません。
埋め込みモデルを使用すると若干は良くなりますが、ヒットしないことがザラにあります。
例えば、先ほど入力した「2024年11月11日に就任した日本内閣総理大臣の名前は?」ですが、
「2024年11月11日」と「大臣」がヒットした文章を持ってきていました。
仮に「現在の日本の内閣総理大臣の名前は?」とすると、以下のように文章を取得できません。
※Difyのスクリーンショット画像
しかし、Difyは常に更新されていますので、私は今後のDifyのアップデートで改善されていくことを期待しています。
DifyのワークフローをPythonから呼び出す
では、ここからはRAGを実装したDifyのワークフローをPythonから呼び出してみます。
まずはDify側で右上の「公開する」からワークフローを公開します。 公開しないとPythonから呼び出せないので注意が必要です。また、ワークフローを更新した際は「公開する」を忘れないようにしてください。
※Difyのスクリーンショット画像
そして、「監視」の「バックエンドサービスAPI」で「APIキー」を発行します。また、「サービスAPIエンドポイント」も覚えておいてください。このあとPython側で使用します。
※Difyのスクリーンショット画像
ここまででDifyの操作は終わりです。続いてPythonでの呼び出しですが、 DifyAPIクラスを呼び出してrun_difyを実行することで利用できます。 Pythonスクリプトの説明や詳細については記事の下にまとめていますので、ご参考になりましたら幸いです。
実行結果の通り、先ほどDifyで作成したワークフローをPythonから実行できました。
もし、実行時に「Error: 'output'」とエラーが出る場合は、Difyの終了ノードで変数名を「output」に変えてみてください。
※Difyのスクリーンショット画像
ここまで読んでいただきありがとうございました。 Difyはローコードで生成AIアプリを簡単に作れるツールであり、 Pythonからワークフローを呼び出すことができるので「Difyでできない処理はPython」で、 「Difyで簡単にできることはDify」で行うという住み分けができます。 Pythonを使わない場合でもDifyだけでアプリを作ることができますので、 ぜひともさまざまな場面でご使用いただければと思います。 最後にPythonのスクリプトの説明を記載して締めたいと思います。ありがとうございました。
Pythonスクリプトの説明
☆実行コード
実行コードは、DifyAPIクラスを使用してDify APIにリクエストを送信し、
結果を取得するプロセスを示しています。
まず、DifyAPIクラスを指定されたパスからインポートします。
ここで {DifyAPI path} は実際のDifyAPIクラスの保存している場所に応じて置き換えます。
次に、Dify APIキーとエンドポイントURLを設定します。
api_keyにはAPIキーを、end_point_urlにはサービスAPIエンドポイントを設定します。このとき、/workflows/runを忘れないようにしてください。
その後、DifyAPIクラスのインスタンスを作成し、APIキーとエンドポイントURLを渡して初期化します。
Dify APIに送信するデータを辞書形式で設定します。
この例では、「2024年11月11日に就任した日本内閣総理大臣の名前は?」という質問を送信します。
Difyの開始ノードの変数を「input」としていたので、「inputs」内の変数も「input」としています。
次に、run_difyメソッドを呼び出してDify APIを実行し、結果を取得します。inputsを引数として渡します。
最後に、取得した結果をコンソールに出力します。
この実行コードは、DifyAPIクラスを使用して特定の質問をDify APIに送信し、
その回答を取得して表示する一連の手順を示しています。
# 実行コード
# DifyAPIクラスをインポート
from {DifyAPI path} import DifyAPI
api_key = "{your api key}"
end_point_url = "{your endpoint url}/workflows/run"
# DifyAPIクラスの初期化
dify = DifyAPI(api_key,end_point_url)
inputs = {"input":"2024年11月11日に就任した日本内閣総理大臣の名前は?"}
# Difyの実行
summary = dify.run_dify(inputs)
print(summary)
☆DifyAPIクラス
初期化メソッド(init) :このメソッドは、DifyAPIクラスのインスタンスを初期化するためのものです。引数としてDify APIキーとエンドポイントURLを受け取り、それらをインスタンス変数として保存します。これにより、他のメソッドでAPIキーとURLを利用できるようになります。
Difyを呼び出すメソッド(call_dify): このメソッドは、Dify APIにリクエストを送信し、レスポンスを取得するためのものです。引数としてエンドポイントURLと送信するデータ(辞書形式)を受け取ります。リクエストには、APIキーを含む認証ヘッダーとJSON形式のペイロードが含まれます。リクエストが成功した場合、レスポンスをJSON形式で返します。タイムアウトやその他のリクエスト例外が発生した場合には、エラーメッセージを返します。
Difyを実行するメソッド(run_dify) :このメソッドは、Dify APIを実行し、結果を取得するためのものです。引数としてDifyへ送るデータ(辞書形式)を受け取ります。ユーザー名とレスポンスモード(blocking)を設定し、これらを含むペイロードを作成します。call_difyメソッドを呼び出してDify APIにリクエストを送信し、レスポンスを取得します。レスポンスにエラーが含まれている場合、そのエラーメッセージを返し、正常な場合はレスポンスのデータから出力フィールドの内容を返します。例外が発生した場合には、そのエラーメッセージを返します。
# DifyAPIクラス
import requests
class DifyAPI:
def __init__(self, api_key: str, base_url: str):
"""
Dify APIの初期化メソッド
Args:
api_key (str): Dify APIキー
base_url (str): Dify エンドポイント URL
"""
self.api_key = api_key
self.base_url = base_url
def call_dify(self, url, payload):
"""
Difyを呼び出すメソッド
Args:
url (str): エンドポイントURL
payload(dict): Difyへ送る辞書
Returns:
request result(str)
"""
headers = {
'Authorization': f'Bearer {self.api_key}',
'Content-Type': 'application/json'
}
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
return response.json()
except requests.Timeout:
return {'error': 'Request timed out'}
except requests.RequestException as e:
return {'error': str(e)}
def run_dify(self, inputs: str):
"""
Difyを実行するメソッド
Args:
inputs (dict): Difyへ送る文章
Difyで入力フィールドの変数名を「input」にした場合:{"input":"Difyへ送るテキスト"}
Returns:
summary(str)
"""
user = "python user" # 適当なユーザー名
response_mode = 'blocking' # blockingは、LLMの実行が完了したらレスポンスを返すモード
payload = {
'inputs': inputs,
'response_mode': response_mode,
'user': user
}
try:
response = self.call_dify(self.base_url, payload)
if 'error' in response:
return response['error']
return response['data']['outputs']['output']
except Exception as e:
return f'Error: {e}'