Eros Live Engine
Internal Architecture Review · 2026-08-19

Eros Live Engine 技术设计与当前实现

面向研发、算法、数据供应商、播放器和运维的内部说明。本文描述已经运行的 CPU-only SUT、接口合同、因果时间轴和故障策略;目标方案与尚未完成的能力会显式标注,不把演示结果写成生产结论。

文档状态Implementation Baseline v1
当前环境GCP CPU 单场部署
代码仓库eros-live-engine / main
阅读对象研发 · 数据 · 播放 · 运维
已实现部分实现生产待办所有时间均为媒体 PTS接口版本 v1
Playout Buffer10,000 ms视频与解说统一延迟
Frame Sampling1,000 ms视觉并发上限 8
Writer SelectionFast + Quality最终只交付一个版本
Deployment8C / 16G单场、CPU-only、无主备

00 · 架构结论与阅读约定

当前已经确定

  • SUT 不接管原视频播放,只输出带目标 PTS 的独立解说音轨
  • 视频、事件、视觉结果和音频统一使用媒体 PTS,而不是模型完成时间
  • 硬事实以官方事件为准;视觉只输出画面状态和未经确认的候选
  • 双路写手都是真实生成,不使用固定句库或结构化文案兜底
  • 单场系统无本地 GPU,视觉、写作和 TTS 均调用外部服务

状态标记

implemented当前 main 分支与线上环境已经运行
partial数据结构存在,但消费链路或生产保障不完整
required正式接入上游或规模化前必须补齐
范围:当前只承诺同时处理一场比赛;数据库可保存多场历史,一场结束后无需重部署即可创建下一场。

01 · 整体架构

四个独立数据面:控制、视频、赛事事件、音频交付。视频里不夹赛事 JSON,事件 API 也不传图片。

控制面

创建比赛、准备 Match Package、arm/end。赛前资料在 arm 后冻结。

媒体面

SRT → MediaMTX → CPU PyAV → 约 1 Hz JPEG + 原始 PTS。

事实面

官方数据通过独立 HTTPS Push;支持修订、撤销、回放和幂等。

播放面

S3 WAV + HMAC Callback;下游按目标 PTS 播放并返回 receipt。

直播视频SRT / OBS / 编码器
MediaMTX鉴权与路径路由
CPU SamplerPyAV · 1 Hz · PTS
Eros SUT融合、写作、记忆
官方事件HTTPS Push
PostgreSQL不可变事件账本
Fish + S3完整 WAV
下游播放器Callback + played
S3 不负责临时传帧。 JPEG 直接进入 SUT/OpenRouter;S3 主要保存下游可下载的音频和可选审计产物。SUT 也不回传原视频,只交付与原媒体 PTS 对齐的独立解说音轨。

02 · 10 秒预算不是串行 13 秒

连续视觉任务并行,官方事件绕过视觉等待,两个写手并行;TTS 只使用剩余预算。

阶段默认值策略
视频抽帧1,000 ms约每秒一帧,视觉池最多 8 个任务并行
云视觉6,000 ms timeout默认 GPT-5.6 Luna;输出结构化低风险状态
Fast Writer2,200 msLuna 实时路
Quality Writer3,000 msSOL 质量路;Fast 有效时只追赶 450 ms
选择截止3,150 ms两路最终只交付一个有效版本
Fish TTS最多 4,000 ms受 source PTS + 10 秒总 deadline 约束
不允许把迟到句子往后挪。音频仍指向它描述的原画面;来不及就静默。否则“上一句话描述下一幅画面”会比短暂留白更破坏体验。

03 · 媒体时钟、视频帧与现场事件对齐

系统不按 HTTP 到达顺序拼接信息。每条信号同时记录“发生在哪里”和“什么时候可用”,写作与播放都以原始画面的媒体 PTS 为主轴。

source_pts_ms

帧或事件在原视频中的位置。由解码帧 pts × time_base 得到,是写作、融合和播放的主时间。

received / available PTS

系统真正获得事件或模型结果的媒体水位。它决定这一事实能否进入当前上下文,禁止后来信息穿越回过去。

