Gemini API 임베딩

Gemini API 임베딩 (Embeddings)

Gemini API는 텍스트, 이미지, 동영상 등 콘텐츠에 대한 임베딩을 생성해 주는 임베딩 모델을 제공해요. 생성된 임베딩은 의미 검색(semantic search), 분류, 클러스터링 같은 작업에 활용할 수 있고, 키워드 기반 방식보다 더 정확하고 맥락을 아우르는 결과를 만들어 줍니다.

출처: 문서

본문

최신 모델인 gemini-embedding-2는 Gemini API에서 처음으로 선보이는 멀티모달 임베딩 모델이에요. 텍스트, 이미지, 동영상, 오디오, 문서를 하나의 임베딩 공간으로 매핑해서 100개 이상의 언어에 걸쳐 교차 모달 검색·분류·클러스터링을 가능하게 해줍니다. 자세한 내용은 멀티모달 임베딩 섹션에서 다룰게요. 텍스트 전용 용도라면 gemini-embedding-001도 계속 사용할 수 있어요.

RAG(Retrieval Augmented Generation) 시스템을 만드는 것은 AI 제품에서 매우 흔한 사용 사례예요. 임베딩은 사실적 정확도·일관성·맥락 풍부함을 높여 모델 출력을 크게 개선하는 핵심 역할을 해요. 관리형 RAG 솔루션을 선호한다면 File Search 도구가 RAG를 더 쉽고 비용 효율적으로 관리하게 도와줄 거예요.

임베딩 생성하기

embedContent 메서드로 텍스트 임베딩을 생성할 수 있어요.

from google import genai

client = genai.Client()

result = client.models.embed_content(
        model="gemini-embedding-2",
        contents="What is the meaning of life?"
)

print(result.embeddings)
import { GoogleGenAI } from "@google/genai";

async function main() {

    const ai = new GoogleGenAI({});

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: 'What is the meaning of life?',
    });

    console.log(response.embeddings);
}

main();
import com.google.genai.Client;
import com.google.genai.types.EmbedContentResponse;

Client client = new Client();

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", "What is the meaning of life?", null);

System.out.println(response.embeddings().orElse(null));
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "google.golang.org/genai"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    contents := []*genai.Content{
        genai.NewContentFromText("What is the meaning of life?", genai.RoleUser),
    }
    result, err := client.Models.EmbedContent(ctx,
        "gemini-embedding-2",
        contents,
        nil,
    )
    if err != nil {
        log.Fatal(err)
    }

    embeddings, err := json.MarshalIndent(result.Embeddings, "", "  ")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(embeddings))
}
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "model": "models/gemini-embedding-2",
        "content": {
        "parts": [{
            "text": "What is the meaning of life?"
        }]
        }
    }'

참고: gemini-embedding-001이 문자열 목록 각각에 대해 개별 임베딩을 만드는 반면, Gemini Embedding 2는 여러 입력에 대해 하나의 집계 임베딩을 만들어요. 자세한 내용은 Embedding aggregation에서 확인할 수 있고, 한 번에 여러 임베딩을 생성하고 싶다면 Batch API를 사용할 수 있어요.

작업 유형 지정으로 성능 높이기

임베딩은 분류부터 문서 검색까지 매우 다양한 작업에 쓰여요. 올바른 작업 유형(task type)을 지정하면 여러분이 원하는 관계에 맞게 임베딩을 최적화해 정확도와 효율을 극대화할 수 있어요.

Embeddings 2의 작업 유형

gemini-embedding-2로 텍스트 전용 작업을 할 때는 프롬프트에 작업 지시(task instruction)를 포함하길 강력히 권장해요. 쿼리와 문서를 올바른 작업 접두사(prefix)로 형식화하면 됩니다.

멀티모달 입력 하나에서 단일 임베딩을 생성할 때는 입력의 텍스트 부분에 작업 지시 접두사를 붙이는 걸 일반적으로 권장하지 않아요. 어떤 경우에는 성능이 좋아지지만, 어떤 경우에는 오히려 나빠지기 때문이에요.

아래 표는 gemini-embedding-2 모델로 대칭·비대칭 사용 사례에 맞게 쿼리와 문서를 형식화하는 예시예요.

검색 사용 사례 (비대칭 형식, Asymmetric format)

비대칭 사용 사례에서는 쿼리에 작업 접두사를 붙이고, 임베딩·검색하려는 콘텐츠에는 문서 구조를 적용해요.

사용 사례 쿼리 구조 문서 구조
검색 쿼리 (Search query) task: search result | query: {content} title: {title} | text: {content} 제목이 없으면 title: none을 사용하세요.
질의응답 (Question answering) task: question answering | query: {content} title: {title} | text: {content}
사실 확인 (Fact checking) task: fact checking | query: {content} title: {title} | text: {content}
코드 검색 (Code retrieval) task: code retrieval | query: {content} title: {title} | text: {content}

사용 예시

# Generate embedding for a task's query. Use your correct task here:
def prepare_query(query):
    # return f"task: question answering | query: {query}"
    # return f"task: fact checking | query: {query}"
    # return f"task: code retrieval | query: {query}"
    return f"task: search result | query: {query}"

