파일 검색(File search)

Gemini API는 File Search 도구를 통해 검색 증강 생성(RAG, Retrieval Augmented Generation)을 지원해요. File Search는 데이터를 가져와 청크로 나누고 인덱싱해, 제공된 프롬프트에 기반한 관련 정보를 빠르게 검색할 수 있게 해 줘요. 이렇게 검색된 정보는 모델의 컨텍스트로 사용되어 더 정확하고 관련성 높은 답변을 제공할 수 있게 돼요. File Search는 gemini-embedding-001이 지원하는 텍스트 임베딩과 gemini-embedding-2가 지원하는 이미지/멀티모달 임베딩으로 멀티모달 기능도 제공할 수 있어요.

참고: 오디오와 비디오 형식은 현재 지원되지 않아요.

파일 저장과 쿼리 시점의 임베딩 생성은 무료이며, 파일을 처음 인덱싱할 때 임베딩을 만드는 비용과 일반적인 Gemini 모델 입력/출력 토큰 비용만 지불하면 돼요. 이 새로운 과금 패러다임 덕분에 File Search 도구는 구축·확장이 더 쉽고 비용 효율적으로 변했어요. 자세한 내용은 pricing 섹션을 참고하세요.

출처: 문서

본문

File Search 스토어에 직접 업로드

이 예시는 file search store에 파일을 직접 업로드하는 방법을 보여줘요.

Python

from google import genai
from google.genai import types
import time

client = genai.Client()

file_search_store = client.file_search_stores.create(
    config={
        'display_name': 'your-fileSearchStore-name',
        'embedding_model': 'models/gemini-embedding-2'
    }
)

operation = client.file_search_stores.upload_to_file_search_store(
  file='sample.txt',
  file_search_store_name=file_search_store.name,
  config={
      'display_name' : 'display-file-name',
  }
)

while not operation.done:
    time.sleep(5)
    operation = client.operations.get(operation)

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="Can you tell me about [insert question]",
    tools=[{
        "type": "file_search",
        "file_search_store_names": [file_search_store.name]
    }]
)

for step in interaction.steps:
    if step.type == "model_output":
        for content_block in step.content:
            if content_block.type == "text":
                print(content_block.text)
                if content_block.annotations:
                    print("\nSources:")
                    for annotation in content_block.annotations:
                        if annotation.type == "file_citation":
                            print(f"  - {annotation.file_name}: {annotation.source}")

JavaScript

import { GoogleGenAI } from '@google/genai';

const ai = new GoogleGenAI({});

async function run() {
  const fileSearchStore = await ai.fileSearchStores.create({
    config: {
      displayName: 'your-fileSearchStore-name',
      embeddingModel: 'models/gemini-embedding-2'
    }
  });

  let operation = await ai.fileSearchStores.uploadToFileSearchStore({
    file: 'file.txt',
    fileSearchStoreName: fileSearchStore.name,
    config: {
      displayName: 'file-name',
    }
  });

  while (!operation.done) {
    await new Promise(resolve => setTimeout(resolve, 5000));
    operation = await ai.operations.get({ operation });
  }

  const interaction = await ai.interactions.create({
    model: "gemini-3.8-flash",
    input: "Can you tell me about [insert question]",
    tools: [{
      type: "file_search",
      file_search_store_names: [fileSearchStore.name]
    }]
  });

  for (const step of interaction.steps) {
    if (step.type === 'model_output') {
      for (const contentBlock of step.content) {
        if (contentBlock.type === 'text') {
          console.log(contentBlock.text);
          if (contentBlock.annotations) {
            console.log("\nSources:");
            for (const annotation of contentBlock.annotations) {
              if (annotation.type === 'file_citation') {
                console.log(`  - ${annotation.file_name}: ${annotation.source}`);
              }
            }
          }
        }
      }
    }
  }
}

run();

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Annotation;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileCitation;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import com.google.genai.types.CreateFileSearchStoreConfig;
import com.google.genai.types.FileSearchStore;
import com.google.genai.types.UploadToFileSearchStoreConfig;
import com.google.genai.types.UploadToFileSearchStoreOperation;
import java.util.Arrays;

Client client = new Client();

FileSearchStore fileSearchStore =
    client.fileSearchStores.create(
        CreateFileSearchStoreConfig.builder()
            .displayName("your-fileSearchStore-name")
            .embeddingModel("models/gemini-embedding-2")
            .build());

UploadToFileSearchStoreOperation operation =
    client.fileSearchStores.uploadToFileSearchStore(
        fileSearchStore.name().get(),
        "sample.txt",
        UploadToFileSearchStoreConfig.builder().displayName("display-file-name").build());

while (!operation.done().orElse(false)) {
  Thread.sleep(5000);
  operation = client.operations.get(operation, null);
}

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Can you tell me about [insert question]"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList(fileSearchStore.name().get()))
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content contentBlock : outputStep.content().get()) {
          if (contentBlock instanceof TextContent) {
            TextContent textContent = (TextContent) contentBlock;
            System.out.println(textContent.text().orElse(""));
            if (textContent.annotations().isPresent()
                && !textContent.annotations().get().isEmpty()) {
              System.out.println("\nSources:");
              for (Annotation annotation : textContent.annotations().get()) {
                if (annotation instanceof FileCitation) {
                  FileCitation citation = (FileCitation) annotation;
                  System.out.printf(
                      "  - %s: %s%n",
                      citation.fileName().orElse(""), citation.source().orElse(""));
                }
              }
            }
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    fileSearchStore, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{
        DisplayName:    "your-fileSearchStore-name",
        EmbeddingModel: "models/gemini-embedding-2",
    })
    if err != nil {
        log.Fatal(err)
    }

    operation, err := client.FileSearchStores.UploadToFileSearchStoreFromPath(
        ctx,
        "sample.txt",
        fileSearchStore.Name,
        &genai.UploadToFileSearchStoreConfig{
            DisplayName: "display-file-name",
        },
    )
    if err != nil {
        log.Fatal(err)
    }

    for !operation.Done {
        time.Sleep(5 * time.Second)
        operation, err = client.Operations.GetUploadToFileSearchStoreOperation(ctx, operation, nil)
        if err != nil {
            log.Fatal(err)
        }
    }

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{fileSearchStore.Name},
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    fmt.Println(content.TextContent.Text)
                    if len(content.TextContent.Annotations) > 0 {
                        fmt.Println("\nSources:")
                        for _, annotation := range content.TextContent.Annotations {
                            if annotation.FileCitation != nil {
                                c := annotation.FileCitation
                                fileName := ""
                                if c.FileName != nil {
                                    fileName = *c.FileName
                                }
                                source := ""
                                if c.Source != nil {
                                    source = *c.Source
                                }
                                fmt.Printf("  - %s: %s\n", fileName, source)
                            }
                        }
                    }
                }
            }
        }
    }
}

REST

# 1. Create a File Search store
curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=$GEMINI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "displayName": "your-file-search-store-name",
      "embeddingModel": "models/gemini-embedding-2"
    }' > store_res.json

