DifyのナレッジをQdrantに載せるには、docker/.envでVECTOR_STORE=qdrantを指定し、COMPOSE_PROFILESにqdrantを加えてからdocker compose up -dを実行します。Dify 1.19.0(2026-11-04公開)からはプロファイルが自動で連動しなくなり、変数1つを替えるだけの古い手順ではQdrantのコンテナが起動しません。この記事では、1.19.0の設定ファイル、同梱Qdrantと外部Qdrantへの接続、flask vdb-migrateによる移行、コレクションの構造までを公式リポジトリのソースに沿って説明します。版番号は2026年11月8日時点の確認値です。
まとめ:DifyをQdrantへ切り替える前に決める接続先と移行の範囲
最初に決めるのは「どのQdrantにつなぐか」です。Dify同梱のQdrantはイメージがlanggenius/qdrant:v1.8.3で、Difyが固定しているqdrant-client 1.9.0と1マイナー差に収まります。2026年11月時点のQdrant最新系であるv1.20系へつなぐと、Qdrant公式が検証していない版差になります。
新規環境なら、.envにVECTOR_STOREとCOMPOSE_PROFILESの2行を書けば同梱Qdrantで動きます。既存環境では、旧ストアのプロファイルを残したまま切り替え、flask vdb-migrateで高品質インデックスのナレッジだけを移します。
- 新規構築:
VECTOR_STORE=qdrantとCOMPOSE_PROFILES=qdrant,postgresql,collaborationを書き、既定のAPIキーを替える - 既存移行:バックアップ、旧ストアのプロファイル維持、
vdb-migrate、件数確認の順に進める - 外部接続:qdrantプロファイルを外し、
QDRANT_URLとAPIキーをルートの.envに書く
Dify 1.19.0でベクトルストアを決める設定ファイルと値の優先順位
1.19.0では、docker/.envに置く値が手動設定の必要なものだけに絞られました。サービスごとの既定値はdocker/envs/配下の.defaultsファイルに分かれ、Composeが自動で読み込みます。Difyのナレッジ機能そのものの作り方はDifyでチャットボットを作る手順と社内ナレッジの設定で扱っているので、ここでは検索基盤の差し替えに絞ります。
1.19.0のVECTOR_STOREとCOMPOSE_PROFILES両方の変更
1.18.0の.env.exampleでは、COMPOSE_PROFILES=${VECTOR_STORE:-weaviate},${DB_TYPE:-postgresql},collaborationと書かれ、VECTOR_STOREを替えればQdrantのコンテナも起動していました。1.19.0の.env.exampleはCOMPOSE_PROFILES=weaviate,postgresql,collaborationと値を直接書く形です。
この差を知らずにVECTOR_STOREだけ替えると、Weaviateのコンテナが動いたままQdrantは立ち上がりません。新しいナレッジの索引作成が失敗する原因は、接続先が無いことです。1.19.0のリリースノートは、ルートの.envを優先させる仕組みのためにDocker Compose v2.35.0以上を必須にしています。上げる前にdocker compose versionで版を確かめます。
qdrant.defaultsの接続変数と既定鍵difyai123456の変更理由
Qdrantの接続設定はenvs/vectorstores/qdrant.defaultsにまとまっています。VECTOR_STORE=qdrantのときだけ、Composeがこのファイルをapi・worker・worker_beatへ読み込ませます。
| 変数 | 既定値 | 役割 |
|---|---|---|
| QDRANT_URL | http://qdrant:6333 | Difyが接続する先 |
| QDRANT_API_KEY | difyai123456 | クライアントとサーバーの共通鍵 |
| QDRANT_CLIENT_TIMEOUT | 20 | クライアントの待ち秒数 |
| QDRANT_GRPC_ENABLED | false | gRPC接続の有無 |
| QDRANT_REPLICATION_FACTOR | 1 | 新規コレクションの複製数 |
同じファイルの末尾でQDRANT__SERVICE__API_KEYにQDRANT_API_KEYの値を写しているため、ルートの.envでQDRANT_API_KEYを1か所替えれば、Dify側とQdrant側の鍵がそろって変わります。既定値は公開リポジトリに載っている文字列なので、社内LANでも替えておきます。
同梱Qdrant v1.8.3とqdrant-client 1.9.0固定の互換範囲
1.19.0のdocker-compose.yamlでは、qdrantサービスのイメージがlanggenius/qdrant:v1.8.3、保存先が./volumes/qdrant、ファイル記述子の上限が524288です。portsの指定は無く、ホストの外からは直接つながりません。
Dify側のクライアントは、vdb-qdrantのpyproject.tomlでqdrant-client==1.9.0に固定された構成です。Qdrant公式のUpgrading Qdrantは、SDKをサーバーの1マイナー以内に保つよう求め、それより大きな差は「動く場合もあるが検証していない」としています。同梱の1.8.3と1.9.0の組み合わせは、この範囲に収まっています。
新規環境で同梱Qdrantを起動しナレッジを作るまでのdocker compose手順
まだナレッジが1件も無い環境なら、移行の手間はかかりません。ここではPostgreSQLと同梱Qdrantを組み合わせる構成を例にします。Qdrant単体の起動や永続化の考え方はQdrant Dockerの構築手順と共通です。
.envの3行とdocker compose up -dによる同梱Qdrant起動
docker/README.mdの例に、APIキーの差し替えを加えた形です。docker/ディレクトリで実行します。
# docker/.env(既存の行は残し、次の3行を書き換える・追記する)
VECTOR_STORE=qdrant
COMPOSE_PROFILES=qdrant,postgresql,collaboration
QDRANT_API_KEY=ここにopenssl rand -hex 32の出力を貼る
# 反映と状態確認
docker compose up -d
docker compose ps --all
Weaviateを一度も使っていなければ、プロファイルからweaviateを外してかまいません。README.mdのとおりdocker compose restartは環境変数を読み直さないので、反映は必ずup -dで行います。COMPOSE_PROFILESとVECTOR_STOREはComposeがサービス別の設定より先に読むため、qdrant.envではなくルートの.envに置きます。
apiコンテナからQdrantのコレクション一覧と件数を確かめるコード
同梱Qdrantはポートを公開していないため、ホストからcurlでは届きません。apiコンテナに入っているqdrant-clientを使えば、Difyと同じ経路で接続を確かめられます。
docker compose exec -T api python - <<'EOF'
import os
from qdrant_client import QdrantClient
client = QdrantClient(url=os.environ["QDRANT_URL"], api_key=os.environ.get("QDRANT_API_KEY"))
for col in client.get_collections().collections:
print(col.name, client.count(col.name, exact=True).count)
EOF
ナレッジに文書を入れた後なら、Vector_index_で始まり_Nodeで終わる名前が並びます。命名はmodels/dataset.pyのgen_collection_name_by_idで、ナレッジIDのハイフンをアンダースコアに置き換えた文字列です。件数が0のままなら、apiとworkerがVECTOR_STORE=qdrantを受け取っているかを先に疑います。
外部Qdrant ServerやQdrant CloudへのDify接続設定と版の注意
Qdrantを別サーバーやマネージドサービスで運用し、Difyから接続だけする構成もとれます。マネージド版のクラスタ作成とAPIキー発行はQdrant Cloudの使い方で手順を説明しています。
qdrantプロファイルを外してQDRANT_URLとAPIキーをルートに書く設定例
DifyのEnvironment Variablesは、外部サーバーを使うときは同梱のプロファイルを外し、接続設定を渡すよう案内しています。
# docker/.env(外部Qdrantへ接続する例)
VECTOR_STORE=qdrant
COMPOSE_PROFILES=postgresql,collaboration
QDRANT_URL=https://qdrant.example.internal:6333
QDRANT_API_KEY=外部Qdrantで発行したキー
# 必要な場合のみ
# QDRANT_CLIENT_TIMEOUT=60
認証を設けていない外部サーバーなら、QDRANT_API_KEYを空にするのが、同ページに記載された設定方法です。Qdrant側はSecurity & Access Controlのとおり、api-keyヘッダーで鍵を受け取ります。社外のネットワークを通すなら、URLはhttpsにして鍵を平文で流さない構成にします。
v1.20系サーバーへqdrant-client 1.9.0でつなぐときの検証範囲
外部のQdrantをv1.20系で立てると、Difyのクライアント1.9.0とは11マイナーの差になります。Qdrant公式の互換方針では未検証の領域です。Dify側のコードはcreate_collection、upsert、search、ペイロード索引の作成という基本操作に限られますが、動くことは自分の環境で確かめるしかありません。
検証するなら、ナレッジの作成、文書追加、検索テスト、文書削除、ハイブリッド検索の5操作を通します。サーバーの版を上げるたびに同じ確認を繰り返す運用になる点も、構成を選ぶ時点で織り込んでおきます。
WeaviateからQdrantへのナレッジ移行とflask vdb-migrate実行
運用中のDifyでは、VECTOR_STOREを替えても作成済みナレッジの索引は動きません。README.mdは、既存のナレッジが保存済みの接続先を使い続けると説明しています。索引をQdrantへ移すのがflask vdb-migrateです。
移行前のバックアップとWeaviateのプロファイルを残す理由
1.19.0のリリースノートは、データベース、ベクトルストアのデータ、アップロード済みファイル、環境設定ファイルを先に退避するよう求めています。Docker Composeの構成ならdocker/volumes/配下と.env群が対象です。ファイルの保存先の扱いはDifyのストレージをAmazon S3に切り替える設定手順で詳しく触れています。
切り替えの間は、旧ストアのプロファイルを外しません。Difyのドキュメントは、旧ストアがWeaviate以外なら、その.defaultsを.envへコピーしておかないと既存ナレッジの接続が切れると注意しています。Weaviateの接続既定値はapi-worker.defaultsに残してあるため、Weaviateからの移行ではコピーは要りません。
# docker/.env(移行期間中)
VECTOR_STORE=qdrant
COMPOSE_PROFILES=weaviate,qdrant,postgresql,collaboration
flask vdb-migrateの–scope指定と移行対象になるナレッジの条件
DifyのStorage & Migrationは、Dockerでの実行例としてdocker exec -it docker-api-1 flask vdb-migrateを示し、検証済みの移行先にQdrantを挙げています。Compose経由なら次のように書けます。
# ナレッジだけを移す(既定はall=ナレッジと注釈返信の両方)
docker compose exec api flask vdb-migrate --scope knowledge
# 注釈返信の索引も移す
docker compose exec api flask vdb-migrate --scope annotation
commands/vector.pyを読むと、対象はインデックス方式が「高品質」のナレッジだけです。「経済的」はベクトルを持たないので移りません。すでに索引の種別がqdrantのナレッジは飛ばされます。文書は索引作成が完了し、有効で、アーカイブされていないものに限られます。
移行はナレッジ単位で、移行先の索引をいったん削除してから作り直す順です。途中で失敗したナレッジはロールバックされ、次のナレッジへ進みます。出力のcreatedとskippedの件数を控えておくと、後の確認で役に立ちます。
埋め込みAPIが再び呼ばれるかはembeddingsテーブルの記録で決まる
移行は保存済みのベクトルをコピーするのではなく、セグメントの本文を埋め込みモデルに通して登録し直します。vector_factory.pyのcreateは、1,000件ずつembed_documentsを呼んでから書き込みます。
ここで効くのがcached_embedding.pyです。PostgreSQLのembeddingsテーブルに同じモデル名と本文ハッシュの行があれば、それを使い回します。記録が無い本文の分だけ埋め込みAPIを呼ぶので、課金が発生するかどうかはこのテーブルの中身しだいです。移行前に行数と、ナレッジに設定したモデル名が一致しているかを見ておきます。
ナレッジ移行後にWeaviateを止めてよいかを判断する確認手順
次の順で確かめ、すべて満たしてからプロファイルからweaviateを外します。
vdb-migrateの出力で、失敗を示す赤字の行が無いことを確かめる- 前述のコードで、ナレッジの数と同じ数の
Vector_index_コレクションがあることを確かめる - 主要なナレッジで検索テストを実行し、移行前と同じ文書が上位に出るかを見る
COMPOSE_PROFILESからweaviateを外してdocker compose up -dし、検索テストをもう一度通す
Weaviateのvolumesはすぐに消さず、1〜2週間は残しておきます。戻すときはVECTOR_STORE=weaviateに替えて同じコマンドを流せば、種別が違うナレッジとして再び移せます。Weaviate自体の版上げを先に済ませる必要がある場合は、EC2上のDifyで1.16系から上げるときのWeaviate段階移行を参考にしてください。
DifyがQdrantに作るコレクション構造とgroup_idフィルタの読み方
DifyのQdrantは、Difyの画面から使う限り中身を意識する必要はありません。ただし、同じQdrantを他のアプリやMCPサーバーからも読む構成では、Difyの作り方を知らないと検索が遅くなります。
ナレッジごとのコレクションとm=0・payload_m=16のHNSW設定
qdrant_vector.pyは、コレクション作成時にHNSWをm=0、payload_m=16、ef_construct=100にする設定です。さらにgroup_id、doc_id、document_idのキーワード索引と、本文の全文索引(トークナイザーはmultilingual、2〜20文字)を張ります。各点のgroup_idにはナレッジIDが入ります。
Qdrant公式のConfigure Multitenancyによると、m=0はコレクション全体のグラフを作らない指定です。payload_mを正の値にすると、作成されるのは、ペイロードの値ごとに分かれた個別のグラフです。DifyはテナントのIDをgroup_idに入れて分ける、公式どおりの構成をとっています。グラフのmやef_constructの意味はHNSWの仕組みとM・ef_constructionの決め方で説明しています。
Difyの外からコレクションを検索するときにgroup_idを外す落とし穴
同じMultitenancyのページには、group_idで絞らない全体検索は全グループをなめるため遅くなると書かれています。Difyのコレクションを別のPythonアプリから検索するなら、group_idが一致する条件をフィルタに必ず入れます。
Claude CodeなどからQdrantを記憶ストアとして使うQdrant MCPの設定では、MCPサーバーが独自の名前付きベクトルを使います。Difyのコレクションとは形が違うため、同じコレクションを共用せず、コレクションを分けて置くほうが安全です。
Qdrantへ切り替えるべきDify環境とWeaviateのままでよい場面の判断
切り替えは手段であって、目的ではありません。ここでは、移す価値がある条件と、やめておく条件を具体的に挙げます。
DifyをQdrantへ移す価値がある条件と移行を見送るべき構成
移す価値があるのは、すでにQdrantを社内の別システムで運用していて、バックアップや監視の手順を一本化できる場合です。Qdrantのスナップショットでナレッジの索引も同じ手順で退避できるようになり、運用の窓口が1つ減ります。
見送るべきなのは、Weaviateで困っていない小規模な環境です。Dify 1.19.0の既定はWeaviateです。不満が具体的に無いまま移すと、移行と検証の工数だけが残ります。
もう1つ、同梱Qdrantで始めて後から最新系に上げる計画はおすすめしません。Upgrading Qdrantは、各中間マイナーの最新パッチを順に経由するよう求めており、1.8系から1.20系までは12回の段階更新になります。vdb-migrateは同じqdrant種別のナレッジを飛ばすため、Qdrant同士の移し替えには使えません。最新系で運用したいなら、最初から外部Qdrantに決めて検証するほうが手戻りが少なく済みます。
PostgreSQLにまとめたいならDifyのベクトルストアをpgvectorにするDocker設定、製品の違いから整理したいならベクトルDBの仕組みと製品比較と比べてください。
RAG基盤の組み替えで外部に任せる作業と社内で決めておく判断範囲
ベクトルストアの切り替えは、設定ファイル2行の変更に見えて、バックアップ、埋め込みコスト、検索精度の比較、旧ストアの撤去判断までがひとまとまりです。社内で決めておくべきなのは、どのナレッジを移すか、検索結果の良し悪しを誰がどの質問で判断するか、の2点です。
手順の実行と検証の自動化、Weaviateとの検索結果の比較は外部に任せやすい作業です。ナレッジの分割方法やハイブリッド検索の組み合わせ方まで含めて見直す場合は、RAG構築支援でDifyの構成診断から相談を受けています。
よくある質問
DifyとQdrantの組み合わせで、実際によく調べられている疑問をまとめました。
DifyでQdrantを使う設定は管理画面からできますか?
セルフホスト版のDifyでは、ベクトルストアは管理画面ではなく環境変数で決めます。docker/.envのVECTOR_STOREとCOMPOSE_PROFILESを書き換え、docker compose up -dで反映します。画面で選べるのはナレッジごとのインデックス方式と検索方式で、Qdrantの接続先やAPIキーの項目はありません。
Difyに同梱のQdrantを最新版のイメージへ差し替えられますか?
イメージのタグを書き換えれば起動自体は試せますが、二つの理由からおすすめしません。1つは、Qdrant公式の更新手順が中間のマイナー版を1つずつ経由するよう求めており、1.8系から一気に上げられないことです。もう1つは、Difyのクライアントが1.9.0に固定されていて、新しいサーバーとの組み合わせが未検証になることです。最新系を使いたいなら、外部Qdrantとして立てて検証します。
QdrantからWeaviateやpgvectorへ戻すことはできますか?
できます。VECTOR_STOREを戻したい種別に替え、そのプロファイルをCOMPOSE_PROFILESに入れてからflask vdb-migrateを実行します。移行コマンドは「現在のVECTOR_STOREと索引の種別が違うナレッジ」を対象にするため、向きは問いません。このときQdrantの接続が切れないよう、qdrant.defaultsをqdrant.envへコピーしておきます。
DifyのハイブリッドはQdrantでも使えますか?
Qdrantでもハイブリッド検索を利用できます。Difyのqdrant_vector.pyはベクトル検索と全文検索の両方を実装しており、コレクション作成時に張る索引には本文の全文索引も含まれる仕様です。ナレッジの検索設定でハイブリッドを選べば、検索結果はベクトル検索と全文検索の両方を組み合わせたものです。全文索引のトークナイザーはmultilingualで、最短2文字・最長20文字のトークンだけを索引に入れます。社内用語や型番が狙いどおりに引けるかは、ナレッジの検索テストで確かめてから本番に使います。
Qdrantのダッシュボードで、Difyが登録したデータを見られますか?
同梱Qdrantはportsを公開していないため、そのままではブラウザから開けません。本記事のPythonコードのようにapiコンテナ経由で件数を見るほうが安全です。ダッシュボードが必要なら、docker-compose.override.yamlで127.0.0.1:6333だけに公開し、外部から届かない形にとどめます。
関連記事
- Qdrant Dockerの構築手順:Difyの外にQdrantを立てるときの永続化とAPIキー設定
- Qdrant Cloudの使い方:外部接続先をマネージド版にする場合のクラスタ作成と料金の増え方
- pgvectorとは?インストール手順と使い方:Difyのベクトルストアをpgvectorにする選択肢
- DifyをHelm chartでAWS EKSに構築する手順:Kubernetes上のDifyで外部ベクトルストアを使う構成
- RAG構築の手順:検索基盤を差し替えた後の精度改善と本番運用の進め方