Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Embedding Model

SCHEMABOUND exposes a pluggable embedding interface through the EmbeddingProvider trait in the backend. This lets you integrate any vector embedding backend — cloud APIs, local models, or hybrid setups — without changing your application code.

The Trait

#![allow(unused)]
fn main() {
use schemabound_backend::memory::embedding::{EmbeddingProvider, EmbeddingError};

pub trait EmbeddingProvider: Send + Sync {
    fn embed(&self, text: &str) -> Result<Vec<f32>, EmbeddingError>;
    fn dimension(&self) -> usize;
}
}

The embed method accepts a string and returns a fixed-dimensional vector of 32-bit floats. Implementations are responsible for tokenization, normalization, and returning vectors in the format expected by your search or retrieval layer. The default dimension is 768 (matching BGE-base-en-v1.5), configurable via SCHEMABOUND_EMBEDDING_DIMENSION environment variable.

Built-In Stub: NoOpEmbeddingModel

The backend includes a zero-vector stub for development and testing. It returns a vector of zeros with the configured dimension, satisfying the trait boundary when you do not need semantic search:

#![allow(unused)]
fn main() {
use schemabound_backend::memory::embedding::{EmbeddingProvider, EmbeddingModel};

// Default dimension is 768; override via SCHEMABOUND_EMBEDDING_DIMENSION env var.
let model = EmbeddingModel::default();
assert_eq!(model.dimension(), 768);

let vector = model.embed("any text").unwrap();
assert_eq!(vector.len(), 768);
assert!(vector.iter().all(|&v| v == 0.0)); // zero-vector stub
}

The model is registered with Rocket’s state system as EmbeddingService(Arc<dyn EmbeddingProvider>) and injected into handlers via the State<EmbeddingService> guard — no factory pattern needed, just direct dependency injection.

Custom Implementations

To use a real embedding backend (e.g., OpenAI text-embedding-ada-002, local BGE models), implement EmbeddingProvider for your type:

#![allow(unused)]
fn main() {
use schemabound_backend::memory::embedding::{EmbeddingProvider, EmbeddingError};
use std::sync::Arc;

struct OpenAiEmbedder {
    api_key: String,
    client: reqwest::Client,
}

impl EmbeddingProvider for OpenAiEmbedder {
    fn embed(&self, text: &str) -> Result<Vec<f32>, EmbeddingError> {
        let response = self.client.post("https://api.openai.com/v1/embeddings")
            .bearer_auth(&self.api_key)
            .json(&serde_json::json!({ "input": text, "model": "text-embedding-ada-002" }))
            .send()
            .map_err(|e| EmbeddingError::Computation(e.to_string()))?;

        let body: serde_json::Value = response.json().await
            .map_err(|e| EmbeddingError::Computation(e.to_string()))?;

        // OpenAI returns 1536-dim vectors as f64 — cast to f32.
        let vec: Vec<f32> = body["data"][0]["embedding"]
            .as_array()
            .unwrap()
            .iter()
            .map(|v| v.as_f64().unwrap() as f32)
            .collect();

        Ok(vec)
    }

    fn dimension(&self) -> usize { 1536 }
}

// Register with Rocket state via build_rocket's .manage() chain.
let model: Arc<dyn EmbeddingProvider> = Arc::new(OpenAiEmbedder { ... });
}

Configuration

Environment VariableDefaultDescription
SCHEMABOUND_EMBEDDING_DIMENSION768Dimension of embedding vectors produced by the model. Must match across all components using the same model.

When you enable semantic trace search, pass your configured EmbeddingProvider to the search subsystem at startup. The search endpoint (POST /api/memory/search) uses the model’s vectors for cosine similarity computation against stored trace embeddings (see Semantic Search API Reference).

The backend automatically computes and persists embeddings when memory entries are created via AgentMemoryStore::on_tool_call(), so no manual wiring is required — just ensure your EmbeddingModel implementation produces vectors with the dimension specified in SCHEMABOUND_EMBEDDING_DIMENSION.

Error Handling

The trait returns Result<Vec<f32>, EmbeddingError> where EmbeddingError covers:

  • Transport failures (network timeouts, rate limits)
  • Malformed responses from upstream APIs
  • Invalid vector dimensions (mismatch between configured dimension and returned length)
  • Model not configured

Propagate with ? in your implementation or map to your application-specific error type using map_err.