Skip to main content

Embedding Providers API

API reference for embedding providers. See Embedding Providers Concept for usage guidance and comparison.

EmbeddingProvider

Protocol/trait/interface that all embedding providers must implement.

#[async_trait]
pub trait EmbeddingProvider: Send + Sync {
fn name(&self) -> &str;
fn model(&self) -> &str;
fn dimensions(&self) -> usize;
async fn generate_embedding(&self, text: &str) -> Result<EmbeddingResult>;
async fn close(&self) -> Result<()>;
}

Methods:

  • name(): Returns provider identifier ("openai", "onnx", etc.)
  • model(): Returns model name (e.g., "text-embedding-3-large")
  • dimensions(): Returns embedding vector size (1536 for OpenAI, 384 for ONNX)
  • generate_embedding(text): Generates normalized embedding from text
  • close(): Cleanup method (closes HTTP sessions, ONNX runtime, etc.)

OpenAIProvider

Embedding provider using OpenAI's API.

Constructor

impl OpenAIProvider {
pub fn new(
api_key: String,
model: Option<String>, // Default: "text-embedding-3-large"
dimensions: Option<usize>, // Default: 1536
name: Option<String>, // Default: "openai"
) -> Self
}

Example:

use odin_prompt_toolkit::providers::OpenAIProvider;

let provider = OpenAIProvider::new(
std::env::var("OPENAI_API_KEY")?,
Some("text-embedding-3-large".to_string()),
Some(1536),
None,
);

Configuration

Environment Variables:

  • OPENAI_API_KEY: API key (can be passed via constructor instead)
  • OPENAI_BASE_URL: Custom API base URL (optional)

Cost: ~0.13per1Mtokens( 0.13 per 1M tokens (~0.000013 per prompt)

Latency: ~100-200ms (network + API processing)

Feature Requirement:

[dependencies]
odin-prompt-toolkit = { version = "0.1", features = ["openai"] }

OnnxProvider

Local ONNX-based embedding provider (no API key required).

Factory Method

impl OnnxProvider {
pub async fn new(
cache: &ModelCache,
model_name: Option<String>, // Default: "0dinai/0din-jailbreak-embeddings-small"
name: Option<String>, // Default: "onnx"
) -> Result<Self>
}

Example:

use odin_prompt_toolkit::providers::{ModelCache, OnnxProvider};

let cache = ModelCache::new()?;
let provider = OnnxProvider::new(&cache, None, None, 0, 0).await?;

// Provider auto-downloads model to cache directory

Configuration

Model: 0dinai/0din-jailbreak-embeddings-small (custom fine-tuned variant for prompt similarity)

Dimensions: 384

Cost: Free (local CPU inference)

Latency: ~50-100ms on M1 Mac (CPU), ~10-20ms on GPU

Model Download: First run auto-downloads ~150MB model to cache directory

Feature Requirement:

[dependencies]
odin-prompt-toolkit = { version = "0.1", features = ["onnx"] }

ModelCache

Model cache manager for ONNX provider.

Constructor

impl ModelCache {
pub fn new() -> Result<Self>
pub fn with_dir(cache_dir: PathBuf) -> Result<Self>
pub fn cache_dir(&self) -> &Path
}

Example:

use odin_prompt_toolkit::providers::ModelCache;

// Use default cache directory
let cache = ModelCache::new()?;

// Or specify custom directory
let cache = ModelCache::with_dir("/path/to/cache".into())?;

Cache Directory

Default Location:

  • Linux/macOS: ~/.cache/odin-prompt-toolkit/models/
  • Windows: %LOCALAPPDATA%\odin-prompt-toolkit\models\

Override via Environment Variable:

export ODIN_PROMPT_TOOLKIT_MODEL_CACHE=/path/to/cache

Directory Structure:

~/.cache/odin-prompt-toolkit/models/
├── v1/
│ ├── onnx/
│ │ └── model_O4.onnx # ONNX model optimized (~235MB)
│ ├── config.json # Model metadata
│ ├── tokenizer.json # Tokenizer config
│ └── special_tokens_map.json
└── .locks/ # Download lock files

Storage Requirements: ~250MB per model version (optimized model)

Thread Safety: ModelCache handles concurrent access via file locks


Custom Providers

You can implement custom providers for any embedding source:

use async_trait::async_trait;
use odin_prompt_toolkit::{EmbeddingProvider, EmbeddingResult, SigError};

pub struct CustomProvider {
// Your provider fields
}

#[async_trait]
impl EmbeddingProvider for CustomProvider {
fn name(&self) -> &str {
"my-custom-provider"
}

fn model(&self) -> &str {
"my-model-v1"
}

fn dimensions(&self) -> usize {
384 // Your embedding size
}

async fn generate_embedding(&self, text: &str) -> Result<EmbeddingResult, SigError> {
// 1. Generate raw embedding
let embedding = your_embedding_function(text)?;

// 2. Normalize
let normalized = normalize_vector(&embedding);

// 3. Compute SHA256
let sha256 = compute_embedding_sha256(&normalized);

Ok(EmbeddingResult {
embedding,
normalized_embedding: normalized,
normalized_embedding_sha256: sha256,
model: self.model().to_string(),
dimensions: self.dimensions(),
token_count: None,
timing_ms: None,
})
}

async fn close(&self) -> Result<(), SigError> {
// Cleanup logic
Ok(())
}
}

Requirements for Custom Providers:

  1. Return normalized embeddings (L2 norm = 1)
  2. Compute SHA256 hash in canonical JSON format
  3. Implement close() for resource cleanup
  4. Handle errors gracefully (network, model loading, etc.)

See Also