FILE_SEARCH_STORE_NAME=$(jq -r ".name" store_res.json)

# 2. Upload directly to File Search store using resumable upload
NUM_BYTES=$(wc -c < "sample.txt")
curl "https://generativelanguage.googleapis.com/upload/v1beta/fileSearchStores/$FILE_SEARCH_STORE_NAME:uploadToFileSearchStore?key=$GEMINI_API_KEY" \
    -D upload-header.tmp \
    -H "X-Goog-Upload-Protocol: resumable" \
    -H "X-Goog-Upload-Command: start" \
    -H "X-Goog-Upload-Header-Content-Length: $NUM_BYTES" \
    -H "X-Goog-Upload-Header-Content-Type: text/plain" \
    -H "Content-Type: application/json" \
    -d '{"displayName": "sample.txt"}' 2> /dev/null

upload_url=$(grep -i "x-goog-upload-url: " upload-header.tmp | cut -d" " -f2 | tr -d "\r")
rm upload-header.tmp

curl "${upload_url}" \
    -H "Content-Length: $NUM_BYTES" \
    -H "X-Goog-Upload-Offset: 0" \
    -H "X-Goog-Upload-Command: upload, finalize" \
    --data-binary "@sample.txt" 2> /dev/null > upload_response.json

cat upload_response.json

# 3. Query using the File Search store
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gemini-3.8-flash",
      "input": "Can you tell me about [insert question]",
      "tools": [{
        "type": "file_search",
        "file_search_store_names": ["'"$FILE_SEARCH_STORE_NAME"'"]
      }]
    }'

자세한 내용은 API 참조의 uploadToFileSearchStore를 확인하세요.

파일 가져오기(Importing files)

대안으로, 기존 파일을 업로드한 다음 file search store로 가져올 수 있어요.

Python

from google import genai
from google.genai import types
import time

client = genai.Client()

sample_file = client.files.upload(file='sample.txt', config={'display_name': 'display_file_name'})

file_search_store = client.file_search_stores.create(
    config={
        'display_name': 'your-fileSearchStore-name',
        'embedding_model': 'models/gemini-embedding-2'
    }
)

operation = client.file_search_stores.import_file(
    file_search_store_name=file_search_store.name,
    file_name=sample_file.name
)

while not operation.done:
    time.sleep(5)
    operation = client.operations.get(operation)

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="Can you tell me about [insert question]",
    tools=[{
        "type": "file_search",
        "file_search_store_names": [file_search_store.name]
    }]
)

for step in interaction.steps:
    if step.type == "model_output":
        for content_block in step.content:
            if content_block.type == "text":
                print(content_block.text)

JavaScript

import { GoogleGenAI } from '@google/genai';

const ai = new GoogleGenAI({});

async function run() {
  const sampleFile = await ai.files.upload({
    file: 'sample.txt',
    config: { displayName: 'file-name' }
  });

  const fileSearchStore = await ai.fileSearchStores.create({
    config: {
      displayName: 'your-fileSearchStore-name',
      embeddingModel: 'models/gemini-embedding-2'
    }
  });

  let operation = await ai.fileSearchStores.importFile({
    fileSearchStoreName: fileSearchStore.name,
    fileName: sampleFile.name
  });

  while (!operation.done) {
    await new Promise(resolve => setTimeout(resolve, 5000));
    operation = await ai.operations.get({ operation: operation });
  }

  const interaction = await ai.interactions.create({
    model: "gemini-3.8-flash",
    input: "Can you tell me about [insert question]",
    tools: [{
      type: "file_search",
      file_search_store_names: [fileSearchStore.name]
    }]
  });

  for (const step of interaction.steps) {
    if (step.type === 'model_output') {
      for (const contentBlock of step.content) {
        if (contentBlock.type === 'text') {
          console.log(contentBlock.text);
        }
      }
    }
  }
}

run();

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import com.google.genai.types.CreateFileSearchStoreConfig;
import com.google.genai.types.File;
import com.google.genai.types.FileSearchStore;
import com.google.genai.types.ImportFileOperation;
import com.google.genai.types.UploadFileConfig;
import java.util.Arrays;

Client client = new Client();

File sampleFile =
    client.files.upload(
        "sample.txt", UploadFileConfig.builder().displayName("display_file_name").build());

FileSearchStore fileSearchStore =
    client.fileSearchStores.create(
        CreateFileSearchStoreConfig.builder()
            .displayName("your-fileSearchStore-name")
            .embeddingModel("models/gemini-embedding-2")
            .build());

ImportFileOperation operation =
    client.fileSearchStores.importFile(
        fileSearchStore.name().get(), sampleFile.name().get(), null);

while (!operation.done().orElse(false)) {
  Thread.sleep(5000);
  operation = client.operations.get(operation, null);
}

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Can you tell me about [insert question]"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList(fileSearchStore.name().get()))
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content contentBlock : outputStep.content().get()) {
          if (contentBlock instanceof TextContent) {
            TextContent textContent = (TextContent) contentBlock;
            System.out.println(textContent.text().orElse(""));
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    sampleFile, err := client.Files.UploadFromPath(ctx, "sample.txt", &genai.UploadFileConfig{
        DisplayName: "display_file_name",
    })
    if err != nil {
        log.Fatal(err)
    }

    fileSearchStore, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{
        DisplayName:    "your-fileSearchStore-name",
        EmbeddingModel: "models/gemini-embedding-2",
    })
    if err != nil {
        log.Fatal(err)
    }

    operation, err := client.FileSearchStores.ImportFile(ctx, fileSearchStore.Name, sampleFile.Name, nil)
    if err != nil {
        log.Fatal(err)
    }

    for !operation.Done {
        time.Sleep(5 * time.Second)
        operation, err = client.Operations.GetImportFileOperation(ctx, operation, nil)
        if err != nil {
            log.Fatal(err)
        }
    }

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{fileSearchStore.Name},
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    fmt.Println(content.TextContent.Text)
                }
            }
        }
    }
}

REST

# 1. Upload file using the Files API
NUM_BYTES=$(wc -c < "sample.txt")
curl "https://generativelanguage.googleapis.com/upload/v1beta/files?key=$GEMINI_API_KEY" \
    -D upload-header.tmp \
    -H "X-Goog-Upload-Protocol: resumable" \
    -H "X-Goog-Upload-Command: start" \
    -H "X-Goog-Upload-Header-Content-Length: $NUM_BYTES" \
    -H "X-Goog-Upload-Header-Content-Type: text/plain" \
    -H "Content-Type: application/json" \
    -d '{"file": {"displayName": "sample.txt"}}' 2> /dev/null

upload_url=$(grep -i "x-goog-upload-url: " upload-header.tmp | cut -d" " -f2 | tr -d "\r")
rm upload-header.tmp

curl "${upload_url}" \
    -H "Content-Length: $NUM_BYTES" \
    -H "X-Goog-Upload-Offset: 0" \
    -H "X-Goog-Upload-Command: upload, finalize" \
    --data-binary "@sample.txt" 2> /dev/null > file_info.json

