Amazon Bedrock
Amazon Bedrock serves embedding models from Amazon, Cohere, and TwelveLabs through the AWS SDKs, inside your AWS account. Call Bedrock from your application and send the vectors to Qdrant.
Models
| Model | Model ID | Dimensions | Max Input | Input |
|---|---|---|---|---|
| Amazon Titan Text Embeddings V2 | amazon.titan-embed-text-v2:0 | 1024 (default), 512, 256 | 8,192 tokens | Text |
| Amazon Nova Multimodal Embeddings | amazon.nova-2-multimodal-embeddings-v1:0 | 3072 (default), 1024, 384, 256 | 8K tokens, or 30 seconds of video or audio per request | Text, document image, image, video, audio |
| Cohere Embed v4 | cohere.embed-v4:0 | 1536 (default), 1024, 512, 256 | 128K tokens | Text, image |
| TwelveLabs Marengo Embed 3.0 | twelvelabs.marengo-embed-3-0-v1:0 | 512 | 500 tokens of text | Text, image, video, audio |
Each model has its own request and response format, documented on its model card. This page uses Titan Text Embeddings V2 for text and Nova Multimodal Embeddings for images. Titan Text Embeddings V2 succeeds Titan Embeddings G1 - Text (amazon.titan-embed-text-v1). Titan Multimodal Embeddings G1 (amazon.titan-embed-image-v1) and Cohere Embed English and Multilingual v3 (cohere.embed-english-v3, cohere.embed-multilingual-v3) are also previous generations. Use Nova Multimodal Embeddings or Cohere Embed v4 in their place.
Titan Text Embeddings V2 returns normalized vectors by default (normalize: true), so the Cosine and Dot distance metrics rank results identically. This page uses Cosine.
Setup
Install the AWS SDK and the Qdrant client:
- Python:
pip install boto3 qdrant-client - TypeScript:
npm install @aws-sdk/client-bedrock-runtime @qdrant/js-client-rest
The AWS SDKs read credentials from the default credential chain, such as the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, the shared credentials file, AWS IAM Identity Center, or an IAM role when the code runs on AWS. They also accept an Amazon Bedrock API key in the AWS_BEARER_TOKEN_BEDROCK environment variable. The identity needs the bedrock:InvokeModel permission. For details, see Credentials for Python and Setting Credentials in Node.js for JavaScript.
The examples use us-east-1, where both models on this page are available. Create both clients, a helper that embeds one text, and a collection sized for the model:
import json
import boto3
from qdrant_client import QdrantClient, models
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
client = QdrantClient(url="http://localhost:6333")
MODEL_ID = "amazon.titan-embed-text-v2:0"
def embed(text: str) -> list[float]:
response = bedrock.invoke_model(
modelId=MODEL_ID,
contentType="application/json",
body=json.dumps({"inputText": text, "dimensions": 1024, "normalize": True}),
)
return json.loads(response["body"].read())["embedding"]
client.create_collection(
collection_name="{collection_name}",
vectors_config=models.VectorParams(size=1024, distance=models.Distance.COSINE),
)
import {
BedrockRuntimeClient,
InvokeModelCommand,
} from "@aws-sdk/client-bedrock-runtime";
import { QdrantClient } from "@qdrant/js-client-rest";
const bedrock = new BedrockRuntimeClient({ region: "us-east-1" });
const client = new QdrantClient({ url: "http://localhost:6333" });
const MODEL_ID = "amazon.titan-embed-text-v2:0";
async function embed(text: string): Promise<number[]> {
const response = await bedrock.send(
new InvokeModelCommand({
modelId: MODEL_ID,
contentType: "application/json",
body: JSON.stringify({ inputText: text, dimensions: 1024, normalize: true }),
})
);
return JSON.parse(new TextDecoder().decode(response.body)).embedding;
}
await client.createCollection("{collection_name}", {
vectors: { size: 1024, distance: "Cosine" },
});
Embed Documents
Titan Text Embeddings V2 embeds one text per request, so this example calls the helper for each document and uses the input order as the point ID:
documents = [
"Qdrant is a vector search engine.",
"Amazon Bedrock serves embedding models through the AWS SDKs.",
]
client.upsert(
collection_name="{collection_name}",
points=[
models.PointStruct(id=idx, vector=embed(doc), payload={"text": doc})
for idx, doc in enumerate(documents)
],
)
const documents = [
"Qdrant is a vector search engine.",
"Amazon Bedrock serves embedding models through the AWS SDKs.",
];
await client.upsert("{collection_name}", {
points: await Promise.all(
documents.map(async (doc, idx) => ({
id: idx,
vector: await embed(doc),
payload: { text: doc },
}))
),
});
Each text can be up to 8,192 tokens or 50,000 characters. For large datasets, batch inference processes many records as one job.
Embed Queries
Titan Text Embeddings V2 has no separate query mode. Embed the query with the same model and dimensions as the documents:
hits = client.query_points(
collection_name="{collection_name}",
query=embed("What is Qdrant?"),
limit=3,
).points
const { points: hits } = await client.query("{collection_name}", {
query: await embed("What is Qdrant?"),
limit: 3,
});
Embed Images
Nova Multimodal Embeddings maps text, images, documents, video, and audio into one vector space, so a text query can find an image. Its vectors don’t share a space with Titan’s, so store them in a separate collection.
Set embeddingPurpose to GENERIC_INDEX when you index content of any type. For queries, pick the purpose that matches the indexed content, such as IMAGE_RETRIEVAL for images or GENERIC_RETRIEVAL for a mix of types. This example uses 1024 dimensions:
import base64
NOVA_ID = "amazon.nova-2-multimodal-embeddings-v1:0"
def nova_embed(purpose: str, content: dict[str, object]) -> list[float]:
body = {
"taskType": "SINGLE_EMBEDDING",
"singleEmbeddingParams": {
"embeddingPurpose": purpose,
"embeddingDimension": 1024,
**content,
},
}
response = bedrock.invoke_model(
modelId=NOVA_ID, contentType="application/json", body=json.dumps(body)
)
return json.loads(response["body"].read())["embeddings"][0]["embedding"]
client.create_collection(
collection_name="{image_collection_name}",
vectors_config=models.VectorParams(size=1024, distance=models.Distance.COSINE),
)
with open("photo.jpg", "rb") as f:
image = {"format": "jpeg", "source": {"bytes": base64.b64encode(f.read()).decode()}}
client.upsert(
collection_name="{image_collection_name}",
points=[
models.PointStruct(
id=1,
vector=nova_embed("GENERIC_INDEX", {"image": image}),
payload={"file": "photo.jpg"},
)
],
)
image_hits = client.query_points(
collection_name="{image_collection_name}",
query=nova_embed(
"IMAGE_RETRIEVAL",
{"text": {"truncationMode": "END", "value": "A dog on a beach"}},
),
limit=3,
).points
import { readFile } from "node:fs/promises";
const NOVA_ID = "amazon.nova-2-multimodal-embeddings-v1:0";
async function novaEmbed(purpose: string, content: object): Promise<number[]> {
const response = await bedrock.send(
new InvokeModelCommand({
modelId: NOVA_ID,
contentType: "application/json",
body: JSON.stringify({
taskType: "SINGLE_EMBEDDING",
singleEmbeddingParams: {
embeddingPurpose: purpose,
embeddingDimension: 1024,
...content,
},
}),
})
);
return JSON.parse(new TextDecoder().decode(response.body)).embeddings[0].embedding;
}
await client.createCollection("{image_collection_name}", {
vectors: { size: 1024, distance: "Cosine" },
});
const image = {
format: "jpeg",
source: { bytes: (await readFile("photo.jpg")).toString("base64") },
};
await client.upsert("{image_collection_name}", {
points: [
{
id: 1,
vector: await novaEmbed("GENERIC_INDEX", { image }),
payload: { file: "photo.jpg" },
},
],
});
const { points: imageHits } = await client.query("{image_collection_name}", {
query: await novaEmbed("IMAGE_RETRIEVAL", {
text: { truncationMode: "END", value: "A dog on a beach" },
}),
limit: 3,
});
An inline request can be up to 25 MB after base64 encoding. Larger files, and video or audio longer than 30 seconds, go through the asynchronous StartAsyncInvoke API with input and output in Amazon S3. See Using Amazon Nova Embeddings and the request and response schema.
Store and Search the Vectors
Next Steps
- Use named vectors to keep Titan and Nova vectors on the same points.
- Filter search results by payload fields.
- Combine Bedrock vectors with sparse vectors for hybrid search.
- Reduce memory use with quantization.