Skip to main content
Orux AIOruxAI

Orux AI / Carnet des modèles

API d'embeddings : migrer l'index et pouvoir revenir

Passez de text-embedding-3-small à large sans mélanger les espaces vectoriels. Exécutez six contrôles et chiffrez reconstruction, stockage et retour arrière.

Orux AIPublié 11 min de lecture
API d'embeddings : migrer l'index et pouvoir revenir — Passez de text-embedding-3-small à large sans mélanger les espaces ve…
Sommaire

Changer de modèle d'embeddings exige un nouvel index de recherche

Pour migrer de text-embedding-3-small vers text-embedding-3-large, construisez un index distinct à partir du texte original des documents et encodez les requêtes avec la configuration d'embeddings correspondante. N'adaptez pas les anciens vecteurs en ajoutant des zéros et ne considérez pas une longueur identique comme la preuve que deux modèles partagent un système de coordonnées. Conservez l'ancien index jusqu'à ce que les nouveaux parcours de traitement des documents et des requêtes réussissent votre propre évaluation de recherche.

Pour une équipe de documentation qui migre le moteur d'aide d'un produit, cela suppose de prévoir une nouvelle passe d'embedding de tout le corpus, un stockage temporaire pour les deux index et un changement de configuration réversible. L'exemple Python exécutable ci-dessous montre pourquoi une simple vérification des dimensions ne suffit pas, rejette six cas de test invalides et calcule un budget concret de reconstruction. Il fonctionne entièrement hors ligne : ses vecteurs bidimensionnels sont une construction géométrique manuelle, pas des sorties de l'un ou l'autre modèle OpenAI.

Les espaces vectoriels initial et tourné retrouvent chacun A ; leur mélange fait remonter B.
Les espaces vectoriels initial et tourné retrouvent chacun A ; leur mélange fait remonter B.

Les vecteurs définis manuellement préservent le bon résultat dans chaque espace. Mélanger la requête et l'index renvoie B malgré des vecteurs de même longueur. Schéma issu de l'exemple exécuté localement.

Dimensions des modèles et limites actuelles d'Orux

Le guide des embeddings d'OpenAI indique une longueur par défaut de 1,536 pour text-embedding-3-small et de 3,072 pour text-embedding-3-large. Il documente aussi le paramètre natif dimensions, qui permet de réduire les dimensions des embeddings de troisième génération. Raccourcir la sortie d'un modèle compatible est un choix de configuration ; cela ne transforme pas ce modèle en un autre.

Ces deux alias exacts figurent actuellement au catalogue Orux. La page du modèle text-embedding-3-small et la page du modèle text-embedding-3-large proposent des entrées textuelles et des vecteurs au format float. Leurs exemples publics enregistrés indiquent respectivement 1,536 et 3,072 dimensions. Ces exemples étayent la forme de sortie annoncée, pas un classement général des modèles selon leur précision.

Les formulaires vérifiés le 3 novembre 2026 ne proposent pas de réglage des dimensions. Ne prévoyez donc pas un index Orux à dimensions réduites au seul motif que la documentation native d'OpenAI décrit cette possibilité. Vérifiez le contrat d'intégration exact avant d'en dépendre. Cet article n'envoie aucune requête d'embedding payante et ne démontre pas la transmission du paramètre de dimensions par Orux. Consultez la documentation de l'API Orux pour connaître l'interface d'intégration actuelle.

Consignez ensemble l'alias du modèle, le nombre de dimensions renvoyé, la version du prétraitement du texte et la métrique de distance. Par exemple, un article d'aide formé de title + body doit porter une version de prétraitement différente d'un article dont seul body est encodé. Conservez les empreintes des révisions des documents avec les identifiants de fragments afin de repérer les textes périmés lors d'une reconstruction ultérieure. Une correspondance des dimensions détecte une erreur de forme évidente ; les autres champs du contrat détectent les erreurs de configuration que la forme ne révèle pas.

