Skip to main content

Embeddings

Generate numeric vector representations of text using the server's configured embedding model.

Overview​

One call accepts one or more strings and returns floating-point vectors for similarity scoring, clustering, classification, or a custom search index.

The model is configured server-side (EMBEDDING_PROVIDER, EMBEDDING_MODEL; backends ollama, openai, bedrock). Callers do not choose it, so all vectors in a deployment share one space.

See the Permissions Reference for the IAM action strings for this module.

Configuration​

Environment VariableRequiredDescription
EMBEDDING_PROVIDERYesEmbedding backend: ollama, openai, or bedrock.
EMBEDDING_MODELYesModel identifier for the backend (e.g. qwen3-embedding:0.6b, text-embedding-3-small, amazon.titan-embed-text-v2:0).
EMBEDDING_DIMENSIONSYesVector dimensionality. Must match the model output, e.g. 1024 — the server fails at startup when unset, or above 2000, the widest vector pgvector can index.
OLLAMA_BASE_URLNoOllama server URL (ollama only). Defaults to http://localhost:11434.
EMBEDDING_API_KEYNoAPI key for the backend: the OpenAI key (openai), or a Bedrock ABSK… bearer token (bedrock). For openai, falls back to OPENAI_API_KEY.
EMBEDDING_BASE_URLNoOverride the base URL for any OpenAI-compatible endpoint (openai only).
EMBEDDING_REGIONNoAWS region for Bedrock (bedrock only). Falls back to AWS_REGION, then us-east-1.
EMBEDDING_INPUT_1M_TOKEN_PRICE_USDNoUSD per million input tokens, the unit vendors publish ($0.02 / 1M → 0.02). Unset meters embeddings at 0. See Pricing embeddings.

Provider selection​

  • ollama — local models via the Ollama client at OLLAMA_BASE_URL. No credentials required.
  • openai — the OpenAI embeddings API (or any OpenAI-compatible endpoint via EMBEDDING_BASE_URL), authenticated with EMBEDDING_API_KEY.
  • bedrock — Amazon Bedrock embedding models. Authenticate with an ABSK… bearer token in EMBEDDING_API_KEY, or leave it unset to use the standard AWS credential chain (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY).

Batch size​

inputs accepts at most 256 values per request (each a model call); larger batches are refused with VALIDATION_FAILED (400).

Data Model​

Stateless; nothing is stored. The response shape depends on the inputs:

FieldTypeDescription
embeddingnumber[]Returned when input (single string) is provided.
embeddingsnumber[][]Returned when inputs (array of strings) is provided.

Both fields can be present if the request includes both input and inputs.

Optional project_id names the project billed; see Metering.

Key Concepts​

Single vs batch​

input (string) for one vector, inputs (array) for many; both may be combined.

Shared vector space​

All embeddings from one deployment share a vector space, so cosine similarity between them is meaningful; vectors from other deployments or models are not comparable.

Metering​

Every embedding call is metered as an llm_tokens usage event with source embedding, whatever the origin: this endpoint, ingestion, a memory write, an embedding_similarity scorer, or a knowledge-search query. Spend appears in GET /api/v1/usage/events and counts towards cost_usd and tokens quotas.

A usage event belongs to a project, so an embedding call needs one:

CallBilled to
POST /api/v1/embeddings with project_idthat project — the caller must be able to write to it
The same call from a project-scoped credentialthe credential's project
The same call with neithernothing — the call is served but not metered
Ingestion, memory, evaluationthe document's, memory's or run's project
A knowledge searchthe project searched, when the search is scoped to exactly one

The query an agent's knowledge_config embeds before its turn is also attributed to that generation: the event carries the generation's generation_id, agent_id, trace_id, session_id and actor_id, so the spend reads per generation and counts towards agent and actor quotas. If the generation's record is never written, the event is billed to the project only.

An embedding of stored text also names what it embedded: document_id on a document chunk (ingestion, a re-chunk, a conversation's turns), memory_store_id on written memory content. The store, not the memory: a store keeps one copy of each text, shared by every memory that states it. A memory an agent or a rule writes during a turn carries that generation's attribution too. A query embedding names neither.

Pricing embeddings​

The rate is deployment configuration, not a price book row. EMBEDDING_INPUT_1M_TOKEN_PRICE_USD prices every embedding; cost_usd = tokens × rate / 1,000,000 at write time. input_tokens is the only dimension; there is no output rate.

Per million tokens, as vendors publish, so the figure is copied as written:

EMBEDDING_PROVIDER=openai
EMBEDDING_MODEL=text-embedding-3-small
EMBEDDING_INPUT_1M_TOKEN_PRICE_USD=0.02

Unset means zero. With no rate, every embedding is metered at cost_usd 0 (not null), so a cost_usd quota window always evaluates. Right for a local model; on a vendor-billed provider it reports spend as free, so the server warns at startup naming the variable. Cost is frozen per event; a rate set later prices the next embedding.

The price book does not reach embeddings. A row naming the embedding model is ignored:

TierScopeApplies to embeddings?
Provider instanceOne ai_provider_idNo — an embedding event carries no provider record
Project + slugOne project's rate for a provider slugNo
Global defaultEvery projectNo

The embedding stack is per deployment, not an AI provider record, so there is no instance or per-project rate to price; the operator who picks EMBEDDING_MODEL sets its price beside it.

An embedding is never named in a QUOTA_UNENFORCEABLE refusal's unpriced_rows and never counts towards one.

503 when unconfigured​

Without EMBEDDING_PROVIDER or EMBEDDING_MODEL, the server returns 503 EMBEDDING_NOT_CONFIGURED (a configuration error).

Examples​

Single text​

soat create-embeddings --project-id "proj_V1StGXR8Z5jdHi6B" \
--input "The quick brown fox jumps over the lazy dog."

Batch of texts​

soat create-embeddings --inputs '["First sentence.", "Second sentence.", "Third sentence."]'