vennaVenna

Embeddings and vectorization

Turn text into vectors with POST /v1/embeddings for semantic search, RAG retrieval, and clustering.

POST /v1/embeddings turns text into a fixed-length vector — the building block for semantic search, RAG retrieval, clustering, and dedup. It's OpenAI-compatible and single-shot: send model and input, get a data array of vectors back in the same response.

Two models, priced per input token

bge-m3 and qwen3-embedding-4b both serve /v1/embeddings. There's no generated text, so billing is prompt tokens onlyusage.prompt_tokens equals usage.total_tokens on every response.

Embed a single string

Pass input as a plain string for one vector back:

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://gateway.venna.net/v1",
  apiKey: process.env.VENNA_API_KEY,
});

const embedding = await client.embeddings.create({
  model: "bge-m3",
  input: "Venna routes inference across a decentralized node fleet.",
});

console.log(embedding.data[0].embedding.length);
console.log(embedding.usage.total_tokens);
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://gateway.venna.net/v1",
    api_key=os.environ["VENNA_API_KEY"],
)

embedding = client.embeddings.create(
    model="bge-m3",
    input="Venna routes inference across a decentralized node fleet.",
)

print(len(embedding.data[0].embedding))
print(embedding.usage.total_tokens)
curl https://gateway.venna.net/v1/embeddings \
  -H "Authorization: Bearer $VENNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bge-m3",
    "input": "Venna routes inference across a decentralized node fleet."
  }'

Batch an array of strings

input also accepts an array — one request embeds a whole batch instead of one round trip per string. Chunk a document, embed every chunk together, and let the response order tell you which vector belongs to which chunk:

const batch = await client.embeddings.create({
  model: "bge-m3",
  input: [
    "Venna routes inference across a decentralized node fleet.",
    "Nodes stake collateral and get paid per token served.",
    "The gateway is OpenAI-compatible at the API layer.",
  ],
});

console.log(batch.data.length); // 3

Read the response

data[i].embedding lines up with input[i] by data[i].index — don't assume array order alone if you reorder or filter results downstream. usage.prompt_tokens is what you're billed for:

for (const item of batch.data) {
  console.log(item.index, item.embedding.slice(0, 4)); // first 4 dims
}

console.log(batch.model); // "bge-m3"
console.log(batch.usage.prompt_tokens, batch.usage.total_tokens);

Swap model to qwen3-embedding-4b for the alternate embedding model — same request and response shape, different vector space. Don't mix vectors from the two models in one index; similarity scores aren't comparable across models.

Semantic search and RAG retrieval

The typical pipeline: embed your corpus once (docs, chunks, product rows) and store the vectors in a vector index or a Postgres column with pgvector. At query time, embed the user's question with the same model, then rank stored vectors by cosine similarity to find the closest matches. Feed the top-k chunks into a chat completion as context — that's retrieval-augmented generation. Re-embed only what changed; embeddings are deterministic per model, so unchanged text never needs a new call.

Next steps

On this page