Re-embedding a Knowledge Base — Unique AI Documentation

Re-embedding a Knowledge Base

Re-embedding a Knowledge Base (Switching the Embedding Model)

Audience: Unique Solution Engineering (running on customer-managed tenants) and platform administrators with chat.admin.all. This is an advanced maintenance operation that re-processes a tenant's entire vector store and can run for hours on large tenants. Coordinate with Unique before running on a production tenant.

Overview

Re-embedding regenerates the vector embeddings for all of a company's ingested content using a different embedding model, then atomically switches the company's live vector collection to the new model. Use it when you need to:

What it does under the hood (operation type SWITCH_EMBEDDING_MODEL):

  1. preparing — creates a new, temporary vector collection sized for the new model's dimension.
  2. reembedding — streams every chunk, re-embeds it with the new model, and writes the vectors into the new collection (in batches).
  3. swap — once the new collection is complete, atomically points the company's live collection at it and updates the relational store.
  4. cleanup — removes the old collection.

The job is checkpointed (a worker restart resumes from the last position) and non-destructive by default: the old collection and live search keep working throughout the run, and the swap only happens at the very end.

Who can run it

Before you start (prerequisites)

# Prerequisite Why it matters
1 Target model is registered & deployed for the tenant The new embedding model must be available in the tenant's embedding configuration. Confirm with Unique which model keys are available.
2 Sufficient embedding quota (TPM/RPM) Re-embedding pushes the entire corpus through the model. Low quotas make large tenants impractical (jobs spend their time rate-limited). See Sizing.
3 Per-request token limit respected Embedding providers cap tokens per request (commonly 300,000 tokens/request). batch size × average chunk tokens must stay under that cap or requests fail with a 400. See Configuration.
4 Run a dry run first Always preview with dryRun: true to validate the plan and get a chunk-count estimate before committing.
5 Plan for duration Large tenants take hours. Plan an overnight/weekend window and monitor.

The operation is resilient to concurrent ingestion and to transient vector-DB / rate-limit errors (they are retried automatically). For the cleanest, fastest run you may still choose to pause heavy ingestion for the company during the switch.

Step 1 — Dry run (preview, makes no changes)

mutation {
  createMaintenanceJob(input: {
    operationType: "SWITCH_EMBEDDING_MODEL"
    newEmbeddingModel: "text-embedding-3-large"
    newEmbeddingDimension: 3072
    dryRun: true
  }) { id status }
}

A dry run validates the request, estimates the number of chunks to process, and completes without changing any data. Read the job back (Step 3) — its result contains the plan, including estimatedChunks, the current collection, and the target model/dimension. Use the estimate to size the run (see Sizing).

Step 2 — Run the switch

mutation {
  createMaintenanceJob(input: {
    operationType: "SWITCH_EMBEDDING_MODEL"
    newEmbeddingModel: "text-embedding-3-large"
    newEmbeddingDimension: 3072
    destructive: false
    dryRun: false
  }) { id status createdAt }
}

Input fields

Field Required Description
operationType "SWITCH_EMBEDDING_MODEL"
newEmbeddingModel The model key as registered for the tenant (e.g. text-embedding-3-large).
newEmbeddingDimension The vector dimension of the new model (e.g. 3072 for text-embedding-3-large). Must match the model's actual output dimension.
destructive ➖ (default false) false = keep the old collection until the new one is durable ( recommended, allows rollback). true = delete the old collection up front (no rollback).
dryRun ➖ (default false) true = preview only (Step 1).

Invoking it (cURL) — authenticate with a chat.admin.all bearer token; companyId is derived from the token:

curl -X POST "$INGESTION_GRAPHQL_URL" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"mutation { createMaintenanceJob(input:{operationType:\"SWITCH_EMBEDDING_MODEL\",newEmbeddingModel:\"text-embedding-3-large\",newEmbeddingDimension:3072,destructive:false,dryRun:false}){ id status } }"}'

$INGESTION_GRAPHQL_URL is the tenant's ingestion GraphQL endpoint and $ADMIN_TOKEN is a Zitadel token for a chat.admin.all user — ask Unique for the endpoint if you don't have it. The mutation returns the new job's id.

Step 3 — Monitor

A background worker claims the job within ~60 seconds of creation. Track it with:

query {
  maintenanceJob(jobId: "mjob_xxx") {
    id status phase processed total failed errorMessage startedAt completedAt result
  }
}

List all jobs for the company with maintenanceJobs { id status phase processed total operationType createdAt }.

Field Meaning
status PENDINGRUNNINGCOMPLETED (or FAILED / CANCELLED).
phase preparingreembeddingswapcleanup.
processed / total Progress (chunks re-embedded vs. estimated total).
failed Per-item failures (non-fatal).
errorMessage Populated when status = FAILED.

Cancel a running job with cancelMaintenanceJob(jobId: "mjob_xxx").

Sizing & duration

Throughput is bounded by the embedding model's tokens-per-minute (TPM) quota:

estimated minutes  ≈  (total_chunks × avg_tokens_per_chunk) ÷ TPM_quota
chunks per minute  ≈  TPM_quota ÷ avg_tokens_per_chunk

Worked example: 750,000 TPM quota, ~400 tokens/chunk → ~1,800 chunks/min → a 1.9M-chunk tenant ≈ **17 hours**. A few-thousand-TPM quota would make the same tenant take many days — raise the quota for large tenants.

Re-embedding is processed sequentially (one batch at a time). The single biggest lever on duration is the embedding deployment's TPM quota.

Safety, atomicity & rollback

Troubleshooting

Symptom (in errorMessage / logs) Cause Resolution
429 ... exceeded call rate limit ... S0 pricing tier Embedding deployment quota too low Raise the model deployment's TPM/RPM quota, then re-run. Transient 429s are retried automatically; a persistently throttled deployment will still exhaust retries.
400 Invalid 'input': maximum request size is 300000 tokens per request Batch is larger than the provider's per-request token cap Reduce the batch size (MAINTENANCE_OPS_CHUNK_BATCH_SIZE), e.g. 512 → 128. Re-run.
Transient vector-DB connection drops (EPIPE, socket errors, "Insert into qdrant did not work") Network / keep-alive blips to the vector DB Retried automatically in current versions. If it persists, check vector-DB health/capacity.
Dimension mismatch on upsert newEmbeddingDimension ≠ the model's real output dimension Set newEmbeddingDimension to the model's actual dimension (e.g. 3072 for text-embedding-3-large).
A maintenance job for this company is still holding the lock A job is active or recently finished (one job per company at a time) Wait for it to finish, or cancelMaintenanceJob, then retry.
Job stays PENDING No worker picked it up Ensure the ingestion / maintenance worker is running.

Configuration reference

Setting Default Purpose
MAINTENANCE_OPS_CHUNK_BATCH_SIZE 512 Number of chunks per embedding request. Lower it if batch × avg-chunk-tokens approaches the provider's per-request token cap (≈300k).
Per-company embedding model registration The new model must be registered/available for the tenant before switching.

Note on multi-endpoint embedding distribution: in environments where embedding requests are distributed across multiple endpoints, confirm that per-company model overrides are honored for the target company before running — otherwise the re-embed may use the default model. Check with Unique if your tenant uses multi-endpoint distribution.

Known limitations