次元の不一致の構造
それは通常、「ちょっとした」設定変更の直後に発生します。ローカルのHuggingFaceモデルをOpenAI API呼び出しに置き換え、サービスを再起動すると、RAG(検索拡張生成)パイプラインが即座にクラッシュします。これはロジックのバグではなく、根本的な数学的失敗です。
AssertionError: Embedding dimension 1536 does not match index dimension 768.
FAISSは、データを多次元グリッド上の点として扱う高性能なC++ライブラリです。これは厳密な一貫性を要求します。もし all-mpnet-base-v2(768次元)を使用してインデックスを構築したのに、OpenAIの text-embedding-3-small(1536次元)でクエリを実行しようとすると、その比較は数学的に不可能です。768次元空間の点と1536次元空間の点を比較することはできません。
衝突箇所の特定
データを削除する前に、2つのコンポーネントの正確な次元を特定しましょう。このエラーは通常、FAISS.load_local() に渡された embeddings オブジェクトが、FAISS.save_local() の実行時に使用されたものと異なるために発生します。
ステップ1:保存されたインデックスの確認
インデックスの要件を確認するためにクエリを実行する必要はありません。基盤となるライブラリを使用して、.faiss ファイルを直接調査します:
import faiss
# 保存されたインデックスファイルを読み込む
index = faiss.read_index("index_path/index.faiss")
print(f"Index dimension: {index.d}")
# 出力: Index dimension: 768
ステップ2:アクティブなモデルの検証
次に、現在のコードが実際に何を生成しているかを確認します。コード1行で、エンベディングプロバイダーの出力サイズを検証できます:
from langchain_openai import OpenAIEmbeddings
# 現在のモデルを初期化
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
test_vector = embeddings.embed_query("test")
print(f"Model dimension: {len(test_vector)}")
# 出力: Model dimension: 1536
768と1536(あるいは384と1024)という数値が一致しない限り、AssertionError は解消されません。
修正方法
選択肢は2つあります。古いインデックスに合わせてモデルをダウングレードするか、新しいモデルを活用するためにインデックスを再構築するかです。より高性能なLLMスタックにアップグレードする場合、ほとんどの開発者は再構築を選択します。
オプションA:インデックスの再構築(アップグレードに推奨)
既存のベクトルを「リサイズ」する方法はありません。768次元のモデルから1536次元のモデルに移行する場合、ソースドキュメントを再度エンベディングする必要があります。これはベクトルストアの新規作成となります。
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
# 1. 新しい1536次元のモデルを使用
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 2. ソースドキュメントの処理
loader = TextLoader("knowledge_base.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=50)
docs = text_splitter.split_documents(documents)
# 3. 新しいインデックスを作成して保存
vectorstore = FAISS.from_documents(docs, embeddings)
vectorstore.save_local("faiss_index_v2")
オプションB:モデルの差し戻し
数百万のドキュメントを再インデックス化するコストや時間がかかりすぎる場合は、元のモデルを使用する必要があります。例えば、インデックスが all-MiniLM-L6-v2 で構築されていた場合、ローダーが正確にそれを使用していることを確認してください:
from langchain_community.embeddings import HuggingFaceEmbeddings
# このモデルは384次元を生成
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
# 一致する384次元のインデックスを読み込む
vectorstore = FAISS.load_local("legacy_index", embeddings, allow_dangerous_deserialization=True)
RAGパイプラインの将来的な保護
アプリケーションがクエリの受け付けを開始する前に、モデルとインデックスの次元を比較するバリデーションチェックを起動シーケンスに追加することで、これらのクラッシュが本番環境に到達するのを防ぎます:
def safe_load_faiss(folder_path, embeddings_model):
vectorstore = FAISS.load_local(folder_path, embeddings_model, allow_dangerous_deserialization=True)
# インデックスに対してサンプルエンベディングをテスト
model_dim = len(embeddings_model.embed_query("validation"))
index_dim = vectorstore.index.d
if model_dim != index_dim:
raise ValueError(f"Critical Mismatch: Model is {model_dim}D, but Index is {index_dim}D.")
return vectorstore
主なポイント
- 明確な命名: 混乱を避けるために、インデックスフォルダにはモデル名と次元数を含めます(例:
vector_store_openai_1536)。 - メタデータの保存: モデル名、バージョン、次元数を記録した
config.jsonファイルを FAISS インデックスの隣に保管します。 - デフォルト値に注意: OpenAIの
text-embedding-3-smallはデフォルトで1536次元ですが、切り詰めることも可能です。デフォルトを使用しない場合は、常に次元を明示してください。

