Понимать и считать жетоны

Gemini и другие модели генеративного ИИ обрабатывают входные и выходные данные с уровнем детализации, называемым токеном .

Для моделей Gemini один токен эквивалентен примерно 4 символам. 100 токенов равны примерно 60-80 английским словам.

О токенах

Токены могут представлять собой отдельные символы, например, z или целые слова, например, cat . Длинные слова разбиваются на несколько токенов. Множество всех токенов, используемых моделью, называется словарем, а процесс разделения текста на токены называется токенизацией .

При включенной плате за использование API Gemini стоимость вызова определяется, в частности, количеством входных и выходных токенов, поэтому знание того, как подсчитывать токены, может быть полезным.

Вы можете попробовать подсчитать токены в нашем Colab.

Посмотреть на ai.google.dev Попробуйте блокнот Colab. Посмотреть блокнот на GitHub

Подсчет токенов

Все входные и выходные данные API Gemini, включая текст, файлы изображений и другие нетекстовые форматы, токенизируются.

Подсчет токенов можно производить следующими способами:

  • Вызовите функцию count_tokens , передав ей входные данные запроса.
    Эта функция возвращает только общее количество токенов во входных данных . Вы можете вызвать её перед отправкой входных данных в модель, чтобы проверить размер ваших запросов.

  • После вызова функции generate_content используйте атрибут usage_metadata объекта response .
    Эта функция возвращает общее количество токенов как на входе, так и на выходе : total_token_count .
    Также он возвращает количество токенов на входе и выходе отдельно: prompt_token_count (токены на входе) и candidates_token_count (токены на выходе).

    Если вы используете модель мышления , токены, использованные в процессе мышления, возвращаются в thoughts_token_count . А если вы используете контекстное кэширование , количество кэшированных токенов будет в cached_content_token_count .

Подсчет текстовых токенов

Если вы вызовете функцию count_tokens с текстовым полем ввода, она вернет количество токенов только из текста в этом поле ( total_tokens ). Вы можете сделать этот вызов перед вызовом generate_content , чтобы проверить размер ваших запросов.

Другой вариант — вызвать функцию generate_content , а затем использовать атрибут usage_metadata объекта response , чтобы получить следующее:

  • Отдельные подсчеты токенов для входных данных ( prompt_token_count ), кэшированного содержимого ( cached_content_token_count ) и выходных данных ( candidates_token_count ).
  • Количество токенов, используемых в процессе мышления ( thoughts_token_count )
  • Общее количество токенов как на входе, так и на выходе ( total_token_count )

Python

from google import genai

client = genai.Client()
prompt = "The quick brown fox jumps over the lazy dog."

total_tokens = client.models.count_tokens(
    model="gemini-3.5-flash", contents=prompt
)
print("total_tokens: ", total_tokens)

response = client.models.generate_content(
    model="gemini-3.5-flash", contents=prompt
)

print(response.usage_metadata)

JavaScript

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

const ai = new GoogleGenAI({});
const prompt = "The quick brown fox jumps over the lazy dog.";

async function main() {
  const countTokensResponse = await ai.models.countTokens({
    model: "gemini-3.5-flash",
    contents: prompt,
  });
  console.log(countTokensResponse.totalTokens);

  const generateResponse = await ai.models.generateContent({
    model: "gemini-3.5-flash",
    contents: prompt,
  });
  console.log(generateResponse.usageMetadata);
}

await main();

Идти

ctx := context.Background()
client, err := genai.NewClient(ctx, nil)

// Convert prompt to a slice of *genai.Content using the helper.
contents := []*genai.Content{
  genai.NewContentFromText(prompt, genai.RoleUser),
}
countResp, err := client.Models.CountTokens(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  return err
}
fmt.Println("total_tokens:", countResp.TotalTokens)

