| name | hai-vecdb |
| description | 使用 @h-ai/vecdb 进行向量数据库操作(LanceDB/pgvector/Qdrant/Chroma)的集合管理与向量增删改查;当需求涉及向量存储、相似度搜索、嵌入检索或语义搜索时使用。 |
hai-vecdb
能力契约
| 项目 | 契约 |
|---|
| 能力 | 使用 @h-ai/vecdb 进行向量数据库操作(LanceDB/pgvector/Qdrant/Chroma)的集合管理与向量增删改查;当需求涉及向量存储、相似度搜索、嵌入检索或语义搜索时使用。 |
| 适用场景 | 当任务与 hai-vecdb 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
@h-ai/vecdb 提供统一的向量数据库操作接口,支持 LanceDB、pgvector、Qdrant、Chroma,包含集合管理和向量 CRUD/搜索。
运行环境
⚠️ 服务端模块(Node.js only)。 浏览器端不直接操作向量数据库,通过 @h-ai/ai 的 API 端点间接使用(如 RAG 检索、知识库查询)。
适用场景
- 新增或修改向量数据库访问逻辑(集合管理/向量插入/搜索)
- 接入不同向量数据库后端(LanceDB / pgvector / Qdrant / Chroma)
- 基于
HaiVecdbError 做错误分支处理
- 构建 RAG、语义搜索、知识库等 AI 场景
使用步骤
1. 配置
type: lancedb
path: ./data/vecdb
operationLog:
read: false
write: false
maxLength: 1000
level: debug
operationLog 在集合/向量操作进入真实 Provider 前输出日志,不要在 vecdb-main.ts 或调用方重复包装。maxLength 用于截断序列化后的向量、文档和过滤条件,level 默认 debug。
2. 初始化与关闭
import { core } from '@h-ai/core'
import { vecdb } from '@h-ai/vecdb'
await vecdb.init(core.config.get('vecdb'))
const closeResult = await vecdb.close()
if (!closeResult.success) {
throw new Error(closeResult.error.message)
}
vecdb.config 返回的是脱敏配置快照;连接字符串中的用户名/密码、独立 password 字段和 apiKey 会被替换为 [REDACTED]。
3. 选择操作接口
| 接口 | 用途 | 入口 |
|---|
| collection | 集合创建/删除/查询/判断存在 | vecdb.collection |
| vector | 向量插入/更新/删除/搜索/计数 | vecdb.vector |
核心 API
集合操作 — vecdb.collection
| 方法 | 签名 | 说明 |
|---|
create | (name, options) => HaiResult<void> | 创建集合 |
drop | (name) => HaiResult<void> | 删除集合 |
exists | (name) => HaiResult<boolean> | 判断集合是否存在 |
info | (name) => HaiResult<CollectionInfo> | 获取集合信息 |
list | () => HaiResult<string[]> | 列出所有集合 |
所有方法均返回 Promise<HaiResult<T>>,上表省略异步与错误类型。
await vecdb.collection.create('docs', { dimension: 1536, metric: 'cosine' })
const info = await vecdb.collection.info('docs')
if (info.success) {
}
const list = await vecdb.collection.list()
CollectionCreateOptions:
interface CollectionCreateOptions {
dimension: number
metric?: 'cosine' | 'euclidean' | 'dot'
}
向量操作 — vecdb.vector
| 方法 | 签名 | 说明 |
|---|
insert | (collection, documents) => HaiResult<void> | 批量插入 |
upsert | (collection, documents) => HaiResult<void> | 批量更新/插入 |
delete | (collection, ids) => HaiResult<void> | 按 ID 删除 |
search | (collection, vector, options?) => HaiResult<SearchResult[]> | 向量搜索 |
count | (collection) => HaiResult<number> | 文档计数 |
所有方法均返回 Promise<HaiResult<T>>,上表省略异步与错误类型。
await vecdb.vector.insert('docs', [
{ id: 'doc-1', vector: embedding, content: '文档内容', metadata: { source: 'wiki' } },
{ id: 'doc-2', vector: embedding2, content: '另一段内容' },
])
const result = await vecdb.vector.search('docs', queryVector, {
topK: 10,
minScore: 0.7,
filter: { source: 'wiki' },
})
if (result.success) {
for (const item of result.data) {
}
}
await vecdb.vector.upsert('docs', [
{ id: 'doc-1', vector: newEmbedding, content: '更新后的内容' },
])
await vecdb.vector.delete('docs', ['doc-1', 'doc-2'])
空批量 insert/upsert/delete 会被视为 no-op;写入与搜索会校验向量维度,不匹配时返回 HaiVecdbError.DIMENSION_MISMATCH。Qdrant collection.exists() 仅在 404 时返回 false,网络异常会返回查询错误而不是误判不存在。
Chroma 在 Node 端只有 HTTP 客户端(无进程内嵌入式)。嵌入式模式(提供 path 且无 url)下 vecdb.init 通过 serverCommand(默认 chroma,来自可选依赖 chromadb)拉起本地服务,vecdb.close 时关闭进程;服务命令不可用或就绪超时时 init 返回 HaiVecdbError.CONNECTION_FAILED。直连模式提供 url 即可,不拉起进程。
VectorDocument:
interface VectorDocument {
id: string
vector: number[]
content?: string
metadata?: Record<string, unknown>
}
VectorSearchOptions:
interface VectorSearchOptions {
topK?: number
filter?: Record<string, unknown>
minScore?: number
}
错误码 — HaiVecdbError
| 错误码 | code | 说明 |
|---|
HaiVecdbError.CONNECTION_FAILED | hai:vecdb:001 | 连接失败 |
HaiVecdbError.QUERY_FAILED | hai:vecdb:002 | 查询失败 |
HaiVecdbError.COLLECTION_NOT_FOUND | hai:vecdb:003 | 集合不存在 |
HaiVecdbError.COLLECTION_ALREADY_EXISTS | hai:vecdb:004 | 集合已存在 |
HaiVecdbError.DIMENSION_MISMATCH | hai:vecdb:005 | 向量维度不匹配 |
HaiVecdbError.INSERT_FAILED | hai:vecdb:006 | 插入失败 |
HaiVecdbError.DELETE_FAILED | hai:vecdb:007 | 删除失败 |
HaiVecdbError.UPDATE_FAILED | hai:vecdb:008 | 更新失败 |
HaiVecdbError.INDEX_BUILD_FAILED | hai:vecdb:009 | 索引构建失败 |
HaiVecdbError.NOT_INITIALIZED | hai:vecdb:010 | 未初始化 |
HaiVecdbError.CONFIG_ERROR | hai:vecdb:011 | 配置错误 |
HaiVecdbError.UNSUPPORTED_TYPE | hai:vecdb:012 | 不支持的数据库类型 |
HaiVecdbError.DRIVER_NOT_FOUND | hai:vecdb:013 | 驱动未安装 |
HaiVecdbError.SERIALIZATION_FAILED | hai:vecdb:014 | 序列化失败 |
常见模式
RAG 检索
import { ai } from '@h-ai/ai'
import { vecdb } from '@h-ai/vecdb'
const embedResult = await ai.embedding.embedText(query)
if (!embedResult.success) return embedResult
const searchResult = await vecdb.vector.search('knowledge', embedResult.data, {
topK: 5,
minScore: 0.7,
})
if (!searchResult.success) return searchResult
const context = searchResult.data.map(r => r.content).join('\n\n')
const chatResult = await ai.llm.chat({
messages: [
{ role: 'system', content: `参考以下资料回答用户问题:\n${context}` },
{ role: 'user', content: query },
],
})
文档入库
import { datapipe } from '@h-ai/datapipe'
import { ai } from '@h-ai/ai'
import { vecdb } from '@h-ai/vecdb'
const pipeline = await datapipe.pipeline()
.clean({ removeHtml: true })
.chunk({ mode: 'markdown', maxSize: 1000, overlap: 100 })
.run(rawText)
if (!pipeline.success) return pipeline
const embeddings = await ai.embedding.embedBatch(
pipeline.data.chunks.map(c => c.content),
)
if (!embeddings.success) return embeddings
const docs = pipeline.data.chunks.map((chunk, i) => ({
id: `doc-${i}`,
vector: embeddings.data[i],
content: chunk.content,
metadata: chunk.metadata,
}))
await vecdb.vector.insert('knowledge', docs)
错误分支处理
import { vecdb, HaiVecdbError } from '@h-ai/vecdb'
const result = await vecdb.collection.create('docs', { dimension: 1536 })
if (!result.success) {
switch (result.error.code) {
case HaiVecdbError.COLLECTION_ALREADY_EXISTS.code:
break
case HaiVecdbError.NOT_INITIALIZED.code:
break
default:
break
}
}
相关 Skills
hai-ai:LLM 与 Embedding 能力
hai-datapipe:文本清洗与分块
hai-reldb:关系型数据库(知识库需要同时使用 reldb 存储结构化数据)
hai-core:配置管理、HaiResult 模型