了解词元并计算词元数量

Gemini 和其他生成式 AI 模型会以一种称为“token”的粒度处理输入和输出。

对于 Gemini 模型,一个 token 大致相当于 4 个字符。 100 个 token 大约相当于 60-80 个英文单词。

令牌简介

词元可以是单个字符(例如 z),也可以是整个字词(例如 cat)。长字词会被拆分为多个 token。模型使用的所有 token 的集合称为词汇,将文本拆分为 token 的过程称为分词

启用结算功能后,对 Gemini API 的调用的费用部分取决于输入和输出令牌的数量,因此了解如何计算令牌数量会很有帮助。


上下文窗口

通过 Gemini API 提供的模型具有以 token 衡量的上下文窗口。上下文窗口定义了您可以提供的输入量以及模型可以生成的输出量。您可以通过调用 getModels 端点或查看模型文档来确定上下文窗口的大小。

在以下示例中,您可以看到 gemini-2.0-flash 模型的输入限制约为 100 万个 token,输出限制约为 8,000 个 token,这意味着上下文窗口为 100 万个 token。

ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
	APIKey:  os.Getenv("GEMINI_API_KEY"),
	Backend: genai.BackendGeminiAPI,
})
if err != nil {
	log.Fatal(err)
}
prompt := "The quick brown fox jumps over the lazy dog."

// 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-2.0-flash", contents, nil)
if err != nil {
	return err
}
fmt.Println("total_tokens:", countResp.TotalTokens)

response, err := client.Models.GenerateContent(ctx, "gemini-2.0-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))

统计 token 数量

Gemini API 的所有输入和输出(包括文本、图片文件和其他非文本模态)都会进行分词。

您可以通过以下方式统计令牌数量:

  • 使用请求的输入调用 CountTokens
    这仅返回输入中的词元总数。您可以在将输入发送给模型之前进行此调用,以检查请求的大小。

  • 在调用 GenerateContent 后,对 response 对象使用 UsageMetadata 属性。
    这会返回输入和输出中的 token 总数:total_token_count
    它还会分别返回输入和输出的 token 数量:prompt_token_count(输入 token)和 candidates_token_count(输出 token)。

    如果您使用的是思考模型(例如 2.5 模型),则思考过程中使用的令牌会返回在 thoughts_token_count 中。如果您使用的是上下文缓存,则缓存的令牌数量将位于 cached_content_token_count 中。

统计文本 token

如果您使用仅包含文本的输入调用 CountTokens,它会返回仅包含输入内容 (total_tokens) 的文本的 token 数量。您可以在调用 GenerateContent 之前进行此调用,以检查请求的大小。

另一种方法是调用 GenerateContent,然后使用 response 对象上的 UsageMetadata 属性来获取以下信息:

  • 输入 (prompt_token_count)、缓存内容 (cached_content_token_count) 和输出 (candidates_token_count) 的单独 token 数
  • 思考过程的 token 数 (thoughts_token_count)
  • 输入和输出中的 token 总数 (total_token_count)
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
	APIKey:  os.Getenv("GEMINI_API_KEY"),
	Backend: genai.BackendGeminiAPI,
})
if err != nil {
	log.Fatal(err)
}
prompt := "The quick brown fox jumps over the lazy dog."

// 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-2.0-flash", contents, nil)
if err != nil {
	return err
}
fmt.Println("total_tokens:", countResp.TotalTokens)

response, err := client.Models.GenerateContent(ctx, "gemini-2.0-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))

统计多轮(聊天)对话的 token 数量

如果您使用聊天记录调用 CountTokens,它会返回聊天中每个角色的文本的总 token 数 (total_tokens)。

另一种方法是调用 SendMessage,然后使用 response 对象上的 UsageMetadata 属性来获取以下信息:

  • 输入 (prompt_token_count)、缓存内容 (cached_content_token_count) 和输出 (candidates_token_count) 的单独 token 数
  • 思考过程的 token 数 (thoughts_token_count)
  • 输入和输出中的 token 总数 (total_token_count)

如需了解下一个对话轮次的大小,您需要在调用 CountTokens 时将其附加到历史记录中。

ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
	APIKey:  os.Getenv("GEMINI_API_KEY"),
	Backend: genai.BackendGeminiAPI,
})
if err != nil {
	log.Fatal(err)
}

