Firebase JS SDK 中 FileData 接口深度解析:在 Gemini 多模态请求中引用 Google Cloud Storage 文件

原创2026-10-14 13:53:461,959 阅读
文章标签:开发工具后端

Firebase JS SDK 中 FileData 接口深度解析:在 Gemini 多模态请求中引用 Google Cloud Storage 文件

本文以 Firebase AI Web SDK(@firebase/ai,位于本仓库 packages/ai)自动生成的 API 参考文档 ai.filedata.md 为骨架,深入讲解 FileData 接口的定义、两个核心属性(fileUri 与 mimeType)的语义,以及它在 Gemini 多模态内容请求(generateContent、countTokens 等)中与 FileDataPart、Part 联合类型之间的协作关系。读完本文,你将掌握如何构造一个合法的 FileData 对象、如何在请求中把它作为内容的一部分发送,以及它与 base64 内联数据(InlineDataPart)在实现层面的本质区别。

FileData 接口:指向云端文件的引用

根据 ai.filedata.md 的定义,FileData 是一个描述“指向 Google Cloud Storage 上已上传文件的引用数据”的接口。它不携带文件二进制内容本身,而是通过一个 gs:// 风格的 URI 指向云端对象,让模型在推理时按需读取。

接口签名(与源码一致):

export interface FileData

其 TypeScript 声明位于 packages/ai/src/types/content.ts:

/**
 * Data pointing to a file uploaded on Google Cloud Storage.
 * @public
 */
export interface FileData {
  mimeType: string;
  fileUri: string;
}

它被标记为 @public,属于 SDK 对外公开的稳定 API,开发者可以直接在请求构造中使用。

属性详解:fileUri 与 mimeType

FileData 只有两个属性,二者均为必填的 string,原文档以属性表的形式给出了完整签名:

属性 类型 说明
fileUri string 指向 Google Cloud Storage 上文件的 URI
mimeType string 文件资源的 MIME 类型

fileUri:文件在云端的位置

fileUri 表示被引用文件在 Google Cloud Storage 上的地址。从仓库测试代码可以看出其实际取值形式:

可以推断,fileUri 的标准格式为 gs://<bucket-name>/<object-path>,对象需事先通过 Cloud Storage 上传,并满足模型后端对该文件的访问权限要求。

mimeType:声明文件资源的媒体类型

mimeType 用于告知模型该文件的媒体类型,以便模型按正确的模态(图像、音频、文档等)处理。仓库测试中出现的真实取值包括:

在 Live 会话场景中还会出现 audio/pcm 等音频类型(见 packages/ai/integration/live.test.ts)。实际可支持的具体媒体类型取决于所选后端(Gemini Developer API 或 Agent Platform Gemini API)的能力,建议按被引用文件的真实媒体格式填写。

FileData 在内容体系中的位置:Part 联合类型与 FileDataPart

FileData 本身只是数据载体,真正把它送入请求的是封装它的内容部件 FileDataPart。在 packages/ai/src/types/content.ts 中定义如下:

/**
 * Content part interface if the part represents {@link FileData}
 * @public
 */
export interface FileDataPart {
  type: 'fileData';
  fileData: FileData;
  thought?: boolean;
}

FileDataPart 通过 type: 'fileData' 判别字段与 Part 联合类型建立联系。Part 在同一文件中定义(content.ts),涵盖 TextPart、InlineDataPart、FunctionCallPart、FunctionResponsePart、FileDataPart、ExecutableCodePart 与 CodeExecutionResultPart 共七种部件:

export type Part =
  | TextPart
  | InlineDataPart
  | FunctionCallPart
  | FunctionResponsePart
  | FileDataPart
  | ExecutableCodePart
  | CodeExecutionResultPart;

对应的 API 参考文档可参见 FileDataPart 接口。此外,content.ts 中的 UnknownPart 也包含可选的 fileData?: FileData 字段,用于表示来自模型 wire API 或调用方提供的、尚未打上 type 标签的原始部件——这正是 SDK 内部做类型归一化的输入形态。

底层实现:请求格式化与类型归一化

理解 FileData 如何“跑通”一次请求,需要看两个关键实现。

assignPartType:给未打标签的 fileData 分配类型

在 packages/ai/src/requests/response-helpers.ts 中,assignPartType(part) 负责把 Part | UnknownPart 归一化为带 type 判别字段的 Part:

} else if (part.fileData !== undefined) {
  return { ...part, type: 'fileData' } as FileDataPart;
}

即只要部件对象中存在 fileData 字段,就会被自动标记为 'fileData' 类型。该函数被 createEnhancedContentResponse 用于逐条处理响应候选中的 parts(response-helpers.ts),相关单元测试见 response-helpers.test.ts,其中断言 { fileData: { mimeType: 'application/pdf', fileUri: 'gs://bucket/file' } } 被正确判定为 type === 'fileData'。

formatGenerateContentInput:把 FileData 部件放进请求