Un exemple en deux dimensions révèle l'incompatibilité cachée

Imaginons deux vecteurs de documents dans un ancien espace fictif : A vaut (1, 0) et B vaut (0, 1). L'ancienne requête (1, 0) retrouve A. Faisons maintenant tourner tout l'espace de 90 degrés. A devient (0, 1), B devient (-1, 0) et la requête représentant le même concept devient (0, 1). Une recherche cohérente dans chacun des deux espaces retrouve toujours A.

En revanche, si l'on mélange la requête tournée avec les anciens documents, B arrive en tête. Tous les vecteurs possèdent encore deux coordonnées. Le calcul s'exécute correctement alors que le sens de la recherche change. C'est un contre-exemple mathématique à l'idée que des dimensions égales établissent la compatibilité ; il ne simule pas le comportement appris de l'un des modèles et n'estime aucun taux d'échec de migrations réelles.

Ajouter des zéros à un ancien vecteur modifie sa longueur, mais ne fournit aucune correspondance vers la représentation apprise par un nouveau modèle. Le tronquer n'établit pas davantage la compatibilité entre modèles. Même lorsque vous réduisez les dimensions au sein d'un même modèle compatible, appliquez une politique cohérente aux documents et aux requêtes, puis évaluez le comportement de recherche obtenu. La prise en charge native de cette réduction n'autorise pas le mélange indiscriminé d'anciennes et de nouvelles représentations.

Le contrôle de l'exemple compare la configuration complète avant de calculer la similarité cosinus. Cette comparaison ne fonctionne que si les métadonnées sont exactes : déclarer volontairement une nouvelle requête comme ancienne contourne le contrôle. Le résultat unsafe_mixed_top ci-dessous illustre précisément cette limite. En production, la provenance doit être établie à partir de la configuration de l'encodeur et du chemin de stockage, pas d'une déclaration non vérifiée de l'appelant.

Coût de reconstruction : chiffrez le corpus, pas le nombre de vecteurs

Les prix ci-dessous ont été vérifiés le 3 novembre 2026. Les tarifs Orux proviennent des fiches publiques des deux modèles. Les tarifs d'entrée standard d'OpenAI en direct proviennent des pages de tarification du modèle small et de tarification du modèle large. Il s'agit de modes d'achat distincts ; cela ne signifie pas que leurs conditions de compte ou leur fonctionnement opérationnel sont identiques.

La conversion actuellement configurée est 1 Credit = USD 0.005. Les montants en USD ci-dessous sont des équivalents arithmétiques ; Orux facture en Credits. Tous les tarifs portent sur un million de tokens d'entrée, pas sur un million de documents. Le tableau exclut les coûts supplémentaires de stockage, d'hébergement de l'index et d'ingénierie. Il ne suppose ni remise Batch ni reconstruction gratuite.

ModèleTarif d'entrée Orux / 1M tokensTarif standard OpenAI en direct / 1M tokensReconstruction prévue de 5M tokens sur Orux
text-embedding-3-small1.53336 Credits (USD 0.0076668)Équivalent à 4 Credits (USD 0.02)7.6668 Credits (USD 0.038334)
text-embedding-3-large9.96672 Credits (USD 0.0498336)Équivalent à 26 Credits (USD 0.13)49.8336 Credits (USD 0.249168)

Faites défiler horizontalement pour voir tout le tableau.

Un corpus prévisionnel de 10,000 fragments comptant en moyenne 500 tokens d'entrée représente cinq millions de tokens. Migrer l'ensemble de ce corpus vers large exige donc de budgéter sa reconstruction avec large, et pas seulement la différence entre les deux lignes. Les dépenses déjà engagées pour small n'achètent pas des vecteurs large. Dans cet instantané, le tarif large d'Orux est environ 6.5 fois celui de small ; ce rapport ne dit rien de l'amélioration de la recherche sur vos documents.