// Initialize chat with some history.
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-2.0-flash", nil, history)
if err != nil {
	log.Fatal(err)
}

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

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

// Append an extra user message and recount.
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-2.0-flash", hist, nil)
if err != nil {
	log.Fatal(err)
}
fmt.Println(secondTokenResp.TotalTokens)

统计多模态 token

Gemini API 的所有输入内容(包括文本、图片文件和其他非文本模态)都会被标记化。请注意以下关于 Gemini API 在处理多模态输入期间进行分词的高级要点:

  • 对于 Gemini 2.0,如果图片输入的两个维度均小于或等于 384 像素,则计为 258 个 token。如果图片在某个或两个维度上较大,则会根据需要将其剪裁和缩放为 768x768 像素的图块,每个图块计为 258 个 token。在 Gemini 2.0 之前,图片使用固定的 258 个 token。

  • 视频和音频文件会按以下固定费率转换为 token:视频为每秒 263 个 token,音频为每秒 32 个 token。

媒体分辨率

Gemini 3 Pro 预览版通过 media_resolution 参数引入了对多模态视觉处理的精细控制。media_resolution 参数用于确定为每个输入图片或视频帧分配的 token 数量上限。分辨率越高,模型读取细小文字或识别细微细节的能力就越强,但 token 用量和延迟时间也会增加。

如需详细了解该参数及其对令牌计算的影响,请参阅媒体分辨率指南。

图片文件

如果您使用文本和图片输入调用 CountTokens,它会返回输入中文本和图片的组合令牌数量 (total_tokens)。您可以在调用 GenerateContent 之前进行此调用,以检查请求的大小。您还可以选择性地分别对文本和文件调用 CountTokens

另一种方法是调用 GenerateContent,然后使用 response 对象上的 UsageMetadata 属性来获取以下信息:

  • 输入 (prompt_token_count)、缓存内容 (cached_content_token_count) 和输出 (candidates_token_count) 的单独 token 数
  • 思考过程的 token 数 (thoughts_token_count)
  • 输入和输出中的 token 总数 (total_token_count)

使用 File API 上传的图片的示例:

ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
	APIKey:  os.Getenv("GEMINI_API_KEY"),
	Backend: genai.BackendGeminiAPI,
})
if err != nil {
	log.Fatal(err)
}

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-2.0-flash", contents, nil)
if err != nil {
	log.Fatal(err)
}
fmt.Println("Multimodal image token count:", tokenResp.TotalTokens)

response, err := client.Models.GenerateContent(ctx, "gemini-2.0-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))

视频或音频文件

音频和视频会分别按以下固定费率转换为 token:

  • 视频:每秒 263 个 token
  • 音频:每秒 32 个 token

如果您使用文本和视频/音频输入调用 CountTokens,它会返回输入中文本和视频/音频文件的总令牌数 (total_tokens)。您可以在调用 GenerateContent 之前进行此调用,以检查请求的大小。您还可以选择分别对文本和文件调用 CountTokens

另一种方法是调用 GenerateContent,然后使用 response 对象上的 UsageMetadata 属性来获取以下信息:

  • 输入 (prompt_token_count)、缓存内容 (cached_content_token_count) 和输出 (candidates_token_count) 的单独 token 数
  • 思考过程的 token 数 (thoughts_token_count)
  • 输入和输出中的 token 总数 (total_token_count)
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
	APIKey:  os.Getenv("GEMINI_API_KEY"),
	Backend: genai.BackendGeminiAPI,
})
if err != nil {
	log.Fatal(err)
}

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

// Poll until the video file is completely processed (state becomes ACTIVE).
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-2.0-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-2.0-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))

系统指令和工具

系统指令和工具也会计入输入的总 token 数。

如果您使用系统指令,total_tokens 数量会增加,以反映 SystemInstruction 的添加。

如果您使用函数调用,total_tokens 数量会增加,以反映 tools 的添加。