wall clock

服务器收包和模型耗时的 Unix/monotonic 时间,只用于超时、延迟和运维审计,不决定音频配哪幅画面。

audio_deadline = source_pts_ms + 10,000 ms  remaining_budget = audio_deadline - available_pts_ms
示例:射门
100.0s 发生
102.4s 事件到达
104.1s 文案完成
105.3s WAV 完成
110.0s 播放截止
媒体时间轴
帧与事件都绑定 100000
received=102400
仍描述 100000
target_start=100000
观众在延迟后的 100s 同步听到

四类时间关系

情况判定系统动作是否改变目标画面
事件正常到达received ≤ source + 10s官方事件直接触发优先级 0 写作,不等待 VLM
事件晚到但仍有预算例如发生于 100s、102.4s 到达使用剩余 7.6s 完成 Writer、TTS 和 Callback否,仍排到 100s
事件超过播放截止ready > source + 10s即时句静默并记录 deadline miss;事实仍入赛中账本供后续统计禁止平移到后面
事件早于对应视频帧数据源比视频编码链路更快目标设计应进入 Event Jitter Buffer,视频水位到达 source PTS 后释放否,也不能提前泄漏
implemented 视频帧保留原始 PTS;VLM 结果保留 source/available;视觉迟到会生成 revision;音频保持原 source PTS,超过总截止即丢弃。
required 正式供应商事件时钟到视频 PTS 的映射,以及“事件早到”的抖动缓冲尚未完整落地。当前演示 sidecar 已知视频文件 PTS,不能代表生产数据天然对齐。

正式事件时钟接入顺序

  1. 优先要求上游提供与视频一致的 timecode/PTS。
  2. 其次使用双方 NTP 同步后的 UTC 时间建立映射。
  3. 只有比赛钟时,用半场开始、开球和关键事件建立分段锚点。
  4. 维护 offset/drift,不用单次事件直接重置全局映射。
  5. 按 stream_epoch 隔离媒体断点,比赛长期记忆继续沿用 match_id。
  6. 监控 clock_offset、event_lateness、early_queue 和 deadline_slack。

04 · SUT 内部处理逻辑

从帧到声音的每一步都保留证据、时间和可拒绝边界。

1. 帧合同与幂等

校验 match、epoch、递增 sequence、SHA-256 和 PTS;重复帧不会重复调用模型。

2. 单帧视觉观察

识别 scene、phase、控球方、区域、压力、镜头和安全 narration atoms;硬事件只能是 candidate。

3. 时序世界融合

保留最近 20 秒,在 5 秒窗口内按置信度和时间衰减投票;迟到观察会产生 revision。

4. Speech Planner

需要稳定画面、足够置信度和安全事实;新句 7 秒、相同状态 12 秒、硬事件后安静 6.5 秒。

5. Director

只决定 action / tactical / evaluation / person、优先级和允许引用的事实,不写固定句子。

6. 赛中记忆

按当前 source/received 水位最多补充 3 条已到达、未说过且可追溯的整场事实。

7. 双路云写作

Luna 与 SOL 阅读同一封闭证据集;程序校验证据引用、硬事实、重复和姓名权限。

8. TTS 与时间轴仲裁

Fish 生成 WAV;高优先级硬事件可 cancel 低优先级背景音频,不平移解说。

9. Outbox 与真实播放

PostgreSQL → S3 → HMAC Callback;只有下游 played 后才把事实记为已经说过。

05 · 关键接口与数据合同

控制、媒体、事实和播放四个数据面互不复用载荷。所有写接口都要求明确身份、版本或幂等键。

入口调用方 → 接收方职责鉴权/幂等
POST /v1/matches管理端 → SUT创建比赛并保存 Match PackageControl Bearer;match_id
POST /v1/matches/{id}/arm管理端 → SUT冻结赛前快照,返回一次性发布凭据Control Bearer;最多一场 ARMED/LIVE
SRT publishOBS/上游 → MediaMTX连续视频流;鉴权后创建 stream_epoch发布用户名、密码、path
POST /v1/events事件供应商 → SUT写入不可变事件 revisionEvent Bearer;event_id + revision + content hash
POST callback_urlSUT → 播放端推送 timed-audio upsert/cancelHMAC;delivery_sequence + idempotency_key
POST /v1/audio/ack播放端 → SUT确认 accepted / played / failed幂等键;只有 played 才消费赛中事实

