Recherche vectorielle et IA avec pgvector

Stockez des embeddings dans votre base de données PostgreSQL et recherchez-les par le sens - activer pgvector, un exemple qui fonctionne, les index, et ce qu'il faut vérifier d'abord.

Une fonction d'IA - recherche sémantique, « trouver des éléments similaires », récupération de contexte pour un chatbot, recommandation - a besoin d'un endroit où garder des embeddings et d'un moyen de trouver les plus proches. Sur ISOGrid, c'est votre base de données PostgreSQL ordinaire avec l'extension pgvector : les vecteurs se trouvent à côté des lignes qu'ils décrivent, dans les mêmes transactions, les mêmes sauvegardes et les mêmes règles d'accès. Il n'y a pas de seconde base de données à faire tourner.

L'activer

Ouvrez la base de données, allez dans sa vue Extensions, et activez pgvector. La plateforme crée l'extension pour vous, parce que la créer exige un super-utilisateur, ce que votre propre rôle n'est pas.

Deux choses à vérifier si pgvector est indiqué comme absent du serveur :

  • Un serveur de base de données à vous créé avant l'arrivée de pgvector tourne sur une image plus ancienne. Redéployez l'instance ; elle passe sur l'image actuelle et l'extension devient disponible. Vos données ne sont pas touchées.
  • Une base de données sur un serveur partagé reçoit pgvector quand le serveur partagé de la région le propose. Si le vôtre ne le propose pas encore, commandez un serveur de base de données à vous, qui l'a toujours.

Un exemple qui fonctionne

-- One row per document, with its embedding. 1536 is the size of the vectors
-- your embedding model returns; use the size of yours.
CREATE TABLE documents (
    id        bigserial PRIMARY KEY,
    title     text NOT NULL,
    body      text NOT NULL,
    embedding vector(1536)
);

-- Store a document with the vector your embedding model returned for it.
INSERT INTO documents (title, body, embedding)
VALUES ('Refund policy', 'Refunds are made within 14 days...', '[0.012, -0.034, ...]');

-- The five documents closest in meaning to a question: embed the question with
-- the same model, then order by distance. <=> is cosine distance.
SELECT id, title
FROM documents
ORDER BY embedding <=> '[0.008, -0.021, ...]'
LIMIT 5;

Les embeddings eux-mêmes viennent du modèle que vous choisissez et que vous appelez depuis votre application ; la base de données les stocke et les recherche. Utilisez un seul modèle par colonne : des vecteurs issus de modèles différents ne peuvent pas être comparés.

La rendre rapide

Sans index, chaque recherche lit toute la table, ce qui convient jusqu'à quelques dizaines de milliers de lignes. Au-delà, ajoutez un index approximatif :

CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);

Faites correspondre la classe d'opérateurs à l'opérateur avec lequel vous recherchez : vector_cosine_ops pour <=>, vector_l2_ops pour <->, vector_ip_ops pour <#>. Un index construit pour l'un n'est pas utilisé par un autre. Le construire demande de la mémoire et du temps en proportion de la table ; faites-le sur une base de données dimensionnée pour cela, pas sur la plus petite.

Filtrer et combiner

Parce que c'est PostgreSQL, une recherche vectorielle est une clause d'une requête ordinaire. Restreignez par client, par date ou par statut dans la même instruction :

SELECT id, title
FROM documents
WHERE customer_id = 42 AND published
ORDER BY embedding <=> '[...]'
LIMIT 5;

C'est la principale raison de garder les vecteurs dans votre base de données plutôt que dans un stockage vectoriel séparé : le filtre et la recherche ne peuvent pas être en désaccord sur les lignes qui existent.

Ce qu'il faut savoir avant de vous y fier

  • Les sauvegardes incluent les vecteurs, comme tout le reste de la base de données.
  • Désactiver pgvector échoue tant qu'une colonne ou un index l'utilise encore, avec l'explication de PostgreSQL.
  • Une base de données en haute disponibilité réplique les vecteurs avec le reste ; les recherches à forte charge de lecture peuvent être envoyées vers les copies.

Pour continuer