# Generate embedding for document of an asymmetric retrieval task:
def prepare_document(content, title=None):
    if title is None:
        title = "none"
    return f"title: {title} | text: {content}"

단일 입력 사용 사례 (대칭 형식, Symmetric format)

대칭 사용 사례에서는 같은 작업에 대해 쿼리와 문서를 같은 형식으로 사용해요.

사용 사례 입력 구조
분류 (Classification) task: classification | query: {content}
클러스터링 (Clustering) task: clustering | query: {content}
의미 유사도 (Semantic similarity) task: sentence similarity | query: {content} 검색이나 검색-재배열에는 사용하지 마세요. 의미론적 텍스트 유사성을 위한 것입니다.

사용 예시

# Generate embedding for query & document of your task.
def prepare_query_and_document(content):
    # return f'task: clustering | query: {content}'
    # return f'task: sentence similarity | query: {content}'
    return f'task: classification | query: {content}'

작업을 일관되게 사용하는 것이 중요해요. 예를 들어 문서가 f'task: classification | query: {content}'로 임베딩됐다면, 쿼리도 같은 작업 형식에 따라 임베딩해야 해요.

Embeddings 1의 작업 유형

gemini-embedding-001에서는 embedContent 메서드의 task_type을 지정할 수 있어요. 지원되는 작업 유형 전체 목록은 지원 작업 유형 표를 참고하세요.

참고: gemini-embedding-2 모델에서는 task_type 필드를 사용할 수 없어요. 대신 위 섹션에서 설명한 것처럼 작업을 프롬프트의 지시로 포함하세요.

다음 예시는 SEMANTIC_SIMILARITY를 사용해 문자열들이 의미적으로 얼마나 비슷한지 확인하는 방법을 보여줘요.

from google import genai
from google.genai import types
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity

client = genai.Client()

texts = [
    "What is the meaning of life?",
    "What is the purpose of existence?",
    "How do I bake a cake?",
]

result = client.models.embed_content(
    model="gemini-embedding-001",
    contents=texts,
    config=types.EmbedContentConfig(task_type="SEMANTIC_SIMILARITY")
)

# Create a 3x3 table to show the similarity matrix
df = pd.DataFrame(
    cosine_similarity([e.values for e in result.embeddings]),
    index=texts,
    columns=texts,
)

print(df)
import { GoogleGenAI } from "@google/genai";
// npm i compute-cosine-similarity
import * as cosineSimilarity from "compute-cosine-similarity";

async function main() {
    const ai = new GoogleGenAI({});

    const texts = [
        "What is the meaning of life?",
        "What is the purpose of existence?",
        "How do I bake a cake?",
    ];

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-001',
        contents: texts,
        config: { taskType: 'SEMANTIC_SIMILARITY' },
    });

    const embeddings = response.embeddings.map(e => e.values);

    for (let i = 0; i < texts.length; i++) {
        for (let j = i + 1; j < texts.length; j++) {
            const text1 = texts[i];
            const text2 = texts[j];
            const similarity = cosineSimilarity(embeddings[i], embeddings[j]);
            console.log(`Similarity between '${text1}' and '${text2}': ${similarity.toFixed(4)}`);
        }
    }
}

main();
import java.util.Arrays;
import com.google.genai.Client;
import com.google.genai.types.ContentEmbedding;
import com.google.genai.types.EmbedContentConfig;
import com.google.genai.types.EmbedContentResponse;
import java.util.List;

Client client = new Client();

List<String> texts =
    Arrays.asList(
        "What is the meaning of life?",
        "What is the purpose of existence?",
        "How do I bake a cake?");

EmbedContentConfig config =
    EmbedContentConfig.builder().taskType("SEMANTIC_SIMILARITY").build();

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-001", texts, config);

List<ContentEmbedding> embeddings = response.embeddings().get();

for (int i = 0; i < texts.size(); i++) {
  for (int j = i + 1; j < texts.size(); j++) {
    List<Float> v1 = embeddings.get(i).values().get();
    List<Float> v2 = embeddings.get(j).values().get();
    double dotProduct = 0.0;
    double normA = 0.0;
    double normB = 0.0;
    for (int k = 0; k < v1.size(); k++) {
      dotProduct += v1.get(k) * v2.get(k);
      normA += v1.get(k) * v1.get(k);
      normB += v2.get(k) * v2.get(k);
    }
    double similarity = dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
    System.out.printf(
        "Similarity between '%s' and '%s': %.4f%n", texts.get(i), texts.get(j), similarity);
  }
}
package main

import (
    "context"
    "fmt"
    "log"
    "math"

    "google.golang.org/genai"
)

// cosineSimilarity calculates the similarity between two vectors.
func cosineSimilarity(a, b []float32) (float64, error) {
    if len(a) != len(b) {
        return 0, fmt.Errorf("vectors must have the same length")
    }

    var dotProduct, aMagnitude, bMagnitude float64
    for i := 0; i < len(a); i++ {
        dotProduct += float64(a[i] * b[i])
        aMagnitude += float64(a[i] * a[i])
        bMagnitude += float64(b[i] * b[i])
    }

    if aMagnitude == 0 || bMagnitude == 0 {
        return 0, nil
    }

    return dotProduct / (math.Sqrt(aMagnitude) * math.Sqrt(bMagnitude)), nil
}

