Qdrant Cloud 추론
Qdrant Cloud 추론 (inference-cloud-inference)
Qdrant Cloud에서 직접 임베딩 생성을 처리하고 싶을 때가 있어요. Qdrant Managed Cloud의 클러스터는 Qdrant Cloud Inference를 사용해 임베딩을 생성할 수 있는데, 이 페이지에서 그 사용법을 살펴볼게요.
출처: Qdrant 공식문서

사용 가능한 모델 목록과 각 모델의 차원은 Qdrant Cloud Console의 클러스터 상세(Cluster Detail) 페이지에 있는 Inference 탭에서 확인할 수 있어요. 이 탭에서 클러스터에 Cloud Inference를 활성화할 수도 있어요.
여러 임베딩 모델은 Qdrant Cloud Inference에서 무료로 쓸 수 있는데, 무료 티어(free-tier) 클러스터에서도 마찬가지예요. Inference 탭의 "Cost: Free" 라벨이 이런 모델을 구분해 줘요.
대부분의 검색 쿼리같은 짧은 페이로드의 추론은 Qdrant Cloud 클러스터와 같은 네트워크에서 처리되어 검색 입력의 지연 시간을 줄여줘요. Qdrant가 호스팅하는 모델에 적용되며 완전히 투명하게 동작해요. 더 긴 검색 입력과 업서트는 전용 원격 추론 서비스가 처리해요.
클라우드 호스팅 임베딩 모델을 쓰기 전에, 컬렉션이 올바른 차원의 벡터로 설정되어 있는지 확인해야 해요. Qdrant Cloud Console의 클러스터 상세 페이지에 있는 Inference 탭은 각 지원 임베딩 모델의 차원을 나열해 줘요.
텍스트 추론 (Text Inference)
dense 벡터를 만드는 텍스트 모델로 Cloud Inference를 사용하는 예를 생각해 볼게요. 이 예시는 포인트 하나를 만들고 Document 추론 객체를 사용한 단순한 검색 쿼리를 실행해요.
# Insert new points with cloud-side inference
PUT /collections/<your-collection>/points?wait=true
{
"points": [
{
"id": 1,
"payload": { "topic": "cooking", "type": "dessert" },
"vector": {
"text": "Recipe for baking chocolate chip cookies",
"model": "<the-model-to-use>"
}
}
]
}
# Search in the collection using cloud-side inference
POST /collections/<your-collection>/points/query
{
"query": {
"text": "How to bake cookies?",
"model": "<the-model-to-use>"
}
}
# Create a new vector
curl -X PUT "https://xyz-example.qdrant.io:6333/collections/<your-collection>/points?wait=true" \
-H "Content-Type: application/json" \
-H "api-key: <paste-your-api-key-here>" \
-d '{
"points": [
{
"id": 1,
"payload": { "topic": "cooking", "type": "dessert" },
"vector": {
"text": "Recipe for baking chocolate chip cookies",
"model": "<the-model-to-use>"
}
}
]
}'
# Perform a search query
curl -X POST "https://xyz-example.qdrant.io:6333/collections/<your-collection>/points/query" \
-H "Content-Type: application/json" \
-H "api-key: <paste-your-api-key-here>" \
-d '{
"query": {
"text": "How to bake cookies?",
"model": "<the-model-to-use>"
}
}'
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, Document
client = QdrantClient(
url="https://xyz-example.qdrant.io:6333",
api_key="<paste-your-api-key-here>",
# IMPORTANT
# If not enabled, inference will be performed locally
cloud_inference=True,
)
points = [
PointStruct(
id=1,
payload={"topic": "cooking", "type": "dessert"},
vector=Document(
text="Recipe for baking chocolate chip cookies",
model="<the-model-to-use>"
)
)
]
client.upsert(collection_name="<your-collection>", points=points)
result = client.query_points(
collection_name="<your-collection>",
query=Document(
text="How to bake cookies?",
model="<the-model-to-use>"
)
)
print(result)
import {QdrantClient} from "@qdrant/js-client-rest";
const points = [
{
id: 1,
payload: { topic: "cooking", type: "dessert" },
vector: {
text: "Recipe for baking chocolate chip cookies",
model: "<the-model-to-use>"
}
}
];
await client.upsert("<your-collection>", { wait: true, points });
const result = await client.query(
"<your-collection>",
{
query: {
text: "How to bake cookies?",
model: "<the-model-to-use>"
},
}
)
console.log(result);
use qdrant_client::{
Payload, Qdrant,
qdrant::{Document, PointStruct, Query, QueryPointsBuilder, UpsertPointsBuilder},
};
let points = vec![PointStruct::new(
1,
Document {
text: "Recipe for baking chocolate chip cookies".into(),
model: "<the-model-to-use>".into(),
..Default::default()
},
Payload::try_from(serde_json::json!(
{"topic": "cooking", "type": "dessert"}
))?,
)];
client
.upsert_points(UpsertPointsBuilder::new("<your-collection>", points).wait(true))
.await?;
let query_document = Document {
text: "How to bake cookies?".into(),
model: "<the-model-to-use>".into(),
..Default::default()
};
let result = client
.query(
QueryPointsBuilder::new("<your-collection>")
.query(Query::new_nearest(query_document))
.build(),
)
.await?;
println!("Result: {:?}", result);
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.QueryFactory.nearest;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Points;
import io.qdrant.client.grpc.Points.Document;
import io.qdrant.client.grpc.Points.PointStruct;
import java.util.List;
import java.util.Map;
client
.upsertAsync(
"<your-collection>",
List.of(
PointStruct.newBuilder()
.setId(id(1))
.setVectors(
vectors(
Document.newBuilder()
.setText("Recipe for baking chocolate chip cookies")
.setModel("<the-model-to-use>")
.build()))
.putAllPayload(Map.of("topic", value("cooking"), "type", value("dessert")))
.build()))
.get();
List<Points.ScoredPoint> points =
client
.queryAsync(
Points.QueryPoints.newBuilder()
.setCollectionName("<your-collection>")
.setQuery(
nearest(
Document.newBuilder()
.setText("How to bake cookies?")
.setModel("<the-model-to-use>")
.build()))
.build())
.get();
System.out.printf(points.toString());
using Qdrant.Client;
using Qdrant.Client.Grpc;
using Value = Qdrant.Client.Grpc.Value;
var client = new QdrantClient(
host: "xyz-example.qdrant.io",
port: 6334,
https: true,
apiKey: "<paste-your-api-key-here>"
);
await client.UpsertAsync(
collectionName: "<your-collection>",
points: new List <PointStruct> {
new() {
Id = 1,
Vectors = new Document() {
Text = "Recipe for baking chocolate chip cookies",
Model = "<the-model-to-use>",
},
Payload = {
["topic"] = "cooking",
["type"] = "dessert"
},
},
}
);
var points = await client.QueryAsync(
collectionName: "<your-collection>",
query: new Document() {
Text = "How to bake cookies?",
Model = "<the-model-to-use>"
}
);
foreach(var point in points) {
Console.WriteLine(point);
}
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client.Upsert(context.Background(), &qdrant.UpsertPoints{
CollectionName: "<your-collection>",
Points: []*qdrant.PointStruct{
{
Id: qdrant.NewIDNum(1),
Vectors: qdrant.NewVectorsDocument(&qdrant.Document{
Text: "Recipe for baking chocolate chip cookies",
Model: "<the-model-to-use>",
}),
Payload: qdrant.NewValueMap(map[string]any{
"topic": "cooking",
"type": "dessert",
}),
},
},
})
client.Query(context.Background(), &qdrant.QueryPoints{
CollectionName: "<your-collection>",
Query: qdrant.NewQueryNearest(
qdrant.NewVectorInputDocument(&qdrant.Document{
Text: "How to bake cookies?",
Model: "<the-model-to-use>",
}),
),
})
각 클러스터와 모델에 특화된 사용 예시는 Qdrant Cloud Console의 클러스터 상세 페이지에 있는 Inference 탭에서도 찾을 수 있어요.
참고로 각 모델에는 컨텍스트 윈도우(context window)가 있는데, 이는 단일 요청에서 모델이 처리할 수 있는 최대 토큰 수예요. 입력 텍스트가 컨텍스트 윈도우를 초과하면 제한에 맞게 잘려요. 컨텍스트 윈도우 크기는 클러스터 상세 페이지의 Inference 탭에 표시돼요.
dense 벡터 모델의 경우 컬렉션에 설정된 벡터 크기가 모델의 출력 크기와 일치하는지도 확인해야 해요. 벡터 크기가 맞지 않으면 업서트가 오류와 함께 실패해요.
이미지 추론 (Image Inference)
이미지 모델로 Cloud Inference를 사용하는 또 다른 예시를 살펴볼게요. 이 예시는 CLIP 모델을 사용해 이미지를 인코딩한 뒤, 텍스트 쿼리로 검색해요.
CLIP 모델은 멀티모달이므로 같은 벡터 필드에 이미지와 텍스트 입력을 모두 사용할 수 있어요.
# Insert new points with cloud-side inference
PUT /collections/<your-collection>/points?wait=true
{
"points": [
{
"id": 1,
"vector": {
"image": "https://qdrant.tech/example.png",
"model": "qdrant/clip-vit-b-32-vision"
},
"payload": {
"title": "Example Image"
}
}
]
}
# Search in the collection using cloud-side inference
POST /collections/<your-collection>/points/query
{
"query": {
"text": "Mission to Mars",
"model": "qdrant/clip-vit-b-32-text"
}
}
# Create a new vector
curl -X PUT "https://xyz-example.qdrant.io:6333/collections/<your-collection>/points?wait=true" \
-H "Content-Type: application/json" \
-H "api-key: <paste-your-api-key-here>" \
-d '{
"points": [
{
"id": 1,
"vector": {
"image": "https://qdrant.tech/example.png",
"model": "qdrant/clip-vit-b-32-vision"
},
"payload": {
"title": "Example Image"
}
}
]
}'
# Perform a search query
curl -X POST "https://xyz-example.qdrant.io:6333/collections/<your-collection>/points/query" \
-H "Content-Type: application/json" \
-H "api-key: <paste-your-api-key-here>" \
-d '{
"query": {
"text": "Mission to Mars",
"model": "qdrant/clip-vit-b-32-text"
}
}'
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, Image, Document
client = QdrantClient(
url="https://xyz-example.qdrant.io:6333",
api_key="<paste-your-api-key-here>",
# IMPORTANT
# If not enabled, inference will be performed locally
cloud_inference=True,
)
points = [
PointStruct(
id=1,
vector=Image(
image="https://qdrant.tech/example.png",
model="qdrant/clip-vit-b-32-vision"
),
payload={
"title": "Example Image"
}
)
]
client.upsert(collection_name="<your-collection>", points=points)
result = client.query_points(
collection_name="<your-collection>",
query=Document(
text="Mission to Mars",
model="qdrant/clip-vit-b-32-text"
)
)
print(result)
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client.Upsert(context.Background(), &qdrant.UpsertPoints{
CollectionName: "<your-collection>",
Points: []*qdrant.PointStruct{
{
Id: qdrant.NewIDNum(1),
Vectors: qdrant.NewVectorsImage(&qdrant.Image{
Model: "qdrant/clip-vit-b-32-vision",
Image: qdrant.NewValueString("https://qdrant.tech/example.png"),
}),
Payload: qdrant.NewValueMap(map[string]any{
"title": "Example image",
}),
},
},
})
client.Query(context.Background(), &qdrant.QueryPoints{
CollectionName: "<your-collection>",
Query: qdrant.NewQueryNearest(
qdrant.NewVectorInputDocument(&qdrant.Document{
Text: "Mission to Mars",
Model: "qdrant/clip-vit-b-32-text",
}),
),
})
Qdrant Cloud Inference 서버는 제공된 URL로 이미지를 다운로드해요. 또는 이미지를 base64로 인코딩한 문자열로 제공할 수도 있어요. 각 모델마다 처리할 수 있는 파일 크기와 확장자에 제한이 있어요. 자세한 내용은 모델 카드를 참고하세요.
자동 쿼리 및 패시지 프리픽스 (Automatic Query and Passage Prefixes)
일부 임베딩 모델은 쿼리 입력과 패시지(passage)/문서 입력에 서로 다른 텍스트 프리픽스를 기대하도록 학습되어 있어요. 잘못된 프리픽스를 쓰거나 생략하면 검색 품질이 떨어질 수 있어요.
Qdrant Cloud Inference는 요청이 검색 쿼리인지 업서트인지에 따라, 사용 중인 모델에 맞는 올바른 프리픽스를 자동으로 적용해요. 예를 들어 E5 계열 모델로 문서를 업서트하면 프록시가 각 입력 텍스트 앞에 passage:를 붙이고, 같은 모델로 쿼리하면 query:를 대신 붙여요. 이런 프리픽스를 직접 추가할 필요는 없어요.
입력 텍스트가 이미 올바른 프리픽스로 시작한다면 그대로 두므로, 프리픽스가 중복되는 일은 없어요.
이 동작은 지원되는 Qdrant 호스팅 모델에 적용돼요. openai/, cohere/, jinaai/ 같은 외부 제공자(external providers)를 통해 접근하는 모델은 해당 제공자가 처리해요.
로컬 추론 호환성 (Local Inference Compatibility)
Python SDK에는 특별한 기능이 하나 있는데, 동일한 인터페이스로 로컬 추론과 클라우드 추론을 모두 지원한다는 점이에요.
QdrantClient 초기화 시 cloud_inference 플래그를 설정하면 로컬과 클라우드 추론 사이를 쉽게 전환할 수 있어요. 예를 들어:
client = QdrantClient(
url="https://your-cluster.qdrant.io",
api_key="<your-api-key>",
cloud_inference=True, # Set to False to use local inference
)
이 유연성 덕분에 클라우드 추론 리소스에 접근하지 않고도 로컬이나 CI(continuous integration) 환경에서 애플리케이션을 개발하고 테스트할 수 있어요.
cloud_inference가False면fastembed를 사용해 로컬에서 추론을 수행해요.True로 설정하면 추론 요청을 Qdrant Cloud가 처리해요.