@h-ai/cli 0.1.0-alpha.54 → 0.1.0-alpha.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/{chunk-FVDXJYMO.js → chunk-O3ANVICQ.js} +31 -2
- package/dist/chunk-O3ANVICQ.js.map +1 -0
- package/dist/cli-config-templates-OWBEGBZQ.js +5 -0
- package/dist/{cli-config-templates-WGN2I23J.js.map → cli-config-templates-OWBEGBZQ.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/{src-6ZBWDBUB.js → src-TBIET7YU.js} +908 -127
- package/dist/src-TBIET7YU.js.map +1 -0
- package/package.json +7 -7
- package/templates/base/.gitignore.hbs +3 -0
- package/templates/base/package.json.hbs +1 -1
- package/templates/skills/AGENTS.md +8 -22
- package/templates/skills/CLAUDE.md +3 -16
- package/templates/skills/bridges/admin/AGENTS.md +3 -16
- package/templates/skills/bridges/admin/CLAUDE.md +3 -11
- package/templates/skills/bridges/admin/copilot-instructions.md +2 -39
- package/templates/skills/bridges/api/AGENTS.md +5 -18
- package/templates/skills/bridges/api/CLAUDE.md +3 -11
- package/templates/skills/bridges/api/copilot-instructions.md +3 -38
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +24 -59
- package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +1 -15
- package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +5 -45
- package/templates/skills/bridges/h5/AGENTS.md +4 -17
- package/templates/skills/bridges/h5/CLAUDE.md +3 -11
- package/templates/skills/bridges/h5/copilot-instructions.md +2 -37
- package/templates/skills/bridges/mobile-app/AGENTS.md +5 -18
- package/templates/skills/bridges/mobile-app/CLAUDE.md +3 -11
- package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -38
- package/templates/skills/bridges/website/AGENTS.md +4 -17
- package/templates/skills/bridges/website/CLAUDE.md +3 -11
- package/templates/skills/bridges/website/copilot-instructions.md +2 -37
- package/templates/skills/copilot-instructions.md +2 -36
- package/templates/skills/hai-ai/SKILL.md +35 -389
- package/templates/skills/hai-ai/guide.md +383 -0
- package/templates/skills/hai-ai/reference.md +1 -1
- package/templates/skills/hai-api-client/SKILL.md +6 -6
- package/templates/skills/hai-api-contract/SKILL.md +10 -25
- package/templates/skills/hai-app-create/SKILL.md +29 -388
- package/templates/skills/hai-app-create/reference.md +350 -0
- package/templates/skills/hai-app-review/SKILL.md +9 -23
- package/templates/skills/hai-app-tests/SKILL.md +29 -494
- package/templates/skills/hai-app-tests/reference.md +442 -0
- package/templates/skills/hai-audit/SKILL.md +6 -6
- package/templates/skills/hai-build/SKILL.md +19 -338
- package/templates/skills/hai-build/reference.md +326 -0
- package/templates/skills/hai-cache/SKILL.md +27 -32
- package/templates/skills/hai-capacitor/SKILL.md +19 -366
- package/templates/skills/hai-capacitor/reference.md +352 -0
- package/templates/skills/hai-ci/SKILL.md +6 -21
- package/templates/skills/hai-core/SKILL.md +25 -566
- package/templates/skills/hai-core/reference.md +533 -0
- package/templates/skills/hai-crypto/SKILL.md +6 -20
- package/templates/skills/hai-datapipe/SKILL.md +9 -23
- package/templates/skills/hai-deploy/SKILL.md +63 -25
- package/templates/skills/hai-framework-sync/SKILL.md +8 -20
- package/templates/skills/hai-iam/SKILL.md +27 -371
- package/templates/skills/hai-iam/reference.md +343 -0
- package/templates/skills/hai-kit/SKILL.md +6 -6
- package/templates/skills/hai-payment/SKILL.md +6 -26
- package/templates/skills/hai-pr-review/SKILL.md +6 -22
- package/templates/skills/hai-reach/SKILL.md +19 -317
- package/templates/skills/hai-reach/reference.md +303 -0
- package/templates/skills/hai-reldb/SKILL.md +19 -472
- package/templates/skills/hai-reldb/reference.md +452 -0
- package/templates/skills/hai-scheduler/SKILL.md +6 -6
- package/templates/skills/hai-serv/SKILL.md +27 -759
- package/templates/skills/hai-serv/reference.md +736 -0
- package/templates/skills/hai-storage/SKILL.md +7 -25
- package/templates/skills/hai-ui/SKILL.md +29 -625
- package/templates/skills/hai-ui/reference.md +598 -0
- package/templates/skills/hai-vecdb/SKILL.md +18 -303
- package/templates/skills/hai-vecdb/reference.md +291 -0
- package/dist/chunk-FVDXJYMO.js.map +0 -1
- package/dist/cli-config-templates-WGN2I23J.js +0 -5
- package/dist/src-6ZBWDBUB.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hai-vecdb
|
|
3
|
-
description: 使用 @h-ai/vecdb
|
|
3
|
+
description: "使用 @h-ai/vecdb 管理 LanceDB/pgvector/Qdrant/Chroma 集合与向量检索。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hai-vecdb
|
|
@@ -9,310 +9,25 @@ description: 使用 @h-ai/vecdb 进行向量数据库操作(LanceDB/pgvector/Q
|
|
|
9
9
|
|
|
10
10
|
| 项目 | 契约 |
|
|
11
11
|
| --- | --- |
|
|
12
|
-
| 能力 | 使用 @h-ai/vecdb
|
|
13
|
-
| 适用场景 |
|
|
14
|
-
| 输入 |
|
|
15
|
-
| 输出 |
|
|
16
|
-
| 限制 |
|
|
12
|
+
| 能力 | 使用 @h-ai/vecdb 管理 LanceDB/pgvector/Qdrant/Chroma 集合与向量检索 |
|
|
13
|
+
| 适用场景 | 向量持久化、集合管理或相似度搜索 |
|
|
14
|
+
| 输入 | VecdbConfigInput、集合、固定维度向量、查询过滤条件 |
|
|
15
|
+
| 输出 | 集合/向量操作的 HaiResult |
|
|
16
|
+
| 限制 | 仅服务端;向量维度须匹配集合。Chroma 是 HTTP 服务,本地 path 模式需可用服务命令;init 失败不得当成空库。 |
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
## 使用路径
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## 运行环境
|
|
23
|
-
|
|
24
|
-
> ⚠️ **服务端模块(Node.js only)。** 浏览器端不直接操作向量数据库,通过 `@h-ai/ai` 的 API 端点间接使用(如 RAG 检索、知识库查询)。
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 适用场景
|
|
29
|
-
|
|
30
|
-
- 新增或修改向量数据库访问逻辑(集合管理/向量插入/搜索)
|
|
31
|
-
- 接入不同向量数据库后端(LanceDB / pgvector / Qdrant / Chroma)
|
|
32
|
-
- 基于 `HaiVecdbError` 做错误分支处理
|
|
33
|
-
- 构建 RAG、语义搜索、知识库等 AI 场景
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## 使用步骤
|
|
38
|
-
|
|
39
|
-
### 1. 配置
|
|
40
|
-
|
|
41
|
-
```yaml
|
|
42
|
-
# config/_vecdb.yml
|
|
43
|
-
|
|
44
|
-
# LanceDB(默认,嵌入式本地存储)
|
|
45
|
-
type: lancedb
|
|
46
|
-
path: ./data/vecdb
|
|
47
|
-
|
|
48
|
-
# pgvector
|
|
49
|
-
# type: pgvector
|
|
50
|
-
# url: postgres://user:pass@localhost:5432/mydb
|
|
51
|
-
# indexType: hnsw
|
|
52
|
-
# tablePrefix: vec_
|
|
53
|
-
|
|
54
|
-
# Qdrant
|
|
55
|
-
# type: qdrant
|
|
56
|
-
# url: http://localhost:6333
|
|
57
|
-
# apiKey: ''
|
|
58
|
-
|
|
59
|
-
# Chroma(嵌入式:提供 path 且无 url 时自动拉起本地 `chroma run` 服务并持久化)
|
|
60
|
-
# type: chroma
|
|
61
|
-
# path: ./data/chroma
|
|
62
|
-
# Chroma(直连已有服务,不拉起进程)
|
|
63
|
-
# type: chroma
|
|
64
|
-
# url: http://localhost:8000
|
|
65
|
-
# apiKey: ''
|
|
66
|
-
# serverCommand: chroma # 嵌入式模式拉起服务的可执行命令(默认 chroma,来自 chromadb 包)
|
|
67
|
-
# startupTimeout: 30000 # 嵌入式服务就绪等待超时(毫秒)
|
|
68
|
-
operationLog:
|
|
69
|
-
read: false # collection.exists/info/list, vector.search/count
|
|
70
|
-
write: false # collection.create/drop, vector.insert/upsert/delete
|
|
71
|
-
maxLength: 1000
|
|
72
|
-
level: debug # info | debug | trace
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
约定环境变量优先于 YAML,例如 `HAI_VECDB_URL`、
|
|
76
|
-
`HAI_VECDB_APIKEY`、`HAI_VECDB_OPERATIONLOG_LEVEL`。
|
|
77
|
-
|
|
78
|
-
`operationLog` 在集合/向量操作进入真实 Provider 前输出日志,不要在 `vecdb-main.ts` 或调用方重复包装。`maxLength` 用于截断序列化后的向量、文档和过滤条件,`level` 默认 `debug`。
|
|
79
|
-
|
|
80
|
-
### 2. 初始化与关闭
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { core } from '@h-ai/core'
|
|
84
|
-
import { vecdb } from '@h-ai/vecdb'
|
|
85
|
-
|
|
86
|
-
await vecdb.init(core.config.get('vecdb'))
|
|
87
|
-
// ... 使用向量数据库
|
|
88
|
-
const closeResult = await vecdb.close()
|
|
89
|
-
if (!closeResult.success) {
|
|
90
|
-
throw new Error(closeResult.error.message)
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
> `vecdb.config` 返回的是**脱敏配置快照**;连接字符串中的用户名/密码、独立 `password` 字段和 `apiKey` 会被替换为 `[REDACTED]`。
|
|
95
|
-
|
|
96
|
-
### 3. 选择操作接口
|
|
97
|
-
|
|
98
|
-
| 接口 | 用途 | 入口 |
|
|
99
|
-
| ---------- | -------------------------- | ----------------- |
|
|
100
|
-
| collection | 集合创建/删除/查询/判断存在 | `vecdb.collection` |
|
|
101
|
-
| vector | 向量插入/更新/删除/搜索/计数 | `vecdb.vector` |
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## 核心 API
|
|
106
|
-
|
|
107
|
-
### 集合操作 — `vecdb.collection`
|
|
108
|
-
|
|
109
|
-
| 方法 | 签名 | 说明 |
|
|
110
|
-
| -------- | ------------------------------------------ | -------------- |
|
|
111
|
-
| `create` | `(name, options) => HaiResult<void>` | 创建集合 |
|
|
112
|
-
| `drop` | `(name) => HaiResult<void>` | 删除集合 |
|
|
113
|
-
| `exists` | `(name) => HaiResult<boolean>` | 判断集合是否存在 |
|
|
114
|
-
| `info` | `(name) => HaiResult<CollectionInfo>` | 获取集合信息 |
|
|
115
|
-
| `list` | `() => HaiResult<string[]>` | 列出所有集合 |
|
|
116
|
-
|
|
117
|
-
> 所有方法均返回 `Promise<HaiResult<T>>`,上表省略异步与错误类型。
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
// 创建集合(指定维度和度量)
|
|
121
|
-
await vecdb.collection.create('docs', { dimension: 1536, metric: 'cosine' })
|
|
122
|
-
|
|
123
|
-
// 查询集合信息
|
|
124
|
-
const info = await vecdb.collection.info('docs')
|
|
125
|
-
if (info.success) {
|
|
126
|
-
// info.data => { name, dimension, metric, count }
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// 列出所有集合
|
|
130
|
-
const list = await vecdb.collection.list()
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
**CollectionCreateOptions**:
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
interface CollectionCreateOptions {
|
|
137
|
-
dimension: number // 向量维度(必填)
|
|
138
|
-
metric?: 'cosine' | 'euclidean' | 'dot' // 距离度量(默认 cosine)
|
|
139
|
-
}
|
|
140
|
-
```
|
|
20
|
+
- `_vecdb.yml` 选择实际后端;init 后检查连接结果,再创建集合并写入相同维度向量。
|
|
21
|
+
- Chroma 本地服务不可用返回连接错误;Qdrant 只有 404 代表集合不存在。
|
|
141
22
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
| 方法 | 签名 | 说明 |
|
|
145
|
-
| -------- | --------------------------------------------------- | -------------- |
|
|
146
|
-
| `insert` | `(collection, documents) => HaiResult<void>` | 批量插入 |
|
|
147
|
-
| `upsert` | `(collection, documents) => HaiResult<void>` | 批量更新/插入 |
|
|
148
|
-
| `delete` | `(collection, ids) => HaiResult<void>` | 按 ID 删除 |
|
|
149
|
-
| `search` | `(collection, vector, options?) => HaiResult<SearchResult[]>` | 向量搜索 |
|
|
150
|
-
| `count` | `(collection) => HaiResult<number>` | 文档计数 |
|
|
151
|
-
|
|
152
|
-
> 所有方法均返回 `Promise<HaiResult<T>>`,上表省略异步与错误类型。
|
|
153
|
-
|
|
154
|
-
```typescript
|
|
155
|
-
// 插入向量文档
|
|
156
|
-
await vecdb.vector.insert('docs', [
|
|
157
|
-
{ id: 'doc-1', vector: embedding, content: '文档内容', metadata: { source: 'wiki' } },
|
|
158
|
-
{ id: 'doc-2', vector: embedding2, content: '另一段内容' },
|
|
159
|
-
])
|
|
160
|
-
|
|
161
|
-
// 向量搜索(返回相似度排序结果)
|
|
162
|
-
const result = await vecdb.vector.search('docs', queryVector, {
|
|
163
|
-
topK: 10,
|
|
164
|
-
minScore: 0.7,
|
|
165
|
-
filter: { source: 'wiki' },
|
|
166
|
-
})
|
|
167
|
-
if (result.success) {
|
|
168
|
-
for (const item of result.data) {
|
|
169
|
-
// item => { id, score, content, metadata }
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// 更新已有文档(按 id 匹配)
|
|
174
|
-
await vecdb.vector.upsert('docs', [
|
|
175
|
-
{ id: 'doc-1', vector: newEmbedding, content: '更新后的内容' },
|
|
176
|
-
])
|
|
177
|
-
|
|
178
|
-
// 删除
|
|
179
|
-
await vecdb.vector.delete('docs', ['doc-1', 'doc-2'])
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
> 空批量 `insert/upsert/delete` 会被视为 no-op;写入与搜索会校验向量维度,不匹配时返回 `HaiVecdbError.DIMENSION_MISMATCH`。Qdrant `collection.exists()` 仅在 404 时返回 `false`,网络异常会返回查询错误而不是误判不存在。
|
|
183
|
-
|
|
184
|
-
> Chroma 在 Node 端只有 HTTP 客户端(无进程内嵌入式)。嵌入式模式(提供 `path` 且无 `url`)下 `vecdb.init` 通过 `serverCommand`(默认 `chroma`,来自可选依赖 `chromadb`)拉起本地服务,`vecdb.close` 时关闭进程;服务命令不可用或就绪超时时 `init` 返回 `HaiVecdbError.CONNECTION_FAILED`。直连模式提供 `url` 即可,不拉起进程。
|
|
185
|
-
|
|
186
|
-
**VectorDocument**:
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
interface VectorDocument {
|
|
190
|
-
id: string // 文档唯一标识
|
|
191
|
-
vector: number[] // 向量数据
|
|
192
|
-
content?: string // 文本内容(可选)
|
|
193
|
-
metadata?: Record<string, unknown> // 元数据(可选)
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
**VectorSearchOptions**:
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
interface VectorSearchOptions {
|
|
201
|
-
topK?: number // 返回数量(默认 10)
|
|
202
|
-
filter?: Record<string, unknown> // 元数据过滤(键值精确匹配)
|
|
203
|
-
minScore?: number // 最低相似度阈值(0-1)
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## 错误码 — `HaiVecdbError`
|
|
210
|
-
|
|
211
|
-
| 错误码 | code | 说明 |
|
|
212
|
-
| ----------------------------------------- | ----------------- | ------------------ |
|
|
213
|
-
| `HaiVecdbError.CONNECTION_FAILED` | `hai:vecdb:001` | 连接失败 |
|
|
214
|
-
| `HaiVecdbError.QUERY_FAILED` | `hai:vecdb:002` | 查询失败 |
|
|
215
|
-
| `HaiVecdbError.COLLECTION_NOT_FOUND` | `hai:vecdb:003` | 集合不存在 |
|
|
216
|
-
| `HaiVecdbError.COLLECTION_ALREADY_EXISTS`| `hai:vecdb:004` | 集合已存在 |
|
|
217
|
-
| `HaiVecdbError.DIMENSION_MISMATCH` | `hai:vecdb:005` | 向量维度不匹配 |
|
|
218
|
-
| `HaiVecdbError.INSERT_FAILED` | `hai:vecdb:006` | 插入失败 |
|
|
219
|
-
| `HaiVecdbError.DELETE_FAILED` | `hai:vecdb:007` | 删除失败 |
|
|
220
|
-
| `HaiVecdbError.UPDATE_FAILED` | `hai:vecdb:008` | 更新失败 |
|
|
221
|
-
| `HaiVecdbError.INDEX_BUILD_FAILED` | `hai:vecdb:009` | 索引构建失败 |
|
|
222
|
-
| `HaiVecdbError.NOT_INITIALIZED` | `hai:vecdb:010` | 未初始化 |
|
|
223
|
-
| `HaiVecdbError.CONFIG_ERROR` | `hai:vecdb:011` | 配置错误 |
|
|
224
|
-
| `HaiVecdbError.UNSUPPORTED_TYPE` | `hai:vecdb:012` | 不支持的数据库类型 |
|
|
225
|
-
| `HaiVecdbError.DRIVER_NOT_FOUND` | `hai:vecdb:013` | 驱动未安装 |
|
|
226
|
-
| `HaiVecdbError.SERIALIZATION_FAILED` | `hai:vecdb:014` | 序列化失败 |
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## 常见模式
|
|
231
|
-
|
|
232
|
-
### RAG 检索
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
import { ai } from '@h-ai/ai'
|
|
236
|
-
import { vecdb } from '@h-ai/vecdb'
|
|
237
|
-
|
|
238
|
-
// 将查询文本转为向量
|
|
239
|
-
const embedResult = await ai.embedding.embedText(query)
|
|
240
|
-
if (!embedResult.success) return embedResult
|
|
241
|
-
|
|
242
|
-
// 检索最相似的文档
|
|
243
|
-
const searchResult = await vecdb.vector.search('knowledge', embedResult.data, {
|
|
244
|
-
topK: 5,
|
|
245
|
-
minScore: 0.7,
|
|
246
|
-
})
|
|
247
|
-
if (!searchResult.success) return searchResult
|
|
248
|
-
|
|
249
|
-
// 拼接上下文,送入 LLM
|
|
250
|
-
const context = searchResult.data.map(r => r.content).join('\n\n')
|
|
251
|
-
const chatResult = await ai.llm.chat({
|
|
252
|
-
messages: [
|
|
253
|
-
{ role: 'system', content: `参考以下资料回答用户问题:\n${context}` },
|
|
254
|
-
{ role: 'user', content: query },
|
|
255
|
-
],
|
|
256
|
-
})
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### 文档入库
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
import { datapipe } from '@h-ai/datapipe'
|
|
263
|
-
import { ai } from '@h-ai/ai'
|
|
264
|
-
import { vecdb } from '@h-ai/vecdb'
|
|
265
|
-
|
|
266
|
-
// 清洗 + 分块
|
|
267
|
-
const pipeline = await datapipe.pipeline()
|
|
268
|
-
.clean({ removeHtml: true })
|
|
269
|
-
.chunk({ mode: 'markdown', maxSize: 1000, overlap: 100 })
|
|
270
|
-
.run(rawText)
|
|
271
|
-
|
|
272
|
-
if (!pipeline.success) return pipeline
|
|
273
|
-
|
|
274
|
-
// 批量生成嵌入
|
|
275
|
-
const embeddings = await ai.embedding.embedBatch(
|
|
276
|
-
pipeline.data.chunks.map(c => c.content),
|
|
277
|
-
)
|
|
278
|
-
if (!embeddings.success) return embeddings
|
|
279
|
-
|
|
280
|
-
// 批量入库
|
|
281
|
-
const docs = pipeline.data.chunks.map((chunk, i) => ({
|
|
282
|
-
id: `doc-${i}`,
|
|
283
|
-
vector: embeddings.data[i],
|
|
284
|
-
content: chunk.content,
|
|
285
|
-
metadata: chunk.metadata,
|
|
286
|
-
}))
|
|
287
|
-
await vecdb.vector.insert('knowledge', docs)
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### 错误分支处理
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
import { vecdb, HaiVecdbError } from '@h-ai/vecdb'
|
|
294
|
-
|
|
295
|
-
const result = await vecdb.collection.create('docs', { dimension: 1536 })
|
|
296
|
-
if (!result.success) {
|
|
297
|
-
switch (result.error.code) {
|
|
298
|
-
case HaiVecdbError.COLLECTION_ALREADY_EXISTS.code:
|
|
299
|
-
// 集合已存在,可跳过
|
|
300
|
-
break
|
|
301
|
-
case HaiVecdbError.NOT_INITIALIZED.code:
|
|
302
|
-
// 未初始化,需先 vecdb.init()
|
|
303
|
-
break
|
|
304
|
-
default:
|
|
305
|
-
// 意外错误
|
|
306
|
-
break
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
---
|
|
23
|
+
## 按需参考
|
|
312
24
|
|
|
313
|
-
|
|
25
|
+
详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
|
|
314
26
|
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
27
|
+
- 运行环境
|
|
28
|
+
- 适用场景
|
|
29
|
+
- 使用步骤
|
|
30
|
+
- 核心 API
|
|
31
|
+
- 错误码 — `HaiVecdbError`
|
|
32
|
+
- 常见模式
|
|
33
|
+
- 相关 Skills
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# hai-vecdb — 详细用法
|
|
2
|
+
|
|
3
|
+
从 [SKILL.md](SKILL.md) 选择主题后读取对应小节。代码片段展示 API 用法;省略的业务变量、schema、依赖与 return 上下文需由应用补齐。
|
|
4
|
+
|
|
5
|
+
> `@h-ai/vecdb` 提供统一的向量数据库操作接口,支持 LanceDB、pgvector、Qdrant、Chroma,包含集合管理和向量 CRUD/搜索。
|
|
6
|
+
|
|
7
|
+
## 运行环境
|
|
8
|
+
|
|
9
|
+
> ⚠️ **服务端模块(Node.js only)。** 浏览器端不直接操作向量数据库,通过 `@h-ai/ai` 的 API 端点间接使用(如 RAG 检索、知识库查询)。
|
|
10
|
+
|
|
11
|
+
## 适用场景
|
|
12
|
+
|
|
13
|
+
- 新增或修改向量数据库访问逻辑(集合管理/向量插入/搜索)
|
|
14
|
+
- 接入不同向量数据库后端(LanceDB / pgvector / Qdrant / Chroma)
|
|
15
|
+
- 基于 `HaiVecdbError` 做错误分支处理
|
|
16
|
+
- 构建 RAG、语义搜索、知识库等 AI 场景
|
|
17
|
+
|
|
18
|
+
## 使用步骤
|
|
19
|
+
|
|
20
|
+
### 1. 配置
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
# config/_vecdb.yml
|
|
24
|
+
|
|
25
|
+
# LanceDB(默认,嵌入式本地存储)
|
|
26
|
+
type: lancedb
|
|
27
|
+
path: ./data/vecdb
|
|
28
|
+
|
|
29
|
+
# pgvector
|
|
30
|
+
# type: pgvector
|
|
31
|
+
# url: postgres://user:pass@localhost:5432/mydb
|
|
32
|
+
# indexType: hnsw
|
|
33
|
+
# tablePrefix: vec_
|
|
34
|
+
|
|
35
|
+
# Qdrant
|
|
36
|
+
# type: qdrant
|
|
37
|
+
# url: http://localhost:6333
|
|
38
|
+
# apiKey: ''
|
|
39
|
+
|
|
40
|
+
# Chroma(嵌入式:提供 path 且无 url 时自动拉起本地 `chroma run` 服务并持久化)
|
|
41
|
+
# type: chroma
|
|
42
|
+
# path: ./data/chroma
|
|
43
|
+
# Chroma(直连已有服务,不拉起进程)
|
|
44
|
+
# type: chroma
|
|
45
|
+
# url: http://localhost:8000
|
|
46
|
+
# apiKey: ''
|
|
47
|
+
# serverCommand: chroma # 嵌入式模式拉起服务的可执行命令(默认 chroma,来自 chromadb 包)
|
|
48
|
+
# startupTimeout: 30000 # 嵌入式服务就绪等待超时(毫秒)
|
|
49
|
+
operationLog:
|
|
50
|
+
read: false # collection.exists/info/list, vector.search/count
|
|
51
|
+
write: false # collection.create/drop, vector.insert/upsert/delete
|
|
52
|
+
maxLength: 1000
|
|
53
|
+
level: debug # info | debug | trace
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
约定环境变量优先于 YAML,例如 `HAI_VECDB_URL`、
|
|
57
|
+
`HAI_VECDB_APIKEY`、`HAI_VECDB_OPERATIONLOG_LEVEL`。
|
|
58
|
+
|
|
59
|
+
`operationLog` 在集合/向量操作进入真实 Provider 前输出日志,不要在 `vecdb-main.ts` 或调用方重复包装。`maxLength` 用于截断序列化后的向量、文档和过滤条件,`level` 默认 `debug`。
|
|
60
|
+
|
|
61
|
+
### 2. 初始化与关闭
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { core } from '@h-ai/core'
|
|
65
|
+
import { vecdb } from '@h-ai/vecdb'
|
|
66
|
+
|
|
67
|
+
await vecdb.init(core.config.get('vecdb'))
|
|
68
|
+
// ... 使用向量数据库
|
|
69
|
+
const closeResult = await vecdb.close()
|
|
70
|
+
if (!closeResult.success) {
|
|
71
|
+
throw new Error(closeResult.error.message)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
> `vecdb.config` 返回的是**脱敏配置快照**;连接字符串中的用户名/密码、独立 `password` 字段和 `apiKey` 会被替换为 `[REDACTED]`。
|
|
76
|
+
|
|
77
|
+
### 3. 选择操作接口
|
|
78
|
+
|
|
79
|
+
| 接口 | 用途 | 入口 |
|
|
80
|
+
| ---------- | -------------------------- | ----------------- |
|
|
81
|
+
| collection | 集合创建/删除/查询/判断存在 | `vecdb.collection` |
|
|
82
|
+
| vector | 向量插入/更新/删除/搜索/计数 | `vecdb.vector` |
|
|
83
|
+
|
|
84
|
+
## 核心 API
|
|
85
|
+
|
|
86
|
+
### 集合操作 — `vecdb.collection`
|
|
87
|
+
|
|
88
|
+
| 方法 | 签名 | 说明 |
|
|
89
|
+
| -------- | ------------------------------------------ | -------------- |
|
|
90
|
+
| `create` | `(name, options) => HaiResult<void>` | 创建集合 |
|
|
91
|
+
| `drop` | `(name) => HaiResult<void>` | 删除集合 |
|
|
92
|
+
| `exists` | `(name) => HaiResult<boolean>` | 判断集合是否存在 |
|
|
93
|
+
| `info` | `(name) => HaiResult<CollectionInfo>` | 获取集合信息 |
|
|
94
|
+
| `list` | `() => HaiResult<string[]>` | 列出所有集合 |
|
|
95
|
+
|
|
96
|
+
> 所有方法均返回 `Promise<HaiResult<T>>`,上表省略异步与错误类型。
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// 创建集合(指定维度和度量)
|
|
100
|
+
await vecdb.collection.create('docs', { dimension: 1536, metric: 'cosine' })
|
|
101
|
+
|
|
102
|
+
// 查询集合信息
|
|
103
|
+
const info = await vecdb.collection.info('docs')
|
|
104
|
+
if (info.success) {
|
|
105
|
+
// info.data => { name, dimension, metric, count }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 列出所有集合
|
|
109
|
+
const list = await vecdb.collection.list()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**CollectionCreateOptions**:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
interface CollectionCreateOptions {
|
|
116
|
+
dimension: number // 向量维度(必填)
|
|
117
|
+
metric?: 'cosine' | 'euclidean' | 'dot' // 距离度量(默认 cosine)
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 向量操作 — `vecdb.vector`
|
|
122
|
+
|
|
123
|
+
| 方法 | 签名 | 说明 |
|
|
124
|
+
| -------- | --------------------------------------------------- | -------------- |
|
|
125
|
+
| `insert` | `(collection, documents) => HaiResult<void>` | 批量插入 |
|
|
126
|
+
| `upsert` | `(collection, documents) => HaiResult<void>` | 批量更新/插入 |
|
|
127
|
+
| `delete` | `(collection, ids) => HaiResult<void>` | 按 ID 删除 |
|
|
128
|
+
| `search` | `(collection, vector, options?) => HaiResult<SearchResult[]>` | 向量搜索 |
|
|
129
|
+
| `count` | `(collection) => HaiResult<number>` | 文档计数 |
|
|
130
|
+
|
|
131
|
+
> 所有方法均返回 `Promise<HaiResult<T>>`,上表省略异步与错误类型。
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// 插入向量文档
|
|
135
|
+
await vecdb.vector.insert('docs', [
|
|
136
|
+
{ id: 'doc-1', vector: embedding, content: '文档内容', metadata: { source: 'wiki' } },
|
|
137
|
+
{ id: 'doc-2', vector: embedding2, content: '另一段内容' },
|
|
138
|
+
])
|
|
139
|
+
|
|
140
|
+
// 向量搜索(返回相似度排序结果)
|
|
141
|
+
const result = await vecdb.vector.search('docs', queryVector, {
|
|
142
|
+
topK: 10,
|
|
143
|
+
minScore: 0.7,
|
|
144
|
+
filter: { source: 'wiki' },
|
|
145
|
+
})
|
|
146
|
+
if (result.success) {
|
|
147
|
+
for (const item of result.data) {
|
|
148
|
+
// item => { id, score, content, metadata }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 更新已有文档(按 id 匹配)
|
|
153
|
+
await vecdb.vector.upsert('docs', [
|
|
154
|
+
{ id: 'doc-1', vector: newEmbedding, content: '更新后的内容' },
|
|
155
|
+
])
|
|
156
|
+
|
|
157
|
+
// 删除
|
|
158
|
+
await vecdb.vector.delete('docs', ['doc-1', 'doc-2'])
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
> 空批量 `insert/upsert/delete` 会被视为 no-op;写入与搜索会校验向量维度,不匹配时返回 `HaiVecdbError.DIMENSION_MISMATCH`。Qdrant `collection.exists()` 仅在 404 时返回 `false`,网络异常会返回查询错误而不是误判不存在。
|
|
162
|
+
|
|
163
|
+
> Chroma 在 Node 端只有 HTTP 客户端(无进程内嵌入式)。嵌入式模式(提供 `path` 且无 `url`)下 `vecdb.init` 通过 `serverCommand`(默认 `chroma`,来自可选依赖 `chromadb`)拉起本地服务,`vecdb.close` 时关闭进程;服务命令不可用或就绪超时时 `init` 返回 `HaiVecdbError.CONNECTION_FAILED`。直连模式提供 `url` 即可,不拉起进程。
|
|
164
|
+
|
|
165
|
+
**VectorDocument**:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
interface VectorDocument {
|
|
169
|
+
id: string // 文档唯一标识
|
|
170
|
+
vector: number[] // 向量数据
|
|
171
|
+
content?: string // 文本内容(可选)
|
|
172
|
+
metadata?: Record<string, unknown> // 元数据(可选)
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**VectorSearchOptions**:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
interface VectorSearchOptions {
|
|
180
|
+
topK?: number // 返回数量(默认 10)
|
|
181
|
+
filter?: Record<string, unknown> // 元数据过滤(键值精确匹配)
|
|
182
|
+
minScore?: number // 最低相似度阈值(0-1)
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 错误码 — `HaiVecdbError`
|
|
187
|
+
|
|
188
|
+
| 错误码 | code | 说明 |
|
|
189
|
+
| ----------------------------------------- | ----------------- | ------------------ |
|
|
190
|
+
| `HaiVecdbError.CONNECTION_FAILED` | `hai:vecdb:001` | 连接失败 |
|
|
191
|
+
| `HaiVecdbError.QUERY_FAILED` | `hai:vecdb:002` | 查询失败 |
|
|
192
|
+
| `HaiVecdbError.COLLECTION_NOT_FOUND` | `hai:vecdb:003` | 集合不存在 |
|
|
193
|
+
| `HaiVecdbError.COLLECTION_ALREADY_EXISTS`| `hai:vecdb:004` | 集合已存在 |
|
|
194
|
+
| `HaiVecdbError.DIMENSION_MISMATCH` | `hai:vecdb:005` | 向量维度不匹配 |
|
|
195
|
+
| `HaiVecdbError.INSERT_FAILED` | `hai:vecdb:006` | 插入失败 |
|
|
196
|
+
| `HaiVecdbError.DELETE_FAILED` | `hai:vecdb:007` | 删除失败 |
|
|
197
|
+
| `HaiVecdbError.UPDATE_FAILED` | `hai:vecdb:008` | 更新失败 |
|
|
198
|
+
| `HaiVecdbError.INDEX_BUILD_FAILED` | `hai:vecdb:009` | 索引构建失败 |
|
|
199
|
+
| `HaiVecdbError.NOT_INITIALIZED` | `hai:vecdb:010` | 未初始化 |
|
|
200
|
+
| `HaiVecdbError.CONFIG_ERROR` | `hai:vecdb:011` | 配置错误 |
|
|
201
|
+
| `HaiVecdbError.UNSUPPORTED_TYPE` | `hai:vecdb:012` | 不支持的数据库类型 |
|
|
202
|
+
| `HaiVecdbError.DRIVER_NOT_FOUND` | `hai:vecdb:013` | 驱动未安装 |
|
|
203
|
+
| `HaiVecdbError.SERIALIZATION_FAILED` | `hai:vecdb:014` | 序列化失败 |
|
|
204
|
+
|
|
205
|
+
## 常见模式
|
|
206
|
+
|
|
207
|
+
### RAG 检索
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { ai } from '@h-ai/ai'
|
|
211
|
+
import { vecdb } from '@h-ai/vecdb'
|
|
212
|
+
|
|
213
|
+
// 将查询文本转为向量
|
|
214
|
+
const embedResult = await ai.embedding.embedText(query)
|
|
215
|
+
if (!embedResult.success) return embedResult
|
|
216
|
+
|
|
217
|
+
// 检索最相似的文档
|
|
218
|
+
const searchResult = await vecdb.vector.search('knowledge', embedResult.data, {
|
|
219
|
+
topK: 5,
|
|
220
|
+
minScore: 0.7,
|
|
221
|
+
})
|
|
222
|
+
if (!searchResult.success) return searchResult
|
|
223
|
+
|
|
224
|
+
// 拼接上下文,送入 LLM
|
|
225
|
+
const context = searchResult.data.map(r => r.content).join('\n\n')
|
|
226
|
+
const chatResult = await ai.llm.chat({
|
|
227
|
+
messages: [
|
|
228
|
+
{ role: 'system', content: `参考以下资料回答用户问题:\n${context}` },
|
|
229
|
+
{ role: 'user', content: query },
|
|
230
|
+
],
|
|
231
|
+
})
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 文档入库
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { datapipe } from '@h-ai/datapipe'
|
|
238
|
+
import { ai } from '@h-ai/ai'
|
|
239
|
+
import { vecdb } from '@h-ai/vecdb'
|
|
240
|
+
|
|
241
|
+
// 清洗 + 分块
|
|
242
|
+
const pipeline = await datapipe.pipeline()
|
|
243
|
+
.clean({ removeHtml: true })
|
|
244
|
+
.chunk({ mode: 'markdown', maxSize: 1000, overlap: 100 })
|
|
245
|
+
.run(rawText)
|
|
246
|
+
|
|
247
|
+
if (!pipeline.success) return pipeline
|
|
248
|
+
|
|
249
|
+
// 批量生成嵌入
|
|
250
|
+
const embeddings = await ai.embedding.embedBatch(
|
|
251
|
+
pipeline.data.chunks.map(c => c.content),
|
|
252
|
+
)
|
|
253
|
+
if (!embeddings.success) return embeddings
|
|
254
|
+
|
|
255
|
+
// 批量入库
|
|
256
|
+
const docs = pipeline.data.chunks.map((chunk, i) => ({
|
|
257
|
+
id: `doc-${i}`,
|
|
258
|
+
vector: embeddings.data[i],
|
|
259
|
+
content: chunk.content,
|
|
260
|
+
metadata: chunk.metadata,
|
|
261
|
+
}))
|
|
262
|
+
await vecdb.vector.insert('knowledge', docs)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 错误分支处理
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { vecdb, HaiVecdbError } from '@h-ai/vecdb'
|
|
269
|
+
|
|
270
|
+
const result = await vecdb.collection.create('docs', { dimension: 1536 })
|
|
271
|
+
if (!result.success) {
|
|
272
|
+
switch (result.error.code) {
|
|
273
|
+
case HaiVecdbError.COLLECTION_ALREADY_EXISTS.code:
|
|
274
|
+
// 集合已存在,可跳过
|
|
275
|
+
break
|
|
276
|
+
case HaiVecdbError.NOT_INITIALIZED.code:
|
|
277
|
+
// 未初始化,需先 vecdb.init()
|
|
278
|
+
break
|
|
279
|
+
default:
|
|
280
|
+
// 意外错误
|
|
281
|
+
break
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## 相关 Skills
|
|
287
|
+
|
|
288
|
+
- `hai-ai`:LLM 与 Embedding 能力
|
|
289
|
+
- `hai-datapipe`:文本清洗与分块
|
|
290
|
+
- `hai-reldb`:关系型数据库(知识库需要同时使用 reldb 存储结构化数据)
|
|
291
|
+
- `hai-core`:配置管理、HaiResult 模型
|