跳至主要內容

Convex 向量儲存

ConvexVector 類別使用 Convex 提供向量儲存與相似度搜尋。它會將嵌入儲存在 Convex 中,並於 Mastra 介接器內執行餘弦相似度搜尋。

開發規模的搜尋

ConvexVector 會透過 Mastra 儲存處理常式讀取相符的向量、在 JavaScript 中篩選、計算餘弦相似度、排序結果,並傳回最相符的項目。它適合用於本機開發、測試與小型資料集。

若要在 Convex 上執行正式環境的向量搜尋,請使用 ConvexNativeVector。它使用 Convex 原生的 vectorSearch API,且需要已部署的 Convex 向量索引和 Convex action。

安裝
「安裝」的直接連結

npm install @mastra/convex@latest

Convex 設定
「Convex 設定」的直接連結

使用 ConvexVector 前,你必須設定 Convex schema 與儲存處理常式。設定方式請參閱 Convex 儲存設定

建構函式選項
「建構函式選項」的直接連結

deploymentUrl:

string
Convex 部署 URL(例如 https://your-project.convex.cloud)

adminAuthToken:

string
Convex 管理員驗證權杖

storageFunction?:

string
= mastra/storage:handle
儲存 mutation 函式的路徑

建構函式範例
「建構函式範例」的直接連結

基本設定
「基本設定」的直接連結

import { ConvexVector } from '@mastra/convex'

const vectorStore = new ConvexVector({
id: 'convex-vectors',
deploymentUrl: 'https://your-project.convex.cloud',
adminAuthToken: 'your-admin-token',
})

正式環境的向量工作負載請使用 ConvexNativeVector。它會將向量儲存在專用的 Convex 資料表中,並查詢 schema 所定義的 Convex 向量索引。

convex/schema.ts 中,為每個 Mastra 向量索引定義專用資料表:

convex/schema.ts
import { defineSchema } from 'convex/server'
import { defineMastraNativeVectorTable } from '@mastra/convex/schema'

export default defineSchema({
docs_vectors: defineMastraNativeVectorTable({
dimensions: 1536,
}),
})

convex/mastra/nativeVector.ts 中匯出原生向量處理常式:

convex/mastra/nativeVector.ts
import {
mastraNativeVectorAction,
mastraNativeVectorMutation,
mastraNativeVectorQuery,
} from '@mastra/convex/server'

export const query = mastraNativeVectorAction
export const read = mastraNativeVectorQuery
export const write = mastraNativeVectorMutation

在 Mastra 應用程式中,使用已部署的資料表與向量索引設定 ConvexNativeVector

src/mastra/index.ts
import { ConvexNativeVector } from '@mastra/convex'

const vectorStore = new ConvexNativeVector({
id: 'convex-native-vectors',
deploymentUrl: process.env.CONVEX_URL!,
adminAuthToken: process.env.CONVEX_ADMIN_KEY!,
indexes: {
docs: {
tableName: 'docs_vectors',
vectorIndexName: 'by_embedding',
dimension: 1536,
},
},
})

const results = await vectorStore.query({
indexName: 'docs',
queryVector: embedding,
topK: 10,
})

若要支援原生篩選,請在 Convex schema 中宣告篩選欄位。寫入向量時,原生向量處理常式會將相符的中繼資料欄位複製到文件的頂層欄位。

convex/schema.ts
import { defineSchema, defineTable } from 'convex/server'
import { v } from 'convex/values'

export default defineSchema({
docs_vectors: defineTable({
id: v.string(),
embedding: v.array(v.float64()),
metadata: v.optional(v.any()),
tenantId: v.string(),
})
.index('by_record_id', ['id'])
.vectorIndex('by_embedding', {
vectorField: 'embedding',
dimensions: 1536,
filterFields: ['tenantId'],
}),
})
src/mastra/index.ts
const vectorStore = new ConvexNativeVector({
id: 'convex-native-vectors',
deploymentUrl: process.env.CONVEX_URL!,
adminAuthToken: process.env.CONVEX_ADMIN_KEY!,
indexes: {
docs: {
tableName: 'docs_vectors',
dimension: 1536,
filterFields: ['tenantId'],
},
},
})

await vectorStore.upsert({
indexName: 'docs',
ids: ['chunk-1'],
vectors: [embedding],
metadata: [{ tenantId: 'acme', text: 'Account setup guide' }],
})

const results = await vectorStore.query({
indexName: 'docs',
queryVector: embedding,
filter: { tenantId: 'acme' },
})

ConvexNativeVector 支援 Convex 原生向量篩選條件的結構:單一等值欄位,或由等值欄位組成的 $or。它不支援僅使用中繼資料的查詢、依篩選條件更新或依篩選條件刪除。更新與刪除時請使用向量 ID。

自訂儲存函式
「自訂儲存函式」的直接連結

const vectorStore = new ConvexVector({
id: 'convex-vectors',
deploymentUrl: 'https://your-project.convex.cloud',
adminAuthToken: 'your-admin-token',
storageFunction: 'custom/path:handler',
})

方法
「方法」的直接連結

createIndex()
「createindex」的直接連結

indexName:

string
要建立的索引名稱

dimension:

number
向量維度(必須與嵌入模型相符)

metric?:

'cosine' | 'euclidean' | 'dotproduct'
= cosine
相似度搜尋使用的距離度量(目前僅支援 cosine)
await vectorStore.createIndex({
indexName: 'my_vectors',
dimension: 1536,
})

upsert()
「upsert」的直接連結

indexName:

string
要 upsert 向量的索引名稱

vectors:

number[][]
嵌入向量陣列

metadata?:

Record<string, any>[]
每個向量的中繼資料

ids?:

string[]
選用的向量 ID(未提供時會自動產生)
await vectorStore.upsert({
indexName: "my_vectors",
vectors: [[0.1, 0.2, 0.3, ...]],
metadata: [{ label: "example" }],
ids: ["vec-1"],
});

query()
「query」的直接連結

indexName:

string
要查詢的索引名稱

queryVector:

number[]
查詢向量

topK?:

number
= 10
要傳回的結果數量

filter?:

Record<string, any>
中繼資料篩選條件

includeVector?:

boolean
= false
結果是否包含向量
const results = await vectorStore.query({
indexName: "my_vectors",
queryVector: [0.1, 0.2, 0.3, ...],
topK: 5,
filter: { category: "documents" },
});

listIndexes()
「listindexes」的直接連結

以字串陣列傳回索引名稱。

const indexes = await vectorStore.listIndexes()
// ["my_vectors", "embeddings", ...]

describeIndex()
「describeindex」的直接連結

indexName:

string
要描述的索引名稱

傳回:

interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}

