# 头盔视频云端 Pipeline：技术设计

v0.6 · 2026-09-20 · 供架构评审与实现拆分使用；更新机器与模型费用，尚未实施或压测。

本系统接收已经在 S3 的原片，用弹性计算集群完成媒体处理、CV 和 VLM 分析。平台按**项目 × 业务日**管理任务，汇总解析结果，在满足出报条件后发送消息触发 Agent。

本文保留执行、调度、状态和监控的关键设计；完整接口与字段清单见[实现契约](/Users/bytedance/aligned-video-pipeline/docs/cloud-video-pipeline-contracts.md)。

## 1. 目标与设计约束

| 条件 | 本方案的约束 |
|---|---|
| 输入规模 | 单项目参考规模：50 顶头盔 × 8 小时 = 400 视频小时、1.08 TB/天；100 个同规模项目为 108 TB/天 |
| 部署范围 | 原片已在 S3；计算与存储位于同一美国区域。本次不设计现场上传和边缘计算 |
| 业务交付 | 次日生成晨报。正常目标是完整处理；截止时解析完成率**严格 >80%**，允许生成带缺失说明的报告 |
| 项目身份 | 复用业务系统的 `project_id`，视频、解析任务与项目进度等 `ext_*` 使用相同项目标识 |
| 结果要求 | 数字由确定性代码聚合；观测和文字可追溯到原片、片段和时间码；建议执行经过工长审批 |
| 资源方式 | 平台服务常驻；CPU/GPU 处理节点按任务扩缩容；VLM 先使用外部 API，模型自部署暂不纳入本版 |

**80% 是故障情况下的最低出报条件，容量规划仍以完整处理为目标。** 夜间资源异常需要提前告警、人工介入，不能等到早晨才发现未达标。严格阈值的分母、完成条件和告警流程在第 7 章集中定义。

10 分钟处理区间、120 秒证据段、30 秒模型窗口，以及下文的机型配置和吞吐都是设计初值。35% VLM 入选比例仅用于成本情景计算，不是已经验证的筛选效果，也不是必须只选 35% 的配额。实际编码、分辨率、业务截止时间、模型 API 配额与有效吞吐和成本上限仍需用客户输入与基准测试确定。

## 2. 总体架构

### 2.1 管理对象：项目日任务

视频文件是输入资产；平台调度和业务交付围绕 `pipeline_run`。它表示某项目某一天的一次解析，唯一键为 `(tenant_id, project_id, business_date, revision)`，业务日按项目时区计算。

| 对象 | 用途与边界 |
|---|---|
| `project_id` | 复用业务项目身份，关联视频与外部项目资料 |
| `run_id` | 记录一次项目日解析的输入、配置、进度、截止时间和成本；重跑创建新 revision |
| `run_input` | 关联本次使用的原片版本与采集区间；同一个文件可以参与不同版本的解析 |
| `shard` | 约 10 分钟源视频区间，是媒体处理的检查点单位 |
| `pack` | 多个 shard 组成一个 Batch 作业，目标实际运行 5–10 分钟，摊薄启动和模型加载成本 |
| `analysis_task` | 一个模型输入窗口，暂定 30 秒；独立领取、限流、重试 |
| `snapshot_id` | 固定一次可供 Agent 使用的视频事实集合，之后不随补算变化 |

两种时间粒度不要混用：10 分钟是源视频长度，5–10 分钟是作业在机器上的运行时间。一个 pack 包含多少 shard，由实测吞吐决定。

### 2.2 逻辑视图

![项目日视频解析流程](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/logical-view.png)

图中的出报门禁在收尾时评估；夜间风险告警从任务开始就独立运行。规划完成后，媒体与 VLM 阶段按已就绪区间流水执行。媒体 worker 生成并提交第一批 proxy 后，VLM 就可以开始。等待外部模型响应由独立 CPU 服务负责，媒体 GPU 继续处理后续区间。项目日协调器负责最终收尾、检查完成率和触发 Agent。

### 2.3 物理部署与组件选择

![常驻平台、媒体 GPU 作业与外部 VLM API](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/physical-view.png)

全部处理发生在云端。图中虚线表示调度或任务引用，实线表示数据读写；省略 worker 上传 S3、向平台提交结果的回程箭头。媒体处理在自己的 GPU 作业中运行；VLM 由 CPU 服务调用外部 API。

| 组件 | 当前建议 | 选择原因与代价 |
|---|---|---|
| 常驻 API / Coordinator / Dispatcher | ECS Service；CPU 服务可用 Fargate | 需要持续接收请求、运行协调器和消费消息，ECS 管副本、部署和健康检查；Fargate 减少 CPU 节点维护，未必是长期满载时最便宜的选择 |
| 媒体 / 探测批处理 | AWS Batch，独立 EC2 计算环境 | shard/pack 是运行后退出的作业，需要排队、资源匹配、Spot 和失败重调度；Batch 管这些机制，平台仍负责项目日语义 |
| VLM 调用服务 | ECS/Fargate CPU worker + 外部模型 API | 领取窗口、取得额度、调用模型并校验响应；推理由提供方执行，本版不部署模型 GPU 池 |
| 阶段编排 | 第一期使用固定阶段 Coordinator；Step Functions 可选 | 当前项目日状态已必须入库，固定阶段可由提交事务和 Outbox 推进；引入 Step Functions 的收益应覆盖增加的一套流程定义和状态映射 |
| 媒体执行图 | FFmpeg CPU/GPU 路径作对照；DeepStream 作多路 CV 候选 | 先验证硬件编解码的整机成本收益；DeepStream 的额外价值是多路批处理、GPU 帧与 CV 插件衔接，需实测后定型 |
| VLM 任务分发 | SQS + CPU Dispatcher | 吸收模型 API 延迟和限流；只传任务 ID，worker 取得额度后调用模型 |
| 持久化 | S3 分层存储 + PostgreSQL | 大对象与可查询状态分离；raw 不能长期全部放 Standard，具体生命周期见第 4.4 节 |
| 多租户准入 | 数据库预算账本；Redis 作共享短期并发/预留协调 | 协调模型账户 RPM/TPM、租户在途请求和预计费用；实际用量仍写数据库 |