FILE_NAME=$(jq -r ".file.name" file_info.json)

# 2. Create a File Search store
curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=$GEMINI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "displayName": "your-file-search-store-name",
      "embeddingModel": "models/gemini-embedding-2"
    }' > store_res.json

FILE_SEARCH_STORE_NAME=$(jq -r ".name" store_res.json)

# 3. Import the file into the File Search store
curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/$FILE_SEARCH_STORE_NAME:importFile?key=$GEMINI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"fileName": "'"$FILE_NAME"'"}'

# 4. Query using the File Search store
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gemini-3.8-flash",
      "input": "Can you tell me about [insert question]",
      "tools": [{
        "type": "file_search",
        "file_search_store_names": ["'"$FILE_SEARCH_STORE_NAME"'"]
      }]
    }'

자세한 내용은 API 참조의 importFile을 확인하세요.

청크 구성(Chunking configuration)

File Search 스토어에 파일을 가져오면 자동으로 청크로 분해되고, 임베딩되고, 인덱싱되어 File Search 스토어에 업로드돼요. 청크 전략을 더 제어해야 한다면 chunking_config 설정을 지정해 청크당 최대 토큰 수와 최대 중첩 토큰 수를 설정할 수 있어요.

Python

from google import genai
from google.genai import types
import time

client = genai.Client()

operation = client.file_search_stores.upload_to_file_search_store(
    file_search_store_name=file_search_store.name,
    file='sample.txt',
    config={
        'chunking_config': {
          'white_space_config': {
            'max_tokens_per_chunk': 200,
            'max_overlap_tokens': 20
          }
        }
    }
)

while not operation.done:
    time.sleep(5)
    operation = client.operations.get(operation)

print("Custom chunking complete.")

JavaScript

import { GoogleGenAI } from '@google/genai';

const ai = new GoogleGenAI({});

let operation = await ai.fileSearchStores.uploadToFileSearchStore({
  file: 'file.txt',
  fileSearchStoreName: fileSearchStore.name,
  config: {
    displayName: 'file-name',
    chunkingConfig: {
      whiteSpaceConfig: {
        maxTokensPerChunk: 200,
        maxOverlapTokens: 20
      }
    }
  }
});

while (!operation.done) {
  await new Promise(resolve => setTimeout(resolve, 5000));
  operation = await ai.operations.get({ operation });
}
console.log("Custom chunking complete.");

Java

import com.google.genai.Client;
import com.google.genai.types.ChunkingConfig;
import com.google.genai.types.UploadToFileSearchStoreConfig;
import com.google.genai.types.UploadToFileSearchStoreOperation;
import com.google.genai.types.WhiteSpaceConfig;

Client client = new Client();

UploadToFileSearchStoreOperation operation =
    client.fileSearchStores.uploadToFileSearchStore(
        "fileSearchStores/my-file-search-store",
        "sample.txt",
        UploadToFileSearchStoreConfig.builder()
            .displayName("file-name")
            .chunkingConfig(
                ChunkingConfig.builder()
                    .whiteSpaceConfig(
                        WhiteSpaceConfig.builder()
                            .maxTokensPerChunk(200)
                            .maxOverlapTokens(20)
                            .build())
                    .build())
            .build());

while (!operation.done().orElse(false)) {
  Thread.sleep(5000);
  operation = client.operations.get(operation, null);
}

System.out.println("Custom chunking complete.");

Go

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "google.golang.org/genai"
)

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

    operation, err := client.FileSearchStores.UploadToFileSearchStoreFromPath(
        ctx,
        "sample.txt",
        "fileSearchStores/my-file-search-store",
        &genai.UploadToFileSearchStoreConfig{
            DisplayName: "file-name",
            ChunkingConfig: &genai.ChunkingConfig{
                WhiteSpaceConfig: &genai.WhiteSpaceConfig{
                    MaxTokensPerChunk: genai.Ptr(int32(200)),
                    MaxOverlapTokens:  genai.Ptr(int32(20)),
                },
            },
        },
    )
    if err != nil {
        log.Fatal(err)
    }

    for !operation.Done {
        time.Sleep(5 * time.Second)
        operation, err = client.Operations.GetUploadToFileSearchStoreOperation(ctx, operation, nil)
        if err != nil {
            log.Fatal(err)
        }
    }

    fmt.Println("Custom chunking complete.")
}

REST

NUM_BYTES=$(wc -c < "sample.txt")
curl "https://generativelanguage.googleapis.com/upload/v1beta/fileSearchStores/$FILE_SEARCH_STORE_NAME:uploadToFileSearchStore?key=$GEMINI_API_KEY" \
    -D upload-header.tmp \
    -H "X-Goog-Upload-Protocol: resumable" \
    -H "X-Goog-Upload-Command: start" \
    -H "X-Goog-Upload-Header-Content-Length: $NUM_BYTES" \
    -H "X-Goog-Upload-Header-Content-Type: text/plain" \
    -H "Content-Type: application/json" \
    -d '{
      "displayName": "sample.txt",
      "chunkingConfig": {
        "whiteSpaceConfig": {
          "maxTokensPerChunk": 200,
          "maxOverlapTokens": 20
        }
      }
    }' 2> /dev/null

upload_url=$(grep -i "x-goog-upload-url: " upload-header.tmp | cut -d" " -f2 | tr -d "\r")
rm upload-header.tmp

curl "${upload_url}" \
    -H "Content-Length: $NUM_BYTES" \
    -H "X-Goog-Upload-Offset: 0" \
    -H "X-Goog-Upload-Command: upload, finalize" \
    --data-binary "@sample.txt" 2> /dev/null > upload_response.json

cat upload_response.json

File Search 스토어를 사용하려면 Upload와 Import 예시에서 보여준 것처럼 스토어를 도구로 interactions.create 메서드에 전달하세요.

작동 방식

File Search는 사용자 프롬프트와 관련된 정보를 찾기 위해 의미 검색(semantic search)이라는 기법을 사용해요. 키워드 기반의 표준 검색과 달리, 의미 검색은 쿼리의 의미와 맥락을 이해해요.

파일을 가져오면 업로드된 콘텐츠의 의미를 담는 embeddings이라는 숫자 표현으로 변환돼요. 이 임베딩은 전용 File Search 데이터베이스에 저장돼요. 쿼리를 하면 쿼리도 역시 임베딩으로 변환돼요. 그러면 시스템이 File Search를 수행해 File Search 스토어에서 가장 유사하고 관련성 높은 문서 청크를 찾아요.

임베딩에는 TTL(Time To Live)이 없어요. 수동으로 삭제하거나 모델이 폐기될 때까지 유지돼요. 그러나 파일은 48시간 후에 삭제돼요.

