Skip to main content
Orux AIOruxAI

Orux AI / Notas sobre modelos

Migração de API de embeddings: reconstrua vetores e mantenha o rollback

Migre de text-embedding-3-small para large sem misturar espaços vetoriais. Execute seis testes e compare reconstrução, armazenamento e troca de índice com rollback.

Orux AIPublicado 11 min de leitura
Migração de API de embeddings: reconstrua vetores e mantenha o rollback — Migre de text-embedding-3-small para large sem mis…
Neste artigo

A troca do modelo de embeddings exige um novo índice de busca

Ao migrar de text-embedding-3-small para text-embedding-3-large, crie um índice separado a partir dos textos originais dos documentos e gere as consultas com a configuração de embeddings correspondente. Não complete vetores antigos com zeros para ajustar seu tamanho, nem considere comprimentos iguais uma prova de que dois modelos compartilham o mesmo sistema de coordenadas. Mantenha o índice antigo disponível até que os novos caminhos de documentos e consultas passem pela sua própria avaliação de recuperação.

Para uma equipe de documentação que está migrando a busca de ajuda de um produto, isso significa prever uma nova geração de embeddings para todo o corpus, armazenamento temporário dos dois índices e uma troca de configuração reversível. O exemplo Python executável abaixo demonstra por que verificar apenas a dimensão é insuficiente, rejeita seis casos de teste inválidos e calcula um orçamento concreto para a reconstrução. Ele roda inteiramente offline: seus vetores bidimensionais são uma construção geométrica manual, não saídas de nenhum dos dois modelos da OpenAI.

Os espaços vetoriais antigo e rotacionado, definidos manualmente, recuperam A de forma consistente; a mistura dos espaços recupera B.
Os espaços vetoriais antigo e rotacionado, definidos manualmente, recuperam A de forma consistente; a mistura dos espaços recupera B.

Os vetores definidos manualmente preservam o resultado correto dentro de cada espaço. Uma consulta e um índice de espaços diferentes retornam B, mesmo com vetores do mesmo tamanho. Diagrama derivado do exemplo local que foi efetivamente executado.

Dimensões dos modelos e o que a Orux oferece hoje

O guia de embeddings da OpenAI informa comprimentos padrão de 1.536 para text-embedding-3-small e 3.072 para text-embedding-3-large. Também documenta o parâmetro nativo dimensions para reduzir embeddings de terceira geração. Reduzir a saída de um modelo compatível é uma escolha de configuração; isso não transforma esse modelo em outro.

Os dois aliases exatos estão atualmente disponíveis na Orux. A página de text-embedding-3-small e a página de text-embedding-3-large oferecem entrada de texto e vetores em formato float. Seus exemplos públicos salvos informam 1.536 e 3.072 dimensões, respectivamente. Esses exemplos sustentam o formato de saída informado, não uma classificação geral de precisão entre os modelos.

Os formulários verificados em 3 de novembro de 2026 não oferecem um controle de dimensões. Portanto, não planeje um índice reduzido na Orux apenas porque a documentação nativa da OpenAI descreve essa possibilidade. Confirme o contrato exato da integração antes de depender dessa opção. Este artigo não envia uma solicitação paga de embeddings nem demonstra o encaminhamento de dimensões pela Orux. Consulte a documentação da API da Orux para conhecer a interface de integração atual.

Registre juntos o alias do modelo, a quantidade de dimensões retornada, a versão do pré-processamento de texto e a métrica de distância. Por exemplo, um artigo de ajuda formado por title + body deve ter uma versão de pré-processamento diferente de outro que incorpora apenas body. Guarde os hashes das revisões dos documentos junto aos identificadores dos chunks, para que uma reconstrução futura consiga identificar textos desatualizados. A correspondência de dimensões detecta um erro óbvio de formato; os outros campos do contrato detectam erros de configuração que o formato não revela.

Um exemplo bidimensional revela a incompatibilidade oculta

Imagine dois vetores de documentos em um espaço antigo simplificado: A é (1, 0) e B é (0, 1). A consulta antiga (1, 0) recupera A. Agora gire todo o espaço em 90 graus. A passa a ser (0, 1), B passa a ser (-1, 0) e a mesma consulta conceitual passa a ser (0, 1). Uma busca consistente dentro de qualquer um dos espaços continua recuperando A.

Mas, ao combinar a consulta rotacionada com os documentos antigos, B vence. Todos os vetores continuam com duas coordenadas. O cálculo termina com sucesso, enquanto o significado da busca muda. Esse é um contraexemplo matemático à suposição de que dimensões iguais comprovam compatibilidade; não é uma simulação do comportamento aprendido de nenhum modelo nem uma estimativa da taxa de falhas de uma migração real.

Completar um vetor antigo com zeros muda seu comprimento, mas não fornece um mapeamento para a representação aprendida por um novo modelo. Truncar também não estabelece compatibilidade entre modelos. Mesmo ao reduzir a dimensão dentro de um único modelo compatível, use uma política de dimensões consistente para documentos e consultas e avalie a recuperação resultante. O suporte nativo à redução não autoriza misturar representações antigas e novas indiscriminadamente.

