Tryb zbiorczy

Tryb zbiorczy interfejsu Gemini API został zaprojektowany do asynchronicznego przetwarzania dużych ilości żądań przy 50% standardowego kosztu. Docelowy czas realizacji to 24 godziny, ale w większości przypadków jest on znacznie krótszy.

Tryb wsadowy jest przeznaczony do zadań na dużą skalę, które nie wymagają natychmiastowej odpowiedzi, takich jak wstępne przetwarzanie danych czy przeprowadzanie ocen.

Tworzenie zadania wsadowego

Prośby w trybie wsadowym możesz przesyłać na 2 sposoby:

  • Żądania wbudowane: lista obiektów GenerateContentRequest bezpośrednio uwzględnionych w żądaniu tworzenia pakietowego. Jest to odpowiednie rozwiązanie w przypadku mniejszych partii, w których łączny rozmiar żądania nie przekracza 20 MB. Dane wyjściowe zwracane przez model to lista inlineResponse obiektów.
  • Plik wejściowy: plik JSON Lines (JSONL), w którym każdy wiersz zawiera kompletny obiekt GenerateContentRequest. Ta metoda jest zalecana w przypadku większych żądań. Dane wyjściowe zwracane przez model to plik JSONL, w którym każdy wiersz jest obiektem GenerateContentResponse lub obiektem stanu.

Żądania w tekście

W przypadku niewielkiej liczby żądań możesz bezpośrednio osadzić obiekty GenerateContentRequest w swoim BatchGenerateContentRequest. W tym przykładzie wywoływana jest metoda BatchGenerateContent z żądaniami wbudowanymi:

Python


from google import genai
from google.genai import types

client = genai.Client()

# A list of dictionaries, where each is a GenerateContentRequest
inline_requests = [
    {
        'contents': [{
            'parts': [{'text': 'Tell me a one-sentence joke.'}],
            'role': 'user'
        }]
    },
    {
        'contents': [{
            'parts': [{'text': 'Why is the sky blue?'}],
            'role': 'user'
        }]
    }
]

inline_batch_job = client.batches.create(
    model="models/gemini-2.5-flash",
    src=inline_requests,
    config={
        'display_name': "inlined-requests-job-1",
    },
)

print(f"Created batch job: {inline_batch_job.name}")

REST

curl https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:batchGenerateContent \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-X POST \
-H "Content-Type:application/json" \
-d '{
    "batch": {
        "display_name": "my-batch-requests",
        "input_config": {
            "requests": {
                "requests": [
                    {
                        "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]},
                        "metadata": {
                            "key": "request-1"
                        }
                    },
                    {
                        "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]},
                        "metadata": {
                            "key": "request-2"
                        }
                    }
                ]
            }
        }
    }
}'

Możesz używać wszystkich żądań, których używasz w trybie niebatchowym (lub interaktywnym). Możesz na przykład określić temperaturę, instrukcje systemowe, a nawet przekazać inne rodzaje danych. Poniżej znajdziesz przykładowe żądania wbudowane, które zawierają instrukcję systemową dla jednego z nich:

inline_requests_list = [
    {'contents': [{'parts': [{'text': 'Write a short poem about a cloud.'}]}]},
    {'contents': [{'parts': [{'text': 'Write a short poem about a cat.'}]}], 'system_instructions': {'parts': [{'text': 'You are a cat. Your name is Neko.'}]}}
]

Podobnie możesz też określić narzędzia, których chcesz użyć w przypadku żądania. Poniższy przykład przedstawia żądanie, które włącza narzędzie wyszukiwarki Google:

inline_requests_list = [
    {'contents': [{'parts': [{'text': 'Who won the euro 1998?'}]}]},
    {'contents': [{'parts': [{'text': 'Who won the euro 2025?'}]}], 'tools': [{'google_search ': {}}]}
]

Plik wejściowy

