LangChain 向量存储集成使用指南,包括 Chroma、Pinecone、FAISS 和内存向量存储
向量存储是经过优化的数据库,用于存储和搜索高维向量(嵌入)。它们通过基于向量相似度而非关键字匹配来查找相似文档,从而实现语义搜索。对于 RAG(检索增强生成)系统至关重要。
| 向量存储 | 最适用于 | 包 | 持久化 | 可扩展性 | 主要特性 |
|---|---|---|---|---|---|
| FAISS | 本地、高性能 | @langchain/community | 磁盘 | 中等 | 快速、支持 CPU/GPU、本地 |
| Chroma |
| 开发、简单 |
@langchain/community |
| 磁盘 |
| 中等 |
| 易于设置、本地优先、Python API |
| Pinecone | 生产环境、托管 | @langchain/pinecone | 云 | 高 | 完全托管、自动扩展、免运维 |
| Memory | 测试、原型 | langchain/vectorstores/memory | 仅内存 | 低 | 简单、无设置、临时 |
| Weaviate | GraphQL、混合搜索 | @langchain/weaviate | 云/自托管 | 高 | GraphQL、混合搜索、模块化 |
| Qdrant | 高性能、过滤 | @langchain/qdrant | 云/自托管 | 高 | 快速、高级过滤、基于 Rust |
| Supabase | PostgreSQL 用户 | @langchain/community | 云/自托管 | 高 | PostgreSQL 扩展、熟悉的工具 |
选择 FAISS 如果:
选择 Chroma 如果:
选择 Pinecone 如果:
选择内存向量存储如果:
选择 Weaviate/Qdrant 如果:
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";
// 内存向量存储 - 适合测试
const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());
// 添加文档
await vectorStore.addDocuments([
{ pageContent: "LangChain is a framework for LLM apps", metadata: { source: "docs" } },
{ pageContent: "Vector stores enable semantic search", metadata: { source: "docs" } },
{ pageContent: "Paris is the capital of France", metadata: { source: "wiki" } },
]);
// 相似度搜索
const results = await vectorStore.similaritySearch("What is LangChain?", 2);
console.log(results);
// 带分数的搜索
const resultsWithScore = await vectorStore.similaritySearchWithScore("LangChain", 2);
resultsWithScore.forEach(([doc, score]) => {
console.log(`Score: ${score}, Content: ${doc.pageContent}`);
});
import { FaissStore } from "@langchain/community/vectorstores/faiss";
import { OpenAIEmbeddings } from "@langchain/openai";
const embeddings = new OpenAIEmbeddings();
// 从文档创建
const vectorStore = await FaissStore.fromDocuments(
[
{ pageContent: "Document 1 content", metadata: { id: 1 } },
{ pageContent: "Document 2 content", metadata: { id: 2 } },
],
embeddings
);
// 搜索
const results = await vectorStore.similaritySearch("query", 3);
// 保存到磁盘
await vectorStore.save("./faiss_index");
// 从磁盘加载
const loadedStore = await FaissStore.load("./faiss_index", embeddings);
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
// 需要运行 Chroma 服务器:docker run -p 8000:8000 chromadb/chroma
const vectorStore = await Chroma.fromDocuments(
[
{ pageContent: "Text 1", metadata: { category: "A" } },
{ pageContent: "Text 2", metadata: { category: "B" } },
],
new OpenAIEmbeddings(),
{
collectionName: "my-collection",
url: "http://localhost:8000", // Chroma 服务器 URL
}
);
// 带元数据过滤器的搜索
const results = await vectorStore.similaritySearch("query", 3, {
category: "A"
});
// 删除集合
await vectorStore.delete({ collectionName: "my-collection" });
import { PineconeStore } from "@langchain/pinecone";
import { Pinecone } from "@pinecone-database/pinecone";
import { OpenAIEmbeddings } from "@langchain/openai";
// 初始化 Pinecone 客户端
const pinecone = new Pinecone({
apiKey: process.env.PINECONE_API_KEY,
});
const pineconeIndex = pinecone.Index("my-index");
// 创建向量存储
const vectorStore = await PineconeStore.fromDocuments(
[
{ pageContent: "Content 1", metadata: { topic: "tech" } },
{ pageContent: "Content 2", metadata: { topic: "science" } },
],
new OpenAIEmbeddings(),
{
pineconeIndex,
maxConcurrency: 5,
}
);
// 带元数据过滤器的搜索
const results = await vectorStore.similaritySearch("query", 3, {
topic: "tech"
});
// 作为检索器使用
const retriever = vectorStore.asRetriever({
k: 5,
searchType: "similarity",
});
const docs = await retriever.getRelevantDocuments("query");
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";
const vectorStore = new MemoryVectorStore(new OpenAIEmbeddings());
// 一次或批量添加文档
await vectorStore.addDocuments([
{ pageContent: "Document 1", metadata: {} },
]);
// 稍后添加更多
await vectorStore.addDocuments([
{ pageContent: "Document 2", metadata: {} },
{ pageContent: "Document 3", metadata: {} },
]);
// 或从文本添加
await vectorStore.addTexts(
["Text 1", "Text 2"],
[{ source: "A" }, { source: "B" }]
);
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";
const vectorStore = await MemoryVectorStore.fromDocuments(
documents,
new OpenAIEmbeddings()
);
// 转换为检索器
const retriever = vectorStore.asRetriever({
k: 4, // 返回前 4 个结果
searchType: "similarity", // 或 "mmr" 用于最大边际相关性
});
// 在链中使用
import { ChatOpenAI } from "@langchain/openai";
import { createRetrievalChain } from "langchain/chains/retrieval";
import { createStuffDocumentsChain } from "langchain/chains/combine_documents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
const llm = new ChatOpenAI();
const prompt = ChatPromptTemplate.fromTemplate(`
Answer based on context:
{context}
Question: {input}
`);
const combineDocsChain = await createStuffDocumentsChain({ llm, prompt });
const chain = await createRetrievalChain({
retriever,
combineDocsChain,
});
const result = await chain.invoke({ input: "What is LangChain?" });
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";
const vectorStore = await MemoryVectorStore.fromTexts(
["text1", "text2", "text3"],
[{}, {}, {}],
new OpenAIEmbeddings()
);
// MMR 平衡相关性和多样性
const results = await vectorStore.maxMarginalRelevanceSearch("query", {
k: 3,
fetchK: 10, // 获取 10 个候选,返回 3 个多样化结果
lambda: 0.5, // 0 = 最大多样性,1 = 最大相关性
});
✅ 初始化向量存储
✅ 添加和查询文档
✅ 持久化和加载
✅ 作为检索器使用
✅ 选择适当的存储
❌ 混合来自不同模型的嵌入
❌ 绕过提供程序限制
❌ 在创建后修改向量维度
❌ 在没有正确设置的情况下查询
// ❌ 错误:为索引和查询使用不同的嵌入
const store1 = await MemoryVectorStore.fromDocuments(
docs,
new OpenAIEmbeddings({ model: "text-embedding-3-small" })
);
const results = await store1.similaritySearch("query"); // 使用相同的嵌入 ✓
// 但如果重新创建:
const store2 = new MemoryVectorStore(
new OpenAIEmbeddings({ model: "text-embedding-ada-002" }) // 不同!
);
// 查询将无法正常工作!
// ✅ 正确:保持嵌入实例
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
const store = await MemoryVectorStore.fromDocuments(docs, embeddings);
// 始终使用相同的嵌入实例
修复方法:为创建和查询使用相同的嵌入模型实例。
// ❌ Chroma 未运行
import { Chroma } from "@langchain/community/vectorstores/chroma";
const store = await Chroma.fromDocuments(docs, embeddings, {
url: "http://localhost:8000"
});
// 错误:连接被拒绝!
// ✅ 先启动 Chroma
// 终端:docker run -p 8000:8000 chromadb/chroma
// 或:chroma run --path ./chroma_data
const store = await Chroma.fromDocuments(docs, embeddings, {
url: "http://localhost:8000"
}); // 可以工作!
修复方法:在创建向量存储之前确保 Chroma 服务器正在运行。
// ❌ 索引不存在
import { Pinecone } from "@pinecone-database/pinecone";
const pinecone = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pinecone.Index("nonexistent-index"); // 不会创建索引!
// ✅ 先创建索引
// 在 Pinecone 控制台或通过 API 执行此操作
const pinecone = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
// 检查索引是否存在,如需要则创建
const indexList = await pinecone.listIndexes();
if (!indexList.indexes?.some(idx => idx.name === "my-index")) {
await pinecone.createIndex({
name: "my-index",
dimension: 1536, // 必须匹配嵌入维度
metric: "cosine",
spec: { serverless: { cloud: "aws", region: "us-east-1" } }
});
}
const index = pinecone.Index("my-index");
修复方法:在使用前创建 Pinecone 索引。
// ❌ 相对路径问题
await vectorStore.save("./index"); // 可能根据当前工作目录失败
// ✅ 使用绝对路径或明确指定
import path from "path";
const indexPath = path.join(process.cwd(), "data", "faiss_index");
await vectorStore.save(indexPath);
// 使用相同路径加载
const loadedStore = await FaissStore.load(indexPath, embeddings);
修复方法:使用绝对路径或注意当前工作目录。
// ❌ 期望持久化
const vectorStore = new MemoryVectorStore(embeddings);
await vectorStore.addDocuments(docs);
// 应用重启...
// 所有数据丢失!
// ✅ 在生产中使用持久化存储
import { FaissStore } from "@langchain/community/vectorstores/faiss";
const vectorStore = await FaissStore.fromDocuments(docs, embeddings);
await vectorStore.save("./faiss_index"); // 持久化到磁盘
修复方法:对于持久化数据,使用 FAISS、Chroma 或云存储(Pinecone)。
// 不同的存储有不同的过滤语法
// Pinecone
const pineconeResults = await pineconeStore.similaritySearch("query", 3, {
category: "tech" // 简单的键值
});
// Chroma
const chromaResults = await chromaStore.similaritySearch("query", 3, {
where: { category: "tech" } // 嵌套结构
});
// 查看每个存储的文档以了解过滤语法!
修复方法:阅读特定向量存储的文档以了解过滤语法。
// ❌ 使用错误的维度创建 Pinecone 索引
await pinecone.createIndex({
name: "my-index",
dimension: 1536, // OpenAI ada-002 维度
});
// 但使用不同的嵌入!
const store = await PineconeStore.fromDocuments(
docs,
new OpenAIEmbeddings({ model: "text-embedding-3-small", dimensions: 512 }),
{ pineconeIndex }
); // 错误:维度不匹配!
// ✅ 匹配维度
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
// 默认为 1536,匹配 Pinecone 索引
修复方法:确保向量存储维度配置与嵌入维度匹配。
# 社区包(包括 FAISS、Chroma 等)
npm install @langchain/community
# Pinecone
npm install @langchain/pinecone @pinecone-database/pinecone
# Weaviate
npm install @langchain/weaviate weaviate-ts-client
# Qdrant
npm install @langchain/qdrant @qdrant/js-client-rest