A proteção do exemplo compara a configuração completa antes de calcular a similaridade de cosseno. Essa comparação só funciona quando os metadados são corretos: rotular deliberadamente uma consulta nova como antiga contorna a proteção. O resultado unsafe_mixed_top abaixo ilustra essa limitação de propósito. Em produção, a procedência deve vir da configuração do encoder e do caminho de armazenamento, não de uma declaração não verificada do chamador.

Custo da reconstrução: calcule o corpus, não a quantidade de vetores

Os preços abaixo foram verificados em 3 de novembro de 2026. As tarifas da Orux vêm dos dois registros públicos de modelos. As tarifas padrão de entrada na contratação direta da OpenAI vêm das páginas de preços do modelo small e de preços do modelo large. São opções de contratação separadas, não uma afirmação de que as condições de conta ou o comportamento operacional sejam idênticos.

A conversão configurada atualmente é 1 Credit = USD 0.005. Os valores em USD abaixo são equivalências aritméticas; a Orux cobra em Credits. Todas as tarifas são por um milhão de tokens de entrada, não por milhão de documentos. A tabela não inclui custos separados de armazenamento, hospedagem do índice e engenharia, nem pressupõe descontos de Batch ou uma reconstrução gratuita.

ModeloTarifa de entrada da Orux / 1 milhão de tokensTarifa padrão direta da OpenAI / 1 milhão de tokensReconstrução planejada na Orux com 5 milhões de tokens
text-embedding-3-small1.53336 Credits (USD 0.0076668)Equivalente a 4 Credits (USD 0.02)7.6668 Credits (USD 0.038334)
text-embedding-3-large9.96672 Credits (USD 0.0498336)Equivalente a 26 Credits (USD 0.13)49.8336 Credits (USD 0.249168)

Deslize para os lados para ver toda a tabela.

Um corpus de planejamento com 10.000 chunks e média de 500 tokens de entrada totaliza cinco milhões de tokens. Migrar todo esse corpus para large exige, portanto, reservar o custo da reconstrução com large, e não apenas pagar a diferença entre as duas linhas. O que já foi gasto com small não compra vetores de large. A tarifa de large na Orux é aproximadamente 6,5 vezes a de small neste retrato de preços; essa proporção nada diz sobre a melhoria da recuperação nos seus documentos.

Esses totais são estimativas baseadas em uma quantidade presumida de tokens e em um cálculo agregado. Os comprimentos reais dos chunks, o tráfego de consultas, as novas tentativas e a granularidade de cobrança podem alterar o gasto. Meça os tokens do corpus com o tokenizer adequado antes de autorizar uma execução real. O código executável usa micro-Credits inteiros no cálculo da tarifa e Decimal na apresentação, evitando cálculos monetários com ponto flutuante binário.

A memória exige uma estimativa separada. Em float32, 10.000 vetores precisam de 61.440.000 bytes com 1.536 dimensões ou 122.880.000 bytes com 3.072 dimensões: aproximadamente 58,59 MiB e 117,19 MiB. Esses valores representam apenas os arrays brutos de coordenadas. Metadados, identificadores, estruturas do grafo de busca, réplicas e serialização acrescentam consumo. Durante uma migração reversível, manter apenas os dois arrays brutos já exige 184.320.000 bytes, antes desse consumo adicional.

Execute a demonstração de compatibilidade e orçamento

Salve o código a seguir como migration_demo.py e execute python3 migration_demo.py com Python 3.9 ou posterior. Ele usa somente a biblioteca padrão e não faz solicitações de rede. As tarifas são um retrato datado para tornar a conta reproduzível; substitua-as por tarifas atuais verificadas ao planejar uma migração futura.

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()

A execução local produziu old_top: A, new_top: A, unsafe_mixed_top: B e rejected_fixtures: 6. Os casos rejeitados são um contrato de modelo diferente, um comprimento de vetor incorreto, um vetor nulo, uma coordenada não finita, uma coordenada booleana e uma versão alterada de pré-processamento. Os totais planejados para small e large são 7.6668 e 49.8336 Credits, iguais aos da tabela.

Esta é uma demonstração executável da regra de compatibilidade e da aritmética de custos, não um adaptador de banco de dados. Ela não obtém embeddings, não constrói um índice de vizinhos mais próximos aproximados, não comprova a qualidade de recuperação de um modelo e não implementa controle de acesso de produção. Seus valores sintéticos de coordenadas são pequenos; uma biblioteca numérica de produção também deve lidar com toda a faixa numérica das entradas aceitas.

Dois pares separados de encoder e índice permitem uma troca coordenada e um rollback.
Dois pares separados de encoder e índice permitem uma troca coordenada e um rollback.

Plano de implantação: mantenha cada encoder de consultas conectado ao índice correspondente; faça a troca e o rollback do par. O diagrama descreve a arquitetura proposta, não uma migração implantada.

Troque o encoder de consultas e o índice como uma única configuração