**ECS、Fargate、Batch 分别解决什么。** ECS 管常驻容器服务；Fargate 是 CPU 容器的一种运行方式；Batch 管有结束条件的计算作业。在本方案中，Batch 的 EC2 计算环境内部也使用 ECS，但常驻平台服务不放进 Batch 托管集群，避免随批处理节点被回收。本版 GPU 只用于媒体/CV；Fargate 上的 VLM worker 负责外部 API 调用。[ECS GPU 支持](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-gpu.html)、[Fargate GPU 限制](https://aws.amazon.com/fargate/faqs/)、[Batch 资源边界](https://docs.aws.amazon.com/batch/latest/userguide/managed_compute_environments.html)。

**为什么 Step Functions 暂不设为必选。** 它能持久化粗粒度流程并通过 [Batch `.sync`](https://docs.aws.amazon.com/step-functions/latest/dg/connect-batch.html)等待作业，适合增加跨服务分支、人工等待和补偿流程之后使用。当前只有固定处理阶段，依赖已由任务账本和提交事务表达。第一期省去它的代价是必须实现可靠 Dispatcher、作业状态核对和截止 Reconciler；这些机制的验收见第 5、6 章。以后引入时仅编排项目日阶段，不为每个 30 秒窗口建工作流。

**为什么 DeepStream 需要基准。** 它适合“多路视频 → 解码 → 多个 CV 分支 → 编码”的 GPU 执行图，但会增加 GStreamer 插件、CUDA/TensorRT 版本适配和排障成本。先用同一批视频、相同输出质量要求、CV 模型与采样配置，对照 FFmpeg 的 CPU 与 GPU 媒体路径，再比较 DeepStream。记录整套媒体/CV 作业的有效吞吐、拷贝、峰值内存和成本，不能只比较解码速度。DeepStream 是否值得引入还要计入开发与维护成本。[FFmpeg GPU 能力](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/ffmpeg-with-nvidia-gpu/index.html)、[DeepStream 执行图](https://docs.nvidia.com/metropolis/deepstream/8.0/text/DS_Overview.html)。

SQS 用于分发独立任务，历史重算依赖 S3 与数据库。已有 Kafka 平台或需要多消费者长期重放事件时，可替换消息层。Cosmos Curator/Ray 可作为执行层候选，但不替代业务项目日状态、>80% 门槛和 Agent 事件。

## 3. Pipeline 阶段设计

### 3.1 CPU 与 GPU 各执行哪些 node

这里的 **node 是一个有输入、处理和输出的逻辑步骤**。本版拆成 **7 个 CPU node、4 个 GPU node**；同一个进程可以执行多个 node，node 数量不等于机器或容器数量。Agent 是管线就绪事件的下游消费者。

**CPU：7 个 node**

| Node | 输入 | 处理 | 输出 → 下一步 |
|---|---|---|---|
| **C1 输入登记** | project_id、业务日、原片清单、预期采集范围 | 校验归属和版本，建立 run，固定人员/设备映射与输入合同 | run_id + 冻结清单 → C2 |
| **C2 探测与任务规划** | 冻结清单、S3 容器头/索引 | 探测编码/时长，建立 seek 索引，划分约 10 分钟 shard，再装成 pack | 带版本、索引 URI、owned/read 范围和 profile 的任务 → C3 |
| **C3 读取与解封装** | 一个 shard 的对象版本、索引与时间范围 | S3 Range 读取压缩字节，demux 为视频包；有界预取，保留 PTS/DTS | 压缩视频包 + 时间戳 → G1 |
| **C4 后处理、封装与上传** | G3 的 CV 输出、G4 的编码包、G2 的缩略图像素 | 将逐帧观测归并为状态区间并作门控；封装视频、编码小缩略图，上传 S3 | proxy/thumb/model-window URI、CV 事实与 gate 决定、输出清单 → C5 |
| **C5 结果提交与分发** | C4 的媒体输出清单，或 C6 的 VLM 结果清单 | 校验版本/证据/租约；事务写事实和任务状态。媒体提交时创建入选 VLM 任务及 Outbox | 基础事实 + 任务 ID → C6；每次提交后的 run 进度 → C7 |
| **C6 VLM API 调用** | 入选模型窗口、prompt/profile、任务 ID | 领取租约与 RPM/TPM 额度，调用外部 VLM；保存原始响应并校验 schema/时间码 | 原始响应 URI、活动/事件/计数/摘要、usage → C5 再提交一次 |
| **C7 项目日收尾与聚合** | run 任务账本、可信总时长、已接受事实、cutoff | 完整成功或截止时关闭集合，固定快照，SQL 聚合，核算严格 >80% 门槛 | 可读 snapshot + 指标 + 缺失说明；达标才发 Agent 就绪事件 |

C5 是统一提交入口，会分别接收媒体和 VLM 两种结果。只有媒体提交会创建 VLM 任务；VLM 结果提交不会再生成自身任务。C7 可以被多次唤醒检查，但只执行一次有效收尾。

**GPU：4 个 node**

| Node | 输入 | 处理 | 输出 → 下一步 |
|---|---|---|---|
| **G1 硬件解码** | C3 的压缩视频包与时间戳 | NVDEC 按编码依赖解码，从必要关键帧开始，保留原片时间映射 | GPU 帧 surface → G2 |
| **G2 帧预处理与分支** | GPU 帧 | GPU 缩放/色彩转换；按 CV 采样策略生成张量；另取缩略图尺寸的小图 | CV 张量 → G3；proxy 帧 → G4；缩略图像素 → C4 |
| **G3 CV 推理** | 采样张量、固定版本的 CV 模型 | 批量执行检测/分类等模型，保留置信度和时间戳 | 逐帧/短窗预测与候选事件 → C4 做时间归并和门控 |
| **G4 proxy 编码** | G2 的 proxy 帧 | NVENC 编码，按证据段/模型窗口边界安排可独立解码的关键帧 | 编码包 → C4 封装成可回放文件和模型输入 |

G3 与 G4 是共享输入的两个分支，分别输出到 C4。GPU 不负责 S3 HTTP 请求、MP4 封装、SQL 事务或消息发送；这些 CPU 工作与 GPU 流水执行。缩略图只把缩放后的小图交给 CPU 编码，避免复制整批原始大帧。

**一段视频的执行顺序**

```text
C1 登记 → C2 规划 → C3 读取 → G1 解码 → G2 预处理
                                              ├→ G3 CV ────────┐
                                              └→ G4 编码 ──────┤
                                    缩略图小图 ────────────────┤
                                                              ↓
                                         C4 后处理/上传 → C5 提交
                                                              ├→ C6 调用外部 VLM → C5 提交
                                                              └→ C7 检查/收尾 → 就绪事件 → Agent
```

**这些 node 实际部署在哪**

| 执行位置 | 包含的 node | 机器如何增加 |
|---|---|---|
| 常驻 CPU 平台服务 | C1、C5；Coordinator 唤醒 C7 | 按请求、提交吞吐和可用性配置副本 |
| 弹性 CPU 作业 | C2；C7 的快照/聚合计算 | 按待规划、待收尾的项目日扩容 |
| **一个媒体 GPU 作业容器** | **CPU 部分 C3/C4 + GPU 部分 G1/G2/G3/G4** | 增加同类媒体作业，在多台 GPU 机器并行处理不同 shard |
| 独立 CPU VLM worker | C6 | 按队列积压与外部 API 配额控制并发 |

因此不会为 G1、G2、G3、G4 各买一组机器。它们在同一个媒体作业内通过有界 GPU 缓冲衔接；C4 上传并由 C5 接受后，才跨机器交接给 C6。

proxy 是模型输入和回放用的压缩副本。C4 输出独立模型窗口时，由 G4 提供对应关键帧边界，再作无重编码封装；若接口要求采样帧，则使用固定采样配置，额外处理成本单独记录。高分辨率复核必须登记为额外依赖任务。

CV 的工作/闲置判断需要现场标注集验证。无法判断保留 unknown；未调用 VLM 保留 NOT_SELECTED。处理完成、画面可见、语义可判定分别统计，不能用节点执行成功代替模型效果。

**门控算法尚未定型。** 本文尚未选定并验证能从头盔视频判断 working/idle 的 CV 模型，也未给出 VLM 入选阈值。G3 目前是模型执行位置的设计；具体模型、训练数据、业务标签和漏检率还需要验证。画面运动量、目标检测置信度只能作为候选信号，不能单独据此排除 VLM；工作状态分类和“是否需要进一步语义分析”应分别定义。

原报告接口中的 `gate_score` 用于选取代表证据。VLM 入选还需单独记录入选原因与门控策略版本，不能只用这个分数解释。若报告需要某个区间的活动、闲置原因、事件或计数，就必须安排能产出这些事实的分析；未做对应分析的范围保留语义缺失，不能从附近片段推成已知结果。

### 3.2 一个 10 分钟区间的完整执行

以头盔 A 的 `08:00–08:10` 原片为例，平均码率 6 Mbps。**本图仅演示入选后的任务拆分，未展示或验证 CV 入选依据。** 假设门控策略决定 S2、S4 需要 VLM，并对这两段各分析全部 4 个窗口，则形成 **2 段 × 4 个窗口 = 8 个任务**。其余段“不送 VLM”也是示例假设，不能据此认定其中没有事件或无需进一步分析。

![一个 10 分钟 shard：5 个证据段、8 个 VLM 任务及并行执行](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/shard-walkthrough.png)

约 450 MB 是这个源区间的压缩数据量，关键帧预读和索引读取会增加实际 I/O。5 个段都有媒体/CV 结果；入选段还要完成规定的 VLM 分析，才累计对应解析时长。媒体 worker 在结果提交后继续下一个 shard，C6 独立推进这 8 个 API 任务。

单个 shard 完成只更新项目日进度；正常提前收尾要求整个项目日完整完成，部分报告在截止时按严格 >80% 门槛判断。

模型窗口可以带相邻上下文，但计时、计数只归属其 `owned_interval`。证据段 ID 不随模型窗口长度改变，模型输出时间必须映射回原片时间轴。

### 3.3 输出如何对接现有 SQL

沿用[报告层数据库与 Tools 设计](/Users/bytedance/Downloads/报告层-数据库表与Tool接口设计.md)中的 `segment / segment_event / segment_count`，由平台投影层统一写入。需要补充的最小能力如下：

| 增量 | 原因 |
|---|---|
| `tenant_id / project_id` 和时间映射 | 视频、人员绑定和 `ext_*` 关联同一个业务项目；租户间隔离 |
| 独立 `processing_status` 与 `state_interval` | 一个 120 秒段内可以有多种状态；未处理和无法判断不能等同于 idle |
| `result_id / snapshot_id` | 重试和模型升级不覆盖历史报告采用的结果 |
| 事件/计数的范围、单位、主体及证据 | 模型观测可追溯；多头盔重复观察未经去重不能直接累计为库存或完工量 |

数字按毫秒区间确定性聚合，展示时才舍入。Tools 保留现有名称，但执行上下文必须带 `project_id + snapshot_id`，历史报告不能读取持续变化的“当前结果”。完整映射放在实现契约中。

## 4. 单机执行与数据读取

### 4.1 大文件怎样读到 worker

**大文件可以分段、分批读取。文件总大小、一个任务累计读多少、此刻内存里放多少，是三个不同的量。**

假设头盔 A 把 `08:00–16:00` 录成一个平均 6 Mbps 的文件：原片约 21.6 GB。Planner 将它规划成 48 个名义 10 分钟 shard；这些是任务记录，不要求先在 S3 复制出 48 个小文件。某个 worker 领取 `09:00–09:10`，它只需要这个区间对应的数据，参考量约 450 MB，加上索引、关键帧上下文及必要预读。以下 raw 指摄像头编码后的原片。

![一份大原片如何被多个 worker 按范围、分批读取](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/range-read.png)

**第一步：把“视频时间”翻译成“文件里的字节位置”。** S3 认识对象和字节，不认识 `09:00`。媒体库解析 MP4/MOV 的容器索引，查出时间、视频包位置和解码起点；不能用“文件大小 × 时间比例”代替索引，因为码率、音视频交织和封装都有影响。C2 提取并缓存可复用的容器元数据/索引，C3 的读取适配层复用它们。

视频帧可能依赖前面的帧。若本任务从 `09:00:00` 开始，而合适的随机访问点在 `08:59:58`，就从那里读取和解码；提前的两秒只用于恢复画面，处理归属仍从 `09:00:00` 算。具体读多少上下文由编码依赖决定。[FFmpeg 时间定位说明](https://ffmpeg.org/ffmpeg.html#Main-options)。

**第二步：用 Range 只取需要的字节。** 下面偏移仅为协议示例，不是用码率推算出的实际索引。假设读取器下一块需要从字节 `2700000000` 开始取 16 MiB：

```http
Range: bytes=2700000000-2716777215
```

S3 返回这一块，而不要求 worker 下载它前面的 2.7 GB 或整个 21.6 GB：

```http
HTTP/1.1 206 Partial Content
Content-Range: bytes 2700000000-2716777215/21600000000
Content-Length: 16777216
```

一个 GET 请求只能指定一个连续 Range；需要不连续数据时发多个请求。worker 保持对象 `version_id` 一致，检查响应范围与长度，失败后重取缺失块。[S3 GetObject 的 Range 接口](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html)。

Range 返回的字节不一定构成独立可播放的 MP4。实现中，FFmpeg/libavformat 或 GStreamer 的解封装器通过支持 `read/seek` 的输入读取容器和视频包，再交给 GPU。要复用旁路索引，需要读取适配层接入；不能把 Planner 的 JSON 索引直接当作 FFmpeg 原生输入。HTTP 随机访问能力参考 [FFmpeg HTTP 协议](https://ffmpeg.org/ffmpeg-protocols.html#http)。

**第三步：读一批、处理一批、释放一批。** 例如每块 16 MiB，每路压缩数据最多保留 4 块，这部分内存上限就是 64 MiB。拿到元数据和起始可解码数据后便可开始处理；消费一块再补一块，不必等约 450 MB 全部到齐。16 MiB / 4 块是解释机制的示例，最终值由压测确定。

| 位置 | 存放什么 | 怎样控制占用 |
|---|---|---|
| S3 | 完整 21.6 GB 原片和持久化产物 | 原片可以比任意一台 worker 的内存、磁盘大 |
| CPU 内存 | 当前几块压缩字节、索引、解封装状态 | 限制缓存块数和在途请求；64 MiB 示例仅指一条流的压缩块，不是整个进程内存 |
| GPU 显存 | 当前正在解码、推理和编码的帧 | 独立限制帧队列、并发流、解码 surface 与模型 workspace，不能存下整段解码帧 |
| 本地磁盘 | 可选输入块缓存、待上传产物 | 有配额，处理/上传完成后释放；第 4.3 节的 32 GiB 是缓存上限，无须每个任务占满 |

下游变慢时，缓冲满了就停止上游读取，这就是背压。Range 本身不会限制内存；限制缓存、帧队列、预取和上传积压才会。具体资源上限见第 4.3 节。

**第四步：不同 worker 读取不同范围。** 多个 worker 可以同时读取同一个 S3 对象的不同 Range，任务按可用 CPU/GPU 分批运行。完整处理这 8 小时，仍需读过相应的全部源数据；约 48 × 450 MB = 21.6 GB，实际还有索引、上下文和重试等开销。并行缩短处理时间，不能消除源数据传输量。[S3 范围读取与并发建议](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html)。

减少多余读取靠三件事：容器索引提取后复用；proxy、缩略图和 CV 共用解码结果；本地缓存保留近期读取块，减少相邻 shard 重叠读取。缓存键包含对象版本和字节范围，缓存未命中照常从 S3 读取，不能把高命中率当作容量规划前提。

输入有例外：完整读取成本很低的小文件可以落本地缓存；缺少有效索引的文件先由 CPU 作业扫描、建索引或重封装，额外 I/O 记账；损坏到无法恢复必要信息的文件标记失败。避免让每个 GPU worker 各自扫描一次完整原片。预签名 URL 在执行时生成并可刷新，或使用受限任务凭证。

**Gateway Endpoint 负责网络路线。** 在本方案中，EC2 worker 和 S3 在同一美国区域，为 worker 子网的路由表配置 S3 Gateway Endpoint 后，S3 请求可经该端点访问，不经过 NAT Gateway。Gateway Endpoint 本身没有额外费用；S3 请求、存储及其他适用费用仍计费。它不提供视频索引或内存管理，也不承诺一个固定下载速度。[AWS Gateway Endpoint 说明](https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html)。

### 4.2 解码、CV、编码怎样共用 GPU

**解码可以用 CPU。当前建议硬件解码，是因为这个媒体作业同时要生成 proxy 和执行 GPU CV；是否更便宜需要用整个作业的成本验证。**

转码包含几个步骤。原片通常已经由摄像头压缩为 H.264/H.265；为了生成更低分辨率的 proxy，需要先还原画面，再缩放和重新压缩：

```text
压缩原片 → 解码成图像帧 → 缩放等处理 → 编码成压缩视频 → 封装为 proxy
                          └→ 采样 / CV 推理 → 状态与候选事件
```

如果仅换容器或在允许的边界裁出片段，可以通过 stream copy 直接复制压缩包，省去解码和重编码。但降低画面分辨率、重新编码控制码率、执行像素级 CV，都需要解码后的帧。FFmpeg 是软件框架，既能调用 CPU 软件编解码器，也能调用 GPU 上的硬件编解码器。[FFmpeg stream copy](https://ffmpeg.org/ffmpeg.html#Streamcopy)、[FFmpeg 硬件转码](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/ffmpeg-with-nvidia-gpu/index.html)。

![媒体 worker 内部数据流](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/worker-dataflow.png)

NVIDIA GPU 上包含不同的硬件单元：

| 单元 | 在本方案里做什么 |
|---|---|
| NVDEC 视频解码引擎 | 将受支持的压缩码流还原成显存中的帧 |
| CUDA / Tensor 计算资源 | 缩放、预处理和 CV 模型推理；具体使用哪些单元由实现决定 |
| NVENC 视频编码引擎 | 把处理后的帧重新压缩，生成 proxy 视频包 |

NVDEC 与核心 NVENC 是独立于通用计算核心的专用视频硬件，因此可与 CV 流水执行。它们仍共享显存、带宽等资源，部分编码功能也会使用 CUDA；不能把硬件解码/编码当成没有资源成本。[NVDEC 硬件分工](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/nvdec-video-decoder-api-prog-guide/index.html)、[NVENC 与 CUDA](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/nvenc-video-encoder-api-prog-guide/index.html#encoder-features-using-cuda)。

这里优先评估 NVDEC 的原因是：按当前方案，CV 部署在 GPU，解码后的帧可以直接留在显存中，供 CV 与 proxy 分支复用，减少 CPU 软件解码和主机到显存的数据搬运。若采用 CPU 解码，也可以先在 CPU 缩放/采样，只上传 CV 需要的帧；CV 很稀疏时，这条路径可能更合算。比较时要求 proxy 质量和 CV 效果等价，核算每输入视频小时的整机、传输和产物存储成本，并检查是否满足处理窗口。

C3/C4 在媒体容器的 CPU 上负责 I/O、解封装、后处理与封装，G1–G4 在该机器的 GPU 上执行。CV 模型只在作业启动时加载一次并跨 shard 复用；本版 VLM 推理由外部 API 提供方执行。DeepStream 是候选实现；实际 GPU 型号必须支持原片编码、位深、色度格式和分辨率。

连续 proxy 要遵守视频解码依赖；CV 可以降低采样频率。仅在缩略图编码或模型接口确有需要时复制帧到 CPU，避免逐帧 GPU→CPU→GPU 往返。解码器、编码器、SM 计算核心与显存分别观测，不能只用一个 GPU utilization 判断瓶颈。

### 4.3 一台 worker 怎样边读、边算、边上传

**实现方式是在同一个媒体容器里，让读取、媒体计算、上传三组执行循环并发运行，中间通过有容量上限的缓冲和队列交接。** 下文是实现设计和伪代码，尚未作为这套云端 worker 跑通或压测。

假设 pack 中有 A、B、C 三个 shard，每个代表约 10 分钟原片。流水线启动后，某一时刻可以是：

| 谁在执行 | 此刻做什么 | 数据放在哪 |
|---|---|---|
| CPU 读取线程 | 持续供应 B 需要的压缩字节；有余量时预取 C 开头少量字节 | 有上限的输入内存缓冲，可选本地块缓存 |
| CPU 媒体控制线程 + GPU | 解码、CV、编码 B，CPU 封装产物 | 有上限的 GPU 帧池；编码后的产物写本地磁盘 |
| CPU 上传线程 | 把 A 已生成的 proxy、图片和结果清单上传 S3 | 本地输出目录；上传任务队列保存路径和元数据 |

这就是“读 C、算 B、传 A”的具体含义。读取和上传主要在等待网络/磁盘，GPU 可以同时处理 B。预取 C 不代表 B 已完整下载；读取调度始终优先供应正在计算的 B。

```text
S3 原片
   ↓ CPU 读取线程：先申请空闲缓冲，再发 Range
有容量上限的输入缓冲
   ↓ 解封装 → GPU 解码 / CV / 编码
已预留空间的本地输出目录
   ↓ 上传队列只传文件路径 → CPU 上传线程
S3 产物 → C5 接受结果 → 清理本地文件、释放输出名额
```

**输入怎样做到“满了就停”。** 例如为单路已启动视频预先分配 4 个 16 MiB 缓冲块，读取线程必须先取得一个空闲块，才允许发起下一次读取。没有空闲块就等待。媒体处理不再引用某块压缩数据后，将它归还给空闲池。不能先下载到另一个无限增长的列表，再等待入队；正在下载、排队和被消费的块都包含在这 4 块里。C 的预取只能使用额外的有限额度，不能占走 B 完成处理所需的保底缓冲。GPU 帧池独立限额，帧要等 CV/编码等消费者都使用完才能复用。

**输出怎样做到“上传慢了就少算”。** 用“最多允许 2 个 shard 占用输出名额”举例：开始计算前，先拿一个名额，并按输出 profile 的上界预留磁盘空间。这个名额覆盖计算中、等待上传和正在上传，直到产物上传校验、C5 接受及本地清理完成才释放。

| 当前占用 | 下一步怎么做 |
|---|---|
| A 正在上传，占一个名额；B 正在计算，占另一个 | B 用已预留的空间继续完成；C 可以少量预取，但尚不能开始计算 |
| A 上传变慢，两个名额一直未释放 | C 等待，暂停 C 的预取；继续供应 B 所需输入，使 B 能收尾 |
| A 上传、提交与清理完成，释放一个名额 | C 取得名额和磁盘预留，开始计算；上传线程继续处理 B |

下面是两个独立执行循环的设计伪代码；输入线程在另外的循环中按缓冲空位供给数据。实际实现还要处理第 6 章的重试、取消和租约失效。

```text
媒体执行循环：
    取得输出名额并预留磁盘空间      # 资源不足就等，不启动下一个 shard
    边读取边处理当前 shard
    将本地输出文件的路径放进上传队列
    尝试处理下一个 shard

上传执行循环：
    从队列领取一个 shard 的输出路径
    上传 S3 并校验
    向 C5 提交该 shard 的结果
    清理已可删除的本地文件
    释放磁盘预留和输出名额          # 等待中的媒体循环现在可以继续
```

这里既限制任务数，也限制字节数。`Queue(maxsize=2)` 只限制队列中的条目数；上传线程取走条目后，文件仍占磁盘，所以不能仅凭队列长度判断还能处理多少。需要单独保存覆盖整个生命周期的输出名额与磁盘预留。输出必须受 profile 大小上界或逐块字节配额约束，不能超过预留继续写。[Python 队列语义](https://docs.python.org/3/library/queue.html)。

如果采用 GStreamer/DeepStream，媒体分支可用 `queue` 元件配置 `max-size-buffers / max-size-bytes / max-size-time`；满了阻塞上游，不靠丢帧腾空间。GPU surface 可能只以句柄经过队列，还要限制实际帧池/显存。磁盘输出、上传和结果提交的额度由 worker 管理，GStreamer 不替平台处理这些。[GStreamer queue](https://gstreamer.freedesktop.org/documentation/coreelements/queue.html)。

这种“下游没有空位，上游就等”的行为叫背压。读取慢时，计算线程拿不到数据也会等待。重叠执行能减少空等，但三个环节仍共享 CPU、网卡和磁盘；上传持续跟不上时，GPU 暂停是正常结果，不能通过无限堆积文件维持 GPU 利用率。

以下是**一张约 24 GiB 显存 GPU 的压测配置候选值**。`memory_mib: 24576` 申请的是 CPU 主机内存；GPU 显存是另一块内存。`decode_streams: 4` 指一张 GPU 尝试并发处理 4 路视频，不是申请 4 张 GPU。上面的 4 个输入块和 2 个输出名额只为解释单路机制，最终数量与整个作业的字节预算一起压测确定。

```yaml
media_profile:
  batch_request: {vcpus: 6, memory_mib: 24576, gpus: 1}
  concurrency: {decode_streams: 4, max_queued_frames_per_stream: 32}
  limits:
    io_buffer_gib: 1
    local_input_cache_gib: 32
    local_output_spool_gib: 8
    local_scratch_quota_gib: 64
    vram_admission_budget_gib: 20
    disk_pause_percent: 80
    disk_resume_percent: 60
```

输入缓存、输出 spool 和 scratch 指本地 NVMe 磁盘；`local_output_spool_gib` 必须同时覆盖预留、生成中、待上传和正在上传的输出，不能只统计队列里的文件。容器内存单独限制。帧队列之外还有解码器 surface、模型 workspace 和编码缓冲，需要一起实测。GPU 显存预算由 worker 准入和水位监测执行，AWS Batch 的 GPU 数量申请不提供显存字节级硬隔离。

作业容器不能预取整个 pack。它只保留当前并发范围的输入与输出；已上传并完成必要校验的临时文件可释放。机器中断后，本地缓存可以丢弃，恢复位置由已提交的 S3/数据库检查点确定。

### 4.4 S3 冷热分层与归档读取

**“热”和“冷”描述数据被读取的频率。** 当天反复处理的原片是热数据，几个月没人读取的历史视频是冷数据。另一个必须单独判断的问题是：下次有人要用时，能否接受等待恢复。很少被看的报告证据也可能需要随时点开，因此冷数据不一定要放进需要等待的归档层。

分层改变存储和访问方式，不改变视频内容、分辨率或清晰度。我们根据访问频率、读取时效和总成本，为对象选择存储等级。

| 名称 | 它是什么 | 谁决定何时改变存储方式 |
|---|---|---|
| S3 Standard | 直接可读的存储等级，适合活跃工作集 | 保持在该等级，直到我们通过配置/API 改变 |
| S3 Intelligent-Tiering | 内部包含多个访问层的存储等级 | AWS 按每个对象的实际访问记录自动调整内部层级 |
| S3 Glacier Deep Archive | 低价长期归档等级，读取前需要恢复 | 我们明确选择归档，或配置 Lifecycle 迁移规则 |
| S3 Lifecycle | 对象迁移/过期规则，本身不是存储等级 | 我们按对象年龄、前缀、标签等条件配置 |

**Intelligent-Tiering 可以理解成“自动按访问频率调档”。** 对象先选择或转入这个存储等级，AWS 才按这套机制管理它。默认有三层：刚存入时在频繁访问层；连续 30 天没有读取，降到不频繁访问层；从上次读取算连续 90 天未读，降到归档即时访问层。后两层再次被读取时自动回到频繁访问层。对象仍属于 Intelligent-Tiering，业务继续用原 bucket/key 读取。[自动分层规则](https://docs.aws.amazon.com/AmazonS3/latest/userguide/intelligent-tiering-overview.html)。

![Intelligent-Tiering 默认三层如何随访问变化](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/intelligent-tiering.png)

**默认这三层都能直接读取，不需要先恢复。** 其中“归档即时访问层”的名字虽然带“归档”，仍保持低延迟访问。Intelligent-Tiering 还可额外开启 Archive Access / Deep Archive Access 两个需要恢复的层；本版用于 proxy/证据视频时保持这两个选项关闭，避免工长打开历史报告时等待恢复。[在线层与可选归档层](https://aws.amazon.com/s3/storage-classes/intelligent-tiering/)。

它会收取按对象数量计算的监控与自动化费用；内部自动转层没有额外转层费，也没有数据取回费，但正常请求和适用网络费用仍计费。小于 128 KB 的对象不参与自动分层，保持在频繁访问层且不收监控费，因此小索引、JSON 和缩略图需要单独比较成本。[Intelligent-Tiering 费用与对象大小限制](https://aws.amazon.com/s3/storage-classes/intelligent-tiering/)。

**本方案采用两种不同的管理方式。** proxy 的后续回放频率难预测，交给 Intelligent-Tiering 在可直接读取的三层之间自动调整。历史 raw 是否可以归档，则由平台结合验收、补算和保热期决定；AWS 的访问记录不能代替这些业务条件。raw 的 `Standard → Deep Archive` 是我们配置的迁移策略，不是 Intelligent-Tiering 默认的下一档。

raw、proxy 和报告的访问方式不同，分别设置生命周期。以下天数是成本方案初值，总保留期由项目约定，尚未确认前不配置永久删除。

| 对象 | 建议生命周期 | 访问与成本取舍 |
|---|---|---|
| 新 raw | S3 Standard 至少 7 天；仍有重试/复核/任务引用时继续保热 | 保证当日计算和近期补算可直接 Range 读取 |
| 已验收的历史 raw | 满足归档条件后转 Glacier Deep Archive | 适合低频取证或未来可能使用的数据；历史重算必须提前恢复 |
| proxy / 证据视频 | 可用 Intelligent-Tiering，先只启用无需恢复的访问层；高频回放留 Standard | 报告可回放不必依赖整段 raw 恢复；按实际访问率选择，不能只比较每 GB 存储费 |
| 当前训练/调参子集 | 单独保留在 Standard；低频但必须立即访问的子集可评估 Glacier Instant Retrieval | 模型迭代所需工作集留在线，其余 raw 归档，避免整年原片都热存 |
| 报告、清单、索引和小缩略图 | 保持在线；按对象数、大小与引用策略管理 | 小对象迁移和元数据开销可能超过存储节省 |

Lifecycle 规则按对象前缀、年龄和 `archive_eligible` 标签过滤。平台仅在结果/证据验收、无活动读取租约且过了保热期后标记可归档；归档协调器与新任务准入串行检查资产状态，避免处理到一半被转冷。S3 版本与数据库引用继续保留，冷归档不等于删除。

历史输入增加 `COLD → RESTORING → AVAILABLE` 状态。恢复服务先调用 RestoreObject，确认可读并取得足够的临时恢复期限后，再准入 GPU 作业；GPU 不等待解冻。新一天的输入仍在热层，因此正常晨报路径不经过恢复流程。

Deep Archive 的标准恢复通常在 12 小时内完成，批量恢复通常在 48 小时内；恢复还产生请求、数据取回和临时 Standard 副本成本。它有 180 天最低计费期，Glacier Instant/Flexible Retrieval 为 90 天；提前删除或转层可能补收剩余期限费用。归档时还要考虑每对象元数据与转换请求开销。[恢复选项](https://docs.aws.amazon.com/AmazonS3/latest/userguide/restoring-objects-retrieval-options.html)、[存储计费规则](https://aws.amazon.com/s3/pricing/)。

后续卖数据或批量重训时，创建独立数据集导出/恢复任务，先核算恢复、在线副本与网络费用，不挤占当晚业务预算。定期核对非当前版本、未完成 multipart upload 和无引用尝试产物，避免主对象已归档而旧版本仍持续计费。

## 5. 分布式调度与扩缩容

### 5.1 固定阶段由谁推进

**任务如何交给下一阶段。** 每一行从左向右读，再进入下一行。黄色框表示数据库事务；蓝色框表示任务投递。媒体结果可以逐批推进 VLM，不必等待项目日全部媒体作业结束。

![固定阶段的任务提交与结果接受](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/stage-dispatch.png)

Outbox 是 PostgreSQL 中的待投递消息表。平台把业务记录和下一步要发的消息放在同一个事务里；Dispatcher 读取这些记录，提交 Batch 作业或投递 SQS 消息。投递失败可以重试，重复提交与结果去重见第 6 章。

**项目日何时触发 Agent。** 结果提交会唤醒 Coordinator 检查进度；截止 Reconciler 定期检查哪些 run 已到分析截止时间。两个入口共用幂等 Finalize，完整成功可提前收尾，其余情况到截止时收尾。

![项目日收尾与 Agent 触发条件](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/project-day-finalize.png)

截止前刚超过 80% 仍继续处理；截止后只有完成率严格 >80%、快照和聚合可读，才发送就绪事件。完成率恰好 80% 不触发。具体收尾条件和分母口径见第 7 章。

Coordinator 只实现这条固定依赖链。平台进程重启后，从持久化 Outbox 和任务状态继续，不把进度保存在内存。Batch 原生状态用于发现节点/容器失败，成功仍以结果已接受为准；事件通知加速更新，周期核对修复漏事件。

一个坏文件记录为局部失败，不中止其他 pack。C6 在独立 CPU 服务中等待模型 API；项目日协调器按已登记依赖判断完成，不让媒体作业占用 GPU 等待模型。

### 5.2 资源池与伸缩控制

**先分清伸缩的对象。** Batch 资源池增减的是 EC2 机器；C6 服务增减的是 Fargate 上的 worker 容器。常驻平台负责判断业务需要多少处理能力，即使处理资源缩到 0，也继续运行并提交新任务。

| 资源池 / 执行内容 | 什么时候需要扩容 | 谁执行扩容 | 什么时候缩容、受什么限制 |
|---|---|---|---|
| Batch `probe-cpu`：探测、索引、必要的重封装 | 已提交且可运行的探测作业，无法放入现有空闲 CPU / 内存 | Batch 增加 CPU EC2 机器，按作业声明的 vCPU / 内存调度 | 待执行作业清空、运行中作业结束后回收空闲机器；`minvCpus=0`。平台限制同时提交的作业数 |
| Batch `media-gpu-spot`：媒体与 CV | 平台按剩余视频时长和截止时间，算出需要更多并发 pack 并提交；现有 GPU / CPU / 内存放不下这些作业 | Batch 增加兼容的 GPU EC2 机器 | 平台随剩余工作减少而少补充新 pack；Batch 回收空闲机器，最低为 0。受队列容量、租户并发和预算限制 |
| Batch `media-gpu-ondemand`：应急媒体与 CV | 平台预计 Spot 无法按时完成，在应急预算内把未完成任务转入此队列 | Batch 根据转入的作业增加 On-Demand GPU 机器 | 应急任务结束后回收空闲机器，最低为 0。不能因 Spot 队列长就无限启用；转移与预算规则见 5.3 |
| ECS/Fargate `vlm-api`：C6 调用外部模型 | 有待调用任务，且现有 worker 不足以承载模型配额允许的并发请求；算法见下例 | 平台计算目标容器数，写 ECS `desiredCount`；ECS 启动对应数量的 Fargate worker | 需求持续降低时，先停止多余 worker 领取任务，等在途请求提交完再缩容；无待处理和在途任务时可缩至 0。副本数和 API 调用额度分别设上限 |
| Batch `finalize-cpu`：C7 快照与 SQL 聚合 | 有满足收尾条件的 run，现有 CPU 容量无法及时执行已准入的收尾作业 | Batch 在独立 CPU 计算环境增加机器 | 出报窗口保留保底容量，完成后回落至配置的最低容量；收尾并发还受 PostgreSQL 连接与 I/O 预算限制。Agent worker 由独立 Harness 管理 |

**媒体例子：还剩 400 小时视频，应该准备几台 GPU 机器。** 假设本组 profile 使用单 GPU 机器，每台同时运行一个媒体作业；再假设端到端压测结果为一台机器每小时能完成 40 小时源视频，即有效实时倍数为 40。媒体阶段还可使用 4 小时：

```text
所需单 GPU 节点数 = ceil(剩余视频小时 / 单节点有效实时倍数 / 可用处理小时)
                  = ceil(400 / 40 / 4)
                  = 3
```

平台据此允许约 3 个媒体作业同时执行，由 Dispatcher 持续补充 pack。若当前只有一台这样的空闲机器，另外两个作业缺资源，Batch 就会尝试补足机器。平台不会同时去操作 Batch 底层的 Auto Scaling Group。**平台控制提交多少工作；Batch 根据已提交作业的资源需求决定开多少机器。** Batch 看到的是可运行作业及其资源请求，不知道“这个项目必须早上出报”。[Batch 作业状态](https://docs.aws.amazon.com/batch/latest/userguide/job_states.html)、[托管计算环境](https://docs.aws.amazon.com/batch/latest/userguide/managed_compute_environments.html)。

40 倍是说明算法的假设值，必须按编码、分辨率、CV 模型和处理配置分别测量，耗时包括读取、启动、上传和失败重试。可用媒体时间还要为末批 VLM 和项目日收尾留余量。多种 profile、多个租户分别估算后汇总资源需求，不能给所有视频套一个速度。

Batch 的 `minvCpus / maxvCpus` 配置容量范围，`desiredvCpus` 由 Batch 按队列需求调整。部分分配策略可能比 `maxvCpus` 多开至多一台实例，因此它不是精确费用上限；平台仍要限制在途作业、预留费用并观测实际开支。计算出需要 3 台也不代表一定能拿到 3 台，容量不足进入截止风险告警。[Batch 容量参数](https://docs.aws.amazon.com/batch/latest/APIReference/API_ComputeResource.html)。

**C6 例子：模型每分钟允许 600 次请求，应该启动几个 worker。** RPM 是每分钟请求数，TPM 是每分钟 token 数；在途请求指已经发出、尚未完成的请求。先假设任务充足，TPM、租户预算和在途上限都没有额外限制：

```text
模型允许的请求速率 = 600 / 60 = 10 次/秒
假设平均请求耗时   = 20 秒
需要的在途并发    ≈ 10 × 20 = 200 个请求

假设一个 C6 worker 可安全承载 50 个异步请求
目标 worker 数    = ceil(200 / 50) = 4 个容器
```

50 个异步请求不等于 50 个 CPU 核，大部分时间是在等网络响应。单 worker 安全并发要根据请求体大小、内存、网络和结果校验耗时压测；上述数字是示例，平均耗时公式只是稳态容量估算，实际需留余量。

平台的伸缩循环从数据库读取待调用与在途任务，从遥测读取 API 耗时，从共享限流器读取可用配额；结合任务到达速度和截止时间确定目标请求速率，再按上式换算容器数。SQS 最老消息年龄用于发现排队延迟；**队列长且 API 配额已满时，应告警或调整处理计划，加容器不能提高模型吞吐。** 每次调用仍需满足 RPM/TPM、租户预算和在途上限：Redis 原子协调短期额度，费用预留与实际 usage 持久化到数据库；429 触发退避，不触发盲目扩容。

第一版由平台作为 C6 `desiredCount` 的唯一写入方，通过 ECS `UpdateService` 调整容器数，不再给同一服务叠加另一个自动修改副本数的策略。CPU/GPU 利用率用于诊断瓶颈和校准单 worker 能力，不能单独说明业务是否需要更多副本。[ECS 副本数接口](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html)、[ECS 自动伸缩行为](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html)。

伸缩循环建议每 60 秒运行一次；目标上升时计入已启动及正在启动的容器，避免重复扩容；目标持续降低 5 分钟后才缩容。缩容先通知选中的 worker 停止领取新任务，处理中的 worker 使用 ECS scale-in protection，直到响应已提交且本地在途清零再解除保护；保护需续期，故障退出仍按第 6 章恢复。60 秒和 5 分钟是待压测的配置初值。[ECS 任务缩容保护](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-scale-in-protection.html)。

### 5.3 多租户、Spot 与业务截止时间

pack 尽量按相同资源 profile 装箱，避免一个低速格式拖住整个大作业。第一版 pack 不跨项目日，便于追踪和成本归集；节点仍可服务多个项目。接近截止时缩小剩余 pack，降低长尾。

Batch fair-share 在每条队列内按租户分配机会；平台另做跨队列的租户在途任务数与费用预留限制，避免同时走 Spot 和 On-Demand 绕过预算。队列内公平调度的机制见 [AWS Batch fair-share 说明](https://aws.amazon.com/blogs/hpc/deep-dive-on-fair-share-scheduling-in-aws-batch/)。

正常使用 Spot 和多个已验证的实例类型/AZ。预计无法完整赶上截止时告警，并在预授权应急预算内转入 On-Demand；若仍无法达到 >80%，立即升级人工处理。切换时作废旧尝试的提交资格，取消旧 job，新 job 从已提交 shard 恢复。上线前验证应急实例池和配额；On-Demand 容量不足仍需告警升级。

资源不足时优先恢复能补齐项目日有效结果的必要任务；不为提高完成率临时降低 CV/VLM 必要处理标准或删减分母。超出预授权预算的操作由值班人通过审计接口调整。

## 6. 状态管理与故障恢复

这一章沿任务的生命周期说明四件事：**记录什么状态 → 怎样确认成功 → 失败后从哪里恢复 → 何时停止接收结果。** PostgreSQL 中被接受的结果是业务进度的依据，S3 文件、Batch 作业状态和 SQS 消息都不能单独证明任务成功。

### 6.1 先分清项目日、子任务和一次执行

| 对象 | 表示什么 | 示例 |
|---|---|---|
| 项目日 `run` | 某项目某一天、某个 revision 的整次视频解析 | 项目 A 的 9 月 19 日视频解析 |
| 子任务 `task` | 需要独立确认结果的处理单元 | 一个媒体 shard，或一个 30 秒 VLM 窗口 |
| 执行尝试 `attempt` | 某个 worker 对同一子任务的一次执行 | 第一次在机器 A 运行，重试时在机器 B 运行 |

pack 是提交给 Batch 的作业包装，一个 pack 可以包含多个 shard。重启 pack 时，worker 从数据库查出已完成 shard 并跳过，继续处理其余 shard。

子任务的正常状态变化是 **`PENDING`（待执行）→ `RUNNING`（已领取）→ `SUCCEEDED`（结果已被平台接受）**。需要重新领取执行时回到 `PENDING`；无法恢复或重试耗尽进入 `FAILED`；截止或用户取消后，仍在等待或运行的任务进入 `CANCELLED`。单个 task 成功不等于整个 run 完成，项目日的完成规则见第 7 章。

### 6.2 正常路径：领取任务、提交结果、通知下游

以 C6 处理一个 VLM 窗口为例，正常执行有五步；媒体 shard 使用相同的领取与提交规则。

1. **领取。** C6 从 SQS 拿到任务 ID，向平台申请执行资格。平台确认任务可领取后，将其改为 `RUNNING`，发放递增的执行编号 `attempt_generation`，以及有效到 `lease_until` 的租约。租约表示“在这段时间内，你有资格处理并提交这个任务”，worker 通过心跳续期。
2. **计算并上传。** worker 调用模型，保存原始响应和处理结果。文件放在本次 attempt 的独立 S3 路径，输出清单固定对象版本和校验值；此时任务仍是 `RUNNING`。
3. **提交校验。** C5 检查产物是否存在、输入版本是否一致、结果结构及证据时间范围是否合法。S3 访问和内容校验在数据库事务外完成，避免长时间占锁。
4. **数据库接受结果。** 在短事务中，先锁 run、再锁 task，确认项目日仍接收结果、尚未到分析截止、执行编号和租约有效。随后一次性写入规范事实、run 的结果成员和任务成功状态；需要下游任务时，同时创建任务及 Outbox。事务提交后才返回成功回执。媒体提交会创建入选 VLM 任务；VLM 提交不会再创建自身任务。
5. **确认与分发。** C6 收到成功回执后删除 SQS 消息；Dispatcher 独立读取 Outbox 并投递下游任务。worker 不需要等下游消息送达才结束。

**为什么要 Outbox。** 它就是数据库里的待发消息表。假设结果已经入库，服务却在发消息前崩溃：由于结果和待发消息在同一个事务里，重启后的 Dispatcher 仍能找到消息并补发。消息可能重复，下游按任务 ID / 事件 ID 去重。[事务 Outbox 模式](https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html)。

C6 还要续期 SQS 的 visibility timeout，即“领取后暂时隐藏消息的时间”。它与数据库租约是两回事：前者减少重复领取，后者决定谁有权修改业务状态；SQS 仍可能重复投递，执行资格始终由数据库检查。[SQS 可见性超时](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)。

### 6.3 失败路径：先查已接受的结果，再决定恢复动作

遇到错误先查数据库：结果已被接受，就补确认或补消息；尚未接受，才考虑重提结果或重算。具体按失败位置处理：

| 发生了什么 | 谁处理、怎样恢复 |
|---|---|
| Spot 被回收、媒体容器退出 | Batch 按配置重启作业；新 worker 向平台领取新执行编号，只处理数据库里尚未成功的 shard。Batch 负责重启容器，跳过已完成 shard 由我们的 worker 实现 |
| S3 读取或上传短暂失败 | I/O SDK 在本次执行内短重试；超出时间或次数上限再上报，不从头重算整个项目日 |
| VLM 返回 429、可恢复 5xx 或超时 | C6 退避后按额度、预算和截止时间决定是否重试；每次实际调用独立记录费用与 request_id |
| GPU 内存不足、确定性程序错误、坏文件或持续无效的模型结果 | 记录失败范围和原因，停止原样反复重跑。按 profile 允许的纠正策略处理，或修正配置/输入后显式重驱；其他任务继续 |
| 文件已上传，但平台尚未接受结果 | 执行资格仍有效时，重提同一份输出清单；资格已失效则保留为尝试产物，需重新校验登记后才能复用 |
| 数据库已接受，但成功回执丢失，或 SQS 消息再次出现 | 查询已有成功记录；相同已接受提交返回原回执，不再计算，也不重复写事实或累计完成时长 |
| Outbox 投递失败、作业通知漏收、任务进入死信队列（DLQ） | Dispatcher 补投递；Reconciler 定期对照数据库与 Batch/SQS 状态，修复漏通知或发起受控重驱，不能直接把任务标成成功 |

**重试时，新的执行接替旧的执行。** 例如 A 领取任务，执行编号为 7；A 失联、租约过期后，B 重新领取，编号变为 8。A 即使稍后恢复，也不能凭编号 7 续租、上报失败或提交新结果。所有状态写入都检查当前编号；任务 ID 不变，重试只增加执行尝试。

媒体作业需要显式配置 Batch 重试策略，只对可恢复的基础设施故障重试；确定性错误匹配退出规则。平台核对 Batch 是否已经在重试，避免同时再提交一份。**主动取消或终止的 Batch 作业不会自动重试**，切换资源池时由平台显式提交替代作业。[Batch 重试规则](https://docs.aws.amazon.com/batch/latest/userguide/job_retries.html)。

建议初始基础设施总尝试上限为 3 次（含首次），无效模型响应最多额外纠正 1 次；其他请求重试次数和退避间隔写入 profile。换 worker 或资源池仍受平台累计次数、预算和截止限制，不能重新获得一轮无限重试。失去租约的 worker 停止新调用和新结果提交。

**平台结果去重不能保证外部模型只收费一次。** 模型已经处理完成、响应却丢失时，若提供方不能按 request_id 查询或保证请求幂等，再调用可能再次收费。已有原始响应应优先复用；不确定的调用保留费用预留并标记待核对。

重试复用相同输入和配置的结果；改变模型或 prompt 属于新的计算版本。结果唯一键和跨 revision 复用规则见[接口与数据契约第 2 节](/Users/bytedance/aligned-video-pipeline/docs/cloud-video-pipeline-contracts.md)。

### 6.4 项目日收尾：停止接收新结果，再固定报告数据

全部规定处理完成，或到达分析截止时间时，Coordinator 调用同一个 Finalize。它按以下顺序收尾：

1. **关闭结果集合。** 锁住 run，将 `RUNNING` 原子改为 `FINALIZING`，停止新任务准入。结果提交也先锁同一行：已通过受理检查并成功提交的结果进入集合；关闭后新到的结果不能加入。提交入口自身也按数据库时间检查截止，避免 Reconciler 延迟执行时继续接受新结果。
2. **固定快照。** 根据已接受的结果成员分批构建 `snapshot_id`，完成 SQL 聚合。构建中崩溃，就继续构建同一个快照，不能重新打开集合吸收后来结果。
3. **决定是否通知 Agent。** 快照和聚合可读，且可信完成率严格 >80%，才在同一事务写项目日终态与 `video_ready` Outbox；不满足则记录原因并告警。完整与部分完成的状态定义见第 7.2 节。

截止关闭集合时，同时发出取消排队作业、终止遗留 job 的请求；Reconciler 持续确认它们已停止，避免继续花钱。清理与快照构建可以并行，结果入口已经关闭。

迟到文件可以留作审计或补算材料，但不能改变本次快照。补算需新建 revision，重新校验并登记可复用产物，生成新的报告版本；旧快照和旧报告保持不变。

## 7. 项目日任务、完成判定与运行观测

### 7.1 >80% 的计算口径

按视频时长计算，使用 64 位毫秒整数。对同一设备的重复文件和重叠区间先去重，不同头盔的时长分别累加。

```text
D = expected_ms：本次项目日输入合同中应处理区间的总时长
S = ready_ms：已提交且满足规定解析步骤的区间总时长
解析完成率 = S / D
允许出报 = 分母可信且 D > 0，且 5 × S > 4 × D
```

D 来自冻结的完整输入清单及其应覆盖区间。缺失、损坏、失败和取消的范围不能从 D 中删除；400 小时只是容量基线，不能拿来替代每个项目实际输入。若上游只提供“已收到的文件”，无法说明全天应有范围，则只能计算已收到数据的处理率，不能宣称项目日达到 80%；须补齐输入合同后判断。

一个范围计入 S，需媒体/CV 成功并完成该范围所有**按既定策略必需**的 VLM/复核任务。未被门控选中的范围可在基础处理成功后计入；入选范围不能在 VLM 失败后改成未选中。计算到窗口对应的时间范围，避免一个窗口失败就扣掉整个 10 分钟 shard。

`unknown` 是已成功解析但无法判断的业务结果，可计入处理完成率；另外显示画面可见率、状态可判定率和 VLM 覆盖率。完成率不代表模型准确率，也不代表未发现风险。

例如 D=400 小时：320 小时恰好是 80%，不触发；321 小时允许出带缺失说明的报告。展示百分比可以舍入，门禁判断必须使用原始整数。

### 7.2 何时收尾、何时触发 Agent

提前收尾需满足：分母可信且 S=D；输入与媒体规划已关闭；所有必要子任务已登记且成功完成；规范事实与覆盖范围已提交。其余情况按截止入口收尾。动态创建 VLM 任务与媒体提交必须在同一事务，防止暂时看不到下游任务就提前完成。计数用于加速，最终核对真实记录。

`analysis_cutoff_at = report_due_at - report_reserve`。预留时间覆盖快照、聚合、消息投递、Agent 与 PDF 的实测耗时及重试余量。完整成功可提前收尾；不足完整的任务在截止前继续按策略恢复，不因刚超过 80% 就停止处理。

| 收尾结果 | run 状态 | Agent 行为 |
|---|---|---|
| 全部规定解析完成，快照可用 | `SUCCEEDED` | 触发正常报告 |
| 截止时 >80% 且 <100%，快照可用 | `PARTIAL` | 触发报告，携带缺失范围和覆盖说明 |
| 截止时 ≤80%，或分母无法可信确定 | `INSUFFICIENT_DATA` | 不触发正常晨报；升级业务告警并继续人工恢复 |
| 输入合同无效或快照构建不可恢复失败 | `FAILED` | 告警并修复，禁止发送就绪事件 |
| 用户主动取消 | `CANCELLED` | 不生成新报告 |

初始状态为 `CREATED`，开始执行为 `RUNNING`；收尾期间为 `FINALIZING`。最后一个子任务结束不直接等于 run 成功，快照和聚合可读后才能进入可出报终态。

收尾服务在同一事务更新可出报状态并写事件 Outbox：

```json
{
  "event_type": "project_day.video_ready.v1",
  "event_id": "evt-project-42-20260919-r1",
  "tenant_id": "tenant-7",
  "project_id": "project-42",
  "business_date": "2026-09-19",
  "run_id": "run-42-r1",
  "revision": 1,
  "report_profile": "foreman-report-v1",
  "snapshot_id": "snapshot-42-r1",
  "outcome": "PARTIAL",
  "coverage": {"expected_ms": 1440000000, "ready_ms": 1155600000}
}
```

上述例子为 400 小时中完成 321 小时。Agent 根据 `(tenant_id, run_id, snapshot_id, report_profile)` 创建唯一报告任务，重复事件返回已有任务。报告状态单独记录 `PENDING / RUNNING / SUCCEEDED / FAILED`；报告失败只重试报告。

视频快照固定视频事实与人员绑定。Agent 启动报告任务时再固定所用 `ext_*` 版本，生成报告读取上下文；重试继续使用该上下文。外部进度、费率或材料数据缺失须按对应章节降级，不能编造；它们不改变视频完成率。

### 7.3 项目看板与资源监控

项目看板从数据库读取业务状态，通过 `run_id → attempt → Batch job / ECS task → instance / GPU UUID` 关联资源遥测。数据库决定是否就绪，CloudWatch/Prometheus 用于诊断与告警，不参与最终完成率判定。

| 看板层级 | 必须可见的信息 | 数据来源 |
|---|---|---|
| 项目日 | D/S、缺失范围、各阶段完成率、预计完整/达到门槛时间、报告状态、预算与费用 | 任务/事实/用量数据库 |
| 阶段与作业 | 排队时间、吞吐、重试、失败原因、I/O 等待、VLM 排队/限流 | worker 结构化日志、计时与原生作业状态 |
| 节点与 GPU | CPU、内存、磁盘、网络、GPU、显存、NVDEC/NVENC、GPU 错误 | CloudWatch Agent / Container Insights / DCGM |

AWS Batch 的 [Container Insights](https://docs.aws.amazon.com/batch/latest/userguide/cloudwatch-container-insights.html)可采集 CPU、内存、磁盘和网络。GPU 基础指标可用 [CloudWatch Agent](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-NVIDIA-GPU.html)；编解码器与更细 GPU 指标采用 [DCGM Exporter](https://docs.nvidia.com/datacenter/dcgm/latest/reference/dcgm-exporter-metrics.html)，按实际 GPU/驱动验证可用字段，并接入 Prometheus 兼容采集与看板。

若执行层采用 Cosmos Curator，可复用其 [阶段指标、Grafana 看板与 profiling](https://github.com/NVIDIA/cosmos-curator/blob/main/docs/curator/guides/observability.md)。常态采集吞吐、资源和队列；详细 CPU/GPU profiling 在基准或排障时开启，避免生产全量采样成本。

日志关联 `tenant_id/project_id/run_id/task_id/attempt_id/trace_id`。每个片段和任务 ID 保存在日志、数据库或采样 trace 中，不全部变成长期时序指标标签。看板支持从项目下钻到失败任务和对应机器。

### 7.4 夜间告警与人工介入

Coordinator 按约 1 分钟周期更新剩余工作量、资源缺口和预计完成时间。预测分别考虑媒体吞吐、模型 API 配额与有效吞吐；不只用已完成比例做线性外推。以下为待压测校准的初始告警规则：

| 条件 | 级别 | 系统动作与人工检查 |
|---|---|---|
| 预计完整处理时间超过 cutoff | P2 | 标记交付风险；检查瓶颈，在应急预算内增加已验证容量 |
| 预计到 cutoff 仍无法严格超过 80%，或剩余可成功范围已不足门槛 | P1 | 立即通知夜间值班人；检查容量、配额、失败范围和恢复路径 |
| 有待执行任务但连续 10 分钟无有效进展；或 Batch RUNNABLE 超过 10 分钟 | P1 | 检查 EC2 配额、实例容量、镜像启动、权限和卡死任务 |
| 持续 OOM/磁盘高水位、VLM 持续限流/服务不可用导致交付风险 | P1/P2 随交付风险 | worker 先背压；人工调整并发、资源 profile、API 额度或实例池 |
| 可出报但 Outbox 超过 2 分钟未送达，或 Agent 失败影响出报时间 | P1 | 检查 Dispatcher、队列和 Agent；重投相同事件/重试报告 |
| 预计超过费用上限，预算准入已阻塞必要任务 | P1 | 展示超额需求；值班人批准临时预算或明确未达业务目标 |

值班动作沿同一条链执行：**确认受影响项目与剩余时间 → 定位阶段 → 扩容/切 On-Demand/恢复配额/重驱任务 → 检查有效吞吐和 ETA 恢复**。资源申请成功不等于业务恢复，必须看到 ready_ms 持续增加。

告警按项目日和根因合并，记录事件、负责人、确认时间和处置记录。建议 P1 在 5 分钟无人确认时升级到备班；实际值班人、渠道、升级时限及应急预算必须在上线前配置。告警链本身需要心跳和演练，不能只依赖可能已卡住的主工作流发告警。

运行中可以调资源、预算和任务优先级，但不得直接修改成功状态、完成率或快照成员。截止未达 >80% 是业务未达标事件，不能通过降低阈值掩盖。恢复后创建新 revision 出补报，保留原事件记录。

## 8. 成本估算与记录

### 8.1 存储成本

以 us-east-1 公布单价估算：Standard 前 50 TiB 为 $0.023/GB·月，后续阶梯为 $0.022、$0.021；Glacier Instant Retrieval 为 $0.004；Deep Archive 为 $0.00099。AWS 存储 GB 按 2³⁰ 字节计费，此处 1.08 TB 输入按十进制换算。[S3 价格](https://aws.amazon.com/s3/pricing/)、[Glacier 存储等级](https://aws.amazon.com/s3/storage-classes/glacier/)。

假设连续产生 365 天数据、没有删除，以下是积累到一年时的**月度存储费量级**，不是全年累计费用；100 项目按同区域合并用量的 Standard 阶梯计算。

| raw 存储策略 | 1 项目：394.2 TB | 100 项目：39.42 PB |
|---|---:|---:|
| 全部留 Standard | 约 $8,128/月 | 约 $771,531/月 |
| 最近 7 天 Standard，其余 Deep Archive | 约 $518/月 | 约 $50,997/月 |

这只是 raw 容量费，未计 proxy、对象元数据、请求、转换、恢复、恢复后的临时副本和网络。实际过热期、失败任务留存及月内增长会改变账单。归档降低单位存储价格，但无限保留仍会持续增加总成本；项目合同必须明确总保留期和例外保留规则。

### 8.2 机器成本

**参考单项目每天 400 视频小时：CPU 编解码中档预算约 $44，GPU 编解码约 $13；Qwen API 约 $7，Gemini API 约 $8–34。常驻平台另需约 $605–705/月，由客户共享。** 这些是下述配置与吞吐假设对应的分项费用，CV、视频存储和流量另计，不能直接当作全系统报价。

价格核对日期为 **2026-09-20**，AWS 选 **us-east-1、Linux、On-Demand**。EC2、RDS、Redis 单价来自 AWS Price List，选中条目的生效日为 2026-09-01；单价、SKU、假设和计算结果保存在[本次成本快照](/Users/bytedance/aligned-video-pipeline/docs/assets/cloud-video-pipeline/cost-estimate-2026-09-20.json)。不扣免费额度，不预支 Spot 折扣，不含税和支持计划。

#### 8.2.1 解码、缩放、编码：CPU 与 GPU 分别多少钱

本次先按 **H.264 1080p30 原片 → H.264 640×360、15 fps、无音频 proxy** 做预算。实际分辨率和编码配置尚未确认；两条路径必须通过相同的画面细节与质量验收，才能比较价格。

| 路径 | 用于比价的 EC2 | 一台机器包含什么 | EC2 单价 |
|---|---|---|---:|
| CPU 软件编解码 | `c7i.2xlarge` | 8 vCPU、16 GiB 内存；FFmpeg 软件解码、缩放、libx264 编码 | $0.357/小时 |
| GPU 硬件编解码 | `g4dn.xlarge` | 4 vCPU、16 GiB 内存、1 张 T4（16 GB 显存）；NVDEC 解码、GPU 缩放、NVENC 编码 | $0.526/小时 |

GPU 行的价格已经包含整台服务器，**不用再加一次 CPU 和内存的钱**。本例两种机器都再配 64 GiB gp3，按 $0.08/GiB·月、30 天折算为 $0.00711/小时；计入后分别为 **$0.36411、$0.53311/节点小时**。节点结束即释放临时 EBS，持久化结果在 S3。[EC2 价格](https://aws.amazon.com/ec2/pricing/on-demand/)、[EBS 价格](https://aws.amazon.com/ebs/pricing/)。

**吞吐尚未实测，所以列出三档算例。** “4 倍实时”指一台机器用 1 小时处理完 4 小时原片，包含该编解码路径的读写和封装，不是单独的编码器 FPS。下面另加 20% 节点小时预算，覆盖启动、空闲和重试；20% 也需要上线后校准。

| 路径 / 吞吐假设 | 1 项目：计费节点小时预算 | 1 项目：费用/天 | 100 项目：费用/天 | 100 项目在 6 小时内处理：并行机器数 |
|---|---:|---:|---:|---:|
| CPU：2 倍实时 | 240 | $87.39 | $8,738.67 | 4,000 |
| **CPU：4 倍实时，中档算例** | **120** | **$43.69** | **$4,369.33** | **2,000** |
| CPU：8 倍实时 | 60 | $21.85 | $2,184.67 | 1,000 |
| GPU：10 倍实时 | 48 | $25.59 | $2,558.93 | 800 |
| **GPU：20 倍实时，中档算例** | **24** | **$12.79** | **$1,279.47** | **400** |
| GPU：40 倍实时 | 12 | $6.40 | $639.73 | 200 |

计算例子：`400 视频小时 ÷ 20 倍 × 1.2 × $0.53311 = $12.79/项目·天`。100 个项目乘 100；并行机器数为 `ceil(计费节点小时预算 ÷ 6 小时)`。这是假设队列持续有工作、资源能及时启动的容量预算，并非保证可申请到这些机器。

**是否用 GPU 的判断线：在同等输出质量下，GPU 整机吞吐超过 CPU 的约 1.46 倍，才比 CPU 便宜。** 不能只比较 $0.526 与 $0.357，也不能把上表假设的 5 倍速度差当作测量结果。AWS 有[编解码实例对比](https://aws.amazon.com/blogs/compute/deep-dive-on-amazon-ec2-vt1-instances/)，但其 1080p60 测试规格不能直接替代我们的 proxy 基准。

**CV 怎样记账：** 上表只计算编解码，不包含尚未选定的 CV 模型。若 CV 与编解码在同一媒体 GPU 作业里执行，就用“含 CV 的整机实测吞吐”替换表中的倍数，按整机实际运行时间付费；不能把相同的一小时 GPU 再收费一次。若另起 CV 实例池，其费用才单列。当前没有证据支持报出完整 CV 费用，也不能把 CPU 编解码费用当成纯 CPU 完成整条解析管线的价格。

#### 8.2.2 平台常驻与辅助作业：没有视频也有账单

以下是**一套共享平台的起步配置预算**，每月按 30 天、720 小时。常驻平台保持在线，媒体和 API worker 不放在这些常驻副本里。此配置需经压测扩容，不能默认一套小数据库永远支撑 100 个客户。

| 项目 | 预算配置与算法 | 每月费用 |
|---|---|---:|
| 平台 API / Coordinator / 提交服务 | 合计 4 个 Fargate 副本，每个 1 vCPU + 2 GiB；约 $0.04937/副本小时 | $142.19 |
| PostgreSQL | RDS `db.m7g.large` Multi-AZ，$0.337/小时，已含主备实例费用 | $242.64 |
| 数据库磁盘 | Multi-AZ gp3，100 GiB × $0.23/GiB·月 | $23.00 |
| Redis | 2 个 `cache.t4g.small`，每个 $0.032/小时 | $46.08 |
| 平台入口 | 1 个 ALB，$0.0225/小时，平均另计 1 LCU × $0.008/小时 | $21.96 |
| API 出站网络固定费 | 2 个 NAT Gateway，每个 $0.045/小时 | $64.80 |
| 公网 IPv4 | 预算 4 个地址：ALB 两个、NAT 两个；每个 $0.005/小时 | $14.40 |
| **以上已列项小计** | 不含按流量增长的项目 | **$555.07** |
| 日志、监控、ECR、SQS 等 | 起步另留 $50–150/月预算；这是预算额，不是固定费率 | $50–150 |
| **共享平台起步预算** | 数据库备份超额、流量、扩容另计 | **$605–705/月** |

依据：[Fargate](https://aws.amazon.com/fargate/pricing/)、[RDS PostgreSQL](https://aws.amazon.com/rds/postgresql/pricing/)、[ElastiCache](https://aws.amazon.com/elasticache/pricing/)、[ALB](https://aws.amazon.com/elasticloadbalancing/pricing/)、[NAT 与 IPv4](https://aws.amazon.com/vpc/pricing/)。AWS Batch 本身不额外收费，底下的 EC2、EBS 等照常计费；ECS on EC2 也不是再收一次机器费。[Batch 计费说明](https://aws.amazon.com/batch/pricing/)。

如果只有 1 个项目承担整套平台，固定预算约 **$20–24/天**；10 个项目共享约 $2.0–2.4/项目·天。客户增长后按实际扩容账单分摊，不能把固定费对每个客户重复全额收取。

另外两类 CPU 用量随任务增长：

| 辅助计算 | 假设 | 1 项目费用/天 | 100 项目费用/天 |
|---|---|---:|---:|
| 探测、规划、收尾作业 | 每项目先预留 1 个 `c7i.2xlarge` 节点小时，含临时盘；待基准替换 | $0.36 | $36.41 |
| VLM API 调用容器 | 每容器 1 vCPU + 2 GiB，最多 50 个在途请求，运行 8 小时；分别需要 1 / 24 个容器 | $0.39 | $9.48 |

API 容器数按本节 35% 入选、平均响应 20 秒计算。100 项目需要约 1,167 个在途请求，`ceil(1,167 ÷ 50) = 24`。这只是 HTTP 调用服务的预算；模型 GPU 由 API 提供方付费运营，其费用体现在下一节的 token 单价里。增加容器仍无法突破账户的 RPM/TPM。

#### 8.2.3 Qwen 与 Gemini API：按视频 token 算，不按 TB 算

沿用当前 API 架构比较。单项目 400 小时，若 35% 入选、每次 30 秒，则为 **140 小时视频、16,800 次请求/天**。预算中只分析画面，采用 1 fps 抽样；额外音频、复核和重试另计。1 fps 与低分辨率仍须通过漏检验收，不能仅因便宜就确定为生产配置。

每个模型先用自己的 token 规则估算，不能把 Qwen 和 Gemini 的 token 当作相同单位的画面质量：

| 输入预算 | 每次 30 秒视频的估算依据 | 本表使用的计费输入 |
|---|---|---:|
| Qwen3-VL | 30 帧；640×360 经 32 对齐后约 640×352，视觉 token 约 `ceil(30/2) × 20 × 11 + 2 = 3,302`；再加提示词、时间码与模板余量 | 4,000 token |
| Gemini 低分辨率静态分析 | 30 帧 × 66 token ≈ 1,980；再加提示词和元数据余量 | 2,500 token |

模型预处理可能再次缩放或补帧，以上是预算值，最终按 `countTokens` / 请求 `usage` 核对。[Qwen 视频 token 算法](https://www.alibabacloud.com/help/en/model-studio/vision)、[Gemini 视频计费规则](https://ai.google.dev/gemini-api/docs/video-understanding)。每次另预算 **500 个总计费输出 token**，包括可能的 thinking；若实际输出更长，应按实际计费总量增加，不能只记最终 JSON。

| API 模型 / 计费范围 | 输入 $/百万 token | 输出 $/百万 token | 35% 入选：1 项目/天 | 35% 入选：100 项目/天 | 100% 入选：1 项目/天 |
|---|---:|---:|---:|---:|---:|
| **Qwen3-VL-Flash，US scope，输入 ≤32K** | **$0.05** | **$0.40** | **$6.72** | **$672** | **$19.20** |
| **Gemini 2.5 Flash-Lite** | **$0.10** | **$0.40** | **$7.56** | **$756** | **$21.60** |
| Gemini 3.1 Flash-Lite | $0.25 | $1.50 | $23.10 | $2,310 | $66.00 |
| Gemini 2.5 Flash | $0.30 | $2.50 | $33.60 | $3,360 | $96.00 |
| Gemini 3.5 Flash-Lite | $0.30 | $2.50 | $33.60 | $3,360 | $96.00 |

单价采用 [Qwen 官方 US 部署范围价格](https://www.alibabacloud.com/help/en/model-studio/model-pricing)与 [Gemini Developer API 标准付费价格](https://ai.google.dev/gemini-api/docs/pricing)，不套中国区、Global 路由或批量折扣。Qwen 运行时要固定具体模型版本和部署范围；Gemini 此处不是 Vertex AI 区域报价。

Qwen 一行的算法为：`16,800 × (4,000 × $0.05 + 500 × $0.40) ÷ 1,000,000 = $6.72/天`。这是调用量和单价相乘，**不代表便宜模型已满足安全检测、计数或活动识别要求**。

清晰度会改变费用：Qwen 若每次输入升到 15,000 token，变为约 **$15.96/项目·天**；Gemini 若改用约 258 token/帧，将每次输入预算提高到 8,500 token，则 2.5 Flash-Lite 约 **$17.64**，2.5 Flash 约 **$63.84/项目·天**。35% 入选尚未验证，若最后必须全量分析，调用量与 API 费用都增加到约 2.86 倍。

本版次日晨报先按标准在线 API 预算。Gemini Batch 通常有 50% 折扣，但其目标周转时间为 24 小时，不适合直接承担 6–8 小时的出报期限。[Batch 时效说明](https://ai.google.dev/gemini-api/docs/batch-api)。100 项目在 8 小时完成仍需平均 **3,500 RPM**；按本表输入预算，对应 Gemini 约 875 万、Qwen 约 1,400 万输入 token/分钟，需提前申请并验证配额。

#### 8.2.4 如果以后自部署 Qwen，要另外付多少 GPU 费

这只是备选比价，**不改变当前采用 API 的架构**。用量化后的 `Qwen3-VL-8B-Instruct` 作为小模型部署候选，以 `g6.2xlarge`（8 vCPU、32 GiB 内存、1 张 24 GB L4）为价格基准：**$0.9776/小时**，加 64 GiB gp3 后约 $0.98471/小时。[Qwen 模型与部署文档](https://github.com/QwenLM/Qwen3-VL)、[AWS G6 规格](https://aws.amazon.com/ec2/instance-types/g6/)。

单机显存能否容纳所需上下文和并发，以及量化后的质量，均待验证。8B 模型与上面的 Flash API 不是同一个模型，不能假定效果等价。下面的吞吐须覆盖视觉编码、prefill、生成及请求处理，不是单独的输出 token/s：

| 假设单机完整请求吞吐 | 1 项目：节点小时预算，含 20% 余量 | 1 项目在 8 小时内需要的 GPU 机器 | 1 项目推理机器费/天 | 100 项目推理机器费/天 |
|---|---:|---:|---:|---:|
| 0.25 请求/秒 | 22.4 | 3 台 | $22.06 | $2,205.75 |
| 0.5 请求/秒 | 11.2 | 2 台 | $11.03 | $1,102.88 |
| 1 请求/秒 | 5.6 | 1 台 | $5.51 | $551.44 |

本例自部署要达到约 **0.82 个完整请求/秒/台**，机器费才低于 Qwen Flash API 的 $6.72/项目·天；运维、保底副本、模型分发和额外存储还未计入。若没有任务也让一台机器连续开 30 天，仅 EC2 与示例临时盘就约 **$709/月**。因此是否自部署，要同时比较实测吞吐、质量与机器空闲时间。

**把账单加齐。** 实际总费用为：`编解码与 CV 整机账单 + 辅助 CPU + API 调用费（或自部署推理费）+ 共享平台分摊 + S3 + 网络`。同一个 GPU 小时只记一次，模型 API 与自部署推理选择对应方案计费。

视频流量也不能漏：若模型窗口平均 0.5 Mbps，140 小时约为 31.5 GB（十进制），约 29.34 GiB。按 $0.09/GiB 首档估算，AWS 出网约 **$2.64/项目·天**；若由 worker 经 NAT 上传，再加约 **$1.32**。若提供方直接读取 S3 签名 URL，视频字节不经过我们的 NAT。这里未扣免费额度和大流量阶梯优惠。[AWS 数据传输](https://aws.amazon.com/ec2/pricing/on-demand/)、[NAT 数据处理费](https://aws.amazon.com/vpc/pricing/)。同区域 S3 → EC2 原片读取走 Gateway Endpoint，避免把 1.08 TB/项目·天送进 NAT。

### 8.3 成本记录

| 成本项 | 记录方式 |
|---|---|
| 媒体 / CV / CPU 作业 | attempt 记录节点、资源申请、起止时间和价格依据；重试与孤儿作业也计入 |
| VLM API | 每次调用记录提供方、部署范围、具体模型版本、provider request_id、输入/输出/thinking token、实际价格版本和费用；重试、响应不确定的尝试也需核对 |
| S3 与网络 | 记录 GET/PUT、读取和写入字节、派生对象大小与保留时间；模型 API 出站、内部跨 AZ 传输及归档恢复单独归集 |
| 常驻平台 | 数据库、Redis、队列、监控费用按约定分摊，保持分摊规则版本 |

运行中显示估算值及其价格时间；云账单到达后核对。共享节点按已分配资源 × 占用时间归集，启动与空闲费用单独分摊，不能把每个并发任务都算成整台机器，也不能只按 GPU 利用率计费。

主要单位指标为 `美元 / 输入视频小时`，同时显示 `美元 / 成功解析小时`，避免通过跳过失败视频美化成本。存储按 raw/proxy/响应/快照分别计算保留量与存储层级单价。此前的 $0.15/helmet-hour 不作为生产报价。

## 9. 上线前的验证与回退

| 验证阶段 | 必须得到的证据 |
|---|---|
| 单机基准 | 真实编码和分辨率样本下的阶段耗时、吞吐、资源峰值与成本；输入大于缓存仍不 OOM |
| 多机扩展 | 逐级增加节点，记录总吞吐、扩展效率、数据库与 S3 瓶颈；不以重复缓存命中代表真实数据吞吐 |
| 故障演练 | 回收 GPU 节点、VLM 持续限流/不可用、消息重投、旧 worker 迟到；恢复后结果唯一、旧快照不变 |
| 业务验收 | 79.99%、80%、80.01% 边界正确；分母缺失时阻止错误触发；告警、确认、升级、人工恢复和 Agent 出报完整演练 |
| 模型验收 | 独立连续标注集验证 CV/门控/VLM 效果；处理完成率不能替代召回率与误报评估 |

基础设施用 Terraform，镜像用 digest，run 固定处理 profile。先跑固定样本，再跑完整项目日影子任务；新版本异常时停止新准入、恢复旧默认镜像/profile，已有快照保留。数据库采用兼容增量迁移，不用删除历史结果做回退。

租户边界落实在鉴权、数据库键、查询上下文和 S3 权限；任务只能读取获准的项目输入。模型 API 密钥放 Secrets Manager，日志不记录签名 URL 或密钥。报告交付继续执行已有 HITL 规则。

待基准与上线准备确认：原片格式/单文件分布、实际出报时刻及预留时间、CV/门控质量要求、VLM 提供方/模型/配额与有效吞吐、实例 profile、raw 保热期与总保留期、租户预算与夜间应急授权。确认这些参数后才能给出可承诺的处理时长和单价。
