Dify APIにNode.jsから接続する
1.はじめに
Difyを使用するようになってから、チャットフロー機能やワークフロー機能がとても気に入っていて、これをLLM(Large Language Model)のように使いたいという欲求が高まってきました。
理由は、Difyの本番環境向けのチャットボットに2点ほど気に入らない点があるからです。
本番環境向けのチャットボットにはチャット履歴やマルチモーダルファイルの添付などの機能があり、十分ではありますが、生成されるユニークキーが含まれるFQDNアドレスは分かりやすいアドレスとは言えません。
また、生成AIを利用するユーザーとしては、プロンプトテンプレートを保存できる機能が非常に欲しいところです。
このページでは私が考える目論見を実現するための一つの要素技術であるDify APIをNode.jsから実行するという点にフォーカスして情報をまとめます。
2.シナリオ
Difyで実現したRAGを用いた問い合わせ対応システムを、リッチなユーザインタフェースのWeb UIから利用します。
現在のDify API機能は他のAPIと互換性がなく、チャットボットUIに組み込む場合には独自のプログラム実装が必要です。
着目したのはDifyのモデルプロバイダーでもサポートされる「OpenAI-API-compatible」というLLM/TEXT EMBEDDINGに対応したインタフェースです。
簡単に言うと作成したDify APIをサポートされることが多い、OpenAI-API-compatibleインタフェースで実行できるようにして、Difyのチャットフロー、ワークフローをリッチなチャットボットUIから利用するという目論見です。
最終的な目標は、Mckay Wrigley氏が開発しているTypeScriptで記述されたChatbotUIのようなリッチUIを持つチャットボットとして新しいLLMをサポートすることです。
まず、Node.jsでシンプルな「Dify API呼び出しプログラム」を作成し、その後、Chatbot UIからの呼び出しを実現します。
次に、PythonでのOpenAI API互換バックエンドサービスを実装し、Chatbot UIからの呼び出しを実現していきます。
No | プロセス | 説明 | 備考 |
---|---|---|---|
1 | DifyAPI呼出しPG作成 | Node.jsでDifyのAPIを実行するサンプルアプリを作成する。 | ー |
2 | ChatbotUIダミーLLM作成 | Chatbot UIの以下のLLM追加のPull requestsを参考にユーザー入力をオウム返しする簡単なダミーLLMを作成する https://github.com/Chr96er/chatbot-ui/commit/0993f54959fbf82d228ff5d35a5ca581936ecf11 |
ー |
3 | ChatbotUIダミーLLMからのDify呼出し | ダミーLLMにDifyAPI呼び出しを追加してテキストベースでChatbot UIからDify APIをLLMとして呼び出せるかを検証する | ー |
4 | OpenAI互換ダミーAPI作成 | ユーザー入力をオウム返しするダミーAPIをPythonのFastAPIで作成する | ー |
5 | OpenAI互換API作成 | ユーザ入力をDify APIに中継するOpenAII互換 APIを作成する | ー |
6 | ChatbotUIからのOpenAI互換API呼出し | ChatbotUIからOpenAI 互換APIを呼び出しチャットボットを動かす。 | ー |
このページでは#1のDifyAPI呼び出しプログラムを作成します。
3.DifyAPI呼出しプログラム
3.1 全体の流れ
No | コンポーネント | 説明 | 備考 |
---|---|---|---|
1 | DifyAPI_eval01 | Node.jsで作成したシンプルなプログラム | |
2 | マイナンバーRAGAPI | Difyで作成したチャットフロー | |
3 | マイナンバーQ&A.txt | デジタル省が作成したマイナンバーカードに関するよくある質問のmynumber_faq_03をテキスト化してDifyのナレッジとして取り込んだもの | https://www.digital.go.jp/policies/mynumber_faq_03 |
①DifyAPI_eval01
ユーザからの問い合わせをqueryとしてDifyのAPIエンドポイントにAPIキーを使用して接続し、Streamingで結果を受け取るプログラムです。
Node.js(JavaScript)で作成します。
②マイナンバーRAGAPI
Dify API呼出しプログラムから呼び出す以下のようなフローです。
APIから質問を受け取るとDifyのナレッジに登録した「マイナンバーQ&A.txt」を知識源としてベクトル検索を行い、LLMで知識源に基づく回答をします。
③マイナンバーQ&A.txt
デジタル省が作成したマイナンバーカードに関するよくある質問のmynumber_faq_03をテキスト化してDifyのナレッジとして取り込んだものです。
FAQの一部ですので、「マイナンバーカード発行の手数料はいくらですか?」などの質問に答えられます。
よくある質問:マイナンバーカードについて|デジタル庁 (digital.go.jp)
4.マイナンバーRAGAPI(Dify)
Difyでチャットボットのチャットフローを作成します。チャットフローはワークフローと似ていますが、DifyではチャットボットUIの有無が異なります。
具体的にはチャットフローはチャットボットUIを持っていますが、ワークフローはチャットフローから呼び出したりAPIから呼び出す際に使用されます。
チャットフロー、ワークフローの何れもAPIアクセスをサポートできますので、ここではチャットボットUIでもデバッグができるチャットフローを使用してAPIを作成します。
4.1 Difyチャットフロー
チャットフローには通常、「引用と帰属」のみがデフォルトの機能で追加されていますが、できるだけリッチにしたいので、「会話の開始」と「コンテンツのも出レーション」以外の全ての
「フォローアップ」、「テキストから音声へ」(モデルプロバイダーでTTSの設定が必要)、「音声からテキストへ」(モデルプロバイダーでSTTの設定が必要)、「引用と帰属」を有効にします。
No | Difyノード | 説明 | 備考 |
---|---|---|---|
1 | 開始 | ユーザーからの入力を司るDifyのノードです sys.queryという変数にユーザー入力 sys.filesと変数にユーザーがアップロードしたファイルが入ります。 sys.conversation_idに会話のIDが入ります。 sys.user_idにユーザー名が入ります |
今回はsys.queryだけを使います。 |
2 | 知識取得 | Difyのナレッジに登録した「マイナンバーQ&A.txt」を検索するノードです。ユーザーからの入力であるsys.queryと意味的に近い「マイナンバーQ&A.txt」のチャンクをN-to-1リトリーバルで最大3個(ナレッジ登録時のトップKの値)でベクトル検索します。 | ベクトル検索とは自然言語処理において意味的に近いものを検索するということです。 例えば「マイナンバーカードの交付手数料」と「マイナンバーカード発行の手数料」は意味的に近いといえるので、キーワード検索では「交付手数料」が検索キーワードになければ検索できませんでしたが、「発行の手数料」という言葉でも検索できるようになります。 |
3 | LLM | 知識取得でベクトル検索したデータをコンテキストとして与えて、システムプロンプトでコンテキストをナレッジとして参照してユーザーからの質問に答える指示をLLMにプロンプトで与えるノードです。 LLMは知識源に回答に必要なデータが見つからなくてもトレーニングデータをもとに回答を生成してしまうので、コンテキストからユーザーの質問に答えられなかったら、答えないように明確な指示をあたえることが重要です。 システムプロンプト Use the following context as your learned knowledge, inside XML tags. {{#context#}} When answer to user: - If you don't know, just say that you don't know. - If you don't know when you are not sure, ask for clarification. Avoid mentioning that you obtained the information from the context. And answer according to the language of the user's question. ユーザプロンプト sys.query |
システムプロンプト(日本語訳) 次のコンテキストを学習した知識として使用し、 XML タグの中に入れてください。 {{#context#}} ユーザーに回答する際には次の点に注意してください。 - 知らない場合は、知らないと言ってください。 - 確信が持てない場合は、明確にするために質問してください。 コンテキストから情報を取得したことに言及しないようにしてください。そして、ユーザーの質問の言語に応じて回答してください。 |
4 | 回答 | LLMから応答されたメッセージをユーザに応答するノードです。 | - |
4.2 APIキー
チャットフローでAPIアクセスを有効にするには[Dify]⇒[スタジオ]⇒<対象のチャットフロー>を開き左側ペインの「APIアクセス」をクリックして、右上の「APIキー」から「APIシークレットキー」を発行します。
Base URLとAPIシークレットキーはNode.js(JavaScript)プログラムで使用しますので控えておいてください。
5.DifyAPI_eval01 プロジェクトの作成
DifyAPI_eval01はNode.js(JavaScript)で作成されたDify APIの呼び出しプログラムです。
コーディング中のqueryに記載した質問をDifyのAPIにDifyのエンドポイントであるBase URとAPIシークレットキーを使って接続し、Dify APIからの応答をコンソールに表示ます。
5.1 Node.jsプロジェクトの作成
Node.jsでプロジェクトを作成するにはフォルダを作成して、フォルダ内にpackage.jsonファイルを作成する必要があります。
Node.jsではこのpackage.jsonでプログラムのパッケージ管理を行っています。
package.jsonはnpm initコマンドでウィザード形式で作成することができます。
Microsoft Windows [Version 10.0.22631.3880]
(c) Microsoft Corporation. All rights reserved.
Q:\OneDrive\Node.js\DifyAPI_eval01>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (difyapi_eval01)
version: (1.0.0)
description: Evaluation of Dify API
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to Q:\OneDrive\Node.js\DifyAPI_eval01\package.json:
{
"name": "difyapi_eval01",
"version": "1.0.0",
"description": "Evaluation of Dify API",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes)
npm notice
npm notice New minor version of npm available! 10.5.0 -> 10.8.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.2
npm notice Run npm install -g npm@10.8.2 to update!
npm notice
Q:\OneDrive\Node.js\DifyAPI_eval01>
制裁されたpackage.json
{
"name": "difyapi_eval01",
"version": "1.0.0",
"description": "Evaluation of Dify API",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
5.2 ソースコードの作成
Node.jsのソースコードはできるだけシンプルなものにします。
Difyのナレッジに登録した「マイナンバーQ&A.txt」はほんの一部のFAQですので、ここではベクトル検索で答えられる「マイナンバーカードの発行の手数料はいくらですか?」をユーザー入力として与え、Difyのナレッジを使用して回答をするプログラムを作成します。
response_modeをstreamingにしている関係でDifyからの応答は非同期となりますので、dataはタイプライターのように繰り返して応答されます。
// npm install axios --save
const axios = require('axios');
const api_endpoint = 'http://localhost/v1/chat-messages'; // ここにDifyのEndpointを入力してください
const api_key = 'app-xxxxxxxxxxxxxxxxxxxxxxxx'; // ここにあなたのAPIキーを入力してください
const data = {
inputs: {},
query: "マイナンバーカードの発行の手数料はいくらですか?",
//query: "マイナンバーカードはどのような時に使うのですか?",
response_mode: "streaming",
conversation_id: "",
user: "user001",
files: []
};
axios.post('http://localhost/v1/chat-messages', data, {
headers: {
'Authorization': `Bearer ${api_key}`,
'Content-Type': 'application/json'
}
})
.then(response => {
const workflow_started = 'workflow_started';
const workflow_finished = 'workflow_finished';
const dataArray = response.data.toString().split('\n');
dataArray.forEach(data => {
if (data.startsWith('data: ')) {
const jsonObject = JSON.parse(data.substring(6));
if(jsonObject.event == workflow_started){
console.log("Q:");
console.log(jsonObject.data.inputs['sys.query']);
}
if(jsonObject.event == workflow_finished){
console.log("A:");
console.log(jsonObject.data.outputs['answer']);
}
}
}
);
})
.catch(error => {
console.error(error);
});
※APIキーは[Dify]⇒[チャットボット]⇒<対象のチャットボット>⇒[APIアクセス]⇒[APIキー]で発行したものです。
json応答仕様
No | event | 分かっていること | 備考 |
---|---|---|---|
1 | workflow_started | チャットフロー又はワークフロー開始時のイベント conversation_idの払い出しがされsys.queryなどが記録されます |
- |
2 | node_started | Difyのノードの開始イベント node_type(「start」、「knowledge-retrieval」、「LLM」、「answer」)でどのノードが開始されたかが分かります。 |
- |
3 | node_finished | Difyのノードの終了イベント node_type(「start」、「knowledge-retrieval」、「LLM」、「answer」)でどのノードが開始されたかが分かります。 ノード終了時のoutputも格納されているようです。 |
- |
4 | message | DifyのLLMノードの推論モデルより非同期で一文字づつ応答されます。 | タイプライターのような出力をしたい場合はこちらを1文字づつ追加していき文章を組み立てます。 |
5 | message_end | メッセージストリームの終了イベント | - |
6 | workflow_finished | チャットフロー又はワークフロー終了時のイベント | - |
7 | tts_message | TTS(Text-To-Speach)用の音声データ(audio)のバイナリーをBase64エンコーディングしたものが応答されます。 チャンク分割されて送られてくるので結合してBase64デコードし再生するのだと思われます。 |
- |
8 | tts_message_end | TTSストリームの終了イベント | - |
5.3 Node.js依存パッケージをインストールする
今回のプログラムではaxiosパッケージを使用してDifyのAPIのエンドポイントに接続しますので、npmでaxiosをインストールします。
package.jsonにも反映させたいので—saveオプションを付けてインストールします
Q:\OneDrive\Node.js\DifyAPI_eval01>npm install axios --save
added 9 packages, and audited 10 packages in 1s
1 package is looking for funding
run `npm fund` for details
found 0 vulnerabilities
Q:\OneDrive\Node.js\DifyAPI_eval01>
※パッケージをインストールするとプロジェクトフォルダー配下にpackage-lock.jsonというファイルとnode_modulesフォルダが作成されます。
6.DifyAPI_eval01 プロジェクトの実行
Node.jsでのプログラム実行はnodeコマンドで行います。
Q:\OneDrive\Node.js\DifyAPI_eval01>node index.js
Q:
マイナンバーカードの発行の手数料はいくらですか?
A:
マイナンバーカードの発行手数料は、一般的には無料です。ただし、一部の金融機関やコンビニエンスストアなどで発行する場合、手数料がかかる場合があります。具体的な手数料については、発行を希望する場所や方法によって異なるため、詳細については発行を希望する場所にお問い合わせいただくか、関連するウェブサイトや資料をご確認ください。
Q:\OneDrive\Node.js\DifyAPI_eval01>
Q:\OneDrive\Node.js\DifyAPI_eval01>node index.js
Q:
マイナンバーカードはどのような時に使うのですか?
A:
マイナンバーカードは、個人の身分証明書として使用されることがあります。例えば、金融機関で口座開設やローンの手続きをする際に、マイナンバーカードを提示することが求められることがあります。また、公的な手続きや申請書類の提出時にもマイナンバーカードが必要とされる場合があります。ただし、具体的な利用範囲や手続きは法律や規則によって定められており、その詳細については各機関や行政機関の指示に従う必要があります。
Q:\OneDrive\Node.js\DifyAPI_eval01>
このケースでベクトル検索された知識源は以下の通りでした
これらのトレース情報は[Dify]⇒[チャットボット]⇒<対象のチャットボット>⇒[ログ&アナウンス]⇒[ログを表示]⇒[トレース]⇒[知識取得]の出力で確認できます。
{
"result": [
{
"metadata": {
"_source": "knowledge",
"position": 1,
"dataset_id": "1e484297-e404-422b-9683-c1247ab28a60",
"dataset_name": "マイナンバーQ&A.txt...",
"document_id": "888151e6-c59d-47fd-80c6-f3326a8b8819",
"document_name": "マイナンバーQ&A.txt",
"document_data_source_type": "upload_file",
"segment_id": "73af0e2f-4b4f-4309-a404-a24466c9235c",
"retriever_from": "workflow",
"score": 0.46970487000000005,
"segment_hit_count": 2,
"segment_word_count": 187,
"segment_position": 15,
"segment_index_node_hash": "cdc56275f0ed562241198a5f3c0041168a8d80c416955d1659e6e48c272bf3ba"
},
"title": "マイナンバーQ&A.txt",
"content": "マイナンバーの通知や利用、マイナンバーカードの交付などの手続で、行政機関などが口座番号や口座の暗証番号、所得の情報、家族構成や年金・保険の情報などを聞いたり、お金やキャッシュカードを要求したりすることは一切ありません。銀行のATMの操作をお願いすることもありません。こうした内容の電話、手紙、メール、訪問などには絶対に応じないよう、注意してください。\n(2023年6月更新)"
},
{
"metadata": {
"_source": "knowledge",
"position": 1,
"dataset_id": "1e484297-e404-422b-9683-c1247ab28a60",
"dataset_name": "マイナンバーQ&A.txt...",
"document_id": "888151e6-c59d-47fd-80c6-f3326a8b8819",
"document_name": "マイナンバーQ&A.txt",
"document_data_source_type": "upload_file",
"segment_id": "030176d2-ce55-4151-a950-9e90c1f7ead7",
"retriever_from": "workflow",
"score": 0.42941403,
"segment_hit_count": 2,
"segment_word_count": 224,
"segment_position": 7,
"segment_index_node_hash": "5e70307a07eddf5b231334f8975496a2e92a5f9fa7864d45e67a004adb79a2af"
},
"title": "マイナンバーQ&A.txt",
"content": "Q1-4 マイナンバーはどのような場面で使うのですか。\nA1-4\nマイナンバーを誰がどのような場面で使ってよいかどうかは、法令や条例で決められています。具体的には、国の行政機関や地方公共団体などが、社会保障制度、税制、災害対策などの、法令又は条例で定められた行政手続で利用することになります。国民の皆さまには、年金、雇用保険、医療保険の手続や生活保護、児童手当その他福祉の給付、確定申告などの税の手続で申請書などにマイナンバーの記載が求められます。"
},
{
"metadata": {
"_source": "knowledge",
"position": 1,
"dataset_id": "1e484297-e404-422b-9683-c1247ab28a60",
"dataset_name": "マイナンバーQ&A.txt...",
"document_id": "888151e6-c59d-47fd-80c6-f3326a8b8819",
"document_name": "マイナンバーQ&A.txt",
"document_data_source_type": "upload_file",
"segment_id": "e6917249-d475-42cc-ae83-33f125fbb6f9",
"retriever_from": "workflow",
"score": 0.42365489999999995,
"segment_hit_count": 2,
"segment_word_count": 97,
"segment_position": 8,
"segment_index_node_hash": "f3d03b4285079fc45901dd66e7844b0c7ecd9af540049bfa1ec85f405672d223"
},
"title": "マイナンバーQ&A.txt",
"content": "また、税や社会保険の手続を勤務先の事業主や金融機関などが個人に代わって手続を行う場合があり、勤務先に加え、一定の取引のある金融機関にマイナンバーを提示する場合があります。\n(2023年6月更新)"
}
]
}
{
"result": [
{
"metadata": {
"_source": "knowledge",
"position": 1,
"dataset_id": "1e484297-e404-422b-9683-c1247ab28a60",
"dataset_name": "マイナンバーQ&A.txt...",
"document_id": "888151e6-c59d-47fd-80c6-f3326a8b8819",
"document_name": "マイナンバーQ&A.txt",
"document_data_source_type": "upload_file",
"segment_id": "030176d2-ce55-4151-a950-9e90c1f7ead7",
"retriever_from": "workflow",
"score": 0.6621090199999999,
"segment_hit_count": 5,
"segment_word_count": 224,
"segment_position": 7,
"segment_index_node_hash": "5e70307a07eddf5b231334f8975496a2e92a5f9fa7864d45e67a004adb79a2af"
},
"title": "マイナンバーQ&A.txt",
"content": "Q1-4 マイナンバーはどのような場面で使うのですか。\nA1-4\nマイナンバーを誰がどのような場面で使ってよいかどうかは、法令や条例で決められています。具体的には、国の行政機関や地方公共団体などが、社会保障制度、税制、災害対策などの、法令又は条例で定められた行政手続で利用することになります。国民の皆さまには、年金、雇用保険、医療保険の手続や生活保護、児童手当その他福祉の給付、確定申告などの税の手続で申請書などにマイナンバーの記載が求められます。"
},
{
"metadata": {
"_source": "knowledge",
"position": 1,
"dataset_id": "1e484297-e404-422b-9683-c1247ab28a60",
"dataset_name": "マイナンバーQ&A.txt...",
"document_id": "888151e6-c59d-47fd-80c6-f3326a8b8819",
"document_name": "マイナンバーQ&A.txt",
"document_data_source_type": "upload_file",
"segment_id": "be03fa74-7767-45b9-b56a-46423da0714b",
"retriever_from": "workflow",
"score": 0.581958,
"segment_hit_count": 5,
"segment_word_count": 163,
"segment_position": 6,
"segment_index_node_hash": "bbee0d87b96e6224f534effc3a3f2c5efd0c7d4be3eec8c71092be51edf5bfd2"
},
"title": "マイナンバーQ&A.txt",
"content": "3つめは、所得をこれまでより正確に把握することで、きめ細やかな社会保障制度を設計し、公平・公正な社会を実現することです。\nさらに、マイナンバーカードやマイナポータルはマイナンバーそのものを使わない利活用が可能であり、民間活用を含め、デジタル社会の重要な基盤として、最大限活用していくこととしています。\n(2022年12月更新)"
},
{
"metadata": {
"_source": "knowledge",
"position": 1,
"dataset_id": "1e484297-e404-422b-9683-c1247ab28a60",
"dataset_name": "マイナンバーQ&A.txt...",
"document_id": "888151e6-c59d-47fd-80c6-f3326a8b8819",
"document_name": "マイナンバーQ&A.txt",
"document_data_source_type": "upload_file",
"segment_id": "e6917249-d475-42cc-ae83-33f125fbb6f9",
"retriever_from": "workflow",
"score": 0.57156718,
"segment_hit_count": 6,
"segment_word_count": 97,
"segment_position": 8,
"segment_index_node_hash": "f3d03b4285079fc45901dd66e7844b0c7ecd9af540049bfa1ec85f405672d223"
},
"title": "マイナンバーQ&A.txt",
"content": "また、税や社会保険の手続を勤務先の事業主や金融機関などが個人に代わって手続を行う場合があり、勤務先に加え、一定の取引のある金融機関にマイナンバーを提示する場合があります。\n(2023年6月更新)"
}
]
}