FrameEnvelope

{
  "match_id": "match-001",
  "stream_epoch": "epoch-...",
  "source_pts_ms": 100000,
  "sequence": 100,
  "codec": "jpeg",
  "payload_base64": "...",
  "trace_id": "media:...:100"
}

MatchEvent revision

{
  "event_id": "shot-4421",
  "revision": 1,
  "canonical_id": "attack-4419",
  "source_pts_ms": 100000,
  "received_pts_ms": 102400,
  "event_type": "SHOT",
  "status": "confirmed",
  "authority": "official",
  "temporal_scope": "live"
}

Timed audio delivery

{
  "action": "upsert",
  "source_pts_ms": 100000,
  "target_start_pts_ms": 100000,
  "expires_pts_ms": 110000,
  "priority": 0,
  "codec": "wav",
  "audio_url": "https://...",
  "idempotency_key": "match:epoch:segment:r1"
}
断流语义:match_id 是整场长期业务主键;stream_epoch 是一次媒体连接。重连必须旋转 epoch,旧帧不能进入新 session,但同一场比赛的事件账本和赛中统计继续存在。

06 · 赛前准备数据

Match Package 是审核后的比赛知识快照,不是随意拼起来的一段 prompt。

维度示例当前用途
比赛身份赛事、轮次、日期、开球、场地业务实体与语言背景
知识边界knowledge_cutoff、source_refs防未来信息泄漏与审计
初始状态phase、片段范围、起始比分中途接入的起始世界
球队稳定 ID、中文名、主客、教练事件和文本统一映射
视觉身份普通/门将球衣及颜色同义词视觉辨别球队,不按球场方向猜
审核背景历史、交锋、人物、形势、战术长暂停中的知识卡
阵容上下文首发变化、关系、换人已存储,实时消费仍需增强
名单候选team、number、player ID/name姓名安全门,不等于视觉身份证明
已经真正消费:球队/球衣进入视觉;verified_context 进入 Director;名单进入姓名拒绝门;官方事件进入球员事实。
不能过度宣称:lineup_context、独立比分等虽已保存,但不会自动全部进入实时 Writer;关键事实仍需审核知识卡或官方事件。

07 · 赛中信号权威与取舍

视觉负责“看起来怎样”,官方事件负责“究竟发生了什么”。

Candidate单帧视觉候选
Corroborated多帧/辅助源支持
Operator人工操作确认
Official官方供应商事实
场景处理结果
官方事件与视觉冲突官方事件决定硬事实与 play state;视觉只保留低风险画面关系
两帧都像进球/犯规只能成为 corroborated visual candidate,仍是 confirmed=false
官方事件迟到按 received PTS 入场,不能让过去的 Writer 偷看未来;可解释此前候选
事件纠正或撤销新 revision 重建投影;retracted 不再参与统计
回放旧进球temporal_scope=replay,可说“回放看一下”,不重复累计
没有事件流visual_only 安全解说继续;禁止硬事实和球员姓名
Fast / Quality 竞争有限时间内 Quality 优先;否则选择通过校验的 Fast
两路都失败静默和告警,不使用固定文案兜底

08 · 赛中数据库:不是 RAG,是可重建的世界

不可变事件账本

event_id + revision 保存完整历史;canonical_id 归并 attempt/result;重试幂等,低权威不能覆盖高权威。

因果投影

只使用当前时刻已经收到的 live/confirmed 事实;排除未来、回放、撤销和未确认数据。

已说事实账本

射门、射偏、牌、犯规和换人等形成可追溯统计;只有 played 后才算真正消费。

因此系统可以在下半场说“他上半场三次攻门都偏出”,也可以在球员第二张黄牌后理解纪律状态;每一句统计都能追溯到原始 event refs,而不是模型凭印象记忆。

09 · 解说风格、TTS 与交付