func main() {
    ctx := context.Background()
    client, _ := genai.NewClient(ctx, nil)
    defer client.Close()

    texts := []string{
        "What is the meaning of life?",
        "What is the purpose of existence?",
        "How do I bake a cake?",
    }

    var contents []*genai.Content
    for _, text := range texts {
        contents = append(contents, genai.NewContentFromText(text, genai.RoleUser))
    }

    result, _ := client.Models.EmbedContent(ctx,
        "gemini-embedding-001",
        contents,
        &genai.EmbedContentRequest{TaskType: genai.TaskTypeSemanticSimilarity},
    )

    embeddings := result.Embeddings

    for i := 0; i < len(texts); i++ {
        for j := i + 1; j < len(texts); j++ {
            similarity, _ := cosineSimilarity(embeddings[i].Values, embeddings[j].Values)
            fmt.Printf("Similarity between '%s' and '%s': %.4f\n", texts[i], texts[j], similarity)
        }
    }
}
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -d '{
    "taskType": "SEMANTIC_SIMILARITY",
    "content": {
        "parts": [
        {
            "text": "What is the meaning of life?"
        },
        {
            "text": "How much wood would a woodchuck chuck?"
        },
        {
            "text": "How does the brain work?"
        }
        ]
    }
    }'

이 코드를 실행하면 서로 다른 텍스트 덩어리가 얼마나 비슷한지 확인할 수 있어요.

참고: 코사인 유사도(Cosine similarity)는 크기(magnitude)가 아니라 방향(direction)에 집중하기 때문에 좋은 거리 지표예요. 이는 개념적 근접성을 더 정확히 반영하죠. 값의 범위는 -1(반대)부터 1(가장 유사)까지예요.

지원 작업 유형

gemini-embedding-001에서 지원하는 작업 유형은 다음과 같아요.

작업 유형 설명 예시
SEMANTIC_SIMILARITY 텍스트 유사성을 평가하도록 최적화된 임베딩 추천 시스템, 중복 감지
CLASSIFICATION 미리 정해진 라벨에 따라 텍스트를 분류하도록 최적화된 임베딩 감성 분석, 스팸 감지
CLUSTERING 유사성에 따라 텍스트를 클러스터링하도록 최적화된 임베딩 문서 정리, 시장 조사, 이상 감지
RETRIEVAL_DOCUMENT 문서 검색에 최적화된 임베딩 검색용 기사·책·웹 페이지 인덱싱
RETRIEVAL_QUERY 일반 검색 쿼리에 최적화된 임베딩. 쿼리에는 RETRIEVAL_QUERY, 검색 대상 문서에는 RETRIEVAL_DOCUMENT를 사용하세요. 커스텀 검색
CODE_RETRIEVAL_QUERY 자연어 쿼리 기반 코드 블록 검색에 최적화된 임베딩. 쿼리에는 CODE_RETRIEVAL_QUERY, 검색 대상 코드 블록에는 RETRIEVAL_DOCUMENT를 사용하세요. 코드 제안과 검색
QUESTION_ANSWERING 질의응답 시스템에서 질문에 대한 답을 담은 문서를 찾도록 최적화된 임베딩. 질문에는 QUESTION_ANSWERING, 검색 대상 문서에는 RETRIEVAL_DOCUMENT를 사용하세요. 챗박스
FACT_VERIFICATION 검증이 필요한 주장에 대한 임베딩으로, 그 주장을 뒷받침하거나 반박하는 증거가 담긴 문서를 검색하도록 최적화. 대상 텍스트에는 FACT_VERIFICATION, 검색 대상 문서에는 RETRIEVAL_DOCUMENT를 사용하세요. 자동 팩트체킹 시스템

임베딩 크기 제어하기

gemini-embedding-001과 gemini-embedding-2 모두 Matryoshka Representation Learning(MRL) 기법으로 학습됐는데, 이는 고차원 임베딩을 배우면서 그 초기 세그먼트(또는 접두사)가 같은 데이터의 유용하고 더 단순한 버전이 되도록 가르치는 기법이에요.

output_dimensionality 파라미터로 출력 임베딩 벡터의 크기를 제어할 수 있어요. 더 작은 출력 차원을 선택하면 저장 공간을 아끼고 다운스트림 애플리케이션의 계산 효율을 높일 수 있으며, 품질 손실은 거의 없어요. 두 모델 모두 기본적으로 3072차원 임베딩을 출력하지만, 품질 손실 없이 더 작은 크기로 줄여 저장 공간을 아낄 수 있어요. 768, 1536, 3072 출력 차원을 권장합니다.

from google import genai
from google.genai import types

client = genai.Client()

result = client.models.embed_content(
    model="gemini-embedding-2",
    contents="What is the meaning of life?",
    config=types.EmbedContentConfig(output_dimensionality=768)
)

[embedding_obj] = result.embeddings
embedding_length = len(embedding_obj.values)

print(f"Length of embedding: {embedding_length}")
import { GoogleGenAI } from "@google/genai";

