关于 api-vector-db-qdrant
面向使用 Qdrant JavaScript 客户端进行向量搜索的开发者,涵盖集合配置、负载过滤、命名向量、推荐查询与量化。
主要功能
- 01集合与向量配置
- 02点的写入、查询和删除
- 03负载过滤与索引
- 04每个点存储多个命名向量
- 05推荐查询
- 06量化选项
适用场景
- 01构建文档语义检索
- 02按元数据筛选相似度搜索
- 03根据正反示例生成推荐
- 04通过量化减少向量内存占用
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-vector-db-qdrant安装后在 Claude Code 中输入/api-vector-db-qdrant确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.yamlreference.mdexamples/core.mdfiltering.mdnamed-vectors-quantization.mdrecommendations-batch.md详细介绍
Qdrant 模式
快速指南: 使用
@qdrant/js-client-rest(v1.17.x)进行高性能向量搜索。集合会预先定义向量维度和距离度量——不匹配会导致无提示的失败。使用带有载荷条件的must/should/must_not过滤子句(而不是 Pinecone 风格的$eq/$and)。载荷索引是可选的,但对于大规模场景下的过滤性能至关重要——请使用createPayloadIndex()显式创建。命名向量可让你在每个点中存储多个嵌入(例如标题 + 内容)。量化(标量/二进制/乘积)以准确度换取内存和速度。query()方法是通用搜索端点——优先使用它,而不是较旧的search()方法。
<critical_requirements>
重要:使用此技能前
(对于过滤器中使用的任何字段,你都必须使用 createPayloadIndex() 创建载荷索引——未建立索引的字段会触发全量扫描,性能会随集合大小线性下降。)
(你必须使用 must/should/must_not 过滤语法——Qdrant 不使用 Pinecone 中的 $eq/$and/$or 运算符。)
(嵌入模型的输出维度必须与你的集合配置完全一致——维度不匹配会导致 upsert 无提示地失败,或搜索结果损坏。)
(如果后续读取依赖写入的数据,你必须在写入时设置 wait: true——Qdrant 默认异步写入,数据可能不会立即可见。)
</critical_requirements>
示例
- 核心模式 -- 客户端设置、集合创建、upsert、查询、滚动、删除
- 过滤 -- must/should/must_not 条件、匹配/范围运算符、载荷索引
- 命名向量与量化 -- 每个点中的多个向量、标量/二进制/乘积量化
- 推荐与批处理 -- 推荐 API、批量操作、快照
其他资源:
- reference.md -- API 快速参考、过滤运算符、限制、决策框架、生产环境检查清单
自动检测: Qdrant、QdrantClient、@qdrant/js-client-rest、createCollection、upsert、query、scroll、recommend、setPayload、createPayloadIndex、must、should、must_not、载荷、命名向量、量化、向量数据库、相似性搜索、语义搜索、RAG 检索、嵌入搜索
适用场景:
- 对文档嵌入进行语义搜索(RAG 检索流水线)
- 用于推荐、去重或分类的相似性搜索
- 使用命名向量进行多向量搜索(例如,每篇文档分别包含标题嵌入和内容嵌入)
- 使用复杂载荷条件(must/should/must_not)进行过滤式向量搜索
- 使用标量、二进制或乘积量化的内存优化型部署
涵盖的关键模式:
- 客户端设置与集合管理(距离度量、HNSW 配置)
- 点的 CRUD 操作(upsert、查询、滚动、检索、删除、计数)
- 使用 must/should/must_not 和匹配/范围条件进行载荷过滤
- 使用命名向量存储每个点的多个嵌入
- 量化配置(标量、二进制、乘积)
- 使用正面/负面示例的推荐 API
- 批量操作与快照管理
- 用于提升过滤性能的载荷索引
不适用场景:
- 使用 BM25 排名的全文搜索(请使用专用搜索引擎)
- 带有联接和事务的关系型数据(请使用关系型数据库)
- 不涉及向量相似性的键值查找(请使用 KV 存储)
- 存储大型文档或二进制数据块(仅存储嵌入和元数据引用)
## 理念
Qdrant 是一个用 Rust 构建的高性能开源向量数据库,专为大规模过滤相似性搜索而设计。核心原则:存储带有丰富负载的向量,按相似性搜索,按负载条件筛选。
核心原则:
- 负载是一等公民——与将元数据视为次要信息的数据库不同,Qdrant 的负载系统支持复杂的嵌套 JSON、多种数据类型和精细的索引。使用负载进行筛选,而不只是注释。
- 为筛选字段创建索引——负载索引不会自动创建。通过
createPayloadIndex()为筛选中使用的字段显式创建索引。没有索引时,筛选会导致扫描整个集合。 - 使用命名向量处理多模态数据——单个点可以保存多个命名向量(例如,标题嵌入和内容嵌入)。搜索时需要指定目标命名向量。这样可以避免在多个集合中重复存储负载。
- 通过量化实现规模化——标量量化(压缩 4 倍)、二进制量化(压缩 32 倍)和乘积量化以精度换取内存节省。可在集合级别或向量级别配置。使用
always_ram: true将量化向量保留在内存中以提升速度。 - 写入默认是异步的——Upsert 会在数据持久化到所有副本之前返回。需要即时一致性时(例如,读后写流程),设置
wait: true。
核心模式
模式 1:客户端初始化
创建连接到本地实例或 Qdrant Cloud 的 QdrantClient。完整示例请参阅 examples/core.md。
// Good Example
import { QdrantClient } from "@qdrant/js-client-rest";
function createQdrantClient(): QdrantClient {
const url = process.env.QDRANT_URL;
const apiKey = process.env.QDRANT_API_KEY;
if (!url) {
throw new Error("QDRANT_URL environment variable is required");
}
return new QdrantClient({ url, apiKey });
}
export { createQdrantClient };
优点: 从环境变量读取 URL 和 API 密钥,构造前进行验证,使用具名导出
// Bad Example
import { QdrantClient } from "@qdrant/js-client-rest";
const client = new QdrantClient({
host: "my-cluster.cloud.qdrant.io",
apiKey: "sk-abc123...",
});
// Hardcoded credentials leak in version control
缺点: API 密钥硬编码,主机未使用 HTTPS(连接云端时应使用带完整协议的 url)
模式 2:创建集合
定义向量维度和距离度量。维度必须与嵌入模型的输出完全一致。请参阅 examples/core.md。
// Good Example
const EMBEDDING_DIMENSION = 1536;
await client.createCollection("documents", {
vectors: {
size: EMBEDDING_DIMENSION,
distance: "Cosine",
},
});
export { EMBEDDING_DIMENSION };
优点: 使用具名常量定义维度,显式指定距离度量,配置简洁
// Bad Example
await client.createCollection("documents", {
vectors: { size: 768, distance: "Cosine" },
// Dimension mismatch if using a 1536-dim model -- upserts may silently fail or produce garbage search results
});
缺点: 维度硬编码,可能与嵌入模型不匹配;未使用具名常量
模式 3:Upsert 带负载的点
Upsert 带负载(Qdrant 对元数据的称呼)的向量。请参阅 examples/core.md。
// Good Example
interface DocumentPayload {
title: string;
category: string;
createdAt: number;
tags: string[];
}
await client.upsert("documents", {
wait: true,
points: [
{
id: "doc-1",
vector: embedding,
payload: {
title: "Guide",
category: "tutorial",
createdAt: 1710000000,
tags: ["ai", "search"],
},
},
],
});
优点: 使用类型化负载接口,通过 wait: true 实现即时一致性,负载结构清晰
模式 4:使用负载过滤器查询
使用 must/should/must_not 过滤子句——不要使用 Pinecone 风格的 $eq/$and。请参阅 examples/filtering.md。
// Good Example
const TOP_K = 10;
const results = await client.query("documents", {
query: queryEmbedding,
filter: {
must: [
{ key: "category", match: { value: "tutorial" } },
{ key: "createdAt", range: { gte: 1700000000 } },
],
},
with_payload: true,
limit: TOP_K,
});
for (const point of results.points) {
console.log(point.id, point.score, point.payload);
}
优点: 使用具名常量定义限制数量,采用 Qdrant 过滤语法(must + match/range),包含 with_payload
// Bad Example -- Pinecone syntax does NOT work in Qdrant
const results = await client.query("documents", {
query: embedding,
filter: {
$and: [{ category: { $eq: "tutorial" } }],
},
limit: 100,
});
缺点: Pinecone 风格的 $and/$eq 运算符在 Qdrant 中无效,限制数量使用了魔法数字
模式 5:命名向量
为每个点存储多个嵌入。请参阅 examples/named-vectors-quantization.md。
// Good Example
const TITLE_DIM = 384;
const CONTENT_DIM = 1536;
await client.createCollection("articles", {
vectors: {
title: { size: TITLE_DIM, distance: "Cosine" },
content: { size: CONTENT_DIM, distance: "Cosine" },
},
});
// Upsert with named vectors
await client.upsert("articles", {
wait: true,
points: [
{
id: "article-1",
vector: { title: titleEmbedding, content: contentEmbedding },
payload: { title: "Intro to Vectors" },
},
],
});
// Search by specific named vector
const results = await client.query("articles", {
query: queryEmbedding,
using: "content",
limit: TOP_K,
});
优点: 不同命名向量可使用不同维度,using 指定要搜索的向量,避免在多个集合中重复存储负载
模式 6:推荐 API
使用正面/负面示例查找相似点。请参阅 examples/recommendations-batch.md。
// Good Example
const results = await client.query("documents", {
query: {
recommend: {
positive: [1, 42],
negative: [7],
strategy: "best_score",
},
},
limit: TOP_K,
with_payload: true,
});
优点: 使用点 ID 作为正面/负面示例,best_score 策略处理负面示例的效果优于默认的 average_vector
<decision_framework>
决策框架
选择哪种距离度量?
Which distance metric should I use?
|-- Using normalized embeddings (OpenAI, Cohere)? -> Cosine (most common, safe default)
|-- Pre-normalized embeddings and need speed? -> Dot (faster, same results as Cosine for unit vectors)
|-- Raw feature vectors where magnitude matters? -> Euclid (L2 distance)
|-- City-block distance needed? -> Manhattan
'-- Unsure? -> Cosine (works with any embedding model)
使用单个向量还是命名向量?
How many embeddings per point?
|-- One embedding model? -> Single vector (simpler config)
|-- Multiple embedding models (title + content)? -> Named vectors
|-- Same model, different text segments? -> Named vectors
|-- Multi-modal (text + image)? -> Named vectors with different dimensions
'-- Want to avoid duplicating payloads across collections? -> Named vectors
选择哪种量化方法?
How should I optimize memory?
|-- Good default, balanced accuracy/speed? -> Scalar (int8, 4x compression)
|-- Maximum speed, can tolerate accuracy loss? -> Binary (32x compression)
| '-- Best with high-dimensional models (>= 1024 dims)
|-- Maximum compression, speed not critical? -> Product (up to 64x compression)
| '-- Slowest quantization, most accuracy loss
'-- No memory pressure? -> Skip quantization (full float32 precision)
如何制定负载索引策略?
Should I create a payload index?
|-- Field used in filter conditions? -> YES, always index
|-- Field used in order_by for scroll? -> YES, index for sort performance
|-- Field only read after search (display only)? -> NO, skip index
|-- High-cardinality field (UUIDs, timestamps)? -> YES, but evaluate index type
'-- Low-cardinality field (enum-like)? -> YES, keyword index is very efficient
</decision_framework>
<red_flags>
风险信号
高优先级问题:
- 使用 Pinecone 风格的过滤器语法(
$eq、$and、$or)——Qdrant 使用must/should/must_not搭配match/range条件 - 嵌入模型与集合配置的向量维度不匹配——会导致静默失败或产生无用结果
- 未为过滤字段创建载荷索引——会导致扫描整个集合,且性能会随集合大小线性下降
- 需要读后写一致性时未设置
wait: true——写入默认是异步的
中优先级问题:
- 使用已弃用的
search()方法,而不是query()——query()是通用端点,支持预取和融合 - 查询时忘记设置
with_payload: true——默认不会包含载荷 - 批量 upsert 后才创建载荷索引,而不是提前创建——事后建索引比在 upsert 期间建索引更慢
- 在滚动查询中使用
offset进行深度分页——性能会下降;应将offset用作游标(点 ID),而不是页码
常见错误:
- 在错误的嵌套层级传入
filter——filter应放在查询参数的顶层,而不是嵌套在另一个对象中 - 使用
id: 0作为点 ID——Qdrant 要求使用正整数或 UUID 字符串;0 无效 - 混淆
setPayload(合并)与overwritePayload(替换)——setPayload会合并字段,overwritePayload会替换整个载荷 - 调用
deletePayload时只传入字段名,却未指定点选择器——必须通过points数组或filter指定要更新的点
注意事项和边界情况:
- 点 ID 必须是正整数或 UUID 字符串——负数、0 和非 UUID 字符串都会被拒绝
- 使用
order_by的scroll()要求排序字段已创建载荷索引——否则请求会失败 - 对大型集合使用
exact: true的count()会很慢——应使用exact: false(默认值)获取近似计数 - 快照恢复要求 Qdrant 的次版本号一致——v1.14.x 快照无法恢复到 v1.15.x 集群
- 二值量化最适合高维向量(>= 1024 dims)——对于较小的向量,标量量化更准确
- 使用
prefetch的query()可启用多阶段检索(先检索 1000 个,再重新排序并取前 10 个)——但需要了解预取流程 - 命名向量搜索需要
using参数——省略该参数会搜索默认的(未命名)向量,而该向量可能不存在 deletePayload会移除指定键,clearPayload会移除所有键——这是两种不同的操作
</red_flags>
<critical_reminders>
关键提醒
(对于过滤器中使用的任何字段,必须使用 createPayloadIndex() 创建载荷索引——未建立索引的字段会导致扫描整个集合,且性能会随集合大小线性下降)
(必须使用 must/should/must_not 过滤器语法——Qdrant 不使用 Pinecone 那样的 $eq/$and/$or 运算符)
(必须确保嵌入模型输出与集合配置的向量维度完全一致——维度不匹配会导致 upsert 静默失败或搜索结果损坏)
(如果后续读取依赖写入的数据,必须在写入时设置 wait: true——Qdrant 的写入默认是异步的,数据可能不会立即可见)
不遵循这些规则会导致搜索结果为空、过滤性能下降、数据一致性问题,以及难以排查的维度不匹配错误。
</critical_reminders>