资讯动态

AI SDK 文件上传架构:FilesV4、Provider Reference 与跨 Provider 消息传递全解析

发布时间:2026/9/10 13:10:33 来源:尧图企业网站定制
AI SDK 文件上传架构FilesV4、Provider Reference 与跨 Provider 消息传递全解析【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai本指南以 architecture/file-uploads.md 为核心系统拆解 Vercel AI SDKThe AI Toolkit for TypeScript中文件上传 Provider 引用的完整架构从用户侧uploadFile顶层 API、Provider 侧的FilesV4规格到 Provider Reference 如何在消息prompt中流转、以及各 ProviderOpenAI / Anthropic / Google / xAI的具体落地实现。读完本文你将掌握如何在应用代码中上传文件、如何在 Provider 中实现文件接口、如何通过resolveProviderReference把已上传文件引用注入对话消息以及面对不支持文件上传的 Provider 时应如何优雅降级。1. 高层架构三个核心角色文件上传能力在 AI SDK 中由三个相互配合的抽象构成角色名称作用用户侧 APIuploadFile位于 packages/ai/src/upload-file/upload-file.ts面向开发者的顶层函数通过某个 Provider 的 files 接口完成上传规格FilesV4位于 packages/provider/src/files/v4/files-v4.tsProvider 需要实现的标准文件接口数据载体SharedV4ProviderReferenceRecordstring, string位于 packages/provider/src/shared/v4/shared-v4-provider-reference.ts把 Provider 名称映射到该 Provider 特有的文件标识符核心数据流应用代码调用uploadFile→ SDK 找到 Provider 的 files 接口 → 调用其uploadFile方法上传原始字节 → 返回一个providerReference例如{ openai: file-abc123 }→ 后续构造消息时在文件 Part 中直接引用这个 reference 而不是重新传字节 → Provider 的消息转换层用resolveProviderReference取出自己的 file id 拼进协议消息。这种设计的价值在于同一个逻辑文件可以在不同 Provider 间复用而无需重复上传。例如一个文件同时上传到 OpenAI 与 Anthropic得到{ openai: file-abc123, anthropic: file-xyz789 }后续与哪个 Provider 对话就用哪个 id。2. 关键类型详解2.1SharedV4ProviderReference跨 Provider 的文件身份证定义于 packages/provider/src/shared/v4/shared-v4-provider-reference.tsexport type SharedV4ProviderReference Recordstring, string { type?: never; };两点值得注意它是Provider 名 → Provider 文件 id的普通映射示例{ openai: file-abc123, anthropic: file-xyz789 }。type?: never约束排除了任何带type属性的对象。这样在一个联合类型中SharedV4ProviderReference不会与带标签的文件数据形状如{ type: data, data }或{ type: reference, reference }混淆——这是isProviderReference判断逻辑的类型基础。2.2FilesV4Provider 侧文件接口规格定义于 packages/provider/src/files/v4/files-v4.ts只有uploadFile是必选方法其余方法均为可选能力方法存在即代表 Provider 支持该项能力与VideoModelV4的可选方法模式一致export type FilesV4 { readonly specificationVersion: v4; readonly provider: string; // 必选上传文件 uploadFile(options: FilesV4UploadFileCallOptions): PromiseLikeFilesV4UploadFileResult; // 可选读取已上传文件的元数据 getFileMetadata?(options: FilesV4GetFileMetadataCallOptions): PromiseLikeFilesV4GetFileMetadataResult; // 可选以字节流下载已上传文件的内容 downloadFile?(options: FilesV4DownloadFileCallOptions): PromiseLikeFilesV4DownloadFileResult; // 可选删除已上传文件 deleteFile?(options: FilesV4DeleteFileCallOptions): PromiseLikeFilesV4DeleteFileResult; };上传入参FilesV4UploadFileCallOptions见 packages/provider/src/files/v4/files-v4-upload-file-call-options.ts注意data是带标签的联合类型比文档示例更丰富data: | { type: data; data: Uint8Array | string } // 原始字节或 base64 字符串 | { type: text; text: string } // 内联文本UTF-8 | { type: stream; stream: ReadableStreamUint8Array }; // 字节流支持流式上传的 Provider 不会整文件缓冲进内存 mediaType: string; // IANA 媒体类型如 application/pdf filename?: string; abortSignal?: AbortSignal; // 取消操作 headers?: Recordstring, string | undefined; // 附加 HTTP 头仅 HTTP 类 Provider providerOptions?: SharedV4ProviderOptions; // Provider 特有选项透传上传结果FilesV4UploadFileResult见 packages/provider/src/files/v4/files-v4-upload-file-result.ts{ providerReference: SharedV4ProviderReference; // 必选{ [provider名]: 文件id } mediaType?: string; // Provider 返回的 IANA 媒体类型若有 filename?: string; // Provider 返回的文件名若有 byteSize?: number; // 文件字节数若有 createdAt?: Date; // 创建时间若有 expiresAt?: Date; // 保留到期时间例如请求了上传 TTL若有 providerMetadata?: SharedV4ProviderMetadata; // Provider 特有元数据透传 warnings: ArraySharedV4Warning; // Provider 警告 }关键点providerReference的键是规范 Provider 名如openai可能与接口的provider字段值如openai.files不同代码注释中明确说明了这一点。2.3LanguageModelV4FilePart.data消息中的文件引用文件 Part 的data字段接受带标签的SharedV4FileData联合见 packages/provider/src/shared/v4/shared-v4-file-data.ts 与 packages/provider/src/language-model/v4/language-model-v4-prompt.tstype SharedV4FileData | { type: data; data: Uint8Array | string } // 原始字节 / base64 | { type: url; url: URL } // 指向文件的 URL | { type: reference; reference: SharedV4ProviderReference } // Provider 引用 | { type: text; text: string }; // 内联文本 export interface LanguageModelV4FilePart { type: file; filename?: string; data: SharedV4FileData; mediaType: string; // 完整 IANA 类型type/subtype或仅顶层段image/audio/video/text providerOptions?: SharedV4ProviderOptions; }这正是已上传文件如何在消息中被引用的答案不再内联字节而是传入uploadFile返回的 Provider Reference。例如// 消息中的文件 part { type: file, filename: report.pdf, mediaType: application/pdf, data: { type: reference, reference: { openai: file-abc123 } }, }mediaType支持*子类型通配符如image/*会被归一化为等价顶层段如imageProvider 可用ai-sdk/provider-utils中的isFullMediaType、getTopLevelMediaType、detectMediaType辅助函数按需解析。3. 在 Provider 中实现文件上传三步走3.1 第一步创建 Files 接口实现实现FilesV4要点调用 Provider 的上传 API、返回{ [providerName]: fileId }形式的providerReference。文档给出的模板结构如下完整实现可参考 packages/openai/src/files/openai-files.tsexport function createMyProviderFiles(config: MyProviderFilesConfig): FilesV4 { return { specificationVersion: v4, provider: config.provider, // e.g. myprovider.files async uploadFile({ data, mediaType, filename, providerOptions }) { // 1. 必要时解析 Provider 特有选项见下方 parseProviderOptions // 2. 调用 Provider 的上传 API // 3. 返回结果 return { providerReference: { myprovider: response.fileId, }, warnings: [], }; }, }; }以 OpenAI 的真实实现为参照packages/openai/src/files/openai-files.tsuploadFile内部做了四件事解析 Provider 选项用parseProviderOptionsopenaiFilesOptionsSchema从providerOptions中取出purpose默认assistants与expiresAfter上传 TTL并把它们拼进 multipart 表单expires_after[anchor]、expires_after[seconds]。按数据类型分流{ type: stream }用postMultipartStreamToApi以流式 multipart 上传文件体不落内存其他类型先用convertInlineFileDataToUint8Array归一化字节构造BlobFormData再走postFormDataToApi。组装结果providerReference: { openai: response.id }并尽可能填充filename、mediaType、byteSize、createdAt秒级时间戳乘 1000 转Date、expiresAt以及providerMetadata.openai含filename、purpose、bytes、createdAt、status、expiresAt。错误处理若在请求发出前解析选项失败会主动cancel调用方传入的流避免流悬挂。测试用例可验证这一契约packages/openai/src/files/openai-files.test.ts断言 multipart 表单包含purpose: assistants、返回的providerReference等于{ openai: file-xyz789 }、providerMetadata包含服务端返回的元数据字段。3.2 第二步在 Provider 上暴露files()工厂方法在 Provider 对象上新增files()工厂方法返回刚创建的 files 接口const provider { // ... 已有的模型工厂 files: () createMyProviderFiles({ provider: myprovider.files, baseURL, headers: getHeaders, fetch: options.fetch, }), };OpenAI 的实际用法完全相同createOpenAI({ apiKey: ... }).files()见 packages/openai/src/files/openai-files.test.ts。3.3 第三步在消息转换层解析 Provider Reference在消息转换代码如convert-to-myprovider-messages.ts中处理case file:时用isProviderReference与resolveProviderReference判定并解析引用import { isProviderReference, resolveProviderReference } from ai-sdk/provider-utils; // Inside the file part handling: case file: { if (isProviderReference(part.data)) { const fileId resolveProviderReference({ reference: part.data, provider: myprovider, }); // 用 fileId 拼 Provider 协议消息 return { type: file, file: { file_id: fileId } }; } // 其余情况照旧处理 URL 与内联数据…… }注意实际消息 Part 中 Provider Reference 以带标签形式出现即part.data应为{ type: reference, reference: { openai: file-abc123 } }。OpenAI 的真实转换代码正是这样做的——先判断part.data.type reference再调用resolveProviderReference({ reference: part.data.reference, provider: openai })取出file_id见 packages/openai/src/chat/convert-to-openai-chat-messages.ts。isProviderReference的判定逻辑packages/provider-utils/src/is-provider-reference.ts一个值只要满足是普通对象、非null、非Uint8Array、非URL、非ArrayBuffer、非 Node Buffer、且没有type属性就被判定为 Provider Reference。对应测试覆盖了这些边界packages/provider-utils/src/is-provider-reference.test.ts纯记录返回true带type: reference/type: data标签的对象、Uint8Array、URL、null、字符串、数字均返回false。resolveProviderReference的解析行为packages/provider-utils/src/resolve-provider-reference.ts在 reference 中查找指定 Provider 的 id找到即返回找不到则抛出NoSuchProviderReferenceError定义于 packages/provider/src/errors/no-such-provider-reference-error.ts其默认错误消息会列出当前 reference 中可用的 Provider方便排查No provider reference found for provider anthropic. Available providers: openai4. 不支持文件上传的 Provider优雅降级守卫对于不支持文件上传的 Provider应在case file:块顶部加一个守卫遇到 Provider Reference 时抛出UnsupportedFunctionalityErrorimport { isProviderReference } from ai-sdk/provider-utils; case file: { if (isProviderReference(part.data)) { throw new UnsupportedFunctionalityError({ functionality: file parts with provider references, }); } // ... 原有文件处理代码 }这样做有双重收益类型收窄isProviderReference是类型守卫data is SharedV4ProviderReference让 TypeScript 正确收窄后续part.data的类型错误可读用户会得到清晰的错误提示而不是晦涩的协议解析失败。5. 现有实现一览下表汇总了仓库中已落地的文件上传实现与其对应的消息转换代码均为架构文档中确认的既有实现ProviderFiles 实现消息转换OpenAIpackages/openai/src/files/openai-files.tspackages/openai/src/chat/convert-to-openai-chat-messages.tsAnthropicpackages/anthropic/src/anthropic-files.tspackages/anthropic/src/convert-to-anthropic-messages-prompt.tsGooglepackages/google/src/google-files.tspackages/google/src/convert-to-google-messages.tsxAIpackages/xai/src/files/xai-files.tspackages/xai/src/convert-to-xai-chat-messages.ts6. 端到端调用链从用户代码到 Provider API把上述三层串起来一次完整的上传与引用流程如下用户侧调用packages/ai/src/upload-file/upload-file.tsuploadFile接受FilesV4实例或带files()方法的ProviderV4实例。若传的是 ProviderSDK 会自动调用其files()若既没有uploadFile方法也没有files()方法则抛出provider does not support file uploads错误。媒体类型兜底mediaType省略时自动推导——text变体固定text/plainstream变体固定application/octet-stream流无法嗅探data变体用detectMediaType嗅探字节失败时再按是否像文本回退到text/plain或application/octet-stream文本判定基于前 512 字节的 ASCII 检查。Provider 上传files 接口的uploadFile把字节或流以 multipart 形式发给 Provider API返回带providerReference的结果。上传失败时包括请求发出前的校验失败SDK 会取消调用方传入的流——流被 Provider 消费失败即取消不要复用。消息引用后续构造 prompt 时文件 Part 用{ type: reference, reference }代替内联字节消息转换层用resolveProviderReference取出本 Provider 的 file id 并拼进协议消息最终随请求发出。通过uploadFile的返回结果providerReference、byteSize、createdAt、expiresAt等与FilesV4的可选方法getFileMetadata/downloadFile/deleteFile应用可以在上传之外进一步实现文件的元数据查询、内容下载与生命周期管理从而构建完整的文件管理能力。7. 小结SharedV4ProviderReferenceRecordstring, string是跨 Provider 复用文件的桥梁type?: never保证其与带标签文件数据形状互斥FilesV4定义 Provider 文件能力uploadFile为唯一必选方法其余为可选能力信号消息中的文件 Part通过{ type: reference, reference }引用已上传文件不再内联字节Provider 接入三步实现FilesV4→ 暴露files()→ 在消息转换层用isProviderReferenceresolveProviderReference解析引用不支持时抛出UnsupportedFunctionalityError优雅降级错误处理引用缺失时resolveProviderReference抛出带可用 Provider 列表的NoSuchProviderReferenceError流式上传失败由 SDK 与 Provider 共同保证流被释放。这套架构让上传一次、多处引用成为可能也为在 AI SDK 生态中接入新 Provider 的文件能力提供了清晰、可复制的实现路径。【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价