Ces totaux sont des estimations fondées sur un nombre supposé de tokens et un calcul agrégé. La longueur réelle des fragments, le trafic des requêtes, les nouvelles tentatives et la granularité de facturation peuvent modifier les dépenses. Mesurez les tokens du corpus avec le tokenizer approprié avant d'autoriser une véritable exécution. Le code exécutable calcule les tarifs en micro-Credits entiers et utilise Decimal pour l'affichage, évitant les calculs monétaires en virgule flottante binaire.

La mémoire nécessite une estimation distincte. En float32, 10,000 vecteurs occupent 61,440,000 octets à 1,536 dimensions ou 122,880,000 octets à 3,072 dimensions, soit environ 58.59 MiB et 117.19 MiB. Il s'agit uniquement des tableaux bruts de coordonnées. Métadonnées, identifiants, structures de graphes de recherche, répliques et sérialisation ajoutent une surcharge. Pendant une migration réversible, conserver ces deux tableaux bruts nécessite à lui seul 184,320,000 octets, avant cette surcharge.

Exécuter la démonstration de compatibilité et de budget

Enregistrez le code suivant dans migration_demo.py, puis exécutez python3 migration_demo.py avec Python 3.9 ou une version ultérieure. Il n'utilise que la bibliothèque standard et n'effectue aucune requête réseau. Les tarifs correspondent à un instantané daté pour rendre le calcul reproductible ; remplacez-les par des tarifs actuels vérifiés lorsque vous planifiez une migration ultérieure.

Python
import json
import math
from dataclasses import asdict, dataclass
from decimal import Decimal

@dataclass(frozen=True)
class Contract:
    model: str
    dimensions: int
    preprocessing: str
    metric: str = 'cosine'

def validate(vector, contract):
    if len(vector) != contract.dimensions:
        raise ValueError('dimension mismatch')
    if any(isinstance(x, bool) or not isinstance(x, (int, float))
           or not math.isfinite(x) for x in vector):
        raise ValueError('non-finite or non-numeric vector')
    if math.hypot(*vector) == 0:
        raise ValueError('zero vector')

def search(query, query_contract, documents, index_contract):
    if query_contract != index_contract:
        raise ValueError('embedding contract mismatch')
    validate(query, query_contract)
    scores = []
    for doc_id, vector in documents.items():
        validate(vector, index_contract)
        score = sum(a*b for a, b in zip(query, vector)) / (
            math.hypot(*query) * math.hypot(*vector))
        scores.append((doc_id, score))
    return sorted(scores, key=lambda row: (-row[1], row[0]))

def budget(rate_micro_credits, total_tokens):
    micro = (rate_micro_credits * total_tokens + 999999) // 1000000
    credits = Decimal(micro) / 1000000
    return {'credits': str(credits), 'usd': str(credits * Decimal('0.005'))}

def main():
    # Handwritten two-dimensional geometry, NOT model outputs.
    old = Contract('toy-old', 2, 'title-body-v1')
    new = Contract('toy-new', 2, 'title-body-v1')
    old_docs = {'A': [1, 0], 'B': [0, 1]}
    new_docs = {'A': [0, 1], 'B': [-1, 0]}
    old_top = search([1, 0], old, old_docs, old)[0][0]
    new_top = search([0, 1], new, new_docs, new)[0][0]
    unsafe_top = search([0, 1], old, old_docs, old)[0][0]
    assert (old_top, new_top, unsafe_top) == ('A', 'A', 'B')
    failures = [
        lambda: search([0, 1], new, old_docs, old),
        lambda: validate([1], old),
        lambda: validate([0, 0], old),
        lambda: validate([float('nan'), 1], old),
        lambda: validate([True, 1], old),
        lambda: search([1, 0], Contract('toy-old', 2, 'title-body-v2'), old_docs, old),
    ]
    rejected = 0
    for test in failures:
        try:
            test()
        except ValueError:
            rejected += 1
        else:
            raise AssertionError('invalid fixture was accepted')
    chunks, tokens_per_chunk = 10000, 500
    tokens = chunks * tokens_per_chunk
    result = {
        'toy_results': {'old_top': old_top, 'new_top': new_top,
                        'unsafe_mixed_top': unsafe_top},
        'rejected_fixtures': rejected,
        'planning_tokens': tokens,
        'orux_small': budget(1533360, tokens),
        'orux_large': budget(9966720, tokens),
        'raw_float32_bytes': {'small_1536': chunks * 1536 * 4,
                             'large_3072': chunks * 3072 * 4},
        'new_contract': asdict(new),
    }
    print(json.dumps(result, indent=2))

