Firebase AI Logic(firebase-js-sdk)CountTokensRequest 接口详解:Token 计数请求的完整配置指南
Firebase AI Logic(firebase-js-sdk)CountTokensRequest 接口详解:Token 计数请求的完整配置指南
CountTokensRequest 是 Firebase AI Logic(firebase-js-sdk 的 packages/ai 模块)中用于调用 GenerativeModel.countTokens() 的请求参数接口。本指南将围绕该接口的四个核心属性(contents、generationConfig、systemInstruction、tools)展开,结合仓库源码与测试用例,讲解如何构造一次准确的 token 计数请求、理解其底层请求管线,以及如何解读返回的 CountTokensResponse 结果。读完本文,你将能够基于该接口精确预估一次生成请求的 token 消耗,为成本控制、上下文窗口管理与提示词优化提供数据支撑。
接口概览:CountTokensRequest 的定义与位置
在 packages/ai 模块中,CountTokensRequest 定义于 packages/ai/src/types/requests.ts#L424-L438,其 JSDoc 明确标注为 “Params for calling GenerativeModel.countTokens()”,即它是 token 计数方法专用的请求参数类型。接口签名如下:
export interface CountTokensRequest {
contents: Content[];
systemInstruction?: string | Part | Content;
tools?: Tool[];
generationConfig?: GenerationConfig;
}
该接口是 @public API,与 GenerateContentRequest、StartChatParams 等同属于请求参数类型族(均定义在同一文件中)。从结构上看,它几乎就是 GenerateContentRequest 的精简版(后者额外包含 toolConfig 与 safetySettings),这是因为 token 计数只需要评估提示词本身的 token 消耗,无需完整推理配置。
接口的四个属性中,contents 是必填项,其余三个均为可选属性(带 ?)。下表汇总了各属性的完整类型签名与语义:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
contents |
Content[] | 是 | 待计数的对话内容(Prompt 内容) |
generationConfig |
GenerationConfig | 否 | 控制模型如何生成响应的配置选项 |
systemInstruction |
string | Part | Content |
否 | 引导模型按特定方式行为的指令 |
tools |
Tool[] | 否 | Tool(工具)配置 |
属性详解:四个字段的语义与取值约束
1. contents(必填):待计数的对话内容
contents: Content<a href="https://link.gitcode.com/i/426cb74c279f5dadbf4c08a04941af49" target="_blank">] 是唯一必填属性,表示需要统计 token 数的对话内容。其元素类型 Content 定义于 [packages/ai/src/types/content.ts#L24-L27:
export interface Content {
role: Role;
parts: Part[];
}
role:消息角色,通常为user或model;parts:消息内容的分段列表,Part是以下类型的联合(见 content.ts#L34-L41):
export type Part =
| TextPart // { type: 'text', text: string, ... }
| InlineDataPart // { type: 'inlineData', inlineData: GenerativeContentBlob, ... },用于图片/音频/视频
| FunctionCallPart
| FunctionResponsePart
| FileDataPart // { type: 'fileData', fileData: { fileUri, mimeType } },用于引用云存储文件
| ExecutableCodePart
| CodeExecutionResultPart;
从集成测试 packages/ai/integration/count-tokens.test.ts 可以看到,contents 支持文本、图片(inlineData)、音频(inlineData)以及云存储文件引用(fileData)等多种模态的组合。例如:
const request: CountTokensRequest = {
contents: [{
role: 'user',
parts: [
{ type: 'text', text: 'Describe these:' },
{
type: 'inlineData',
inlineData: { mimeType: 'image/png', data: base64EncodedImage }
},
{
type: 'inlineData',
inlineData: { mimeType: 'audio/mpeg', data: base64EncodedAudio }
}
]
}]
};
const response = await model.countTokens(request);
2. generationConfig(可选):影响 token 计数的生成配置
generationConfig?: GenerationConfig 的文档说明为 “Configuration options that control how the model generates a response”,即控制模型生成响应的配置选项。GenerationConfig 的完整定义同样位于 packages/ai/src/types/requests.ts#L162-L239,其常用字段及当前仓库标注的注意事项如下:
| 字段 | 类型 | 说明 |
|---|---|---|
stopSequences |
string[] |
停止序列 |
maxOutputTokens |
number |
响应最大输出 token 数 |
responseMimeType |
string |
输出 MIME 类型,支持 text/plain(默认)、application/json、text/x.enum |
responseSchema |
TypedSchema | SchemaRequest |
输出响应 JSON Schema(仅当 responseMimeType 为 application/json 或 text/x.enum 时生效) |
responseJsonSchema |
{[key: string]: unknown} |
基于 JSON Schema 的替代写法,设置后必须省略 responseSchema 且 responseMimeType 须为 application/json |
responseModalities |
ResponseModality[] |
响应模态(当前仅支持图片生成,@beta) |
thinkingConfig |
ThinkingConfig |
兼容模型的 “思考” 行为配置(thinkingBudget / thinkingLevel / includeThoughts) |
speechConfig |
SpeechConfig |
语音合成配置(@beta) |
imageConfig |
ImageConfig |
图片生成配置 |
需要注意的废弃字段(源码 JSDoc 已明确标注):candidateCount、temperature、topP、topK 在 Gemini 3.x 及以后模型中不再受支持,模型会忽略这些参数;presencePenalty、frequencyPenalty 在包含这些参数的请求中会直接以 400 错误失败。因此构造 generationConfig 时应省略这些字段。
另外,generative-model.ts#L252-L287 中的 validateGenerationConfig() 会在客户端校验三类组合错误并抛出 AIError:thinkingBudget 与 thinkingLevel 不能同时设置;responseSchema 与 responseJsonSchema 不能同时设置;设置任一 schema 时 responseMimeType 必须为 application/json 或 text/x.enum。
3. systemInstruction(可选):系统指令
systemInstruction?: string | Part | Content 的文档说明为 “Instructions that direct the model to behave a certain way”,即引导模型按特定方式行为的指令。它支持三种形式:
- 字符串:如
'You are a friendly and helpful assistant.'; - 单个 Part:如
{ type: 'text', text: '...' }; - 完整 Content:如
{ role: 'system', parts: [{ type: 'text', text: '...' }] }。
集成测试 count-tokens.test.ts#L74-L88 演示了以 Content 形式传入系统指令并调用 countTokens() 的完整用法。由于系统指令是提示词的一部分,其 token 消耗会计入 CountTokensResponse 的结果中。
4. tools(可选):工具配置
tools?: Tool<a href="https://link.gitcode.com/i/b2937e5f7ddd7b1d285a579920cd57d1" target="_blank">] 的文档说明为 “Tool configuration”。Tool 是联合类型(见 [requests.ts#L515-L520):
export type Tool =
| FunctionDeclarationsTool // 函数声明工具(最多 64 个函数声明)
| GoogleMapsTool // Google Maps 接地工具
| GoogleSearchTool // Google Search 接地工具
| CodeExecutionTool // 代码执行工具
| URLContextTool; // URL 上下文工具
当提示词中附带函数声明、接地或代码执行等工具时,工具定义本身也会消耗 token,因此 tools 被纳入计数请求,以便更真实地预估实际生成请求的成本。
调用方式:GenerativeModel.countTokens() 的三种入参形态
CountTokensRequest 是 countTokens() 的类型化入参,但方法本身还支持字符串与 Part 数组两种便捷形态(见 packages/ai/src/models/generative-model.ts#L229-L245):
async countTokens(
request: CountTokensRequest | string | Array<string | Part>,
singleRequestOptions?: SingleRequestOptions
): Promise<CountTokensResponse> {
const formattedParams = formatGenerateContentInput(request);
return countTokens(
this._apiSettings,
this.model,
formattedParams,
this.chromeAdapter,
{ ...this.requestOptions, ...singleRequestOptions }
);
}
即以下三种写法均可:
// 写法一:完整 CountTokensRequest 对象
await model.countTokens({ contents: [{ role: 'user', parts: [{ type: 'text', text: 'Hello' }] }] });
// 写法二:直接传字符串
await model.countTokens('Why is the sky blue?');
// 写法三:直接传 Part 数组(如单张图片)
await model.countTokens([{ type: 'inlineData', inlineData: { mimeType: 'image/png', data } }]);
内部会调用 formatGenerateContentInput()(见 packages/ai/src/requests/request-helpers.ts#L120-L144)将字符串或数组归一化为 { contents: <a href="https://link.gitcode.com/i/747cc861a919a903e8dece1b5d06b25f" target="_blank">content] } 结构,并为每个 Part 补上 type 判别字段。singleRequestOptions 可覆盖模型级默认选项(如 timeout、baseUrl),并支持通过 AbortSignal 取消请求(见 [requests.ts#L477-L509)。
一个结合 generationConfig、systemInstruction 与 safetySettings 的完整调用示例(源自集成测试 count-tokens.test.ts#L46-L105):
const model = getGenerativeModel(ai, {
model: 'gemini-2.0-flash',
generationConfig: {
temperature: 0,
topP: 0,
responseMimeType: 'text/plain'
},
systemInstruction: {
role: 'system',
parts: [{ type: 'text', text: 'You are a friendly and helpful assistant.' }]
},
safetySettings: [
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
}
]
});
const response = await model.countTokens('Why is the sky blue?');
console.log(response.totalTokens); // 总 token 数
console.log(response.promptTokensDetails); // 按模态拆分的明细
底层实现:一次 countTokens 请求的完整调用链
GenerativeModel.countTokens() 最终委托给 packages/ai/src/methods/count-tokens.ts 中的 countTokens() / countTokensOnCloud()。核心流程如下:
-
设备端前置检查:
countTokens()会检查chromeAdapter.mode,若为InferenceMode.ONLY_ON_DEVICE(纯端侧推理),直接抛出AIError(错误码UNSUPPORTED),提示 “countTokens() is not supported for on-device models”。这说明 token 计数仅支持云端推理路径(见 count-tokens.ts#L61-L74 与测试 count-tokens.test.ts#L202-L210)。 -
发送前清洗:
countTokensOnCloud()首先调用cleanCountTokensRequestForWire()(见 request-helpers.ts#L244-L257),递归地对contents与systemInstruction中的每个 Part 执行stripPartType(),剥离开客户端用于类型判别的type字段(如type: 'text'),生成符合后端 wire 协议的纯净请求体;同时创建新的 Part 对象,不会修改调用方持有的原始请求对象(测试 count-tokens.test.ts#L195-L199 专门验证了这一点)。 -
后端适配映射:若
apiSettings.backend.backendType为GOOGLE_AI(Gemini Developer API),则调用mapCountTokensRequest()(见 packages/ai/src/googleai-mappers.ts#L121-L133),将请求包装为 Google AI 期望的格式:
const mappedCountTokensRequest: GoogleAICountTokensRequest = {
generateContentRequest: {
model,
...countTokensRequest
}
};
- 发起请求:最终通过
makeRequest()发送,任务类型为Task.COUNT_TOKENS(即'countTokens',见 packages/ai/src/requests/request.ts#L38),stream: false,并把CountTokensResponse作为 JSON 直接返回。单元测试 count-tokens.test.ts#L56-L109 通过 mockmakeRequest验证了请求参数中包含contents,以及 Google AI 后端下请求被正确映射。
结果解读:CountTokensResponse 的字段含义
countTokens() 返回 CountTokensResponse,定义于 packages/ai/src/types/responses.ts#L569-L578:
export interface CountTokensResponse {
/** The total number of tokens counted across all instances from the request. */
totalTokens: number;
/** The breakdown, by modality, of how many tokens are consumed by the prompt. */
promptTokensDetails?: ModalityTokenCount[];
}
totalTokens:请求中所有内容合计的 token 总数,可直接用于成本估算与上下文窗口校验;promptTokensDetails:按模态(文本 / 图片 / 音频等)拆分的 token 明细,ModalityTokenCount包含modality与tokenCount字段。
集成测试 count-tokens.test.ts 展示了不同输入下的结果形态:
- 纯文本:
promptTokensDetails长度为 1,modality为TEXT,例如 Google AI 后端下totalTokens === 7、Agent Platform 下为6; - 单张图片:
modality为IMAGE,例如一张测试图片在 Gemini 2.x 上约计 258 token(gemini-3-pro-preview约 1089–1120 token); - 音频:
modality为AUDIO,且不同后端对totalTokens与tokenCount的返回略有差异(Google AI 返回具体数值,Agent Platform 下部分字段可能为undefined); - 多模态混合:
promptTokensDetails会按模态分别列出各项的 token 数; - 云存储文件引用(
fileData,仅 Agent Platform 支持):可直接对gs://存储桶中的文件计数,无需在客户端加载文件内容。
使用边界与注意事项
- 仅云端支持:当推理模式为
ONLY_ON_DEVICE(纯端侧)时,countTokens()会抛出UNSUPPORTED错误;PREFER_ON_DEVICE模式则会走云端计数路径。 - 请勿混用已废弃的生成参数:Gemini 3.x 及以后模型会忽略
temperature/topP/topK/candidateCount,对含presencePenalty/frequencyPenalty的请求返回 400。 - 返回字段存在后端差异:Google AI 与 Agent Platform 两个后端在
totalTokens、promptTokensDetails的具体数值与字段填充上存在细微差异(集成测试中均有注释说明),跨后端迁移时应以实际响应为准。 - 建议与真实生成请求保持参数一致:将
generationConfig、systemInstruction、tools一并传入计数请求,得到的 token 数才更接近后续实际generateContent()调用的消耗。
延伸阅读
- 接口原始定义:docs-devsite/ai.counttokensrequest.md
- 返回类型说明:docs-devsite/ai.counttokensresponse.md
- 依赖类型:
Content(docs-devsite/ai.content.md)、GenerationConfig(docs-devsite/ai.generationconfig.md)、Part与Tool(docs-devsite/ai.md) - 源码实现:types/requests.ts、methods/count-tokens.ts、models/generative-model.ts、googleai-mappers.ts
- 测试用例:methods/count-tokens.test.ts、integration/count-tokens.test.ts