在请求侧,formatGenerateContentInput 会把用户提供的输入(含 fileData 部件)规整为后端可接受的 contents<a href="https://link.gitcode.com/i/cea1a7afb00b4828b00d3e6960b782b8" target="_blank">].parts[] 结构。测试 [request-helpers.test.ts 给出了完整行为:

const result = formatGenerateContentInput([
  'What is this?',
  {
    type: 'fileData',
    fileData: {
      mimeType: 'image/jpeg',
      fileUri: 'gs://sample.appspot.com/image.jpeg'
    }
  }
]);
// 结果为:
// {
//   contents: [{
//     role: 'user',
//     parts: [
//       { type: 'text', text: 'What is this?' },
//       {
//         type: 'fileData',
//         fileData: {
//           mimeType: 'image/jpeg',
//           fileUri: 'gs://sample.appspot.com/image.jpeg'
//         }
//       }
//     ]
//   }]
// }

可以看到,FileData 对象原样保留在 fileData 字段内,SDK 只负责将其放入正确的 parts 数组,不改变其属性结构。文本与文件部件可以混合出现在同一次请求的 parts 中,实现“看图提问”式调用。

实战示例:在 generateContent 与 countTokens 中使用 FileData

综合上述源码与测试,一次完整的引用云存储文件的调用可以这样组织(基于 count-tokens.test.ts 的结构,同样适用于 generateContent):

import { getAI, getGenerativeModel, GoogleAIBackend } from 'firebase/ai';
import { initializeApp } from 'firebase/app';

const app = initializeApp({ /* 你的 Firebase 配置 */ });
const ai = getAI(app, { backend: new GoogleAIBackend() });
const model = getGenerativeModel(ai, { model: 'gemini-2.0-flash' });

const filePart = {
  type: 'fileData',
  fileData: {
    mimeType: 'image/png',
    fileUri: 'gs://your-project.appspot.com/images/tree.png'
  }
};

const response = await model.generateContent(['描述这张图片的内容', filePart]);
const text = response.text();

在 token 计数场景中,FileDataPart 同样可以直接作为请求内容传入:

const response = await model.countTokens([filePart]);

集成测试对同一 fileUri 断言了 promptTokensDetails<a href="https://link.gitcode.com/i/c2968f302ef58cd4a7d5eb557901687c" target="_blank">0].modality 为 Modality.IMAGE,说明后端会依据 mimeType 将文件识别为对应模态参与计费与处理([count-tokens.test.ts)。同时测试注释明确指出,基于公开存储引用的该用例“不保证在 Google AI 后端通过”(count-tokens.test.ts),即此用法以 Agent Platform Gemini API(原 Vertex AI Gemini API)为预期环境,实际接入时需结合你所选后端的文件访问能力验证。

FileData 与 InlineDataPart:两种文件传递方式的取舍

在同一内容体系里,还有另一种携带媒体数据的部件:InlineDataPart,其数据载体是 GenerativeContentBlob(定义于 content.ts):

export interface GenerativeContentBlob {
  mimeType: string;
  /** Image as a base64 string. */
  data: string;
}

两者的对比如下:

维度 FileData(云存储引用) InlineDataPart(base64 内联)
数据存放位置 Google Cloud Storage,请求中只携带 URI 请求体中携带 base64 编码的二进制数据
属性结构 fileUri + mimeType inlineData.mimeType + inlineData.data
适用场景 大文件、可复用对象、已托管在云端的资源 小体积、即时生成、无需持久化的数据
请求体积 小(仅引用信息) 随数据量线性增长

集成测试 count-tokens.test.ts 展示了内联图片部件的构造方式:inlineData: { mimeType: IMAGE_MIME_TYPE, data: TINY_IMG_BASE64 }。当文件已经上传到 Cloud Storage 时,优先使用 FileData 可以显著减小请求体并复用已有对象存储能力;当数据来自内存或临时生成时,InlineDataPart 更直接。

使用建议与注意事项

  • 两个字段都必须提供:fileUri 与 mimeType 均为必填字符串,缺一不可,且 mimeType 应如实反映文件内容,以免后端按错误模态处理。
  • URI 采用 gs:// 协议:参照测试中的 gs://${storageBucket}/... 写法,可直接基于 Firebase 项目的 storageBucket 构造,也可使用 Cloud Storage 控制台给出的对象 URI。
  • 关注后端差异:本仓库的集成测试表明,云端文件引用相关的行为在不同后端(BackendType.AGENT_PLATFORM 与 BackendType.GOOGLE_AI)下可能不一致(count-tokens.test.ts),接入前建议针对目标后端做一次端到端验证。
  • 源码即规范:接口的最终权威定义始终以 packages/ai/src/types/content.ts 为准,API 参考文档(ai.filedata.md、ai.filedatapart.md)由 SDK 团队从源码自动生成,两者保持一致。
登录后查看全文
firebase-js-sdk