Section 13.6.3 : Base de données vectorielle et embeddings
🎯 Objectif pédagogique
Comprendre les embeddings vectoriels, les bases de données vectorielles (pgvector, Pinecone), et implémenter une recherche sémantique performante dans une application Rails.
Qu'est-ce qu'un embedding ?
Un embedding est une représentation numérique d'un texte sous forme de vecteur (liste de nombres). Les textes sémantiquement proches ont des vecteurs proches dans l'espace vectoriel.
# "chat" et "félin" sont proches dans l'espace vectoriel
embedding_chat = EmbeddingService.generate("Le chat dort")
# => [0.023, -0.041, 0.089, ..., 0.012] (1536 dimensions)
embedding_felin = EmbeddingService.generate("Le félin sommeille")
# => [0.025, -0.039, 0.091, ..., 0.010] (très similaire !)
embedding_voiture = EmbeddingService.generate("La voiture roule")
# => [-0.067, 0.082, -0.015, ..., 0.044] (très différent)
Similarité cosinus
La similarité cosinus mesure l'angle entre deux vecteurs. Plus ils pointent dans la même direction, plus les textes sont similaires :
def cosine_similarity(vec_a, vec_b)
dot_product = vec_a.zip(vec_b).sum { |a, b| a * b }
magnitude_a = Math.sqrt(vec_a.sum { |a| a ** 2 })
magnitude_b = Math.sqrt(vec_b.sum { |b| b ** 2 })
dot_product / (magnitude_a * magnitude_b)
end
# "chat" vs "félin" => ~0.95 (très similaire)
# "chat" vs "voiture" => ~0.15 (pas similaire)
pgvector : les vecteurs dans PostgreSQL
pgvector est une extension PostgreSQL qui ajoute un type vector et des index de recherche vectorielle. C'est la solution la plus simple pour Rails.
# Migration Rails
class AddVectorToDocuments < ActiveRecord::Migration[7.0]
def up
enable_extension 'vector'
add_column :documents, :embedding, :vector, limit: 1536
add_index :documents, :embedding,
using: :ivfflat,
opclass: :vector_cosine_ops
end
end
# Gemfile
gem 'neighbor' # Gem Rails pour pgvector
# app/models/document.rb
class Document < ApplicationRecord
has_neighbors :embedding
# Recherche les documents les plus similaires
scope :search_similar, ->(query_embedding, limit: 5) {
nearest_neighbors(:embedding, query_embedding, distance: :cosine)
.first(limit)
}
end
Pipeline complet de recherche sémantique
# app/services/semantic_search.rb
class SemanticSearch
def self.index_document(document)
chunks = DocumentProcessor.chunk(document.content)
chunks.each_with_index do |chunk, index|
embedding = EmbeddingService.generate(chunk)
DocumentChunk.create!(
document: document,
content: chunk,
chunk_index: index,
embedding: embedding
)
end
end
def self.search(query, limit: 5)
query_embedding = EmbeddingService.generate(query)
DocumentChunk
.nearest_neighbors(:embedding, query_embedding, distance: :cosine)
.first(limit)
.map do |chunk|
{
content: chunk.content,
document: chunk.document,
similarity: chunk.neighbor_distance
}
end
end
end
# Utilisation
SemanticSearch.index_document(article)
results = SemanticSearch.search("Comment configurer l authentification ?")
Solutions de vector DB
Bases de données vectorielles
← Scroll horizontally →
Si deux textes ont une similarité cosinus de 0.95, que signifie-t-il ?
Learn AI, from prompts to agents