Crie uma nova coleção ou namespace com o contrato de destino. Leia o texto original, aplique as regras registradas de divisão em chunks e pré-processamento e grave os vetores do modelo de destino com identificadores estáveis de documento e chunk. Preserve a coleção existente. Acompanhe os IDs de chunks esperados, os IDs concluídos e as revisões de origem, em vez de confiar em um único contador de linhas processadas.

Se os documentos de origem mudarem durante a reconstrução, escolha uma política clara de consistência. Um snapshot simples em uma janela de manutenção evita gravações concorrentes, mas adia atualizações. Uma reconstrução online precisa de um log de alterações que possa ser reaplicado, ou de uma reconciliação equivalente, para que edições e exclusões cheguem ao novo índice antes da troca. Uma contagem igual de vetores não basta quando um documento excluído e outro ausente se compensam numericamente por acaso.

Depois, vincule cada encoder de consultas ao índice previsto. Não atualize a aplicação para gerar consultas com large enquanto ela ainda lê a coleção de small. Trate o par como uma configuração versionada da aplicação, incluindo pré-processamento, dimensões e métrica. Rejeite solicitações quando o manifesto armazenado da coleção e a configuração da consulta divergirem. Em sistemas com múltiplos tenants, preserve os mesmos filtros de tenant e permissões de documentos nas duas coleções.

Para o rollback, mantenha juntos a configuração antiga de consultas e sua coleção. Guardar apenas os vetores antigos não basta se a aplicação não conseguir mais gerar consultas antigas compatíveis. Após a troca, acompanhe a qualidade dos resultados, os relatos de documentos ausentes, a latência e o custo das consultas. Desative o par antigo somente depois da janela de avaliação e retenção combinada, não simplesmente quando a nova coleção começar a aceitar gravações.

Decida com perguntas de busca avaliadas, não pelo tamanho do vetor

Prepare um conjunto pequeno e representativo de avaliação antes de reconstruir tudo. Para um serviço de ajuda de produto, inclua números exatos de peças, perguntas vagas de solução de problemas, consultas multilíngues e documentos com restrições de acesso. Registre quais IDs de documentos são relevantes para cada pergunta. Separe o julgamento de relevância da impressão de fluência da resposta gerada.

Para cada configuração candidata, recupere a mesma quantidade de resultados do mesmo snapshot de documentos. Compare a presença de documentos relevantes entre os primeiros resultados e examine falhas importantes. Não compare um índice de small feito de fragmentos curtos do corpo do texto com um índice de large feito de textos enriquecidos com título e corpo e atribua toda a diferença ao modelo. Divisão em chunks, pré-processamento e filtragem de acesso são variáveis experimentais independentes.

Este artigo não apresenta um vencedor medido. Escolha small quando a própria avaliação dele atender aos seus requisitos com o menor custo atual de entrada e armazenamento. Considere large quando os ganhos medidos no seu trabalho justificarem a reconstrução, os vetores maiores e o custo contínuo de consultas. Um teste local de compatibilidade bem-sucedido estabelece uma proteção, não um motivo para comprar um modelo mais caro.

FAQ

Preciso gerar novamente todos os vetores dos documentos ao trocar de modelo?

Sim, gere novamente o corpus pesquisável no espaço do modelo de destino para a migração descrita aqui. Preserve o texto original e os IDs estáveis de chunks e codifique as futuras consultas com a mesma configuração de destino. Renomear o campo do modelo não torna os vetores existentes compatíveis.

Posso completar vetores de 1.536 dimensões até chegar a 3.072?

Completar pode satisfazer um requisito de comprimento do array, mas não estabelece um mapeamento entre modelos. Essa não é uma estratégia adequada de compatibilidade para esta migração. O exemplo simplificado mostra que um formato válido ainda pode retornar o documento errado quando os espaços são misturados.

A Orux oferece o parâmetro nativo dimensions da OpenAI?

Os formulários públicos verificados para esses dois aliases da Orux não o oferecem. A documentação nativa da OpenAI, por si só, não verifica o comportamento da Orux. Confirme o contrato real da integração antes de depender de saídas reduzidas e, depois, construa e consulte um índice configurado de forma consistente.

text-embedding-3-large é automaticamente melhor para minha busca?

Este artigo não comprova uma melhoria específica para sua carga de trabalho. Avalie as duas configurações com suas próprias perguntas avaliadas e o mesmo snapshot de origem. Dimensões maiores e preços mais altos não substituem a medição de quais documentos relevantes são recuperados.

O que o exemplo Python realmente testou?

Ele testou a geometria de vetores definidos manualmente, a rejeição de contratos incompatíveis, seis casos inválidos e a aritmética datada de orçamento e armazenamento. Não chamou APIs de embeddings, não gastou Orux Credits e não fez benchmark de saídas dos modelos nem de um banco de dados vetorial real.

Experimente página de text-embedding-3-small na Orux AIExecute online e veja preços e exemplos de API na página do modelo.Abrir modeloExperimente página de text-embedding-3-large na Orux AIExecute online e veja preços e exemplos de API na página do modelo.Abrir modelo

Use estes modelos com uma única API

Uma API compatível com OpenAI para modelos de chat, imagem, vídeo e áudio, cobrada em Credits.

Artigos relacionados

Ver todos os artigos →