async function main() {
    const ai = new GoogleGenAI({});

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: 'What is the meaning of life?',
        config: { outputDimensionality: 768 },
    });

    const embeddingLength = response.embeddings[0].values.length;
    console.log(`Length of embedding: ${embeddingLength}`);
}

main();
import com.google.genai.Client;
import com.google.genai.types.ContentEmbedding;
import com.google.genai.types.EmbedContentConfig;
import com.google.genai.types.EmbedContentResponse;

Client client = new Client();

EmbedContentConfig config =
    EmbedContentConfig.builder().outputDimensionality(768).build();

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", "What is the meaning of life?", config);

ContentEmbedding embeddingObj = response.embeddings().get().get(0);
int embeddingLength = embeddingObj.values().get().size();

System.out.println("Length of embedding: " + embeddingLength);
package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
)

func main() {
    ctx := context.Background()
    // The client uses Application Default Credentials.
    // Authenticate with 'gcloud auth application-default login'.
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    contents := []*genai.Content{
        genai.NewContentFromText("What is the meaning of life?", genai.RoleUser),
    }

    result, err := client.Models.EmbedContent(ctx,
        "gemini-embedding-2",
        contents,
        &genai.EmbedContentRequest{OutputDimensionality: 768},
    )
    if err != nil {
        log.Fatal(err)
    }

    embedding := result.Embeddings[0]
    embeddingLength := len(embedding.Values)
    fmt.Printf("Length of embedding: %d\n", embeddingLength)
}
curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H 'Content-Type: application/json' \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -d '{
        "content": {"parts":[{ "text": "What is the meaning of life?"}]},
        "output_dimensionality": 768
    }'

코드 실행 결과 예시:

Length of embedding: 768

작은 차원에서도 품질 보장하기

참고: gemini-embedding-2는 기본이 아닌 차원에 대해 자동 재정규화(auto renormalization)를 도입했어요.

기본 3072차원 임베딩은 항상 정규화되는데, Gemini Embedding 2는 잘린 차원(예: 768, 1536)도 자동으로 정규화해요. 덕분에 의미 유사성이 크기가 아니라 벡터 방향으로 계산돼, 별도 설정 없이도 더 정확한 결과를 얻을 수 있어요.

이전 모델(Older Models): gemini-embedding-001을 사용한다면 3072가 아닌 차원을 아래처럼 수동으로 정규화해야 해요.

import numpy as np
from numpy.linalg import norm

# Only for embeddings from `gemini-embedding-001`
embedding_values_np = np.array(embedding_obj.values)
normed_embedding = embedding_values_np / np.linalg.norm(embedding_values_np)

print(f"Normed embedding length: {len(normed_embedding)}")
print(f"Norm of normed embedding: {np.linalg.norm(normed_embedding):.6f}") # Should be very close to 1

이 코드의 실행 결과 예시:

Normed embedding length: 768
Norm of normed embedding: 1.000000

아래 표는 임베딩 벤치마크로 흔히 쓰이는 MTEB 점수를 차원별로 보여줘요. 특히 흥미로운 점은 성능이 임베딩 차원의 크기에 엄격히 비례하지 않는다는 것으로, 낮은 차원이 높은 차원과 비슷한 점수를 내기도 해요.

MRL 차원 MTEB 점수 (Gemini Embedding 001)
2048 68.16
1536 68.17
768 67.99
512 67.55
256 66.19
128 63.31

멀티모달 임베딩

gemini-embedding-2 모델은 멀티모달 입력을 지원해서 이미지, 동영상, 오디오, 문서 콘텐츠를 텍스트와 함께 임베딩할 수 있어요. 모든 모달리티가 같은 임베딩 공간으로 매핑되므로 교차 모달 검색과 비교가 가능해집니다.

지원 모달리티와 제한

전체 최대 입력 토큰 한도는 8192 토큰이에요.

모달리티 사양과 제한
텍스트 (Text) 최대 8,192 토큰 지원
이미지 (Image) 요청당 최대 6개 이미지. 지원 형식: PNG, JPEG
오디오 (Audio) 최대 길이 180초. 지원 형식: MP3, WAV
동영상 (Video) 최대 길이 120초. 지원 형식: MP4, MOV. 지원 코덱: H264, H265, AV1, VP9. 동영상당 최대 32프레임 처리: 짧은 동영상(≤32초)은 1fps로 샘플링하고, 긴 동영상은 32프레임으로 균일 샘플링해요. 동영상 파일의 오디오 트랙은 처리되지 않아요.
문서 (PDF) 요청당 최대 1개 파일, 최대 6페이지

이미지 임베딩

아래 예시는 gemini-embedding-2로 이미지를 임베딩하는 방법을 보여줘요.

이미지는 인라인 데이터로 제공하거나 Files API를 통해 업로드한 파일로 제공할 수 있어요.

from google import genai
from google.genai import types

with open('example.png', 'rb') as f:
    image_bytes = f.read()

client = genai.Client()

result = client.models.embed_content(
    model='gemini-embedding-2',
    contents=[
        types.Part.from_bytes(
            data=image_bytes,
            mime_type='image/png',
        ),
    ]
)

print(result.embeddings)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