if __name__ == '__main__':
    main()

L'exécution locale a produit old_top: A, new_top: A, unsafe_mixed_top: B et rejected_fixtures: 6. Les cas rejetés sont un contrat de modèle différent, une longueur de vecteur incorrecte, un vecteur nul, une coordonnée non finie, une coordonnée booléenne et une version de prétraitement modifiée. Les budgets small et large s'élèvent à 7.6668 et 49.8336 Credits, conformément au tableau.

C'est une démonstration exécutable de la règle de compatibilité et du calcul des coûts, pas un adaptateur de base de données. Elle ne récupère pas d'embeddings, ne construit pas d'index de recherche approximative des plus proches voisins, ne prouve pas la qualité de recherche d'un modèle et n'implémente pas les contrôles d'accès de production. Ses coordonnées synthétiques ont de petites valeurs ; une bibliothèque numérique de production doit également gérer toute la plage numérique des entrées qu'elle accepte.

Deux paires distinctes d'encodeur et d'index permettent une bascule coordonnée et un retour arrière.
Deux paires distinctes d'encodeur et d'index permettent une bascule coordonnée et un retour arrière.

Plan de déploiement : gardez chaque encodeur de requêtes relié à l'index correspondant ; basculez ou restaurez la paire complète. Ce schéma décrit l'architecture proposée, pas une migration déployée.

Basculer l'encodeur de requêtes et l'index comme une seule configuration

Créez une nouvelle collection ou un nouvel espace de noms avec le contrat cible. Relisez le texte source original, appliquez les règles enregistrées de découpage et de prétraitement, puis écrivez les vecteurs du modèle cible sous des identifiants stables de document et de fragment. Laissez la collection existante intacte. Suivez les identifiants de fragments attendus, les identifiants traités et les révisions sources plutôt que de vous fier à un simple compteur de lignes traitées.

Si les documents sources changent pendant la reconstruction, choisissez une politique de cohérence explicite. Un instantané pris pendant une fenêtre de maintenance évite les écritures concurrentes, mais retarde les mises à jour. Une reconstruction en ligne nécessite un journal de modifications rejouable ou un rapprochement équivalent afin que les modifications et suppressions atteignent le nouvel index avant la bascule. Un nombre identique de vecteurs ne suffit pas lorsqu'un document supprimé et un document manquant se compensent par hasard dans le total.

Associez ensuite chaque encodeur de requêtes à l'index prévu. Ne faites pas générer des requêtes avec large à l'application pendant qu'elle lit encore la collection small. Traitez la paire comme une configuration d'application versionnée comprenant prétraitement, dimensions et métrique. Rejetez les requêtes lorsque le manifeste enregistré de la collection et la configuration de la requête divergent. Dans les systèmes multilocataires, préservez les mêmes filtres de locataire et autorisations documentaires dans les deux collections.

Pour permettre un retour arrière, conservez ensemble l'ancienne configuration de requêtes et sa collection. Garder uniquement les anciens vecteurs ne suffit pas si l'application ne sait plus produire de requêtes anciennes compatibles. Après la bascule, surveillez la qualité des résultats, les signalements de documents manquants, la latence et les coûts des requêtes. Retirez l'ancienne paire seulement à l'issue de la période d'évaluation et de conservation convenue, pas dès que la nouvelle collection accepte des écritures.

