云选科普

AI 大文件上云:用 OSS 对象引用设计可靠任务链路

面向需要处理 PDF、图片和音频的 AI 应用,介绍如何用 OSS 保存原始文件、用轻量任务信封传递对象引用,并在函数计算侧完成校验、幂等和权限隔离。

AI 工作流从文本扩展到 PDF、图片、音频和知识库导出文件后,最容易出现的架构问题是把完整内容复制到队列、工作流参数和函数事件中。文件越大,重试成本越高,日志和调试页面也更容易暴露敏感内容。

更清晰的做法是把内容和控制信息分开:原始文件交给 OSS 保存,消息只传任务 ID 和对象引用,函数计算按权限读取并校验后再进入解析、审核和模型调用。

为什么要把文件和任务消息分开

消息适合描述“发生了什么”和“下一步做什么”,不适合承担完整文件的长期存储职责。一个输入可能依次经过上传、文本提取、审核和生成,如果每一步都携带正文,任何一次失败重试都会复制同一份数据。日志还可能留下多份内容副本,清理和权限管理随之变得困难。

对象引用模式可以把链路拆成:

客户端上传文件
  -> OSS 保存原始对象
  -> 生成任务信封
  -> 队列或工作流传递对象引用
  -> 函数计算按需读取并校验
  -> 解析、审核、模型调用

OSS 对象创建事件可以触发函数计算,事件中通常会提供 Bucket、Object Key、对象大小和 ETag 等信息。这个事件只回答“哪个对象发生了变化”,不能替代应用自己的任务契约,因此还需要在信封中记录任务、版本和处理规则。

任务信封应该记录哪些字段

一个可审计的最小信封可以这样设计:

{
  "task_id": "t-001",
  "object": {
    "bucket": "input-bucket",
    "key": "jobs/t-001/input.pdf",
    "version_id": "v1",
    "size": 1048576,
    "sha256": "..."
  },
  "processor_version": "extract-v3"
}

task_id用于幂等、状态查询和日志关联;bucketkey定位对象;启用版本控制时,version_id固定本次处理的具体版本;size用于下载前后检查;sha256把业务任务绑定到确定的内容;processor_version则区分解析器、提示词或规则升级。

不要只传临时下载链接。链接会过期,也容易被写入日志或转发。让函数通过执行角色访问指定 OSS 资源,消息只保存对象身份,通常更便于吊销权限和审计。读取对象需要相应的 oss:GetObject 权限;按版本读取时还要配置版本读取权限,使用 KMS 加密对象则应补充解密权限。

在函数计算侧建立校验边界

处理函数可以按固定顺序工作:

解析事件
  -> 校验 Bucket 与 Key 前缀
  -> 查询任务信封
  -> 检查任务状态
  -> 按 version_id 读取对象
  -> 校验大小与摘要
  -> 解析并调用模型
  -> 保存结果对象与处理记录

先校验 Bucket 和 Key 前缀,是为了避免任意目录中的对象进入模型链路。输入和输出也应使用不同前缀,例如 input/jobs/t-001/source.pdfoutput/jobs/t-001/result.json。如果输出再次匹配输入触发规则,可能形成循环触发或重复处理,上线前应使用少量文件验证规则。

下面的本地示例展示了大小和 SHA-256 校验的基本边界。示例中的 10 MiB 只是应用自定义阈值,不代表云产品或模型限制。

import hashlib

def verify_stream(stream, expected_size, expected_sha256, max_size=10 * 1024 * 1024):
    digest = hashlib.sha256()
    total = 0
    for block in stream:
        total += len(block)
        if total > max_size:
            raise ValueError("object_too_large")
        digest.update(block)
    if total != expected_size:
        raise ValueError("size_mismatch")
    if digest.hexdigest() != expected_sha256:
        raise ValueError("digest_mismatch")

不要把 ETag 当成所有场景的文件 MD5

OSS 提供多种完整性信息,但它们解决的问题不同。ETag 在部分上传方式下可用于内容校验,通过其他方式创建对象时可能由特定算法产生,因此更适合检测对象是否变化,不能无条件当作文件 MD5。传输层可以使用 SDK 提供的 Content-MD5 或 CRC64 校验;任务业务层再保存 SHA-256,确认处理器读取的内容与提交时一致;启用版本控制时同时保存 version_id,避免同一个 Key 被覆盖后任务读取到新内容。

这套分层校验的价值在于能回答两个不同问题:传输过程中对象有没有损坏,以及本次生成究竟使用了哪一份输入。不要用一个字段替代所有一致性语义。

幂等、权限和大文件处理要一起设计

对象事件可能因为网络重试、事件重复或人工再次上传而多次到达。可将幂等键定义为:

task_id + version_id + sha256 + processor_version

函数开始处理前先创建状态记录,例如 received -> validating -> processing -> completed,异常进入 rejectedfailed。相同幂等键已经完成时直接返回已有结果;仍在处理时不要启动第二次模型调用。

权限按角色拆分更容易控制影响范围:上传方只写输入前缀,处理函数只读输入并写输出,审核方只读结果,清理任务单独负责生命周期删除。处理函数没有必要拥有整个 Bucket 的删除权限。

文件读取优先采用流式或分块方式,并同时限制总字节数、页数、像素、音频时长和解压后大小。密码、API Key、未经授权的客户文件和未知脚本不应直接交给模型,还要在进入推理前完成权限检查、恶意内容扫描和必要脱敏。

适合谁,怎样分阶段落地

这套模式适合处理多媒体或知识库文件、需要队列和异步重试、或者要经过人工审核的 AI 应用。小团队可以按以下顺序实施:

  1. 原始文件只保存一份到 OSS,消息只传对象引用。
  2. 每个任务生成 task_id、版本号和 SHA-256。
  3. 函数读取后先校验,再解析和调用模型。
  4. 分离输入、输出和失败前缀,配置生命周期清理。
  5. 将状态、错误类型和结果对象写入可查询记录。

先把文件、任务和结果建立稳定关联,再逐步增加队列、人工审批和成本监控,通常比把完整内容复制到每个环节更容易维护。

结语

AI 大文件上云的关键不是把消息体做得更大,而是把内容平面与控制平面分开:OSS 保存对象,任务信封描述对象,函数计算按权限读取并验证,状态记录负责幂等和审计。ETag、CRC64、业务 SHA-256 和对象版本各自解决不同问题,不能互相混用。

先在对象身份、权限、触发边界和重复处理上建立规则,后续接入更多模型或工作流时,数据链路会更清晰,失败成本也更容易控制。

继续浏览

还想继续看,可以再看这些文章

适合想继续在同一主题下横向阅读、对比不同切入角度的用户。