async function main() {
    const ai = new GoogleGenAI({});

    const imgBase64 = fs.readFileSync("example.png", { encoding: "base64" });

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: [{
            inlineData: {
                mimeType: 'image/png',
                data: imgBase64,
            },
        }],
    });

    console.log(response.embeddings);
}

main();
import com.google.genai.Client;
import com.google.genai.types.Content;
import com.google.genai.types.EmbedContentResponse;
import com.google.genai.types.Part;
import java.nio.file.Files;
import java.nio.file.Paths;

Client client = new Client();

byte[] imageBytes = Files.readAllBytes(Paths.get("example.png"));

Content content = Content.fromParts(Part.fromBytes(imageBytes, "image/png"));

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", content, null);

System.out.println(response.embeddings().orElse(null));
IMG_PATH="/path/to/your/image.png"
IMG_BASE64=$(base64 -w0 "${IMG_PATH}")

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "content": {
            "parts": [{
                "inline_data": {
                    "mime_type": "image/png",
                    "data": "'"${IMG_BASE64}"'"
                }
            }]
        }
    }'

임베딩 집계 (Embedding aggregation)

멀티모달 콘텐츠를 다룰 때 입력을 어떻게 구성하는지에 따라 임베딩 출력이 달라져요.

  • 여러 부분 (집계, aggregated): contents 파라미터에 여러 입력을 직접 추가하면 모든 입력에 대해 하나의 집계 임베딩을 만들어요.
  • 여러 Content 객체 (분리, separate): 각 입력을 Content 객체로 감싸 contents 파라미터로 전달하면 각 항목에 대해 별도의 임베딩을 반환해요.
  • 포스트 수준 표현 (Post-level representation): 미디어 항목이 여러 개인 소셜 미디어 게시물 같은 복잡한 객체의 경우, 개별 임베딩을 집계(예: 평균)해 일관된 포스트 수준 표현을 만드는 것을 권장해요.

아래 예시는 텍스트와 이미지 입력에 대해 집계 임베딩 하나를 만드는 방법을 보여줘요. contents 파라미터에 여러 입력을 추가하면 됩니다:

from google import genai
from google.genai import types

client = genai.Client()

with open('dog.png', 'rb') as f:
    image_bytes = f.read()

result = client.models.embed_content(
    model='gemini-embedding-2',
    contents=[
        "An image of a dog",
        types.Part.from_bytes(
            data=image_bytes,
            mime_type='image/png',
        ),
    ]
)

# This produces one embedding
for embedding in result.embeddings:
    print(embedding.values)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

async function main() {
    const ai = new GoogleGenAI({});

    const imgBase64 = fs.readFileSync("dog.png", { encoding: "base64" });

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: [
            'An image of a dog',
            {
                inlineData: {
                    mimeType: 'image/png',
                    data: imgBase64,
                },
            },
        ],
    });

    // This produces one embedding
    for (const embedding of response.embeddings) {
        console.log(embedding.values);
    }
}

main();
import com.google.genai.Client;
import com.google.genai.types.Content;
import com.google.genai.types.ContentEmbedding;
import com.google.genai.types.EmbedContentResponse;
import com.google.genai.types.Part;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;

Client client = new Client();

byte[] imageBytes = Files.readAllBytes(Paths.get("dog.png"));

Content content =
    Content.fromParts(
        Part.fromText("An image of a dog"),
        Part.fromBytes(imageBytes, "image/png"));

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", content, null);

// This produces one embedding
for (ContentEmbedding embedding : response.embeddings().orElse(Collections.emptyList())) {
  System.out.println(embedding.values().orElse(Collections.emptyList()));
}
IMG_PATH="/path/to/your/dog.png"
IMG_BASE64=$(base64 -w0 "${IMG_PATH}")

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "content": {
            "parts": [
                {"text": "An image of a dog"},
                {
                    "inline_data": {
                        "mime_type": "image/png",
                        "data": "'"${IMG_BASE64}"'"
                    }
                }
            ]
        }
    }'

참고: 멀티모달 입력의 텍스트 부분에는 작업 유형 정보가 포함되면 안 돼요.

반면 contents 파라미터 안에서 Content 객체를 사용하면 별도의 임베딩이 반환돼요. 이 예시는 한 번의 임베딩 호출로 여러 임베딩을 만듭니다:

from google import genai
from google.genai import types

client = genai.Client()

with open('dog.png', 'rb') as f:
    image_bytes = f.read()

result = client.models.embed_content(
    model="gemini-embedding-2",
    contents=[
        types.Content(parts=[types.Part.from_text(text="task: classification | query: An image of a dog")]),
        types.Content(
            parts=[
                types.Part.from_bytes(
                    data=image_bytes,
                    mime_type="image/png",
                ),
            ]
        ),
    ],
)

# This produces two embeddings
for embedding in result.embeddings:
    print(embedding.values)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

async function main() {
    const ai = new GoogleGenAI({});

    const imgBase64 = fs.readFileSync("dog.png", { encoding: "base64" });

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: [
            { parts: [{ text: 'task: classification | query: An image of a dog' }] },
            {
                parts: [{
                    inlineData: {
                        mimeType: 'image/png',
                        data: imgBase64,
                    },
                }],
            },
        ],
    });

    // This produces two embeddings
    for (const embedding of response.embeddings) {
        console.log(embedding.values);
    }
}