W przypadku większych zestawów żądań przygotuj plik JSON Lines (JSONL). Każdy wiersz w tym pliku musi być obiektem JSON zawierającym zdefiniowany przez użytkownika klucz i obiekt żądania, gdzie żądanie jest prawidłowym obiektem GenerateContentRequest. Klucz zdefiniowany przez użytkownika jest używany w odpowiedzi, aby wskazać, które dane wyjściowe są wynikiem którego żądania. Na przykład żądanie z kluczem zdefiniowanym jako request-1 będzie miało odpowiedź opatrzoną tą samą nazwą klucza.

Ten plik jest przesyłany za pomocą interfejsu File API. Maksymalny rozmiar pliku wejściowego to 2 GB.

Poniżej znajdziesz przykład pliku JSONL. Możesz go zapisać w pliku o nazwie:my-batch-requests.json

{"key": "request-1", "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}], "generation_config": {"temperature": 0.7}}}
{"key": "request-2", "request": {"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}}

Podobnie jak w przypadku żądań wbudowanych, w każdym żądaniu JSON możesz określić inne parametry, takie jak instrukcje systemowe, narzędzia lub inne konfiguracje.

Możesz przesłać ten plik za pomocą interfejsu File API, jak pokazano w tym przykładzie. Jeśli pracujesz z danymi wejściowymi multimodalnymi, możesz odwoływać się do innych przesłanych plików w pliku JSONL.

Python


from google import genai
from google.genai import types

client = genai.Client()

# Create a sample JSONL file
with open("my-batch-requests.jsonl", "w") as f:
    requests = [
        {"key": "request-1", "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]}},
        {"key": "request-2", "request": {"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}}
    ]
    for req in requests:
        f.write(json.dumps(req) + "\n")

# Upload the file to the File API
uploaded_file = client.files.upload(
    file='my-batch-requests.jsonl',
    config=types.UploadFileConfig(display_name='my-batch-requests', mime_type='jsonl')
)

print(f"Uploaded file: {uploaded_file.name}")

REST

tmp_batch_input_file=batch_input.tmp
echo -e '{"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}], "generationConfig": {"temperature": 0.7}}\n{"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}' > batch_input.tmp
MIME_TYPE=$(file -b --mime-type "${tmp_batch_input_file}")
NUM_BYTES=$(wc -c < "${tmp_batch_input_file}")
DISPLAY_NAME=BatchInput

tmp_header_file=upload-header.tmp

# Initial resumable request defining metadata.
# The upload url is in the response headers dump them to a file.
curl "https://generativelanguage.googleapis.com/upload/v1beta/files \
-D "${tmp_header_file}" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-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: ${MIME_TYPE}" \
-H "Content-Type: application/jsonl" \
-d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null

upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file}"

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

file_uri=$(jq ".file.uri" file_info.json)

W tym przykładzie wywoływana jest metoda BatchGenerateContent z plikiem wejściowym przesłanym za pomocą interfejsu File API:

Python


# Assumes `uploaded_file` is the file object from the previous step
file_batch_job = client.batches.create(
    model="gemini-2.5-flash",
    src=uploaded_file.name,
    config={
        'display_name': "file-upload-job-1",
    },
)

print(f"Created batch job: {file_batch_job.name}")

REST

BATCH_INPUT_FILE='files/123456' # File ID
curl https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:batchGenerateContent \
-X POST \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type:application/json" \
-d "{
    'batch': {
        'display_name': 'my-batch-requests',
        'input_config': {
            'requests': {
                'file_name': ${BATCH_INPUT_FILE}
            }
        }
    }
}"

Po utworzeniu zadania zbiorczego otrzymasz jego nazwę. Użyj tej nazwy do monitorowania stanu zadania, a także do pobierania wyników po jego zakończeniu.

Oto przykładowe dane wyjściowe zawierające nazwę zadania:


Created batch job from file: batches/123456789

Sprawdzanie stanu zadania monitorowania

Aby sprawdzić stan zadania wsadowego, użyj nazwy operacji uzyskanej podczas jego tworzenia. Pole stanu zadania wsadowego będzie wskazywać jego bieżący stan. Zadanie wsadowe może mieć jeden z tych stanów:

  • JOB_STATE_PENDING: zadanie zostało utworzone i oczekuje na przetworzenie przez usługę.
  • JOB_STATE_SUCCEEDED: zadanie zostało wykonane. Możesz teraz pobrać wyniki.
  • JOB_STATE_FAILED: zadanie nie powiodło się. Więcej informacji znajdziesz w szczegółach błędu.
  • JOB_STATE_CANCELLED: zadanie zostało anulowane przez użytkownika.

Możesz okresowo sprawdzać stan zadania, aby dowiedzieć się, czy zostało ukończone.

Python


# Use the name of the job you want to check
# e.g., inline_batch_job.name from the previous step
job_name = "YOUR_BATCH_JOB_NAME"  # (e.g. 'batches/your-batch-id')
batch_job = client.batches.get(name=job_name)

completed_states = set([
    'JOB_STATE_SUCCEEDED',
    'JOB_STATE_FAILED',
    'JOB_STATE_CANCELLED',
])

print(f"Polling status for job: {job_name}")
batch_job = client.batches.get(name=job_name) # Initial get
while batch_job.state.name not in completed_states:
  print(f"Current state: {batch_job.state.name}")
  time.sleep(30) # Wait for 30 seconds before polling again
  batch_job = client.batches.get(name=job_name)

print(f"Job finished with state: {batch_job.state.name}")
if batch_job.state.name == 'JOB_STATE_FAILED':
    print(f"Error: {batch_job.error}")

Pobieranie wyników

Gdy stan zadania wskazuje, że zadanie wsadowe zostało wykonane, wyniki są dostępne w polu response.

Python

import json

# Use the name of the job you want to check
# e.g., inline_batch_job.name from the previous step
job_name = "YOUR_BATCH_JOB_NAME"
batch_job = client.batches.get(name=job_name)

if batch_job.state.name == 'JOB_STATE_SUCCEEDED':

    # If batch job was created with a file
    if batch_job.dest and batch_job.dest.file_name:
        # Results are in a file
        result_file_name = batch_job.dest.file_name
        print(f"Results are in file: {result_file_name}")

        print("Downloading result file content...")
        file_content = client.files.download(file=result_file_name)
        # Process file_content (bytes) as needed
        print(file_content.decode('utf-8'))

    # If batch job was created with inline request
    elif batch_job.dest and batch_job.dest.inlined_responses:
        # Results are inline
        print("Results are inline:")
        for i, inline_response in enumerate(batch_job.dest.inlined_responses):
            print(f"Response {i+1}:")
            if inline_response.response:
                # Accessing response, structure may vary.
                try:
                    print(inline_response.response.text)
                except AttributeError:
                    print(inline_response.response) # Fallback
            elif inline_response.error:
                print(f"Error: {inline_response.error}")
    else:
        print("No results found (neither file nor inline).")
else:
    print(f"Job did not succeed. Final state: {batch_job.state.name}")
    if batch_job.error:
        print(f"Error: {batch_job.error}")

REST

BATCH_NAME="batches/123456" # Your batch job name

curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type:application/json" 2> /dev/null > batch_status.json

if jq -r '.done' batch_status.json | grep -q "false"; then
    echo "Batch has not finished processing"
fi

batch_state=$(jq -r '.metadata.state' batch_status.json)
if [[ $batch_state = "JOB_STATE_SUCCEEDED" ]]; then
    if [[ $(jq '.response | has("inlinedResponses")' batch_status.json) = "true" ]]; then
        jq -r '.response.inlinedResponses' batch_status.json
        exit
    fi
    responses_file_name=$(jq -r '.response.responsesFile' batch_status.json)
    curl https://generativelanguage.googleapis.com/download/v1beta/$responses_file_name:download?alt=media \
    -H "x-goog-api-key: $GEMINI_API_KEY" 2> /dev/null
elif [[ $batch_state = "JOB_STATE_FAILED" ]]; then
    jq '.error' batch_status.json
elif [[ $batch_state == "JOB_STATE_CANCELLED" ]]; then
    echo "Batch was cancelled by the user"
fi

Anulowanie zadania wsadowego

Trwające zadanie wsadowe możesz anulować, używając jego nazwy. Gdy zadanie zostanie anulowane, przestanie przetwarzać nowe żądania.

Python

# Cancel a batch job
client.batches.cancel(name=batch_job_to_cancel.name)

REST

BATCH_NAME="batches/123456" # Your batch job name

# Cancel the batch
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME:cancel \
-H "x-goog-api-key: $GEMINI_API_KEY" \

# Confirm that the status of the batch after cancellation is JOB_STATE_CANCELLED
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type:application/json" 2> /dev/null | jq -r '.metadata.state'

Usuwanie zadania wsadowego

Istniejące zadanie wsadowe możesz usunąć, podając jego nazwę. Gdy zadanie zostanie usunięte, przestanie przetwarzać nowe żądania i zostanie usunięte z listy zadań wsadowych.

Python

# Delete a batch job
client.batches.delete(name=batch_job_to_delete.name)

REST

BATCH_NAME="batches/123456" # Your batch job name

# Cancel the batch
curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME:delete \
-H "x-goog-api-key: $GEMINI_API_KEY" \

Szczegóły techniczne

  • Obsługiwane modele: tryb wsadowy obsługuje różne modele Gemini. Najnowszą listę zgodnych modeli znajdziesz na stronie z modelami. Obsługiwane tryby w przypadku trybu wsadowego są takie same jak w przypadku interaktywnego interfejsu API (czyli trybu innego niż wsadowy).
  • Ceny: korzystanie z trybu wsadowego kosztuje 50% standardowej ceny interaktywnego interfejsu API dla danego modelu.
  • Docelowy poziom usług: zadania wsadowe są zaprojektowane tak, aby można było je wykonać w ciągu 24 godzin. Wiele zadań może zostać wykonanych znacznie szybciej, w zależności od ich rozmiaru i bieżącego obciążenia systemu.
  • Buforowanie: w przypadku żądań zbiorczych włączone jest buforowanie kontekstu. Jeśli żądanie w partii spowoduje trafienie w pamięci podręcznej, tokeny z pamięci podręcznej będą kosztować tyle samo co w przypadku ruchu w trybie bez partii.

Sprawdzone metody

  • W przypadku dużych żądań używaj plików wejściowych: w przypadku dużej liczby żądań zawsze używaj metody wprowadzania plików, aby ułatwić zarządzanie i uniknąć przekroczenia limitów rozmiaru żądań dla samego wywołania BatchGenerateContent. Pamiętaj, że maksymalny rozmiar pliku wejściowego to 2 GB.
  • Obsługa błędów: po zakończeniu zadania sprawdź batchStats pod kątem failedRequestCount. Jeśli używasz danych wyjściowych w postaci pliku, przeanalizuj każdy wiersz, aby sprawdzić, czy jest to GenerateContentResponse, czy obiekt stanu wskazujący błąd w przypadku konkretnego żądania.
  • Przesyłaj zadania tylko raz: tworzenie zadania wsadowego nie jest idempotentne. Jeśli wyślesz to samo żądanie utworzenia 2 razy, utworzone zostaną 2 osobne zadania wsadowe.
  • Dziel duże partie: docelowy czas realizacji to 24 godziny, ale rzeczywisty czas przetwarzania może się różnić w zależności od obciążenia systemu i rozmiaru zadania. W przypadku dużych zadań rozważ podzielenie ich na mniejsze partie, jeśli wyniki pośrednie są potrzebne wcześniej.

Co dalej?

Więcej przykładów znajdziesz w notatniku trybu wsadowego.