= Models :nav-title: Models :description: Set the embedding and reranking models your service uses, with your provider keys, verified before they are saved; then follow the guided steps to a semantic search on a collection. :keywords: embedding model, Voyage AI, OpenAI embeddings, reranking, vector index, $vectorize, $vectorSearch, semantic search, API key :group: AI :order: 20 Under **AI → Models** you tell the service which model computes its vectors and, if you want, which one reorders search results, and you give it the keys of your provider. Vector indexes, `$vectorize` and reranking all run on what you set here. The provider bills the calls to your account. == Before you start Get a key from a provider with an embeddings API: * https://dashboard.voyageai.com/api-keys[Voyage AI], the default: models made for retrieval, and a contextual variant that embeds the chunks of a document aware of each other. * Any provider that answers OpenAI's `/v1/embeddings`: https://platform.openai.com/api-keys[OpenAI], https://openrouter.ai/settings/keys[OpenRouter], https://api.together.ai/settings/api-keys[Together AI], or your own base URL. Then **Install** the feature from the page header. The badge says whether it is enabled; **Disable** stops the service from calling the provider without forgetting the keys, **Uninstall** forgets them. == Set the models The form has two blocks. **Embedding** is required. Pick the provider, the model and, where the model allows it, the length of the vector: [cols="1,2,1"] |=== | Provider | Models | Dimensions | Voyage AI | `voyage-4`, `voyage-4-large`, `voyage-4-lite`, `voyage-code-4` | 1024, or 256, 512, 2048 | Voyage AI | `voyage-finance-2`, `voyage-law-2` | 1024 | Voyage AI contextual | `voyage-context-4` | 1024, or 256, 512, 2048 | OpenAI-compatible | `text-embedding-3-small`, `text-embedding-3-large` on OpenAI; the model's name on any other provider | 1536 or 3072 by default, shorter on request |=== With an OpenAI-compatible provider other than OpenAI, type the model's name as the provider calls it: the vector's length is read from the verification. **Reranking** is optional: Voyage AI (`rerank-2.5`, `rerank-2.5-lite`) or Cohere (`rerank-v3.5`), each with its key. With Voyage you can reuse the embedding key. **Verify** calls the provider: it embeds one word and, with reranking on, reranks one document. The answer is written under the fields: «Key accepted by Voyage, 1024 dimensions», or the provider's refusal, «Voyage refused the key (401)». **Save** stays disabled until a verification succeeds, and any change to the form asks for a new one, so a key that does not work never reaches the service. Saved, the page shows a status card: provider, model, dimensions, «key set», reranking. The key is never shown again; **Change** opens the form with the key masked, and leaving it masked keeps the one stored. == One index, one model A vector index declares the length of the vectors it holds, and a search compares vectors of the same model. Change the model, or its dimensions, and the vectors already stored no longer match: the index has to be created again with the new length, and the documents written again to get new vectors. The page warns when you pick a model different from the saved one. == Demo setup Under **Tools → Demo setup** the page takes you from the key to a semantic search on `catalog`, the collection of the ecommerce starter and of the xref:mcp.adoc#demo-setup[MCP demo]: the same products for the agent, the search and the shop. Each step has a checkbox that says whether the thing exists, a button, and **Do all** runs the missing ones in order, stopping at the first error. [cols="1,2"] |=== | Step | What it does | Collection `catalog` with auto-embedding on `description` | Creates the collection if missing, and sets `vectorSearch: { textField: "description", embeddingField: "embedding" }` on it: from then on every product written gets the vector of its description. | Sample products of the ecommerce starter | Shown only while the collection is empty. Loads a hundred or so products from the starter's repository, each embedded as it is written. | Vectors of the products already stored | Shown only when the collection holds something. Products written before the vectors were switched on have none: each is patched with its own description, which is enough for the service to embed it. One call to the provider per product. | Vector index `catalog_vectors` | A `vectorSearch` index on `embedding`, cosine similarity, with the dimensions of the saved model. | Aggregation `search`, published on MCP | `$vectorSearch` on the index, the question vectorized with `$vectorize` from the parameter `q`. With a reranking model saved, a `rerank` block keeps the best five of the ten closest. Published on MCP with its parameter, so an agent can run it. |=== Then ask: `GET /catalog/_aggrs/search?q=a gift for a gardener` returns the products closest in meaning to the question. == By hand Under **Tools → By hand** the same steps are HTTP calls, in curl, HTTPie, JavaScript and Python, with a temporary admin token in them, so each one runs as it is. Pick a tool on one block and every block follows. The calls are the ones your own application makes: [source] ---- PUT /catalog { "vectorSearch": { "textField": "description", "embeddingField": "embedding" } } PUT /catalog/_indexes/catalog_vectors { "type": "vectorSearch", "fields": [ { "type": "vector", "path": "embedding", "numDimensions": 1024, "similarity": "cosine" } ] } PATCH /catalog { "aggrs": [ { "uri": "search", "type": "pipeline", "stages": [ { "$vectorSearch": { "index": "catalog_vectors", "path": "embedding", "queryVector": { "$vectorize": { "$var": "q" } }, "numCandidates": 100, "limit": 10 } }, { "$project": { "embedding": 0 } } ] } ] } GET /catalog/_aggrs/search?q=a%20gift%20for%20a%20gardener ---- On a collection that already exists, send the first body with `PATCH`: `PUT` replaces the whole set of properties, `PATCH` merges. A vector index takes a few seconds to be ready after it is created; a search before that returns nothing, without an error. [[reranking-a-search]] == Reranking a search A `rerank` block beside the `stages` of an aggregation hands its results to the reranking model, which reorders them by how well each answers the question: [source,json] ---- { "uri": "search", "type": "pipeline", "stages": [ { "$vectorSearch": { "...": "..." } }, { "$set": { "text": "$description" } } ], "rerank": { "query": { "$var": "q" }, "topK": 5 } } ---- `query` is the text to judge by, usually the same `$var` that vectorizes the question; `topK` is how many results to keep, all of them when omitted. The model reads each result's `text` field, or the whole document when there is none, so add a `$set` stage that copies the field to judge by into `text`. The block names no model: the service uses the reranking model saved here. On the xref:aggregations.adoc[Aggregations] page the same block is a section of the form, with the query variable and `topK` as fields. == What it costs The provider bills every embedding, one per document written and one per question, and every reranking call, to your account. RESTHeart Cloud adds nothing. Loading the sample products embeds a hundred of them; the step says so before you click.