deleteIndex()
「deleteindex」的直接連結

indexName:

string
要刪除的索引名稱

刪除索引及其中所有向量。

await vectorStore.deleteIndex({ indexName: 'my_vectors' })

updateVector()
「updatevector」的直接連結

依 ID 或中繼資料篩選條件更新單一向量。必須提供 idfilter 其中一項,但不能同時提供兩者。

indexName:

string
包含該向量的索引名稱

id?:

string
要更新的向量 ID(不可與 filter 同時使用)

filter?:

Record<string, any>
用於識別待更新向量的中繼資料篩選條件(不可與 id 同時使用)

update:

{ vector?: number[]; metadata?: Record<string, any>; }
包含待更新向量及/或中繼資料的物件
// Update by ID
await vectorStore.updateVector({
indexName: 'my_vectors',
id: 'vector123',
update: {
vector: [0.1, 0.2, 0.3],
metadata: { label: 'updated' },
},
})

// Update by filter
await vectorStore.updateVector({
indexName: 'my_vectors',
filter: { category: 'product' },
update: {
metadata: { status: 'reviewed' },
},
})

deleteVector()
「deletevector」的直接連結

indexName:

string
包含該向量的索引名稱

id:

string
要刪除的向量 ID
await vectorStore.deleteVector({ indexName: 'my_vectors', id: 'vector123' })

deleteVectors()
「deletevectors」的直接連結

依 ID 或中繼資料篩選條件刪除多個向量。必須提供 idsfilter 其中一項,但不能同時提供兩者。

indexName:

string
包含待刪除向量的索引名稱

ids?:

string[]
要刪除的向量 ID 陣列(不可與 filter 同時使用)

filter?:

Record<string, any>
用於識別待刪除向量的中繼資料篩選條件(不可與 ids 同時使用)
// Delete by IDs
await vectorStore.deleteVectors({
indexName: 'my_vectors',
ids: ['vec1', 'vec2', 'vec3'],
})

// Delete by filter
await vectorStore.deleteVectors({
indexName: 'my_vectors',
filter: { status: 'archived' },
})

回應型別
「回應型別」的直接連結

查詢結果會以下列格式傳回:

interface QueryResult {
id: string
score: number
metadata: Record<string, any>
vector?: number[] // Only included if includeVector is true
}

中繼資料篩選
「中繼資料篩選」的直接連結

ConvexVector 支援搭配運算子的中繼資料篩選。從 Convex 載入向量後,介接器會套用這些篩選條件。

// Simple equality
const results = await vectorStore.query({
indexName: 'my_vectors',
queryVector: embedding,
filter: { category: 'documents' },
})

// Comparison operators
const results = await vectorStore.query({
indexName: 'my_vectors',
queryVector: embedding,
filter: {
price: { $gt: 100 },
status: { $in: ['active', 'pending'] },
},
})

// Logical operators
const results = await vectorStore.query({
indexName: 'my_vectors',
queryVector: embedding,
filter: {
$and: [{ category: 'electronics' }, { price: { $lte: 500 } }],
},
})

支援的篩選運算子
「支援的篩選運算子」的直接連結

運算子說明
$eq等於
$ne不等於
$gt大於
$gte大於或等於
$lt小於
$lte小於或等於
$in位於陣列中
$nin不在陣列中
$and邏輯 AND
$or邏輯 OR

架構
「架構」的直接連結

ConvexVector 會將向量儲存在 mastra_vectors 資料表中,結構如下:

  • id:不重複的向量識別碼
  • indexName:索引名稱
  • embedding:向量資料(浮點數陣列)
  • metadata:選用的 JSON 中繼資料

向量相似度搜尋會在 Mastra 介接器中使用餘弦相似度執行。這種方式能保持設定彈性,但並非為正式環境中的大型向量集合而設計。

ConvexNativeVector 會將每個 Mastra 向量索引儲存在專用的 Convex 資料表中。查詢時會呼叫使用 ctx.vectorSearch 的 Convex action,再透過 Convex query 載入相符文件。這遵循 Convex 原生向量搜尋模型:

  • 向量索引在 convex/schema.ts 中宣告。
  • 向量搜尋從 Convex action 執行。
  • topK 必須介於 1256 之間。
  • 篩選條件必須以 Convex 向量索引 filterFields 中列出的欄位為目標。
  • 每個 Mastra 向量索引應使用一個專用資料表,以避免產生跨索引結果。

若需要在執行階段建立動態定義的索引、僅使用中繼資料查詢、複雜篩選運算子、依篩選條件大量更新或刪除,或結果數量超過 Convex 原生向量搜尋上限,請使用外部向量資料庫。