chat-rs
Capabilities

Embeddings

Turn text into vectors with the same chat builder you already use, via with_embeddings and chat.embed.

Embeddings turn text into a vector of floats you can use for search, clustering, or similarity. chat-rs exposes this through the same builder you use for chat, so you do not need a separate client. Opt in with .with_embeddings() and call chat.embed(&mut messages).

This works with any provider that implements EmbeddingsProvider. Today that includes Gemini, OpenAI, Ollama, and mistral.rs. Where a provider supports it, you can also ask for a specific vector size, covered in Choosing dimensions below.

A local Ollama example

.with_embeddings() switches the builder into an embedding chat. embed returns an EmbeddingsResponse, which carries metadata and an embeddings value.

embeddings.rs
use chat_rs::{
    ChatBuilder,
    ollama::OllamaBuilder,
    parts,
    types::messages::{self, content},
};

let client = OllamaBuilder::new().with_model("nomic-embed-text").build();

let mut chat = ChatBuilder::new()
    .with_model(client)
    .with_embeddings()
    .build();

let mut messages = messages::Messages::default();
messages.push(content::from_user(parts!["The quick brown fox."]));

let response = chat.embed(&mut messages).await.map_err(|err| err.err)?;
println!("Dimensions:\t{}", response.embeddings.dimension);
println!("Embedding[..5]:\t{:?}", &response.embeddings.content[..5]);
println!("Metadata:\t{:?}", response.metadata);

The response shape

pub struct EmbeddingsResponse {
    pub metadata: Option<Metadata>,
    pub embeddings: Embeddings,
}

pub struct Embeddings {
    pub content: Vec<f32>,
    pub dimension: usize,
}

content is the vector itself, and dimension tells you how long it is. From here you can store it, compare it, or feed it into a vector index.

Choosing dimensions with Gemini

Some providers let you ask for a specific vector size. With Gemini you set that on the provider builder via .with_embeddings(Some(dimensions)), then opt the chat in as usual.

use chat_rs::{
    ChatBuilder,
    gemini::GeminiBuilder,
    parts,
    types::messages::{self, content},
};

let client = GeminiBuilder::new()
    .with_model("gemini-embedding-001")
    .with_embeddings(Some(126))
    .build();

let mut chat = ChatBuilder::new()
    .with_model(client)
    .with_embeddings()
    .build();

let mut messages = messages::Messages::default();
messages.push(content::from_user(parts!["A sentence to embed."]));

let response = chat.embed(&mut messages).await.map_err(|err| err.err)?;
println!("Model:\t{:?}", response.embeddings);

The pattern is the same across providers: pick an embedding-capable model, opt in with .with_embeddings(), and call embed.

On this page