风格与语气

  • Director 轮换动作、战术、评价和人物层
  • 最近 8 句进入写作上下文,程序再阻止重复
  • energy 映射 calm / focused / emphasis / excited
  • pace 限制在 0.90–1.08,避免赶读

单音轨优先级

0官方硬事件
1即时动作 / 回放切入
2普通战术与停止阶段
3赛前知识背景
当前 Fish 是流式 HTTP 接收,但播放器拿到完整 WAV 后才排程。TTFA 已经审计,尚未实现 chunk 级边生成边播放。

10 · 故障模型、降级与可观测性

实时系统不以“最终成功”作为唯一标准;迟到、错配和重复播放都属于失败。每个外部边界必须有超时、幂等和可审计结果。

故障当前行为用户侧表现关键指标/告警
视频断流sampler 停止提交;session 标记 disconnected;重连旋转 epoch停止产生新句,已有比赛记忆保留last_frame_age、media_state、epoch rotation
VLM 超时/失败该帧无观察;其他并发帧继续;事件通道不受影响可能降低解说密度,不编造画面vision_ok/failed、p50/p95、inflight
事件源中断进入 visual_only 安全描述仍能说场面,但不说进球、犯规、牌和姓名硬事实event_feed_age、visual_only_duration
两路 Writer 均失败静默,不生成固定兜底文案出现空档,但不会重复机械句或制造事实writer_rejection、lane winner、silent count
Fish 超时放弃该段,不让晚音频占用后续画面该句缺失tts_ttfa、tts_total、deadline_slack
S3/Callback 暂时失败Outbox 保留并重试;下游按幂等键去重预算内恢复则无感,过期则不播放delivery_retry、callback_late_ms、receipt_age
事件纠错/撤销追加新 revision,重建投影,不覆写历史未来解说使用新事实;过去已播音频不可撤回revision_count、retracted_count

建议的单场 SLO

  • 有效输入时每 2 秒至少产生一帧
  • clock offset p95 由上游合同确定
  • Callback late_ms=0 比例至少 99.5%
  • 重复播放为 0,幂等冲突为 0
  • 硬事实幻觉为 0 容忍
  • 事件链路与视频链路分开计量可用性

每段音频的审计链

match_id / stream_epoch
frame sequence + source PTS
vision evidence refs
world revision
director slot + fact refs
writer lane / rejection
TTS latency
object key + callback
played receipt
partial 当前状态页能看实时计数和最近错误,但历史 run metrics、正式 Prometheus/Grafana、集中日志告警、备份演练和 on-call 阈值仍需由部署阶段补齐。

11 · 当前能力边界

已经具备

  • 无 GPU 的真实视频全链路
  • 官方事件与视觉的因果融合
  • 双路真实模型择优
  • 赛中长期统计和去重
  • S3、Callback、HMAC、重试和 receipt
  • 断流保留比赛记忆,重连旋转 epoch

仍需建设

  • 连续球衣号码 + track + roster 绑定
  • 正式供应商事件与时钟合同
  • Fish chunk 级流式播放
  • 90+ 分钟非循环全场验收
  • 正式 SSO/RBAC、HA、备份和告警
  • 历史 run metrics 持久化报告
球员身份必须实话实说:名单和号码已经是候选知识与姓名安全门,但当前生产 SUT 尚无连续球衣号码识别/人物轨迹 worker。只有官方事件或可追溯的稳定身份事实才能授权 Writer 点名。

12 · 当前线上证据与结论强度

Demo 事件流4 / 4正式事件 API 入链
音频 Callback6真实 Fish WAV
已观测晚到0 mslate_ms
自动化测试1531 个环境型 skip

最近的 60 秒线上回归验证:无事件安全视觉不会再出现“视觉成功但写作 0”;金标 sidecar 只按精确视频 SHA 匹配;文件 EOF 后有界 drain 10 秒并自动释放活动槽位。

短样片验证的是架构和链路,不等于已经证明任意 90 分钟比赛、任意球队、任意供应商都能达到相同质量。下一阶段的硬结论必须来自真实整场非循环输入和正式数据源。