File Search uploadToFileSearchStore API 사용 프로세스의 분석은 다음과 같아요.

  • File Search 스토어 만들기: File Search 스토어는 파일에서 처리된 데이터를 담아요. 의미 검색이 작동할 임베딩의 영구 컨테이너예요.
  • 파일 업로드 및 File Search 스토어로 가져오기: 파일을 업로드함과 동시에 결과를 File Search 스토어로 가져와요. 이것은 원시 문서를 참조하는 임시 File 객체를 만드는 것이에요. 그 데이터는 청크로 분해되고, File Search 임베딩으로 변환되며, 인덱싱돼요. File 객체는 48시간 후 삭제되는 반면, File Search 스토어로 가져온 데이터는 삭제를 선택할 때까지 무기한 저장돼요.
  • File Search로 쿼리하기: 마지막으로 generateContent 호출에서 FileSearch 도구를 사용해요. 도구 구성에서 검색하려는 FileSearchStore를 가리키는 FileSearchRetrievalResource를 지정해요. 이렇게 하면 모델이 특정 File Search 스토어에 대해 의미 검색을 수행해 응답을 그라운딩할 관련 정보를 찾도록 지시해요.

File Search의 인덱싱 및 쿼리 프로세스 — 이 다이어그램에서 Documents에서 Embedding model로 가는 점선(gemini-embedding-001](/gemini-api/docs/embeddings) 사용)은 uploadToFileSearchStore API를 나타내며(File storage를 우회). 그렇지 않으면 Files API로 파일을 별도로 만들고 가져오는 방식은 인덱싱 프로세스를 Documents에서 File storage로, 그다음 Embedding model로 이동시켜요.

File Search 스토어

File Search 스토어는 문서 임베딩의 컨테이너예요. File API를 통해 업로드된 원시 파일은 48시간 후 삭제되지만, File Search 스토어로 가져온 데이터는 수동으로 삭제할 때까지 무기한 저장돼요. 문서를 정리하기 위해 여러 File Search 스토어를 만들 수 있어요. FileSearchStore API는 파일 검색 스토어를 관리하기 위한 생성, 목록, 조회, 삭제를 제공해요. File Search 스토어 이름은 전역 범위로 지정돼요.

File Search 스토어를 관리하는 몇 가지 예시는 다음과 같아요.

Python

file_search_store = client.file_search_stores.create(
    config={
        'display_name': 'myfilesearchstore123',
        'embedding_model': 'models/gemini-embedding-2'
    }
)

for store in client.file_search_stores.list():
    print(store)

my_file_search_store = client.file_search_stores.get(name=file_search_store.name)

client.file_search_stores.delete(name=file_search_store.name, config={'force': True})

JavaScript

const fileSearchStore = await ai.fileSearchStores.create({
  config: {
    displayName: 'myfilesearchstore123',
    embeddingModel: 'models/gemini-embedding-2'
  }
});

const fileSearchStores = await ai.fileSearchStores.list();
for await (const store of fileSearchStores) {
  console.log(store);
}

const myFileSearchStore = await ai.fileSearchStores.get({
  name: fileSearchStore.name
});

await ai.fileSearchStores.delete({
  name: fileSearchStore.name,
  config: { force: true }
});

Java

import com.google.genai.Client;
import com.google.genai.types.CreateFileSearchStoreConfig;
import com.google.genai.types.DeleteFileSearchStoreConfig;
import com.google.genai.types.FileSearchStore;

Client client = new Client();

FileSearchStore fileSearchStore =
    client.fileSearchStores.create(
        CreateFileSearchStoreConfig.builder()
            .displayName("myfilesearchstore123")
            .embeddingModel("models/gemini-embedding-2")
            .build());

for (FileSearchStore store : client.fileSearchStores.list(null)) {
  System.out.println(store);
}

FileSearchStore myFileSearchStore =
    client.fileSearchStores.get(fileSearchStore.name().get(), null);

client.fileSearchStores.delete(
    fileSearchStore.name().get(), DeleteFileSearchStoreConfig.builder().force(true).build());

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
)

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

    fileSearchStore, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{
        DisplayName:    "myfilesearchstore123",
        EmbeddingModel: "models/gemini-embedding-2",
    })
    if err != nil {
        log.Fatal(err)
    }

    for store, err := range client.FileSearchStores.All(ctx) {
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(store)
    }

    myFileSearchStore, err := client.FileSearchStores.Get(ctx, fileSearchStore.Name, nil)
    if err != nil {
        log.Fatal(err)
    }
    _ = myFileSearchStore

    err = client.FileSearchStores.Delete(ctx, fileSearchStore.Name, &genai.DeleteFileSearchStoreConfig{
        Force: genai.Ptr(true),
    })
    if err != nil {
        log.Fatal(err)
    }
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=${GEMINI_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{ "displayName": "My Store", "embedding_model": "models/gemini-embedding-2" }'

curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=${GEMINI_API_KEY}"

curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/myfilesearchstore123?key=${GEMINI_API_KEY}"

curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/myfilesearchstore123?key=${GEMINI_API_KEY}"

File Search 문서

File Search Documents API를 사용해 파일 스토어의 개별 문서를 관리할 수 있어요. 파일 검색 스토어의 각 문서를 list하고, 문서에 대한 정보를 get하고, 이름으로 문서를 delete할 수 있어요.

Python

for document_in_store in client.file_search_stores.documents.list(parent='fileSearchStores/myfilesearchstore123'):
  print(document_in_store)

file_search_document = client.file_search_stores.documents.get(name='fileSearchStores/myfilesearchstore123/documents/sampletxt123')
print(file_search_document)

client.file_search_stores.documents.delete(name='fileSearchStores/myfilesearchstore123/documents/sampletxt123', config={'force': True})

JavaScript

const documents = await ai.fileSearchStores.documents.list({
  parent: 'fileSearchStores/myfilesearchstore123'
});
for await (const doc of documents) {
  console.log(doc);
}

const fileSearchDocument = await ai.fileSearchStores.documents.get({
  name: 'fileSearchStores/myfilesearchstore123/documents/sampletxt123'
});

await ai.fileSearchStores.documents.delete({
  name: 'fileSearchStores/myfilesearchstore123/documents/sampletxt123',
  config: { force: true }
});

Java

import com.google.genai.Client;
import com.google.genai.types.DeleteDocumentConfig;
import com.google.genai.types.Document;

Client client = new Client();

for (Document documentInStore :
    client.fileSearchStores.documents.list("fileSearchStores/myfilesearchstore123", null)) {
  System.out.println(documentInStore);
}

Document fileSearchDocument =
    client.fileSearchStores.documents.get(
        "fileSearchStores/myfilesearchstore123/documents/sampletxt123", null);
System.out.println(fileSearchDocument);

client.fileSearchStores.documents.delete(
    "fileSearchStores/myfilesearchstore123/documents/sampletxt123",
    DeleteDocumentConfig.builder().force(true).build());

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
)

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

    for documentInStore, err := range client.FileSearchStores.Documents.All(ctx, "fileSearchStores/myfilesearchstore123") {
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(documentInStore)
    }

    fileSearchDocument, err := client.FileSearchStores.Documents.Get(ctx, "fileSearchStores/myfilesearchstore123/documents/sampletxt123", nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(fileSearchDocument)

    err = client.FileSearchStores.Documents.Delete(ctx, "fileSearchStores/myfilesearchstore123/documents/sampletxt123", &genai.DeleteDocumentConfig{
        Force: genai.Ptr(true),
    })
    if err != nil {
        log.Fatal(err)
    }
}

