1
0

image.png
作成日:2024年7月21日(日)

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に対応したインタフェースです。

image.png

簡単に言うと作成した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で知識源に基づく回答をします。

image.png

③マイナンバー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の設定が必要)、「引用と帰属」を有効にします。

image.png

チャットフロー
image.png

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シークレットキー」を発行します。

image.png

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フォルダが作成されます。

image.png

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月更新)"
    }
  ]
}

7.参考URL

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0