Décider avec des questions de recherche annotées, pas avec la taille des vecteurs

Préparez un petit jeu d'évaluation représentatif avant de tout reconstruire. Pour le service d'aide d'un produit, incluez des références exactes de pièces, des questions de dépannage imprécises, des demandes multilingues et des documents soumis à des restrictions d'accès. Consignez les identifiants de documents pertinents pour chaque question. Distinguez le jugement de pertinence de l'impression de fluidité donnée par la réponse générée.

Pour chaque configuration candidate, récupérez le même nombre de résultats depuis le même instantané documentaire. Comparez la présence de documents pertinents parmi les premiers résultats et examinez les omissions importantes. Ne comparez pas un index small construit à partir de courts fragments du corps du texte avec un index large construit à partir de titres et de corps enrichis pour attribuer ensuite toute la différence au modèle. Le découpage, le prétraitement et le filtrage des accès sont des variables expérimentales indépendantes.

Cet article ne désigne aucun vainqueur mesuré. Choisissez small si sa propre évaluation satisfait vos besoins avec le coût actuel plus faible d'entrée et de stockage. Envisagez large si ses gains mesurés sur votre charge de travail justifient la reconstruction, les vecteurs plus volumineux et le coût continu des requêtes. Réussir un test local de compatibilité apporte un garde-fou, pas une raison d'acheter un modèle plus cher.

FAQ

Faut-il régénérer tous les vecteurs documentaires lorsque l'on change de modèle ?

Oui : pour la migration décrite ici, régénérez le corpus interrogeable dans l'espace du modèle cible. Conservez le texte original et les identifiants stables de fragments, puis encodez les futures requêtes avec la même configuration cible. Renommer le champ du modèle ne rend pas les vecteurs existants compatibles.

Peut-on compléter des vecteurs de 1,536 dimensions pour atteindre 3,072 dimensions ?

L'ajout de valeurs peut satisfaire une contrainte de longueur de tableau, mais n'établit pas de correspondance entre modèles. Ce n'est pas une stratégie de compatibilité adaptée à cette migration. L'exemple fictif montre qu'une forme valide peut encore retrouver le mauvais document lorsque les espaces sont mélangés.

Orux expose-t-il le paramètre dimensions natif d'OpenAI ?

Les formulaires publics vérifiés pour ces deux alias Orux ne le proposent pas. La documentation native d'OpenAI ne suffit pas à vérifier le comportement d'Orux. Confirmez le contrat d'intégration réel avant de dépendre de sorties raccourcies, puis construisez et interrogez un index configuré de façon cohérente.

text-embedding-3-large est-il automatiquement meilleur pour ma recherche ?

Cet article n'établit aucune amélioration propre à votre charge de travail. Évaluez les deux configurations sur vos questions annotées et votre instantané source. Des dimensions plus nombreuses et des prix plus élevés ne remplacent pas la mesure de la récupération des documents pertinents.

Qu'a réellement testé l'exemple Python ?

Il a testé la géométrie de vecteurs définis manuellement, le rejet des contrats incompatibles, six cas de test invalides et des calculs datés de budget et de stockage. Il n'a effectué aucun appel à une API d'embeddings, dépensé aucun Credit Orux ni évalué les sorties des modèles ou une base de données vectorielle en fonctionnement.

Essayer page du modèle text-embedding-3-small sur Orux AILancez-le en ligne, puis consultez les tarifs et les exemples d’API sur la page du modèle.Ouvrir le modèleEssayer page du modèle text-embedding-3-large sur Orux AILancez-le en ligne, puis consultez les tarifs et les exemples d’API sur la page du modèle.Ouvrir le modèle

Utilisez ces modèles avec une seule API

Une API compatible OpenAI pour les modèles de chat, d’image, de vidéo et d’audio, facturée en Credits.

Articles similaires

Voir tous les articles →