REST

curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/myfilesearchstore123/documents?key=${GEMINI_API_KEY}"

curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/myfilesearchstore123/documents/sampletxt123?key=${GEMINI_API_KEY}"

curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/myfilesearchstore123/documents/sampletxt123?key=${GEMINI_API_KEY}&force=true"

파일 메타데이터

파일을 필터링하거나 추가 컨텍스트를 제공하기 위해 파일에 사용자 정의 메타데이터를 추가할 수 있어요. 메타데이터는 key-value 쌍의 집합이에요.

Python

op = client.file_search_stores.import_file(
    file_search_store_name=file_search_store.name,
    file_name=sample_file.name,
    config={
        'custom_metadata': [
            {"key": "author", "string_value": "Robert Graves"},
            {"key": "year", "numeric_value": 1934}
        ]
    }
)

JavaScript

let operation = await ai.fileSearchStores.importFile({
  fileSearchStoreName: fileSearchStore.name,
  fileName: sampleFile.name,
  config: {
    customMetadata: [
      { key: "author", stringValue: "Robert Graves" },
      { key: "year", numericValue: 1934 }
    ]
  }
});

Java

import com.google.genai.Client;
import com.google.genai.types.CustomMetadata;
import com.google.genai.types.ImportFileConfig;
import com.google.genai.types.ImportFileOperation;
import java.util.Arrays;

Client client = new Client();

ImportFileOperation op =
    client.fileSearchStores.importFile(
        "fileSearchStores/myfilesearchstore123",
        "files/samplefile123",
        ImportFileConfig.builder()
            .customMetadata(
                Arrays.asList(
                    CustomMetadata.builder().key("author").stringValue("Robert Graves").build(),
                    CustomMetadata.builder().key("year").numericValue(1934f).build()))
            .build());

Go

package main

import (
    "context"
    "log"

    "google.golang.org/genai"
)

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

    op, err := client.FileSearchStores.ImportFile(
        ctx,
        "fileSearchStores/myfilesearchstore123",
        "files/samplefile123",
        &genai.ImportFileConfig{
            CustomMetadata: []*genai.CustomMetadata{
                {Key: "author", StringValue: "Robert Graves"},
                {Key: "year", NumericValue: genai.Ptr(float32(1934))},
            },
        },
    )
    if err != nil {
        log.Fatal(err)
    }
    _ = op
}

이것은 File Search 스토어에 여러 문서가 있고 그 중 일부만 검색하고 싶을 때 유용해요.

Python

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="Tell me about the book 'I, Claudius'",
    tools=[{
        "type": "file_search",
        "file_search_store_names": [file_search_store.name],
        "metadata_filter": 'author="Robert Graves"',
    }]
)

for step in interaction.steps:
    if step.type == "model_output":
        for content_block in step.content:
            if content_block.type == "text":
                print(content_block.text)

JavaScript

const interaction = await ai.interactions.create({
  model: "gemini-3.8-flash",
  input: "Tell me about the book 'I, Claudius'",
  tools: [{
    type: "file_search",
    file_search_store_names: [fileSearchStore.name],
    metadata_filter: 'author="Robert Graves"',
  }]
});

for (const step of interaction.steps) {
  if (step.type === 'model_output') {
    for (const contentBlock of step.content) {
      if (contentBlock.type === 'text') {
        console.log(contentBlock.text);
      }
    }
  }
}

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Tell me about the book 'I, Claudius'"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123"))
                    .metadataFilter("author=\"Robert Graves\"")
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content contentBlock : outputStep.content().get()) {
          if (contentBlock instanceof TextContent) {
            TextContent textContent = (TextContent) contentBlock;
            System.out.println(textContent.text().orElse(""));
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Tell me about the book 'I, Claudius'"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"},
                        MetadataFilter:       genai.Ptr(`author="Robert Graves"`),
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    fmt.Println(content.TextContent.Text)
                }
            }
        }
    }
}

REST

curl "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
            "model": "gemini-3.8-flash",
            "input": [{"type": "text", "text": "Tell me about the book I, Claudius"}],
            "tools": [{
                "type": "file_search",
                "file_search_store_names": ["'$STORE_NAME'"],
                "metadata_filter": "author = \"Robert Graves\""
            }]
        }' 2> /dev/null > response.json

cat response.json

metadata_filter에 대한 목록 필터 문법 구현 지침은 google.aip.dev/160에서 찾을 수 있어요.

멀티모달 File Search를 사용하면 이미지를 기본적으로 임베딩하고 검색할 수 있어, 풍부한 멀티모달 RAG 애플리케이션을 만들 수 있어요.

임베딩 모델 구성

FileSearchStore를 만들 때 기본 텍스트 전용 임베딩 모델을 멀티모달 모델로 오버라이드해야 해요. 텍스트와 이미지를 모두 처리하려면 models/gemini-embedding-2를 사용하세요.

Python

store = client.file_search_stores.create(
    config={
        "display_name": "Multimodal Catalog",
        "embedding_model": "models/gemini-embedding-2",
    }
)

JavaScript

const fileSearchStore = await ai.fileSearchStores.create({
  config: {
    displayName: "Multimodal Catalog",
    embeddingModel: "models/gemini-embedding-2",
  },
});

Java

import com.google.genai.Client;
import com.google.genai.types.CreateFileSearchStoreConfig;
import com.google.genai.types.FileSearchStore;

Client client = new Client();

FileSearchStore store =
    client.fileSearchStores.create(
        CreateFileSearchStoreConfig.builder()
            .displayName("Multimodal Catalog")
            .embeddingModel("models/gemini-embedding-2")
            .build());

Go

package main

import (
    "context"
    "log"

    "google.golang.org/genai"
)

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

    store, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{
        DisplayName:    "Multimodal Catalog",
        EmbeddingModel: "models/gemini-embedding-2",
    })
    if err != nil {
        log.Fatal(err)
    }
    _ = store
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=$GEMINI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "display_name": "Multimodal Catalog",
      "embedding_model": "models/gemini-embedding-2"
    }'

이미지 업로드

멀티모달 임베딩 모델로 스토어를 만든 후에는 Directly upload to File Search store 또는 Importing files에서 설명한 동일한 업로드 API를 사용해 이미지 파일을 직접 업로드할 수 있어요.

이미지 파일 요구 사항:

  • 이미지 파일은 해상도가 최대 4K x 4K 픽셀이어야 해요.
  • 지원 형식은 PNG, JPEG예요.

인용(Citations)