main();
import java.util.Arrays;
import com.google.genai.Client;
import com.google.genai.types.Content;
import com.google.genai.types.ContentEmbedding;
import com.google.genai.types.EmbedContentResponse;
import com.google.genai.types.Part;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;

Client client = new Client();

byte[] imageBytes = Files.readAllBytes(Paths.get("dog.png"));

List<Content> contents =
    Arrays.asList(
        Content.fromParts(Part.fromText("task: classification | query: An image of a dog")),
        Content.fromParts(Part.fromBytes(imageBytes, "image/png")));

// Embed each Content object separately to produce separate embeddings
for (Content content : contents) {
  EmbedContentResponse response =
      client.models.embedContent("gemini-embedding-2", content, null);
  for (ContentEmbedding embedding : response.embeddings().orElse(Collections.emptyList())) {
    System.out.println(embedding.values().orElse(Collections.emptyList()));
  }
}
IMG_PATH="/path/to/your/dog.png"
IMG_BASE64=$(base64 -w0 "${IMG_PATH}")

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:batchEmbedContents" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "requests": [
            {
                "model": "models/gemini-embedding-2",
                "content": {"parts": [{"text": "task: classification | query: An image of a dog"}]}
            },
            {
                "model": "models/gemini-embedding-2",
                "content": {"parts": [{"inline_data": {"mime_type": "image/png", "data": "'"${IMG_BASE64}"'"}}]}
            }
        ]
    }'

오디오 임베딩

아래 예시는 gemini-embedding-2로 오디오 파일을 임베딩하는 방법을 보여줘요.

오디오 파일은 인라인 데이터로 제공하거나 Files API를 통해 업로드한 파일로 제공할 수 있어요.

from google import genai
from google.genai import types

with open('example.mp3', 'rb') as f:
    audio_bytes = f.read()

client = genai.Client()

result = client.models.embed_content(
    model='gemini-embedding-2',
    contents=[
        types.Part.from_bytes(
            data=audio_bytes,
            mime_type='audio/mpeg',
        ),
    ]
)

print(result.embeddings)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

async function main() {
    const ai = new GoogleGenAI({});

    const audioBase64 = fs.readFileSync("example.mp3", { encoding: "base64" });

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: [{
            inlineData: {
                mimeType: 'audio/mpeg',
                data: audioBase64,
            },
        }],
    });

    console.log(response.embeddings);
}

main();
import com.google.genai.Client;
import com.google.genai.types.Content;
import com.google.genai.types.EmbedContentResponse;
import com.google.genai.types.Part;
import java.nio.file.Files;
import java.nio.file.Paths;

Client client = new Client();

byte[] audioBytes = Files.readAllBytes(Paths.get("example.mp3"));

Content content = Content.fromParts(Part.fromBytes(audioBytes, "audio/mpeg"));

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", content, null);

System.out.println(response.embeddings().orElse(null));
AUDIO_PATH="/path/to/your/example.mp3"
AUDIO_BASE64=$(base64 -w0 "${AUDIO_PATH}")

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "content": {
            "parts": [{
                "inline_data": {
                    "mime_type": "audio/mpeg",
                    "data": "'"${AUDIO_BASE64}"'"
                }
            }]
        }
    }'

동영상 임베딩

아래 예시는 gemini-embedding-2로 동영상을 임베딩하는 방법을 보여줘요.

동영상은 인라인 데이터로 제공하거나 Files API를 통해 업로드한 파일로 제공할 수 있어요.

from google import genai
from google.genai import types

client = genai.Client()

with open('example.mp4', 'rb') as f:
    video_bytes = f.read()

result = client.models.embed_content(
    model='gemini-embedding-2',
    contents=[
        types.Part.from_bytes(
            data=video_bytes,
            mime_type='video/mp4',
        ),
    ]
)

print(result.embeddings[0].values)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

async function main() {
    const ai = new GoogleGenAI({});

    const videoBase64 = fs.readFileSync("example.mp4", { encoding: "base64" });

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: [{
            inlineData: {
                mimeType: 'video/mp4',
                data: videoBase64,
            },
        }],
    });

    console.log(response.embeddings);
}

main();
import com.google.genai.Client;
import com.google.genai.types.Content;
import com.google.genai.types.EmbedContentResponse;
import com.google.genai.types.Part;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;

Client client = new Client();

byte[] videoBytes = Files.readAllBytes(Paths.get("example.mp4"));

Content content = Content.fromParts(Part.fromBytes(videoBytes, "video/mp4"));

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", content, null);

System.out.println(
    response.embeddings().get().get(0).values().orElse(Collections.emptyList()));
VIDEO_PATH="/path/to/your/video.mp4"
VIDEO_BASE64=$(base64 -w0 "${VIDEO_PATH}")

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "content": {
            "parts": [{
                "inline_data": {
                    "mime_type": "video/mp4",
                    "data": "'"${VIDEO_BASE64}"'"
                }
            }]
        }
    }'

120초가 넘는 동영상을 임베딩해야 한다면, 동영상을 겹치는 여러 세그먼트로 나눈 뒤 각 청크를 개별적으로 임베딩할 수 있어요.

