Upstage
Upstage provides Solar Embedding models as a pair: a passage model for the documents you store and a query model for the searches you run. Both map text into the same vector space. The Upstage API is compatible with the OpenAI API, so your application calls it with the OpenAI SDK and sends the vectors to Qdrant.
Models
| Model | Dimensions | Max Tokens per Input | Role |
|---|---|---|---|
solar-embedding-2-passage | 1024 | 8,000 | Documents |
solar-embedding-2-query | 1024 | 8,000 | Queries |
solar-embedding-1-large-passage and solar-embedding-1-large-query are the previous generation, with 4096-dimensional vectors and a 4,000-token limit. Upstage deprecates them on December 31, 2026, after which requests that name them return an error. The embedding-passage and embedding-query aliases still point to them. Use the solar-embedding-2 names for new projects. Moving from Solar Embedding 1 means re-embedding your data into a new 1024-dimensional collection.
Upstage embeddings are normalized to length 1, so the Cosine and Dot distance metrics rank results identically. This page uses Cosine.
Setup
Install the OpenAI SDK and the Qdrant client:
- Python:
pip install openai qdrant-client - TypeScript:
npm install openai @qdrant/js-client-rest
Create an OpenAI client pointed at the Upstage API, the Qdrant client, and a collection sized for the model. These examples read your API key, which you can create in the Upstage Console, from the UPSTAGE_API_KEY environment variable.
import os
from openai import OpenAI
from qdrant_client import QdrantClient, models
upstage_client = OpenAI(
api_key=os.environ["UPSTAGE_API_KEY"],
base_url="https://api.upstage.ai/v1",
)
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
collection_name="{collection_name}",
vectors_config=models.VectorParams(size=1024, distance=models.Distance.COSINE),
)
import OpenAI from "openai";
import { QdrantClient } from "@qdrant/js-client-rest";
const upstage = new OpenAI({
apiKey: process.env.UPSTAGE_API_KEY,
baseURL: "https://api.upstage.ai/v1",
});
const client = new QdrantClient({ url: "http://localhost:6333" });
await client.createCollection("{collection_name}", {
vectors: { size: 1024, distance: "Cosine" },
});
Embed Documents
Embed documents with the passage model. One request embeds a list of inputs, and each item in the response carries the index of its input, which this example uses as the point ID:
documents = [
"Qdrant is a vector search engine.",
"Upstage Solar Embedding models turn text into dense vectors.",
]
response = upstage_client.embeddings.create(
model="solar-embedding-2-passage",
input=documents,
)
client.upsert(
collection_name="{collection_name}",
points=[
models.PointStruct(
id=item.index,
vector=item.embedding,
payload={"text": documents[item.index]},
)
for item in response.data
],
)
const documents = [
"Qdrant is a vector search engine.",
"Upstage Solar Embedding models turn text into dense vectors.",
];
const response = await upstage.embeddings.create({
model: "solar-embedding-2-passage",
input: documents,
});
await client.upsert("{collection_name}", {
points: response.data.map((item) => ({
id: item.index,
vector: item.embedding,
payload: { text: documents[item.index] },
})),
});
A request accepts up to 100 inputs and 204,800 tokens in total. Upstage lists a rate limit of 100 requests and 300,000 tokens per minute for these models, so split larger datasets into several requests, and see Upload Points for batching on the Qdrant side.
Embed Queries
Embed queries with the query model. The query model is tuned for short questions and search terms, and the passage model for the longer texts that answer them. Both write to the same vector space, so a query vector can be compared directly with the passage vectors in the collection:
query_vector = (
upstage_client.embeddings.create(model="solar-embedding-2-query", input="What is Qdrant?")
.data[0]
.embedding
)
hits = client.query_points(
collection_name="{collection_name}",
query=query_vector,
limit=3,
).points
const queryResponse = await upstage.embeddings.create({
model: "solar-embedding-2-query",
input: "What is Qdrant?",
});
const { points: hits } = await client.query("{collection_name}", {
query: queryResponse.data[0].embedding,
limit: 3,
});
Store and Search the Vectors
Next Steps
- Use Binary Quantization to store vectors in less memory.
- Upstage embeddings documentation.
- Filter search results by payload fields.
- Combine Upstage vectors with sparse vectors for hybrid search.