File Search를 사용하면 모델의 응답에 업로드한 문서 중 답변 생성에 사용된 부분을 지정하는 인용이 포함될 수 있어요. 이것은 사실 확인과 검증에 도움이 돼요.

인용 정보는 응답의 model_output 단계 content 블록 안의 annotations 속성을 통해 접근할 수 있어요.

Python

for step in interaction.steps:
    if step.type == 'model_output':
        for content in step.content:
            if content.type == 'text' and content.annotations:
                print(content.annotations)

JavaScript

for (const step of interaction.steps) {
  if (step.type === 'model_output') {
    for (const contentBlock of step.content) {
      if (contentBlock.type === 'text' && contentBlock.annotations) {
        console.log(JSON.stringify(contentBlock.annotations, null, 2));
      }
    }
  }
}

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Can you tell me about [insert question]"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123"))
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content content : outputStep.content().get()) {
          if (content instanceof TextContent) {
            TextContent textContent = (TextContent) content;
            if (textContent.annotations().isPresent()) {
              System.out.println(textContent.annotations().get());
            }
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"},
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil && len(content.TextContent.Annotations) > 0 {
                    fmt.Println(content.TextContent.Annotations)
                }
            }
        }
    }
}

REST

{
  "steps": [
    {
      "type": "model_output",
      "content": [
        {
          "type": "text",
          "text": "...",
          "annotations": [
            {
              "type": "file_citation",
              "file_name": "sample.txt",
              "source": "..."
            }
          ]
        }
      ]
    }
  ]
}

인용 구조에 대한 자세한 정보는 Interactions API 참조를 참고하세요.

페이지 번호

페이지(예: PDF)가 있는 문서와 함께 File Search를 사용하면 모델의 응답에 정보가 발견된 페이지 번호가 포함될 수 있어요. 이 정보는 file_citation 주석의 page_number 속성을 통해 접근할 수 있어요.

Python

for step in interaction.steps:
    if step.type == "model_output":
        for content in step.content:
            if content.type == "text" and content.annotations:
                for annotation in content.annotations:
                    if annotation.type == "file_citation" and annotation.page_number:
                        print(f"Cited Page: {annotation.page_number}")

JavaScript

for (const step of interaction.steps) {
  if (step.type === 'model_output') {
    for (const block of step.content) {
      if (block.type === 'text' && block.annotations) {
        for (const annotation of block.annotations) {
          if (annotation.type === 'file_citation' && annotation.pageNumber) {
            console.log(`Cited Page: ${annotation.pageNumber}`);
          }
        }
      }
    }
  }
}

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Annotation;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileCitation;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Can you tell me about [insert question]"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123"))
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content content : outputStep.content().get()) {
          if (content instanceof TextContent) {
            TextContent textContent = (TextContent) content;
            if (textContent.annotations().isPresent()) {
              for (Annotation annotation : textContent.annotations().get()) {
                if (annotation instanceof FileCitation) {
                  FileCitation citation = (FileCitation) annotation;
                  if (citation.pageNumber().isPresent()) {
                    System.out.println("Cited Page: " + citation.pageNumber().get());
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"},
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    for _, annotation := range content.TextContent.Annotations {
                        if annotation.FileCitation != nil && annotation.FileCitation.PageNumber != nil {
                            fmt.Println("Cited Page:", *annotation.FileCitation.PageNumber)
                        }
                    }
                }
            }
        }
    }
}

REST

{
  "steps": [
    {
      "type": "model_output",
      "content": [
        {
          "type": "text",
          "text": "...",
          "annotations": [
            {
              "type": "file_citation",
              "file_name": "document.pdf",
              "page_number": 1,
              "source": "..."
            }
          ]
        }
      ]
    }
  ]
}

미디어 인용

모델이 생성 중 이미지 청크를 참조하면 API는 media_id를 포함하는 file_citation 유형의 주석을 annotations에 반환해요. 이 ID를 사용해 모델이 참조한 정확한 이미지 청크를 다운로드할 수 있어요. 이 media_id는 여러 검색 호출에 걸쳐 유지되므로, 동일한 이미지를 안정적으로 가져오거나 ID를 사용해 캐시할 수 있어요.

다음 스니펫은 REST 응답 단계의 예시예요.

{
  "type": "model_output",
  "content": [
    {
      "type": "text",
      "text": "...",
      "annotations": [
        {
          "type": "file_citation",
          "file_name": "product_image",
          "media_id": "fileSearchStores/my-store-123/media/BlobId-456"
        }
      ]
    }
  ]
}

다음 코드 스니펫은 media_id를 검색하고 미디어를 다운로드하는 방법을 보여줘요.

Python

for step in interaction.steps:
    if step.type == "model_output":
        for content in step.content:
            if content.type == "text" and content.annotations:
                for annotation in content.annotations:
                    if annotation.type == "file_citation" and annotation.media_id:
                        print(f"Cited Media ID: {annotation.media_id}")
                        blob_content = client.file_search_stores.download_media(
                            media_id=annotation.media_id
                        )

JavaScript

for (const step of interaction.steps) {
  if (step.type === 'model_output') {
    for (const block of step.content) {
      if (block.type === 'text' && block.annotations) {
        for (const annotation of block.annotations) {
          if (annotation.type === 'file_citation' && annotation.mediaId) {
            console.log(`Cited Media ID: ${annotation.mediaId}`);
            const blobContent = await ai.fileSearchStores.downloadMedia(annotation.mediaId);
          }
        }
      }
    }
  }
}

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Annotation;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileCitation;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Can you tell me about [insert question]"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123"))
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content content : outputStep.content().get()) {
          if (content instanceof TextContent) {
            TextContent textContent = (TextContent) content;
            if (textContent.annotations().isPresent()) {
              for (Annotation annotation : textContent.annotations().get()) {
                if (annotation instanceof FileCitation) {
                  FileCitation citation = (FileCitation) annotation;
                  if (citation.mediaId().isPresent()) {
                    System.out.println("Cited Media ID: " + citation.mediaId().get());
                    byte[] blobContent =
                        client.fileSearchStores.downloadMedia(citation.mediaId().get(), null);
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"},
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    for _, annotation := range content.TextContent.Annotations {
                        if annotation.FileCitation != nil && annotation.FileCitation.MediaID != nil {
                            fmt.Println("Cited Media ID:", *annotation.FileCitation.MediaID)
                            blobContent, err := client.FileSearchStores.DownloadMedia(ctx, *annotation.FileCitation.MediaID, nil)
                            if err != nil {
                                log.Fatal(err)
                            }
                            _ = blobContent
                        }
                    }
                }
            }
        }
    }
}

REST

curl -X GET "https://generativelanguage.googleapis.com/v1/fileSearchStores/my-store-123/media/BlobId-456" \
  -H "x-goog-api-key: $GEMINI_API_KEY"

사용자 정의 메타데이터

파일에 사용자 정의 메타데이터를 추가했다면 모델 응답의 annotations에서 접근할 수 있어요. 이는 소스 문서의 추가 컨텍스트(URL, 페이지 번호, 작성자 등)를 애플리케이션 로직에 전달하는 데 유용해요. file_citation 유형의 각 인용 주석에는 이 사용자 정의 메타데이터가 포함돼요.

Python

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="Tell me about [insert question]",
    tools=[{
        "type": "file_search",
        "file_search_store_names": [file_search_store.name]
    }]
)