문서 임베딩

PDF 형식의 문서는 바로 임베딩할 수 있어요. 모델이 각 페이지의 시각적·텍스트 콘텐츠를 처리합니다.

PDF는 인라인 데이터로 제공하거나 Files API를 통해 업로드한 파일로 제공할 수 있어요.

모델이 PDF를 처리하는 방법

PDF를 임베딩하면 모델이 시각적 feature와 텍스트 feature를 모두 사용해 문서를 처리해요.

  • 시각적 표현 (Visual representation): 모델이 각 페이지를 이미지로 렌더링하며, 페이지당 258 토큰을 소비해요.
  • 텍스트 추출 (Text extraction): 모델이 문서에서 텍스트를 추출해요. 네이티브 PDF(디지털 텍스트 포함)는 텍스트를 바로 추출하고, 스캔된 PDF(텍스트 이미지 포함)는 OCR(광학 문자 인식)을 자동 실행해 텍스트를 추출해요.

PDF의 총 토큰 수를 계산하려면 시각 토큰(페이지당 258)에 텍스트 토큰을 더하면 돼요. 입력은 모델의 8,192 토큰 한도(모든 모달리티 공유) 안에 들어와야 해요. 이 한도를 넘는 입력은 시스템이 조용히 잘라냅니다.

참고: Gemini Developer API는 PDF에 대해 항상 OCR을 활성화하며 비활성화를 지원하지 않아요(document_ocr 파라미터는 Vertex AI에서만 사용 가능).

PDF 제한
  • 요청당 파일 수: 최대 1개 PDF 파일을 제출할 수 있어요.
  • 페이지 수 제한: 파일당 최대 6페이지를 제출할 수 있어요. 최상의 품질을 위해 PDF당 1페이지를 강력히 권장합니다.

아래 예시는 gemini-embedding-2로 PDF를 임베딩하는 방법을 보여줘요:

from google import genai
from google.genai import types

with open('example.pdf', 'rb') as f:
    pdf_bytes = f.read()

client = genai.Client()

result = client.models.embed_content(
    model='gemini-embedding-2',
    contents=[
        types.Part.from_bytes(
            data=pdf_bytes,
            mime_type='application/pdf',
        ),
    ]
)

print(result.embeddings)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

async function main() {
    const ai = new GoogleGenAI({});

    const pdfBase64 = fs.readFileSync("example.pdf", { encoding: "base64" });

    const response = await ai.models.embedContent({
        model: 'gemini-embedding-2',
        contents: [{
            inlineData: {
                mimeType: 'application/pdf',
                data: pdfBase64,
            },
        }],
    });

    console.log(response.embeddings);
}

main();
import com.google.genai.Client;
import com.google.genai.types.Content;
import com.google.genai.types.EmbedContentResponse;
import com.google.genai.types.Part;
import java.nio.file.Files;
import java.nio.file.Paths;

Client client = new Client();

byte[] pdfBytes = Files.readAllBytes(Paths.get("example.pdf"));

Content content = Content.fromParts(Part.fromBytes(pdfBytes, "application/pdf"));

EmbedContentResponse response =
    client.models.embedContent("gemini-embedding-2", content, null);

System.out.println(response.embeddings().orElse(null));
PDF_PATH="/path/to/your/example.pdf"
PDF_BASE64=$(base64 -w0 "${PDF_PATH}")

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-2:embedContent" \
    -H "Content-Type: application/json" \
    -H "x-goog-api-key: ${GEMINI_API_KEY}" \
    -d '{
        "content": {
            "parts": [{
                "inline_data": {
                    "mime_type": "application/pdf",
                    "data": "'"${PDF_BASE64}"'"
                }
            }]
        }
    }'

사용 사례

텍스트 임베딩은 다양한 일반적인 AI 사용 사례에 필수적이에요.

  • RAG (Retrieval-Augmented Generation): 임베딩이 모델의 컨텍스트에 관련 정보를 검색·반영해 생성 텍스트의 품질을 높여요.

  • 정보 검색 (Information retrieval): 입력 텍스트가 주어졌을 때 의미상 가장 유사한 텍스트나 문서를 검색해요.

    문서 검색 튜토리얼

  • 검색 재배열 (Search reranking): 초기 결과를 쿼리와 의미적으로 점수화해 가장 관련성 높은 항목을 우선시해요.

    검색 재배열 튜토리얼

  • 이상 감지 (Anomaly detection): 임베딩 그룹을 비교하면 숨은 트렌드나 이상치를 찾는 데 도움이 돼요.

    이상 감지 튜토리얼

  • 분류 (Classification): 감성 분석이나 스팸 감지처럼 콘텐츠에 따라 텍스트를 자동으로 분류해요.

    분류 튜토리얼

  • 클러스터링 (Clustering): 임베딩의 클러스터와 시각화를 만들어 복잡한 관계를 효과적으로 파악해요.

    클러스터링 시각화 튜토리얼

임베딩 저장하기

