Aller au contenu principal

Stockage vectoriel Convex

La classe ConvexVector fournit un stockage vectoriel et une recherche par similarité au moyen de Convex. Elle stocke les embeddings dans Convex et effectue la recherche par similarité cosinus dans l'adaptateur Mastra.

Recherche à l'échelle du développement

ConvexVector lit les vecteurs correspondants via le gestionnaire de stockage Mastra, les filtre en JavaScript, calcule leur similarité cosinus, trie les résultats et renvoie les meilleures correspondances. Utilisez-le pour le développement local, les tests et les petits jeux de données.

Pour la recherche vectorielle en production sur Convex, utilisez ConvexNativeVector. Il utilise l'API native vectorSearch de Convex, qui nécessite un index vectoriel Convex déployé et une action Convex.

Installation
Lien direct vers Installation

npm install @mastra/convex@latest

Configuration de Convex
Lien direct vers Configuration de Convex

Avant d'utiliser ConvexVector, vous devez configurer le schéma et le gestionnaire de stockage Convex. Consultez la configuration du stockage Convex pour obtenir les instructions.

Options du constructeur
Lien direct vers Options du constructeur

deploymentUrl:

string
URL du déploiement Convex (par exemple, https://your-project.convex.cloud)

adminAuthToken:

string
Token d'authentification administrateur Convex

storageFunction?:

string
= mastra/storage:handle
Chemin de la fonction de mutation du stockage

Exemples de constructeur
Lien direct vers Exemples de constructeur

Configuration de base
Lien direct vers Configuration de base

import { ConvexVector } from '@mastra/convex'

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

Utilisez ConvexNativeVector pour les charges vectorielles de production. Il stocke les vecteurs dans une table Convex dédiée et interroge un index vectoriel Convex défini dans le schéma.

Dans convex/schema.ts, définissez une table dédiée pour chaque index vectoriel Mastra :

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

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

Dans convex/mastra/nativeVector.ts, exportez les gestionnaires vectoriels natifs :

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

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

Dans votre application Mastra, configurez ConvexNativeVector avec la table et l'index vectoriel déployés :

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,
})

Pour prendre en charge les filtres natifs, déclarez leurs champs dans votre schéma Convex. Lors de l'écriture des vecteurs, les gestionnaires vectoriels natifs copient les champs de métadonnées correspondants dans les champs de premier niveau du document.

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 prend en charge les formes de filtres vectoriels natifs de Convex : un champ d'égalité, ou un $or de champs d'égalité. Il ne prend pas en charge les requêtes reposant uniquement sur les métadonnées, ni les mises à jour ou suppressions fondées sur des filtres. Utilisez les identifiants des vecteurs pour les mises à jour et les suppressions.

Fonction de stockage personnalisée
Lien direct vers Fonction de stockage personnalisée

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

Méthodes
Lien direct vers Méthodes

createIndex()
Lien direct vers createindex

indexName:

string
Nom de l'index à créer

dimension:

number
Dimension du vecteur (doit correspondre à votre modèle d'embedding)

metric?:

'cosine' | 'euclidean' | 'dotproduct'
= cosine
Métrique de distance pour la recherche par similarité (seule la similarité cosinus est actuellement prise en charge)
await vectorStore.createIndex({
indexName: 'my_vectors',
dimension: 1536,
})

upsert()
Lien direct vers upsert

indexName:

string
Nom de l'index dans lequel effectuer l'upsert des vecteurs

vectors:

number[][]
Tableau de vecteurs d'embedding

metadata?:

Record<string, any>[]
Métadonnées de chaque vecteur

ids?:

string[]
Identifiants facultatifs des vecteurs (générés automatiquement s'ils ne sont pas fournis)
await vectorStore.upsert({
indexName: "my_vectors",
vectors: [[0.1, 0.2, 0.3, ...]],
metadata: [{ label: "example" }],
ids: ["vec-1"],
});

query()
Lien direct vers query

indexName:

string
Nom de l'index à interroger

queryVector:

number[]
Vecteur de requête

topK?:

number
= 10
Nombre de résultats à renvoyer

filter?:

Record<string, any>
Filtres de métadonnées

includeVector?:

boolean
= false
Indique si le vecteur doit être inclus dans le résultat
const results = await vectorStore.query({
indexName: "my_vectors",
queryVector: [0.1, 0.2, 0.3, ...],
topK: 5,
filter: { category: "documents" },
});

listIndexes()
Lien direct vers listindexes

Renvoie un tableau de noms d'index sous forme de chaînes.

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

describeIndex()
Lien direct vers describeindex

indexName:

string
Nom de l'index à décrire

Renvoie :

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

deleteIndex()
Lien direct vers deleteindex

indexName:

string
Nom de l'index à supprimer

Supprime l'index et tous ses vecteurs.

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

updateVector()
Lien direct vers updatevector

Met à jour un seul vecteur à partir de son identifiant ou d'un filtre de métadonnées. Vous devez fournir soit id, soit filter, mais pas les deux.

indexName:

string
Nom de l'index contenant le vecteur

id?:

string
Identifiant du vecteur à mettre à jour (mutuellement exclusif avec filter)

filter?:

Record<string, any>
Filtre de métadonnées permettant de repérer le ou les vecteurs à mettre à jour (mutuellement exclusif avec id)

update:

{ vector?: number[]; metadata?: Record<string, any>; }
Objet contenant le vecteur et/ou les métadonnées à mettre à jour
// 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()
Lien direct vers deletevector

indexName:

string
Nom de l'index contenant le vecteur

id:

string
Identifiant du vecteur à supprimer
await vectorStore.deleteVector({ indexName: 'my_vectors', id: 'vector123' })

deleteVectors()
Lien direct vers deletevectors

Supprime plusieurs vecteurs à partir de leurs identifiants ou d'un filtre de métadonnées. Vous devez fournir soit ids, soit filter, mais pas les deux.

indexName:

string
Nom de l'index contenant les vecteurs à supprimer

ids?:

string[]
Tableau d'identifiants de vecteurs à supprimer (mutuellement exclusif avec filter)

filter?:

Record<string, any>
Filtre de métadonnées permettant de repérer les vecteurs à supprimer (mutuellement exclusif avec 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' },
})

Types de réponse
Lien direct vers Types de réponse

Les résultats de la requête sont renvoyés au format suivant :

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

Filtrage des métadonnées
Lien direct vers Filtrage des métadonnées

ConvexVector prend en charge le filtrage des métadonnées au moyen d'opérateurs. L'adaptateur applique ces filtres après avoir chargé les vecteurs depuis 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 } }],
},
})

Opérateurs de filtre pris en charge
Lien direct vers Opérateurs de filtre pris en charge

OpérateurDescription
$eqÉgal à
$neDifférent de
$gtSupérieur à
$gteSupérieur ou égal à
$ltInférieur à
$lteInférieur ou égal à
$inDans le tableau
$ninAbsent du tableau
$andET logique
$orOU logique

Architecture
Lien direct vers Architecture

ConvexVector stocke les vecteurs dans la table mastra_vectors avec la structure suivante :

  • id : identifiant unique du vecteur
  • indexName : nom de l'index
  • embedding : données du vecteur (tableau de nombres à virgule flottante)
  • metadata : métadonnées JSON facultatives

La recherche par similarité vectorielle est effectuée au moyen de la similarité cosinus dans l'adaptateur Mastra. Cette approche garantit une configuration flexible, mais n'est pas conçue pour de grandes collections vectorielles de production.

ConvexNativeVector stocke chaque index vectoriel Mastra dans une table Convex dédiée. Ses requêtes appellent une action Convex qui utilise ctx.vectorSearch, puis chargent les documents correspondants au moyen d'une requête Convex. Cette approche suit le modèle de recherche vectorielle natif de Convex :

  • Les index vectoriels sont déclarés dans convex/schema.ts.
  • La recherche vectorielle est exécutée depuis une action Convex.
  • topK doit être compris entre 1 et 256.
  • Les filtres doivent cibler les champs répertoriés dans filterFields de l'index vectoriel Convex.
  • Utilisez une table dédiée par index vectoriel Mastra afin d'éviter les résultats provenant de plusieurs index.

Utilisez une base de données vectorielle externe lorsque vous avez besoin de créer des index définis à l'exécution, d'effectuer des requêtes reposant uniquement sur les métadonnées, d'utiliser des opérateurs de filtre complexes, de réaliser des mises à jour ou suppressions groupées fondées sur des filtres, ou de dépasser la limite de résultats de la recherche vectorielle native de Convex.