for step in interaction.steps:
    if step.type == "model_output":
        for content_block in step.content:
            if content_block.annotations:
                for annotation in content_block.annotations:
                    print(annotation)

JavaScript

const interaction = await ai.interactions.create({
  model: "gemini-3.8-flash",
  input: "Tell me about [insert question]",
  tools: [{
    type: "file_search",
    file_search_store_names: [fileSearchStore.name]
  }]
});

for (const step of interaction.steps) {
  if (step.type === 'model_output') {
    for (const contentBlock of step.content) {
      if (contentBlock.annotations) {
        contentBlock.annotations.forEach((annotation) => {
          console.log(annotation);
        });
      }
    }
  }
}

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Annotation;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Tell me about [insert question]"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123"))
                    .build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content contentBlock : outputStep.content().get()) {
          if (contentBlock instanceof TextContent) {
            TextContent textContent = (TextContent) contentBlock;
            if (textContent.annotations().isPresent()) {
              for (Annotation annotation : textContent.annotations().get()) {
                System.out.println(annotation);
              }
            }
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Tell me about [insert question]"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"},
                    }),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    for _, annotation := range content.TextContent.Annotations {
                        fmt.Println(annotation)
                    }
                }
            }
        }
    }
}

REST

{
  "steps": [
    {
      "type": "model_output",
      "content": [
        {
          "type": "text",
          "text": "...",
          "annotations": [
            {
              "file_name": "...",
              "source": "...",
              "custom_metadata": [
                {
                  "key": "author",
                  "string_value": "Robert Graves"
                },
                {
                  "key": "year",
                  "numeric_value": 1934
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

구조화된 출력

Gemini 3 모델부터 파일 검색 도구를 구조화된 출력과 결합할 수 있어요.

Python

from pydantic import BaseModel, Field

class Money(BaseModel):
    amount: str = Field(description="The numerical part of the amount.")
    currency: str = Field(description="The currency of amount.")

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="What is the minimum hourly wage in Tokyo right now?",
    tools=[{
        "type": "file_search",
        "file_search_store_names": [file_search_store.name]
    }],
    response_format={
        "type": "text",
        "mime_type": "application/json",
        "schema": Money.model_json_schema()
    },
)
result = Money.model_validate_json(interaction.output_text)
print(result)

JavaScript

import { z } from "zod";

const moneyJsonSchema = {
  type: "object",
  properties: {
    amount: { type: "string", description: "The numerical part of the amount." },
    currency: { type: "string", description: "The currency of amount." }
  },
  required: ["amount", "currency"]
};

const moneySchema = z.fromJSONSchema(moneyJsonSchema);

async function run() {
  const interaction = await ai.interactions.create({
    model: "gemini-3.8-flash",
    input: "What is the minimum hourly wage in Tokyo right now?",
    tools: [{
      type: "file_search",
      file_search_store_names: [fileSearchStore.name],
    }],
    response_format: {
      type: 'text',
      mime_type: 'application/json',
      schema: moneyJsonSchema
    },
  });

  const result = moneySchema.parse(JSON.parse(interaction.output_text));
  console.log(result);
}

run();

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.CreateModelInteractionResponseFormat;
import com.google.genai.gaos.models.interactions.FileSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ResponseFormat;
import com.google.genai.gaos.models.interactions.TextResponseFormat;
import com.google.genai.gaos.models.interactions.TextResponseFormatMimeType;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

Client client = new Client();

Map<String, Object> properties = new HashMap<>();

Map<String, Object> amountProp = new HashMap<>();
amountProp.put("type", "string");
amountProp.put("description", "The numerical part of the amount.");
properties.put("amount", amountProp);

Map<String, Object> currencyProp = new HashMap<>();
currencyProp.put("type", "string");
currencyProp.put("description", "The currency of amount.");
properties.put("currency", currencyProp);

Map<String, Object> moneyJsonSchema = new HashMap<>();
moneyJsonSchema.put("type", "object");
moneyJsonSchema.put("properties", properties);
moneyJsonSchema.put("required", Arrays.asList("amount", "currency"));

CreateModelInteractionResponseFormat format =
    CreateModelInteractionResponseFormat.of(
        ResponseFormat.of(
            TextResponseFormat.builder()
                .mimeType(TextResponseFormatMimeType.APPLICATION_JSON)
                .schema(moneyJsonSchema)
                .build()));

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("What is the minimum hourly wage in Tokyo right now?"))
        .tools(
            Arrays.asList(
                FileSearch.builder()
                    .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123"))
                    .build()))
        .responseFormat(format)
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

System.out.println(interaction.outputText().orElse(""));

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

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

    moneyJsonSchema := map[string]any{
        "type": "object",
        "properties": map[string]any{
            "amount": map[string]any{
                "type":        "string",
                "description": "The numerical part of the amount.",
            },
            "currency": map[string]any{
                "type":        "string",
                "description": "The currency of amount.",
            },
        },
        "required": []string{"amount", "currency"},
    }

    format := interactions.NewCreateModelInteractionResponseFormat(
        interactions.NewResponseFormat(interactions.TextResponseFormat{
            MimeType: interactions.TextResponseFormatMimeTypeApplicationJSON.ToPointer(),
            Schema:   moneyJsonSchema,
        }),
    )

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("What is the minimum hourly wage in Tokyo right now?"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.FileSearch{
                        FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"},
                    }),
                },
                ResponseFormat: &format,
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.Interaction.GetOutputText())
}

REST

curl "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H 'Content-Type: application/json' \
  -X POST \
  -d '{
    "model": "gemini-3.8-flash",
    "input": "What is the minimum hourly wage in Tokyo right now?",
    "tools": [{
      "type": "file_search",
      "file_search_store_names": ["$FILE_SEARCH_STORE_NAME"]
    }],
    "response_format": {
      "type": "text",
      "mime_type": "application/json",
      "schema": {
        "type": "object",
        "properties": {
          "amount": {"type": "string", "description": "The numerical part of the amount."},
          "currency": {"type": "string", "description": "The currency of amount."}
        },
        "required": ["amount", "currency"]
      }
    }
  }'

지원 모델

다음 모델이 File Search를 지원해요.

모델 File Search
Gemini 3.8 Flash ✔️
Gemini 3.7 Flash ✔️
Gemini 3.6 Flash ✔️
Gemini 3.5 Flash-Lite ✔️
Gemini 3.5 Flash ✔️
Gemini 3.1 Pro Preview ✔️
Gemini 3.1 Flash-Lite ✔️
Gemini 3 Flash Preview ✔️

지원 파일 유형

File Search는 다음 섹션에 나열된 광범위한 파일 형식을 지원해요.

응용 프로그램 파일 유형

  • application/dart
  • application/ecmascript
  • application/json
  • application/ms-java
  • application/msword
  • application/pdf
  • application/sql
  • application/typescript
  • application/vnd.curl
  • application/vnd.dart
  • application/vnd.ibm.secure-container
  • application/vnd.jupyter
  • application/vnd.ms-excel
  • application/vnd.oasis.opendocument.text
  • application/vnd.openxmlformats-officedocument.presentationml.presentation
  • application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • application/vnd.openxmlformats-officedocument.wordprocessingml.document
  • application/vnd.openxmlformats-officedocument.wordprocessingml.template
  • application/x-csh
  • application/x-hwp
  • application/x-hwp-v5
  • application/x-latex
  • application/x-php
  • application/x-powershell
  • application/x-sh
  • application/x-shellscript
  • application/x-tex
  • application/x-zsh
  • application/xml
  • application/zip

텍스트 파일 유형

  • text/1d-interleaved-parityfec
  • text/RED
  • text/SGML
  • text/cache-manifest
  • text/calendar
  • text/cql
  • text/cql-extension
  • text/cql-identifier
  • text/css
  • text/csv
  • text/csv-schema
  • text/dns
  • text/encaprtp
  • text/enriched
  • text/example
  • text/fhirpath
  • text/flexfec
  • text/fwdred
  • text/gff3
  • text/grammar-ref-list
  • text/hl7v2
  • text/html
  • text/javascript
  • text/jcr-cnd
  • text/jsx
  • text/markdown
  • text/mizar
  • text/n3
  • text/parameters
  • text/parityfec
  • text/php
  • text/plain
  • text/provenance-notation
  • text/prs.fallenstein.rst
  • text/prs.lines.tag
  • text/prs.prop.logic
  • text/raptorfec
  • text/rfc822-headers
  • text/rtf
  • text/rtp-enc-aescm128
  • text/rtploopback
  • text/rtx
  • text/sgml
  • text/shaclc
  • text/shex
  • text/spdx
  • text/strings
  • text/t140
  • text/tab-separated-values
  • text/texmacs
  • text/troff
  • text/tsv
  • text/tsx
  • text/turtle
  • text/ulpfec
  • text/uri-list
  • text/vcard
  • text/vnd.DMClientScript
  • text/vnd.IPTC.NITF
  • text/vnd.IPTC.NewsML
  • text/vnd.a
  • text/vnd.abc
  • text/vnd.ascii-art
  • text/vnd.curl
  • text/vnd.debian.copyright
  • text/vnd.dvb.subtitle
  • text/vnd.esmertec.theme-descriptor
  • text/vnd.exchangeable
  • text/vnd.familysearch.gedcom
  • text/vnd.ficlab.flt
  • text/vnd.fly
  • text/vnd.fmi.flexstor
  • text/vnd.gml
  • text/vnd.graphviz
  • text/vnd.hans
  • text/vnd.hgl
  • text/vnd.in3d.3dml
  • text/vnd.in3d.spot
  • text/vnd.latex-z
  • text/vnd.motorola.reflex
  • text/vnd.ms-mediapackage
  • text/vnd.net2phone.commcenter.command
  • text/vnd.radisys.msml-basic-layout
  • text/vnd.senx.warpscript
  • text/vnd.sosi
  • text/vnd.sun.j2me.app-descriptor
  • text/vnd.trolltech.linguist
  • text/vnd.wap.si
  • text/vnd.wap.sl
  • text/vnd.wap.wml
  • text/vnd.wap.wmlscript
  • text/vtt
  • text/wgsl
  • text/x-asm
  • text/x-bibtex
  • text/x-boo
  • text/x-c
  • text/x-c++hdr
  • text/x-c++src
  • text/x-cassandra
  • text/x-chdr
  • text/x-coffeescript
  • text/x-component
  • text/x-csh
  • text/x-csharp
  • text/x-csrc
  • text/x-cuda
  • text/x-d
  • text/x-diff
  • text/x-dsrc
  • text/x-emacs-lisp
  • text/x-erlang
  • text/x-gff3
  • text/x-go
  • text/x-haskell
  • text/x-java
  • text/x-java-properties
  • text/x-java-source
  • text/x-kotlin
  • text/x-lilypond
  • text/x-lisp
  • text/x-literate-haskell
  • text/x-lua
  • text/x-moc
  • text/x-objcsrc
  • text/x-pascal
  • text/x-pcs-gcd
  • text/x-perl
  • text/x-perl-script
  • text/x-python
  • text/x-python-script
  • text/x-r-markdown
  • text/x-rsrc
  • text/x-rst
  • text/x-ruby-script
  • text/x-rust
  • text/x-sass
  • text/x-scala
  • text/x-scheme
  • text/x-script.python
  • text/x-scss
  • text/x-setext
  • text/x-sfv
  • text/x-sh
  • text/x-siesta
  • text/x-sos
  • text/x-sql
  • text/x-swift
  • text/x-tcl
  • text/x-tex
  • text/x-vbasic
  • text/x-vcalendar
  • text/xml
  • text/xml-dtd
  • text/xml-external-parsed-entity
  • text/yaml

제한 사항

  • Live API: File Search는 Live API에서 지원되지 않아요.
  • 도구 비호환성: 내장 그라운딩 도구는 서로 결합할 수 없어요. 예를 들어 File Search는 같은 요청에서 Google Search 그라운딩이나 URL Context와 동시에 사용할 수 없어요.

속도 제한

File Search API에는 서비스 안정성을 유지하기 위한 다음 제한이 있어요.

  • 최대 파일 크기/문서당 제한: 100 MB
  • 프로젝트 File Search 스토어 총 크기(사용자 티어 기준):
    • Free: 1 GB
    • Tier 1: 10 GB
    • Tier 2: 100 GB
    • Tier 3: 1 TB
  • 권장 사항: 최적의 검색 지연 시간을 보장하려면 각 File Search 스토어의 크기를 20 GB 미만으로 제한하세요.

참고: File Search 스토어 크기 제한은 입력 크기에 그와 함께 생성·저장되는 임베딩을 더한 값을 기준으로 백엔드에서 계산돼요. 이는 일반적으로 입력 데이터 크기의 약 3배예요.

가격

  • 임베딩은 인덱싱 시점에 기존 embeddings 가격에 따라 청구돼요.
  • 저장 공간은 무료예요.
  • 쿼리 시점 임베딩은 무료예요.
  • 검색된 문서 토큰은 일반 context 토큰으로 청구돼요.

다음 단계

더 알아보기 (Learn more)

File Search 도구는 문서를 임베딩·청크·인덱싱해 의미 검색으로 관련 정보를 빠르게 찾아내는 RAG를 구현할 수 있게 해 줘요. gemini-embedding-001(텍스트)과 gemini-embedding-2(멀티모달) 임베딩을 지원하며, 저장·쿼리 임베딩은 무료예요. embeddings, pricing, tokens 문서를 이어서 살펴보세요.