Prerequisites
- A running Quivr with an ingestion plugin pinned. This guide keeps
core.ingestserving and addshosted.embed, the hosted text embedding plugin. curl,jq, Go and thequivrCLI (curl --version,jq --version,go version,command -v quivr). Run package commands from a Quivr checkout.- Your API address in
QUIVR_API_URLand the id of a collection of documents (Corpus) inCORPUS_ID. - API keys with the following permissions and grants for the Corpus:
All three keys for a Corpus must belong to its Organization. Plugin, plan and promotion requests affect the whole deployment; backfills and coverage reads see only the key’s Organization and grants.
You also need a reachable model endpoint, its model name and dimensions, and its credential in the plugin process environment. The plugin reads
AZURE_FOUNDRY_KEY for every provider, despite that variable’s name. The examples use a hosted Cohere v2 endpoint and 1024 dimensions; choose a model that supports them.
The package generation runs offline. The API sequence is checked with a local fake embedding provider; the provider configuration below is an example, not a live provider run. Replace placeholders with your installation’s values.
This procedure changes the plugin that produces segments and vectors (the ingestion owner). If your new model is another space of the same plugin, follow Fill a new vector space, then use this page’s comparison and alert-migration checks. That path promotes a space; this example activates a registration.
Keep the former model reachable and filling new documents throughout the trial and switch, so rollback remains possible.
Steps
1
Prepare the second model
Build the plugin, then write its configuration. Replace the URL and model placeholders before generating the manifest:For Cohere’s own API, use Check that the report says Changing the model, dimensions, format, metric, input templates or
"base_url":"https://api.cohere.com/v2" and "auth":"bearer" in both configuration copies instead.The generated manifest binds the model and settings to a distinct vector space, the coordinate system for its numeric vectors. Use that exact configuration when pinning or registering it. Copy the space name from contributions.ingestion.spaces; its API id is that name followed by @ and the declared space version.Certify with a fixture carrying the same configuration. Inject AZURE_FOUNDRY_KEY into the certification command’s environment so its plugin subprocess receives it. This step calls your provider:CERTIFIED. Start the plugin in a separate terminal, with the provider key injected from your secret manager. Choose a free port reachable by Quivr’s API and workers:model_revision creates another space. Set model_revision when the provider changes weights behind a stable model name. A changed package needs a new immutable registration: increment plugin_version, regenerate and certify it. To compare several hosted models at once, give each a distinct plugin_id before generation.2
Install it for evaluation
Keep your current served routing, and add Two settings use the same words. The Extract
hosted.embed under ingestion.evaluation for each source format you want to compare. An ingestion owner is the plugin that produces a document’s segments and vectors. Evaluation adds another owner’s output without replacing the served owner’s output.For example, merge these settings into each API, worker and migrate configuration, preserving existing pins and routes:spaces pin picks which of this plugin’s spaces it uses: hosted.embed has only one, so it is served. ingestion.evaluation decides whether its output reaches ordinary search: it does not until you activate it in step 5. Apply the pin; for a runtime registration, follow Upgrade or switch a plugin.Routing uses the original source media type: a PDF normalized to text still follows application/pdf. Both owners read the normalized document pieces (canonical Parts), but each keeps its own segment cuts and vectors.Ordinary search reads the served owner’s output; an explicit evaluation search reads the second owner’s output.In words: each model builds its own segments and vectors from the same document. Ordinary search uses the served model; evaluation search names the candidate and its space. An evaluation failure is recorded in document diagnostics and does not change served readiness.Find the active hosted.embed registration and save its registration_id as REGISTRATION_ID:SPACE_ID from the generated manifest, which is JSON-compatible YAML. Save the current plan for an exact rollback target:3
Fill existing documents
Live ingestion fills a space once the Corpus’s search index carries it. Installing the plugin alone does not prepare every existing Corpus. A backfill can add the space and fill old documents. Run it for every Corpus in the deployment, in every Organization, including empty ones, without date filters.Use your deployment’s list of Organizations and each Organization’s keys. List its authorized Corpora:Follow For two short documents, the dry run includes these fields (trimmed; your counts vary):Read Save the returned See Backfill a vector space for pausing, resuming and failures. The same accepted key and body return the same Operation; a later fill needs a fresh key and its own dry run before starting. One unfinished backfill per Corpus is allowed.
next_page_cursor by sending it as page_cursor until it is absent (displayed here as null). Quivr cannot list all Organizations’ Corpora with one key. Ensure the key grants access to every Corpus in its Organization.Make a dry run with an explicit registration and its primary space:versions, segments, input_tokens, estimated_seconds and confirmation_required. Cost is unknown when estimated_cost_usd is absent. A plugin without its own segments yet is estimated using the current owner’s cuts; completion uses the new owner’s actual cuts.The start request must reuse the dry run’s key and scope, changing dry_run to false. Add confirm_cost:true only after accepting an estimate that requires confirmation:operation_id in OPERATION_ID. An Operation records this long-running task. Follow it until state is succeeded, failed or canceled. Continue only after succeeded; otherwise inspect the failure or rerun the fill:4
Compare searches and coverage
Use the same query, Corpora, mode, search profile, filters and limit. These two requests differ only in selecting the evaluation path:Both evaluation fields are required together. The space must belong to that plugin and be carried by every requested Corpus; invalid selections return In the same two-document run, the candidate entry reads (trimmed):For each space,
422 unsupported_search.Each hit is one segment (passage), so one document can appear several times. Compare relevant document ids and passage order across several queries, including paraphrases and other languages. Owners can cut documents differently, so segment offsets need not match. Raw similarity scores from different models are not comparable probabilities. Check hit vector_space_id to confirm which model answered.Read each Corpus’s coverage:coverage.segments counts vectors present, coverage.total_segments counts that owner’s current segments, and coverage.versions_covered counts current document revisions fully covered. Compare segment counts within that owner; the response’s top-level segments describes served segments and can differ.Before switching, require coverage.segments to equal coverage.total_segments and the backfill Operation to be succeeded for each Corpus. An empty Corpus reads 0/0, which is fine. These counts describe stored segments; skipped documents can still lack candidate output. The switch rechecks coverage across the deployment and refuses if anything is missing.5
Switch the model
Fill and compare before switching ordinary search; migrate meaning alerts immediately afterward.In words: run both models, fill existing documents, compare, then switch and update alerts. If results worsen, return to the saved plan and update alerts again. Changing spaces within one owner uses space promotion; changing the ingestion owner uses registration activation.Different owner, as in this For the example’s three source formats, expect this output (plan id replaced):This switches every source format that names this plugin as an evaluation owner, moving its segments and vectors together. Its primary space must be carried by every Corpus’s index across every Organization, including empty Corpora. Every current document routed to the candidate must have all its candidate segments and primary vectors.Missing coverage returns
hosted.embed example: activate the already active evaluation registration:409 plugin_conflict and leaves the plan unchanged; an unreachable candidate returns 409 plugin_unreachable. Repeating activation returns the same plan. The previous owner becomes an evaluation owner for those formats and continues filling new documents asynchronously. If a configuration change leaves an existing Corpus serving another owner, new documents also fill the active plan’s default or source-route owner. Keep these plugins reachable and check coverage before returning to either model.Same owner, another space: follow Fill a new vector space, which ends with a space promotion. That API allows force as an explicit exception for incomplete coverage; documents without vectors then disappear from semantic results until filled. Registration activation has no force option.6
Move vector meaning alerts
A Saved Query stores an alert definition; each immutable Saved Query Version fixes its query vectors. A Subscription pins one such Version and the evaluator that judges documents. Switching search does not re-encode those vectors or move those pins. Vectors from different spaces cannot be compared.Migrate immediately after the switch. Until you do, these alerts return Save its returned The query Version must still be that Saved Query’s current Version. Finish its Subscription migrations before creating another query Version. Replaying the same key and body returns the same Version; a changed body conflicts. Subscription edits preserve enabled state and affect future changes from their commit, without replaying past documents or rewriting existing Matches.Use your application’s inventory to include disabled Subscriptions before re-enabling them. The Subscription API requires an owner filter and lists only enabled, non-deleted items; follow all pages for each owner and list global Subscriptions separately with
not_ready because the document and query vectors are in different spaces. Quivr records that result as final: it does not automatically re-check those documents when you migrate. A new Subscription Version takes effect from its commit, so documents accepted between the switch and migration can miss alerts permanently. The same gap opens after rollback; migrate immediately then too.For every Saved Query using meaning_check: vectors in the affected Corpora, create a new Version after the served-model switch. Set SAVED_QUERY_ID to its id from your application’s alert inventory. Preserve its definition:version_id as QUERY_VERSION_ID. For each Subscription of this Saved Query, set SUBSCRIPTION_ID and create a new Version, retaining its evaluator settings and destination:owner=none. Gather Saved Query ids from those lists or your inventory; the API cannot list Saved Queries. Recalibrate the evaluator’s similarity threshold against the new model. This is separate from upgrading an alert-rule plugin.Check it worked
Repeat the current-model search without evaluation fields:current_version.saved_query_version_id matches the new query Version.
Roll back
Keep the previous plugin reachable with its expected build, and keep its evaluation coverage filling new documents. A missing vector or owner projection can block rollback; backfill the returning owner first. Do not stop it while work or alerts still pin it. For an owner switch, return to the saved plan, using a new key for this rollback attempt:drain for sound output; use stop for bad output or hangs. The same key and body replay this rollback. Keep the explicit target: another untargeted rollback can return to the plan you just left. Unreachable builds return 409 plugin_unreachable; missing owner coverage returns 409 plugin_conflict. Its message names the owner, space and number of missing documents, and points to POST /v0/admin/backfills. It also reports missing index generations: even an empty Corpus must carry the returning space. Find the returning owner’s registration with GET /v0/admin/plugins and read each Corpus’s coverage to locate gaps. Use the backfill procedure for that registration and space in each affected Corpus, wait for complete coverage, then retry. Historical gaps and failed optional calls still need this recovery.
For a same-owner space switch, promote the returned previous_space_id back with the space-promotion request. It needs complete coverage too. Immediately after either rollback, create another Saved Query Version using the restored served model and migrate its Subscriptions again with fresh keys; the earlier migrations do not reverse themselves.
Compatible redeploys preserve activated serving and evaluation routes; see Redeploy a configured build for the compatibility conditions. Earlier plans and pinned work still require their original builds. If a redeploy makes the saved plan unreachable, restore that build or follow the linked procedure to activate the returning owner’s current evaluation registration, then migrate alerts again.
Clean up
Delete the localquery-version.json and subscription-version.json files after migration. Retaining an evaluation owner is useful for rollback but continues provider calls. Once you no longer need that rollback option:
- Copy the active plan’s default, served routes and evaluation owners into
ingestion.default,ingestion.routesandingestion.evaluationin every process’s configuration. Apply this configuration first, so it records the routing you chose by activation or rollback. - Remove the retiring owner from each
ingestion.evaluationlist and apply the configuration again. After rollback in this example, removehosted.embed; if you keep the candidate serving, remove the former owner instead. This stops new evaluation calls for those formats. - If that plugin no longer serves any format or other plugin role, remove its
pluginspin too. Keep it reachable until pinned work and Subscriptions release it and its registration becomesinactive; see the plugin lifecycle. A plugin still serving another format or role must keep running.
Next
- Backfill a vector space for estimates and Operation controls.
- Plugin lifecycle for draining work and deciding when a plugin can stop.
- Meaning alerts for vector matching and calibration.