임베딩을 프로덕션으로 가져갈 때는 고차원 임베딩을 효율적으로 저장·인덱싱·검색하기 위해 벡터 데이터베이스를 쓰는 것이 일반적이에요. Google Cloud는 이런 용도에 쓸 수 있는 관리형 데이터 서비스로 Gemini Enterprise Agent Platform Vector Search 2.0, BigQuery, AlloyDB, Cloud SQL을 제공해요.

아래 튜토리얼들은 Gemini Embedding과 함께 타사 벡터 데이터베이스를 사용하는 방법을 보여줘요.

모델 버전

Gemini Embedding 2

속성 설명
모델 코드 Gemini API gemini-embedding-2
지원 데이터 유형 입력 텍스트, 이미지, 동영상, 오디오, PDF 출력 텍스트 임베딩
토큰 제한[*] 입력 토큰 한도 8,192 출력 차원 크기 유연, 지원: 128 - 3072, 권장: 768, 1536, 3072
버전 모델 버전 패턴을 참고하세요. - Stable: gemini-embedding-2
최신 업데이트 2026년 4월

Gemini Embedding

속성 설명
모델 코드 Gemini API gemini-embedding-001
지원 데이터 유형 입력 텍스트 출력 텍스트 임베딩
토큰 제한[*] 입력 토큰 한도 2,048 출력 차원 크기 유연, 지원: 128 - 3072, 권장: 768, 1536, 3072
버전 모델 버전 패턴을 참고하세요. - Stable: gemini-embedding-001
최신 업데이트 2025년 6월

폐기된(deprecated) Embeddings 모델은 Deprecations 페이지를 참고하세요.

gemini-embedding-001에서 마이그레이션

gemini-embedding-001과 gemini-embedding-2의 임베딩 공간은 호환되지 않아요. 즉 한 모델이 생성한 임베딩을 다른 모델의 임베딩과 직접 비교할 수 없어요. gemini-embedding-2로 업그레이드한다면 기존 데이터를 전부 다시 임베딩해야 합니다.

비호환성 외에도 두 모델 사이에는 몇 가지 주목할 만한 차이점이 있어요.

  • 작업 유형 지정 (Task type specification): gemini-embedding-001에서는 task_type 파라미터(예: SEMANTIC_SIMILARITY, RETRIEVAL_DOCUMENT)로 작업 유형을 지정해요. gemini-embedding-2에서는 task_type 파라미터가 지원되지 않아요. 대신 텍스트 전용 작업의 프롬프트에 작업 지시를 직접 포함해야 해요. 사용 사례별 프롬프트 형식은 Task types with Embeddings 2를 참고하세요.
  • 임베딩 집계 (Embedding aggregation): gemini-embedding-001은 입력 목록의 각 문자열에 대해 개별 임베딩을 생성해요. 반면 gemini-embedding-2는 한 요청에 여러 입력(예: 텍스트와 이미지)을 직접 넣으면 단일 집계 임베딩을 만들어요. 개별 입력에 대한 별도 임베딩을 만들려면 각 입력을 Content 객체로 감싸거나 Batch API를 사용하세요. 자세한 내용은 Embedding aggregation을 참고하세요.
  • 정규화 (Normalization): output_dimensionality로 3072차원보다 적은 임베딩을 요청하면 gemini-embedding-2가 잘린 임베딩을 자동 정규화해요. gemini-embedding-001에서는 3072가 아닌 차원에 대해 수동 정규화가 필요해요. 자세한 내용은 작은 차원 품질 보장을 참고하세요.

배치 임베딩 (Batch embeddings)

지연 시간이 중요하지 않다면 Gemini Embeddings 모델을 Batch API와 함께 사용해 보세요. 기본 Embedding 가격의 50%로 훨씬 높은 처리량을 얻을 수 있어요. 시작 방법은 Batch API cookbook에서 확인할 수 있어요.

책임 있는 사용 고지 (Responsible use notice)

새 콘텐츠를 만드는 생성형 AI 모델과 달리, Gemini Embedding 모델은 입력 데이터의 형식을 숫자 표현으로 변환하는 용도로만 쓰입니다. Google은 입력 데이터를 요청된 숫자 형식으로 변환하는 임베딩 모델 제공에 책임이 있지만, 입력하는 데이터와 그 결과물인 임베딩에 대한 전적인 책임은 사용자에게 있어요. Gemini Embedding 모델을 사용함으로써 업로드하는 모든 콘텐츠에 필요한 권리가 있음을 확인하는 것입니다. 타인의 지적 재산권이나 프라이버시 권리를 침해하는 콘텐츠를 생성하지 마세요. 이 서비스 사용에는 금지 사용 정책(Prohibited Use Policy)과 Google 서비스 약관이 적용됩니다.

임베딩으로 시작하기

embeddings quickstart 노트북을 확인해 모델 기능을 살펴보고 임베딩을 커스터마이즈·시각화하는 방법을 배워 보세요.

더 알아보기 (Learn more)

임베딩을 통해 RAG나 의미 검색을 만들어 보려면 File Search 문서와 Batch API를 이어서 보면 좋아요. 텍스트 임베딩뿐 아니라 이미지·동영상·오디오·PDF까지 한 공간으로 매핑하는 gemini-embedding-2의 멀티모달 특성이 가장 큰 차별점이라는 점을 기억해 주세요.