response, err := client.Models.GenerateContent(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")
if err != nil {
  log.Fatal(err)
}
fmt.Println(string(usageMetadata))
    ```

Подсчет токенов для многоходовых (чат) операций

Если вы вызовете count_tokens используя историю чата, она вернет общее количество токенов текста от каждой роли в чате ( total_tokens ).

Другой вариант — вызвать функцию send_message , а затем использовать атрибут usage_metadata объекта response , чтобы получить следующее:

  • Отдельные подсчеты токенов для входных данных ( prompt_token_count ), кэшированного содержимого ( cached_content_token_count ) и выходных данных ( candidates_token_count ).
  • Количество токенов, используемых в процессе мышления ( thoughts_token_count )
  • Общее количество токенов как на входе, так и на выходе ( total_token_count )

Чтобы понять, насколько значимым будет ваш следующий диалог, необходимо добавить его в историю при вызове функции count_tokens .

Python

from google import genai
from google.genai import types

client = genai.Client()

chat = client.chats.create(
    model="gemini-3.5-flash",
    history=[
        types.Content(
            role="user", parts=[types.Part(text="Hi my name is Bob")]
        ),
        types.Content(role="model", parts=[types.Part(text="Hi Bob!")]),
    ],
)

print(
    client.models.count_tokens(
        model="gemini-3.5-flash", contents=chat.get_history()
    )
)

response = chat.send_message(
    message="In one sentence, explain how a computer works to a young child."
)
print(response.usage_metadata)

extra = types.UserContent(
    parts=[
        types.Part(
            text="What is the meaning of life?",
        )
    ]
)
history = [*chat.get_history(), extra]
print(client.models.count_tokens(model="gemini-3.5-flash", contents=history))

JavaScript

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

const ai = new GoogleGenAI({});

async function main() {
  const history = [
    { role: "user", parts: [{ text: "Hi my name is Bob" }] },
    { role: "model", parts: [{ text: "Hi Bob!" }] },
  ];
  const chat = ai.chats.create({
    model: "gemini-3.5-flash",
    history: history,
  });

  const countTokensResponse = await ai.models.countTokens({
    model: "gemini-3.5-flash",
    contents: chat.getHistory(),
  });
  console.log(countTokensResponse.totalTokens);

  const chatResponse = await chat.sendMessage({
    message: "In one sentence, explain how a computer works to a young child.",
  });
  console.log(chatResponse.usageMetadata);

  const extraMessage = {
    role: "user",
    parts: [{ text: "What is the meaning of life?" }],
  };
  const combinedHistory = [...chat.getHistory(), extraMessage];
  const combinedCountTokensResponse = await ai.models.countTokens({
    model: "gemini-3.5-flash",
    contents: combinedHistory,
  });
  console.log(
    "Combined history token count:",
    combinedCountTokensResponse.totalTokens,
  );
}

await main();

Идти

ctx := context.Background()
client, err := genai.NewClient(ctx, nil)

history := []*genai.Content{
  {Role: genai.RoleUser, Parts: []*genai.Part({Text: "Hi my name is Bob"})},
  {Role: genai.RoleModel, Parts: []*genai.Part({Text: "Hi Bob!"})},
}
chat, err := client.Chats.Create(ctx, "gemini-3.5-flash", nil, history)
if err != nil {
  log.Fatal(err)
}

firstTokenResp, err := client.Models.CountTokens(ctx, "gemini-3.5-flash", chat.History(false), nil)
if err != nil {
  log.Fatal(err)
}
fmt.Println(firstTokenResp.TotalTokens)

resp, err := chat.SendMessage(ctx, genai.NewPartFromText("In one sentence, explain how a computer works to a young child."))
if err != nil {
  log.Fatal(err)
}
fmt.Printf("%#v\n", resp.UsageMetadata)

extra := genai.NewContentFromText("What is the meaning of life?", genai.RoleUser)
hist := chat.History(false)
hist = append(hist, extra)

secondTokenResp, err := client.Models.CountTokens(ctx, "gemini-3.5-flash", hist, nil)
if err != nil {
  log.Fatal(err)
}
fmt.Println(secondTokenResp.TotalTokens)

Подсчет мультимодальных токенов

Все входные данные в API Gemini токенизируются, включая текст, файлы изображений и другие нетекстовые форматы. Обратите внимание на следующие основные моменты, касающиеся токенизации мультимодальных входных данных в процессе обработки API Gemini:

  • Изображения, у которых оба измерения <=384 пикселей, учитываются как 258 токенов. Изображения большего размера в одном или обоих измерениях обрезаются и масштабируются по мере необходимости в фрагменты размером 768x768 пикселей, каждый из которых учитывается как 258 токенов.

  • Видео- и аудиофайлы преобразуются в токены со следующей фиксированной скоростью: видео — 263 токена в секунду, аудио — 32 токена в секунду.

Резолюции СМИ

В моделях Gemini 3 реализован детальный контроль над обработкой мультимодального зрения с помощью параметра media_resolution . Параметр media_resolution определяет максимальное количество токенов, выделяемых на каждое входное изображение или видеокадр. Более высокое разрешение улучшает способность модели считывать мелкий текст или идентифицировать мелкие детали, но увеличивает использование токенов и задержку.

Для получения более подробной информации о параметре и о том, как он может влиять на вычисления токенов, см. руководство по разрешению медиаконтента .

Файлы изображений

Если вы вызываете count_tokens с текстовым и графическим входным файлом, она возвращает суммарное количество токенов только для текста и изображения во входном файле ( total_tokens ). Вы можете вызвать эту функцию перед вызовом generate_content , чтобы проверить размер ваших запросов. Вы также можете дополнительно вызвать count_tokens отдельно для текста и файла.

Другой вариант — вызвать функцию generate_content , а затем использовать атрибут usage_metadata объекта response , чтобы получить следующее:

  • Отдельные подсчеты токенов для входных данных ( prompt_token_count ), кэшированного содержимого ( cached_content_token_count ) и выходных данных ( candidates_token_count ).
  • Количество токенов, используемых в процессе мышления ( thoughts_token_count )
  • Общее количество токенов как на входе, так и на выходе ( total_token_count )

Пример использования загруженного изображения через File API:

Python

from google import genai

client = genai.Client()
prompt = "Tell me about this image"
your_image_file = client.files.upload(file=media / "organ.jpg")

print(
    client.models.count_tokens(
        model="gemini-3.5-flash", contents=[prompt, your_image_file]
    )
)

response = client.models.generate_content(
    model="gemini-3.5-flash", contents=[prompt, your_image_file]
)
print(response.usage_metadata)

JavaScript

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

const ai = new GoogleGenAI({});
const prompt = "Tell me about this image";

async function main() {
  const organ = await ai.files.upload({
    file: path.join(media, "organ.jpg"),
    config: { mimeType: "image/jpeg" },
  });

  const countTokensResponse = await ai.models.countTokens({
    model: "gemini-3.5-flash",
    contents: createUserContent([
      prompt,
      createPartFromUri(organ.uri, organ.mimeType),
    ]),
  });
  console.log(countTokensResponse.totalTokens);

  const generateResponse = await ai.models.generateContent({
    model: "gemini-3.5-flash",
    contents: createUserContent([
      prompt,
      createPartFromUri(organ.uri, organ.mimeType),
    ]),
  });
  console.log(generateResponse.usageMetadata);
}

await main();

Идти

ctx := context.Background()
client, err := genai.NewClient(ctx, nil)

file, err := client.Files.UploadFromPath(
  ctx, 
  filepath.Join(getMedia(), "organ.jpg"), 
  &genai.UploadFileConfig{
    MIMEType : "image/jpeg",
  },
)
if err != nil {
  log.Fatal(err)
}
parts := []*genai.Part{
  genai.NewPartFromText("Tell me about this image"),
  genai.NewPartFromURI(file.URI, file.MIMEType),
}
contents := []*genai.Content{
  genai.NewContentFromParts(parts, genai.RoleUser),
}

tokenResp, err := client.Models.CountTokens(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
fmt.Println("Multimodal image token count:", tokenResp.TotalTokens)

response, err := client.Models.GenerateContent(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")
if err != nil {
  log.Fatal(err)
}
fmt.Println(string(usageMetadata))

Пример, предоставляющий изображение в виде встроенных данных:

Python

from google import genai
import PIL.Image

client = genai.Client()
prompt = "Tell me about this image"
your_image_file = PIL.Image.open(media / "organ.jpg")

print(
    client.models.count_tokens(
        model="gemini-3.5-flash", contents=[prompt, your_image_file]
    )
)

response = client.models.generate_content(
    model="gemini-3.5-flash", contents=[prompt, your_image_file]
)
print(response.usage_metadata)

JavaScript

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

const ai = new GoogleGenAI({});
const prompt = "Tell me about this image";
const imageBuffer = fs.readFileSync(path.join(media, "organ.jpg"));

const imageBase64 = imageBuffer.toString("base64");

const contents = createUserContent([
  prompt,
  createPartFromBase64(imageBase64, "image/jpeg"),
]);

async function main() {
  const countTokensResponse = await ai.models.countTokens({
    model: "gemini-3.5-flash",
    contents: contents,
  });
  console.log(countTokensResponse.totalTokens);

  const generateResponse = await ai.models.generateContent({
    model: "gemini-3.5-flash",
    contents: contents,
  });
  console.log(generateResponse.usageMetadata);
}

await main();

Идти

ctx := context.Background()
client, err := genai.NewClient(ctx, nil)

imageBytes, err := os.ReadFile("organ.jpg")
if err != nil {
    log.Fatalf("Failed to read image file: %v", err)
}
parts := []*genai.Part{
  genai.NewPartFromText("Tell me about this image"),
  {
        InlineData: &genai.Blob{
              MIMEType: "image/jpeg",
              Data:     imageBytes,
        },
  },
}
contents := []*genai.Content{
  genai.NewContentFromParts(parts, genai.RoleUser),
}

tokenResp, err := client.Models.CountTokens(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
fmt.Println("Multimodal image token count:", tokenResp.TotalTokens)

response, err := client.Models.GenerateContent(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")
if err != nil {
  log.Fatal(err)
}
fmt.Println(string(usageMetadata))

Видео- или аудиофайлы

Аудио- и видеоматериалы конвертируются в токены по следующим фиксированным курсам:

  • Видео: 263 токена в секунду
  • Аудио: 32 токена в секунду

Если вы вызываете count_tokens с текстовым и видео/аудио входными данными, она возвращает суммарное количество токенов только для текста и видео/аудиофайла во входных данных ( total_tokens ). Вы можете вызвать эту функцию перед вызовом generate_content , чтобы проверить размер ваших запросов. Вы также можете дополнительно вызвать count_tokens для текста и файла по отдельности.

Другой вариант — вызвать функцию generate_content , а затем использовать атрибут usage_metadata объекта response , чтобы получить следующее:

  • Отдельные подсчеты токенов для входных данных ( prompt_token_count ), кэшированного содержимого ( cached_content_token_count ) и выходных данных ( candidates_token_count ).
  • Количество токенов, используемых в процессе мышления ( thoughts_token_count )
  • Общее количество токенов как на входе, так и на выходе ( total_token_count ).

Python

from google import genai
import time

client = genai.Client()
prompt = "Tell me about this video"
your_file = client.files.upload(file=media / "Big_Buck_Bunny.mp4")

while not your_file.state or your_file.state.name != "ACTIVE":
    print("Processing video...")
    print("File state:", your_file.state)
    time.sleep(5)
    your_file = client.files.get(name=your_file.name)

print(
    client.models.count_tokens(
        model="gemini-3.5-flash", contents=[prompt, your_file]
    )
)

response = client.models.generate_content(
    model="gemini-3.5-flash", contents=[prompt, your_file]
)
print(response.usage_metadata)

JavaScript

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

const ai = new GoogleGenAI({});
const prompt = "Tell me about this video";

async function main() {
  let videoFile = await ai.files.upload({
    file: path.join(media, "Big_Buck_Bunny.mp4"),
    config: { mimeType: "video/mp4" },
  });

  while (!videoFile.state || videoFile.state.toString() !== "ACTIVE") {
    console.log("Processing video...");
    console.log("File state: ", videoFile.state);
    await sleep(5000);
    videoFile = await ai.files.get({ name: videoFile.name });
  }

  const countTokensResponse = await ai.models.countTokens({
    model: "gemini-3.5-flash",
    contents: createUserContent([
      prompt,
      createPartFromUri(videoFile.uri, videoFile.mimeType),
    ]),
  });
  console.log(countTokensResponse.totalTokens);

  const generateResponse = await ai.models.generateContent({
    model: "gemini-3.5-flash",
    contents: createUserContent([
      prompt,
      createPartFromUri(videoFile.uri, videoFile.mimeType),
    ]),
  });
  console.log(generateResponse.usageMetadata);
}

await main();

Идти

ctx := context.Background()
client, err := genai.NewClient(ctx, nil)

file, err := client.Files.UploadFromPath(
  ctx,
  filepath.Join(getMedia(), "Big_Buck_Bunny.mp4"),
  &genai.UploadFileConfig{
    MIMEType : "video/mp4",
  },
)
if err != nil {
  log.Fatal(err)
}

for file.State == genai.FileStateUnspecified || file.State != genai.FileStateActive {
  fmt.Println("Processing video...")
  fmt.Println("File state:", file.State)
  time.Sleep(5 * time.Second)

  file, err = client.Files.Get(ctx, file.Name, nil)
  if err != nil {
    log.Fatal(err)
  }
}

parts := []*genai.Part{
  genai.NewPartFromText("Tell me about this video"),
  genai.NewPartFromURI(file.URI, file.MIMEType),
}
contents := []*genai.Content{
  genai.NewContentFromParts(parts, genai.RoleUser),
}

tokenResp, err := client.Models.CountTokens(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
fmt.Println("Multimodal video/audio token count:", tokenResp.TotalTokens)
response, err := client.Models.GenerateContent(ctx, "gemini-3.5-flash", contents, nil)
if err != nil {
  log.Fatal(err)
}
usageMetadata, err := json.MarshalIndent(response.UsageMetadata, "", "  ")
if err != nil {
  log.Fatal(err)
}
fmt.Println(string(usageMetadata))

Подсчитайте количество жетонов мыслей

При включении функции «мышления» ценообразование ответа представляет собой сумму выходных токенов и токенов мышления. Общее количество сгенерированных токенов мышления можно получить из поля thoughtsTokenCount (или его эквивалента в SDK).

Python

# ...
print("Thoughts tokens:", response.usage_metadata.thoughts_token_count)
print("Output tokens:", response.usage_metadata.candidates_token_count)

JavaScript

// ...
console.log(`Thoughts tokens: ${response.usageMetadata.thoughtsTokenCount}`);
console.log(`Output tokens: ${response.usageMetadata.candidatesTokenCount}`);

Идти

// ...
fmt.Println("Thoughts tokens:", response.UsageMetadata.ThoughtsTokenCount)
fmt.Println("Output tokens:", response.UsageMetadata.CandidatesTokenCount)

Модели мышления генерируют полные мысли для повышения качества конечного ответа, а затем выдают сводки , позволяющие понять ход мысли. Таким образом, API основывает ценообразование на полных токенах мыслей, которые модель генерирует для создания сводки, даже несмотря на то, что API выдает только сводку.

Более подробную информацию о том, как настроить мышление, вы можете найти в руководстве по мышлению для Близнецов .

Контекстные окна

Модели, доступные через API Gemini, имеют контекстные окна, размер которых измеряется в токенах. Контекстное окно определяет, какой объем входных данных вы можете предоставить и какой объем выходных данных может сгенерировать модель. Размер контекстного окна можно определить, вызвав конечную точку models.get или обратившись к документации моделей .

Python

from google import genai

client = genai.Client()
model_info = client.models.get(model="gemini-3.5-flash")
print(f"{model_info.input_token_limit=}")
print(f"{model_info.output_token_limit=}")

JavaScript

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

const ai = new GoogleGenAI({});

async function main() {
  const modelInfo = await ai.models.get({model: 'gemini-3.5-flash'});
  console.log(modelInfo.inputTokenLimit);
  console.log(modelInfo.outputTokenLimit);
}

await main();

Идти

ctx := context.Background()
client, err := genai.NewClient(ctx, nil)
if err != nil {
  log.Fatal(err)
}
modelInfo, err := client.ModelInfo(ctx, "models/gemini-3.5-flash")
if err != nil {
  log.Fatal(err)
}
fmt.Println("input token limit:", modelInfo.InputTokenLimit)
fmt.Println("output token limit:", modelInfo.OutputTokenLimit)