Files
yovision/docs/raw/02-需求分析.md
T

45 KiB
Raw Blame History

🔍 YoVision 智能视频事件平台 — 需求分析文档

版本 v0.3 · 2026-08-03 上游:《01-需求收集》 · 下游:《03-通用场景应用方案》 本文档负责把原始需求分层、规格化、发现矛盾、推导出架构性约束,不负责技术选型细节


1. 分析结论摘要

先给结论,后面是推导过程。

# 结论 依据
C1 系统必须切成「通用底座 + 场景包」两层,场景包是配置与插件,不是分支代码 三个场景 60% 需求重合,但检测能力与升级策略完全不同(§3)
C2 事件(Event)与预警(Alert)是两个独立实体,不可合并 一次事件可产生多次预警、多条投递;一次预警可聚合多个事件(§5.2)
C3 「指定人群」的判定分四类并在能力层解耦;ReID 为默认手段,人脸识别为按租户授权开启的可插拔能力 合规风险与技术依赖不同;多数"同一性"需求不需要知道"是谁"(§4.3、§4.4)
C4 规则引擎必须放在推理之后、告警之前的独立环节,不能编进模型插件 规则变更频率远高于模型,且需支持热更新与多级覆盖(§6)
C5 接入层必须控制面/数据面分离,且数据面为边缘主动推流 家庭场景摄像头在 NAT 后,中心不可达(§7.1)
C6 系统状态一致性靠水平触发的对账器,不靠事件驱动 三个下游系统(媒体路由、推理、存储)无分布式事务(§7.3)
C7 默认 16 路可用单媒体/推理分片起步;扩展到 128 路必须横向分片,触发式推理用于降低平均算力 GPU 数量不能由路数直接推导,须按真实模型、分辨率、FPS、batch 与硬件压测(§8.1–8.2)
C8 业务预警系统的核心是 ack 与升级,不是"发消息" 没有 ack 环节的告警系统等于没有(§9.2)
C9 误报反馈闭环是产品飞轮,必须在 M3 第一天就有,不是后期优化项 真实误报案例是最稀缺的训练数据(§10)

2. 需求分层

原始需求(《01》共 8 个场景需求组 + 36 条通用需求)按变化频率重新分层。同一层内的东西一起变,不同层之间靠契约解耦。

flowchart TD
    L5["L5 场景包<br/>规则模板 · 升级策略 · 话术 · 报表口径"]
    L4["L4 业务编排<br/>事件生成 · 去重防抖 · 预警状态机 · 处置流"]
    L3["L3 能力层<br/>检测 · 姿态 · 跟踪 · ReID · 属性 · (人脸)"]
    L2["L2 流水线层<br/>解码 · 抽帧 · 调度 · 故障隔离 · 触发式唤醒"]
    L1["L1 接入层<br/>设备台账 · ONVIF · 媒体路由 · 隧道 · 对账"]
    L0["L0 基础设施<br/>多租户 · RBAC · 存储 · 可观测 · 审计"]
    L5 --> L4 --> L3 --> L2 --> L1 --> L0
层 变化频率 谁在改 改动方式
L5 场景包 每周 实施/产品 配置,不发版
L4 业务编排 每月 后端 发版
L3 能力层 每季度 算法 模型热替换
L2 流水线 半年 平台 发版
L1 接入 半年 平台 发版
L0 基础设施 年 平台 发版

这张表是本文档最重要的产出。 如果一个需求变更需要同时改 L5 和 L1,说明分层错了。典型反例:把"上课时段"这个校历概念写进 mediamtx 的 path 配置。


3. 场景共性与差异分析

3.1 共性度量

把《01》§4.2 的场景需求逐条拆成原子能力,统计复用度:

原子能力 S1 家庭 S2 校园 S3 社区 复用
人体检测 + 跟踪 ✅ ✅ ✅ 3/3
姿态关键点 ✅ ✅ ✅ 3/3
跌倒判定 ✅ ✅ ✅ 3/3
区域入侵 / 越线 ○ ✅ ✅ 2/3
停留 / 徘徊时长 ✅ ✅ ✅ 3/3
静止 / 无活动 ✅ ○ ✅ 2/3
人群聚集 / 密度 — ✅ ○ 1.5/3
打架 / 剧烈动作 — ✅ ○ 1.5/3
攀爬 / 翻越 — ✅ ✅ 2/3
非人目标(电动车、堆物) — ○ ✅ 1.5/3
ReID 跨镜跟踪(匿名) ○ ✅ ✅ 2.5/3
身份比对(人脸) ○ 🔐 🔐 授权后启用
高空抛物 — — ✅ 1/3

✅ 核心 ○ 可选 — 不需要 🔐 需租户授权 + 前置条件齐备(§4.4)

结论:前 6 项覆盖了三个场景的 P0 需求主体,构成通用能力包;后续按场景增量。高空抛物(RQ-S3-04)需要专用仰拍机位与独立轨迹算法,与其余能力无复用,建议独立立项或后期外采,不进本期通用底座。

3.2 差异分析(差异才是场景包要装的东西)

维度 S1 家庭 S2 校园 S3 社区
单点位路数 1–3 100–500 50–300
部署形态 边缘盒子(必须) 校内边缘或中心 混合
摄像头可达性 NAT 后 专网可达 专网可达
预警接收人 家属(非专业、随时可能没看手机) 安保值班室(7×24 有人) 物业值班(夜间可能无人)
升级链 4 级,含语音电话与呼叫中心 2 级,值班室 → 校领导 3 级,值班 → 主管 → 业主群
超时容忍 30s / 60s / 90s 2min / 10min 1min / 5min
误报容忍 极低(家属会卸载 App) 中(有人筛) 中
隐私敏感度 极高 高(未成年人) 中
常态录像 ❌ 禁止上云 ✅ 允许 ✅ 允许

关键洞察:S1 的接收人是非专业个人,没有值班室兜底,所以升级链必须做到"穿透勿扰模式"级别;S2/S3 有值班室,升级链可以简化,但需要批量事件的看板与工单能力(S1 完全不需要)。这两种形态的 UI 和交互是两个东西,不要试图用一套界面覆盖。


4. 领域模型

4.1 核心实体关系

erDiagram
    TENANT ||--o{ SITE : "拥有"
    SITE ||--o{ AREA : "划分"
    SITE ||--o{ DEVICE : "部署"
    DEVICE ||--o{ STREAM_BINDING : "产生"
    AREA ||--o{ ZONE : "标注(多边形/警戒线)"
    DEVICE ||--o{ ZONE : "画在画面上"
    TENANT ||--o{ RULE : "定义"
    RULE }o--|| SCENE_PACK : "继承自"
    RULE ||--o{ EVENT : "命中生成"
    EVENT ||--o{ EVIDENCE : "附带"
    EVENT }o--o{ ALERT : "触发/聚合"
    ALERT ||--o{ DELIVERY : "投递"
    ALERT ||--o{ ALERT_LOG : "审计"
    SITE ||--o{ CONTACT_CHAIN : "配置"
    ALERT }o--|| CONTACT_CHAIN : "按级投递"

4.2 实体职责界定

实体 定义 关键约束
Tenant 租户 计费与数据隔离的最小单位 所有查询必须带 tenant_id,无例外
Site 站点 一个物理场所(一户 / 一所学校 / 一个小区) 升级链、时段策略挂在这一层
Area 区域 站点内的逻辑分区(教学楼 / 单元 / 客厅) 用于权限范围与报表口径
Device 设备 不叫 Camera,device_type 取 camera/radar/door/button 为异构传感器预留(继承参考项目 §4.5)
Zone 画面区域 画在某路画面上的多边形或警戒线 与 Area 是两回事:Area 是物理概念,Zone 是像素坐标
Rule 规则 「主体 × 条件 × 时空 × 动作」的可配置组合 三级覆盖:租户默认 → 站点 → 设备
Event 事件 一次被判定成立的客观发生 不可变。误判只能被标记,不能被删改
Alert 预警 一次需要人响应的通知过程 有生命周期状态机,可被 ack
Delivery 投递 一次向某人某通道的发送尝试 独立实体,一次 Alert 有多条

4.3 「指定人群」的建模

《01》§5 提出四类判定。分析后确定为主体过滤器(Subject Filter),作用于跟踪目标而非规则整体:

Track(跟踪目标)
  ├─ class: person | vehicle | e_bike | object
  ├─ attributes: {age_group, posture, ppe, ...}      ← A 类,模型直接产出
  ├─ states: {falling, running, loitering_sec, ...}  ← B 类,时序分析产出
  ├─ anon_id: "pid_88213" | null                     ← B+ 类,ReID 匿名同一性,默认开
  └─ identity: {ref_id, group, confidence} | null    ← C 类,人脸,按租户授权开
判定类 实现位置 默认 开启条件 回答什么问题
A 属性 检测模型多头输出 / 独立分类器 开 — 他是什么样的人
B 状态 时序窗口分析插件 开 — 他在做什么
B+ ReID ReID 模型,跨镜特征匹配 开(默认手段) — 是不是同一个人
C 身份 独立身份服务,异步比对后回填 关 租户授权 + §4.4 全部前置条件 他是谁

设计原则(已定):

  1. 能用 ReID 解决的不上人脸。 徘徊、尾随、跟随、跨镜追踪这类"同一性"需求一律走 B+ 类。人脸只用于必须知道"是谁"的需求(白名单放行、关注名单告警、访客核验),且需逐条论证"为什么 ReID 不够"。
  2. identity 为 null 时规则必须仍能工作,降级为"未知人员"。身份服务不可用、比对超时、人脸角度不佳都会产生 null——不得因此漏报。这条决定了规则 DSL 必须显式声明 on_unavailable 语义(见《03》§2.5)。
  3. anon_id 与 identity 是两个独立字段,不可互相顶替。ReID 的 anon_id 只在会话/时间窗内有效,不是身份标识,也不应被持久化成长期人员画像。

4.4 身份识别(人脸)子系统的需求分析

客户已确认将授权使用人脸识别,因此该能力进入方案范围。但授权解决的是"能不能用",不解决"怎么用才安全"。分析出以下约束:

4.4.1 授权是租户级开关,不是全局开关

层级 语义
平台级 能力是否编译/部署(私有化交付时可整体不部署)
租户级 主开关。未授权租户在 API 与 UI 层均不可见该能力,不是"能看到但点不动"
站点级 在已授权租户内进一步限定生效范围(如只在校门口,不在教室)
规则级 单条规则是否使用 identity 过滤

未授权租户"看得到但用不了"是错误设计——它会诱导客户询问和绕过,也会让审计难以证明"该租户从未启用"。

4.4.2 底库是独立的高敏资产

需求 理由
底库与业务库逻辑分离,独立加密 泄露后果与一般业务数据不在一个量级
默认只存特征向量,不存原始人脸图 原图泄露可直接冒用;特征向量至少不可直接还原为可用照片。若业务必须留原图(如核验展示),原图单独分库 + 单独授权
人员档案必须有有效期 学生毕业、住户搬离、访客当日有效——没有有效期的底库必然越积越脏
到期自动失效,不依赖人工清理 依赖运维记得清理是不可靠的
支持整体导出与彻底删除 客户终止服务时的义务
每次比对命中与每次底库查询均独立审计 "谁查了谁"必须可追溯

4.4.3 比对是异步旁路,不在主判定链路上

主链路(必须实时):检测 → 跟踪 → 姿态/行为 → 规则 → 事件
                                        ↑
旁路(可延迟、可失败):人脸检测 → 质量筛选 → 特征提取 → 底库比对 → 回填 identity

推导:若把比对放进主链路,一次底库慢查询会拖垮整条 pipeline 的实时性;而人身安全类事件(跌倒、打架)根本不需要知道是谁。

派生需求:

编号 需求
FR-ID-01 比对为异步旁路,超时/失败不阻塞事件生成
FR-ID-02 identity 回填有时间窗;超窗未回填则事件以 identity: null 定稿
FR-ID-03 依赖 identity 的规则须声明 on_unavailable:treat_as_unknown(默认,倾向报警)或 skip(倾向不报)
FR-ID-04 人脸质量筛选(角度、清晰度、遮挡、尺寸)前置,低质量帧不送比对,避免误配
FR-ID-05 置信度阈值可配;高风险动作(如触发告警、拒绝放行)前可要求人工复核

FR-ID-03 的两个取值对应两种业务倾向。默认必须是 treat_as_unknown:在监护与安防场景,"不确定是谁"应当倾向于报警而非放过。若某条规则选 skip,需在规则上显式写明并有审批记录。

4.4.4 误识别的后果分级

人脸比对有两种错误,后果完全不同,阈值不能用同一个:

错误类型 场景 后果 阈值倾向
假阳性(认错人) 白名单放行 陌生人被当成住户放行 → 安防失效 阈值调高,宁可认不出
假阳性(认错人) 关注名单告警 无辜者被当成关注对象告警 → 对个人的实质伤害 阈值调最高 + 强制人工复核
假阴性(认不出) 白名单放行 住户被当成陌生人 → 体验差,但安全 可容忍
假阴性(认不出) 关注名单告警 漏报 靠 ReID 与其他规则兜底

关注名单类规则不得自动触发对人的处置动作(如自动锁门、自动通报),只能生成待人工确认的事件。这是产品红线,写进 L4 编排层的硬约束。


5. 核心流程分析

5.1 主流程

flowchart TD
    A["摄像头 / 传感器"] --> B["接入层<br/>台账 · 隧道 · 媒体路由"]
    B --> C{"触发判定<br/>常态 / 运动 / 传感器"}
    C -->|无触发| C
    C -->|唤醒| D["推理流水线<br/>检测 · 跟踪 · 姿态 · 属性"]
    D --> E["规则引擎<br/>主体过滤 × 时空 × 条件"]
    E -->|未命中| F["丢弃<br/>仅记指标"]
    E -->|命中| G["事件生成器<br/>回捞 pre-roll · 抓拍 · 元数据"]
    G --> H{"去重 / 防抖 / 聚合"}
    H -->|抑制| I["静默记录"]
    H -->|通过| J["事件实例落库"]
    J --> K["管理系统<br/>看板 · 详情 · 处置"]
    J --> L{"是否需要预警"}
    L -->|是| M["预警状态机<br/>投递 → ack → 升级"]
    M --> N["App / 短信 / 语音 / Webhook / 大屏"]
    N --> O["处置结果回填"]
    K --> O
    O --> P["误报标记 → 标注队列 → 模型迭代"]

5.2 为什么 Event 和 Alert 必须分开(C2 的推导)

反例:把预警状态直接放在事件表上。会立刻遇到三个无法表达的情况:

情况 合并模型下的困境
客厅两个机位拍到同一次跌倒 两条事件、两次预警,家属收到两遍
消防通道堆物持续存在 每帧都命中规则,要么事件爆炸,要么无法表达"仍未整改"
一次事件在不同时间升级到不同人 事件表上放不下多级投递记录
值班员批量确认 20 条事件 ack 语义作用在哪个粒度说不清

正确关系:

Event  N ──┐
           ├──> Alert  1 ──> Delivery N
Event  N ──┘
  • Event:一次客观发生,不可变,是证据与统计的单位
  • Alert:一次需要人响应的过程,可聚合多个事件,是 SLA 与考核的单位

5.3 预警生命周期状态机

[触发] ─→ [投递中] ─→ [已送达] ─→ [已确认 ack] ─→ [处置中] ─→ [关闭]
   │           │            │                                     │
   │           │            └─超时未 ack─→ [升级] ─→ 下一级投递    │
   │           └─投递失败─→ [升级]                                │
   └─防抖命中─→ [抑制]                             [标记误报] ←───┘

硬约束(继承参考项目 §10.10):告警先落库再投递。进程崩溃重启后,扫描所有非终态告警并接续升级链——与 §7.3 对账器的"水平触发"是同一个思路。

5.4 三个不同的事实,不可混淆

事实 含义 字段 拿不到时的处理
发出去了 调用了上游 API sent_at —
送达了 上游回执确认到达终端 receipt_at 当失败处理并升级,不做乐观假设
被看到了 用户主动 ack acked_at 超时升级

6. 规则引擎需求分析

6.1 为什么必须独立(C4 的推导)

如果把规则写进模型插件 后果
客户要改一个停留时长阈值 要改 Python 代码、重启 pipeline、影响同机所有路
不同租户要不同阈值 插件里写 if tenant == ...
要审计"这条事件是哪条规则判的" 无从追溯
要做规则的灰度/回滚 做不了

结论:模型插件只输出客观观测(这里有个人、他的姿态是躺倒、他在多边形 A 内停留了 12 秒),规则引擎负责主观判定(这属于需要报警的情况)。这条边界要写进代码规范。

6.2 规则表达能力需求

一条规则必须能表达的五个维度:

维度 内容 例
主体 class + 属性过滤 + 身份过滤 人 且 未识别为本校学生
时空 哪些设备/Zone + 哪些时段/日历 实验室 B 区 且 非上课时段
条件 观测量的逻辑组合 + 持续时长 进入区域 且 停留 > 3s 且 无教师同行
抑制 冷却期、聚合键、静默窗口 同区域 5 分钟内不重复
动作 事件等级 + 证据规格 + 通知策略 高危 + 前 10s 后 15s + 升级链 A

6.3 三级覆盖模型

场景包默认规则  ──继承──>  租户规则  ──覆盖──>  站点规则  ──覆盖──>  设备规则

覆盖语义必须明确定义(否则运维会被"为什么这条没生效"折磨死):

字段类型 覆盖语义
标量(阈值、时长) 就近覆盖
列表(联系人、通道) 替换,不合并(合并会导致意外扩大通知面)
开关(enabled) 就近覆盖,且允许下级关闭上级下发的规则
Zone 坐标 只能在设备级定义,上级不可下发

6.4 规则变更的非功能要求

要求 理由
热生效,不重启 pipeline 一次重启影响同机全部路数
变更有版本与操作人记录 事故复盘时"谁把阈值改了"
支持"试运行"模式:命中但不通知 新规则上线前评估误报量
支持按规则统计命中量与误报率 规则质量可度量,否则只能靠感觉调

试运行模式是被低估的需求。 没有它,每条新规则上线都是拿真实用户做实验。


7. 接入层需求分析

7.1 NAT 约束推导(C5)

家庭场景摄像头在运营商 NAT + 家庭路由 NAT 之后,中心机房无法主动发起连接。校园/社区虽有专网,但不能假设每个项目都有公网 IP。

分析出的唯一可行结构:控制面与数据面分离(直接继承参考项目 §2.1)

平面 方向 通道 流量
控制面 中心 → 设备 边缘侧 WireGuard 隧道 极小,仅配置与探活
数据面 边缘 → 中心 边缘主动推流(RTSP announce / SRT / RTMP) 大

派生需求:

编号 需求
FR-ACC-01 每个站点分配不冲突的内网段,设备地址确定化(如 10.<站点高位>.<站点低位>.0/24,摄像头从 .10 起)
FR-ACC-02 控制面失联不得中断视频推流(两者已解耦),仅告警
FR-ACC-03 边缘侧断网时本地缓存事件与证据,恢复后补传
FR-ACC-04 推流鉴权走 HTTP 回调到自有服务,注销/欠费/隐私模式在业务库判断,媒体层零配置变更

7.2 设备身份与状态机

需求 理由
设备身份用序列号,不用 IP DHCP 续租、Wi-Fi 漫游换 AP 都会换 IP
IP 变化时按序列号自动重定位并重连 家庭场景常态
设备状态含 pending_activation 批量开通必然有凭据待补的中间态
探活用独立的 ONVIF 轻量调用,不用流状态代替设备状态 「设备离线」与「无人订阅」在媒体层表现相同

设备状态机:

[录入] → [pending_activation] ──补齐凭据──> [active] ⇄ [offline]
                │                              │
                └──────────────> [disabled] <──┘

7.3 对账器:一致性方案(C6 的推导)

一次设备开通需要在多个独立系统各做一次操作,且它们之间没有分布式事务:

数据库(唯一真相源)
   ├──> 媒体路由:建 path
   ├──> 推理流水线:挂 source
   └──> 存储:建 bucket/前缀

为什么必须是水平触发而非事件驱动

方案 部分失败时
事件驱动(边沿触发) 事件丢了就永久不一致,需要补偿事务,补偿也会失败
水平触发(对账) 不处理"事件",只不断比对期望与实际并向期望收敛。失败自动在下一轮重试

派生的硬性需求

编号 需求 理由
FR-REC-01 数据库是唯一真相源,下游均为被驱动的从属状态 —
FR-REC-02 建 path 前先查是否存在,绝不盲目 add 盲目 add 会踢掉正在推流的 publisher
FR-REC-03 改配置前比对 desired_hash / applied_hash,没变绝不调 API 同上
FR-REC-04 每个下游系统一行 sync_state,全部收敛才算开通成功 中间态必须可见
FR-REC-05 开通顺序:媒体路由先 → 推理后;停用顺序:推理先 → 媒体路由后 建立与拆除逆序,写进代码注释
FR-REC-06 部分失败不回滚,只收敛(退避重试) 回滚本身会失败,导致回滚的回滚,无限递归
FR-REC-07 每个下游系统独立限流预算(各 8 并发),不共享信号量 一个系统变慢会饿死另一个
FR-REC-08 孤儿资源清理需有安全闸:单轮删除量 > 总量 10% 时停止并告警 防止"期望集合意外为空"把全部路数拆掉
FR-REC-09 不设放弃阈值,持续重试 + 告警引入人工 对账器放弃 = 设备静默不工作,监护场景不可接受
FR-REC-10 循环周期:正常 30s,有未收敛项降到 5s,另有 10min 全量对账(含孤儿扫描) —

必须暴露的指标

指标 用途
reconciler_unconverged_bindings{system} 核心健康指标,持续 > 0 即异常
reconciler_orphans_detected{type} 有人手改了生产系统
reconciler_safety_brake_triggered 安全闸触发,应当直接呼人
reconciler_loop_duration_seconds 循环超时 = 规模到顶,该分片了

8. 非功能需求分析

8.1 容量模型

本项目以单站点 16 路为默认交付规格,支持 32 / 64 / 128 路扩展,单站点本阶段上限 128 路。16 是默认配额而非代码上限;128 路通过增加媒体分片与推理 Worker 实现,不把全部流压在一个进程或一块 GPU 上。

以下仅用于初步预算,最终以 M1–M5 的真实流水线压测为准:

项 默认 16 路 上限 128 路 说明
子码流 640×360 @ 512 kbps ≈ 8 Mbps ≈ 64 Mbps 推理优先使用子码流
主码流按 4–6 Mbps ≈ 64–96 Mbps ≈ 512–768 Mbps 常态录像与证据回捞的预算口径
抽帧 5 fps 80 帧/秒 640 帧/秒 GPU、解码器和 batch 均需实测
媒体分片 1 个 建议 4 个起步 media_shard.max_streams 初始建议 32;可按故障域降为 16
推理分片 1 个逻辑分片 最多 8 个 16 路逻辑分片 一个 Worker 可承载几个分片由压测决定

容量必须按四个维度分别验收:接入/录像带宽、同时解码、AI 推理、证据存储。不能用“NVR 能录 128 路”推导“GPU 能分析 128 路”。连续录像时每 1 Mbps 约产生 10.8 GB/天;因此默认由客户已有 NVR 承担常态录像,YoVision 优先保存事件证据,避免重复存储全量视频。

实现约束:site.max_video_channels 默认 16、最大 128;media_shard.max_streams 与 inference_profile.max_sources 为配置项。数据库、规则、数组、前端分页与批量操作中不得写死 16。

8.2 算力与触发式推理(C7 的推导)

模式 默认 16 路 扩展到 128 路 适用
常态全量推理 单逻辑推理分片起步 按 16 路切成最多 8 个逻辑分片,分配到多个 Worker 高价值点位
触发式推理 保持同一分片结构,空闲时不解码/不推理 通过降低各分片占空比减少平均 GPU 需求 家庭、社区大部分点位

GPU 型号和数量不在需求阶段写死。M1 用 5 路打通,M3 以 16 路建立性能基线,再依次验证 64 路和 128 路;每档都以端到端 P95/P99 延迟、丢帧率和故障隔离为出口标准。

触发信号的三个来源(按成本与可靠性排序):

触发源 成本 可靠性 适用
运动侦测(软件,参考 Frigate 思路) 零 中(光照变化、树叶晃动会误触) 通用兜底
摄像头 ONVIF 事件订阅 零 中 支持的型号
毫米波雷达等传感器 硬件成本 高 家庭卧室/卫生间(且解决隐私)

重要澄清:流水线框架(Savant 等)主要解决多路调度、复用与故障隔离,不会自动降低单帧推理成本。触发式推理是降低平均算力的主要手段之一,但最终容量仍取决于模型、分辨率、FPS、batch、解码方式与硬件实测。

8.3 两级判定与误报(准确性需求的可实现形式)

单一信号源的误报都会让使用者很快失去信任:

信号源 典型误判
纯视觉 遮挡、逆光、坐下、弯腰、宠物、访客
纯雷达 快速坐下、弯腰

两级串联是行业标准做法:

  • 一级(低成本、常开):宁可多报,不能漏报
  • 二级(高成本、按需唤醒):审核一级的候选,剥离干扰

派生需求:架构必须支持"一级触发源"可插拔(运动侦测 / ONVIF 事件 / 雷达 / 门磁),且触发入口独立成 handler,接新传感器时不改动流控制逻辑。

8.4 分类粒度对误报的影响

参考实现的经验:GajuuzZ/Human-Falling-Detect-Tracks 对每个人轨迹每 30 帧预测动作,输出站立/行走/坐下/躺下/起身/坐下动作/跌倒共 7 类。

七分类而非二分类是降误报的关键。 二分类模型面对"坐下"只能在"跌倒/非跌倒"之间硬选;七分类可以明确输出"这是坐下"。本项目所有行为判定模型均按此原则设计。

负面经验:Y-B-Class-Projects/Human-Fall-Detection 用约 500 张网络图片训 LSTM 完全学不会,最终退回 if-else 规则。→ 小数据量下时序模型学不动,先解决数据再上模型。

8.5 可用性与降级

故障 要求 降级行为
单路摄像头掉线 不影响其他路 告警 + 自动重连
推理节点崩溃 不影响接入与其他节点 该分片流量转移或降级为仅录制
算力不足 不得积压至崩溃 实时模式:主动丢帧优于积压
突发流量(早晨集中活动) 不丢事件 持久化磁盘缓冲,抗突发
中心平台不可达 不丢事件 边缘缓存,恢复后补传
通知供应商故障 不丢预警 多供应商冗余,provider 字段为切换预留

8.6 安全需求

编号 需求
NFR-SEC-01 设备凭据(ONVIF 用户名密码)加密存储,不落明文日志
NFR-SEC-02 推流鉴权,未授权设备推不上来
NFR-SEC-03 所有查询强制带 tenant_id,在数据访问层统一拦截,不依赖业务代码自觉
NFR-SEC-04 证据文件访问用带时效的签名 URL,不可枚举
NFR-SEC-05 管理界面不得对局域网默认无密码暴露(第三方面板的常见坑)
NFR-SEC-06 人脸底库(若启用)独立加密存储,独立审计,独立授权

8.7 合规需求

编号 需求
NFR-CMP-01 alerts 与 alert_deliveries 只追加不修改,状态变更写事件表,独立备份
NFR-CMP-02 每条预警须能回答:何时触发、基于什么证据、向谁发过、走什么通道、是否送达、谁在何时确认、处置结果、升到第几级、每级耗时
NFR-CMP-03 证据留存期限可配置,到期自动清理并留清理记录
NFR-CMP-04 数据主体的知情同意记录可查
NFR-CMP-05 隐私区域(卧室、卫生间)在设备录入时即标记,系统层面拒绝配置摄像头类设备

NFR-CMP-05 是代码层面的硬约束,不是流程约束。依赖实施人员"记得别装"是不可靠的。


9. 预警系统需求分析

9.1 两类告警必须彻底分开

运维告警 业务预警
触发源 设备离线、对账未收敛、GPU 过载、缓冲积压 规则命中
收件人 运维团队 家属 / 值班员 / 呼叫中心
延迟容忍 分钟级 秒级
漏报后果 服务降级 人身伤害 + 法律责任
方案 Prometheus + Alertmanager(现成) 自研状态机 + 复用投递通道

两套系统不得共用投递通道和值班配置,否则运维噪声会淡化业务预警。这是本节最重要的一条。

9.2 ack 是核心,不是附加功能(C8)

「发出去」和「被人看到」是两回事。整个预警系统的设计围绕 确认或升级 这一对概念展开:

  • 无 ack → 无法知道是否有人在处理 → 无法决定是否升级 → 升级链形同虚设
  • 无 ack → 无法度量响应时长 → 无法做 SLA 与考核
  • 无 ack → 出事后无法举证"我们报了且某人确认了"

9.3 升级链需求

需求 说明
层级数与超时值按站点可配 独居老人与有同住家属的策略应当不同
时段策略 白天找子女、夜间找同住者;校园白天找安保、夜间找宿管
通道冗余 至少两条独立路径,且需有绕过互联网的通道
联系人可用性 支持轮值排班,而非固定人

通道独立性分析:推送依赖 APNs/FCM,短信依赖运营商,任何单一通道都可能整体故障。语音电话是唯一能穿透勿扰模式且不依赖互联网的通道,在 S1 场景是必需项。

9.4 去重与防抖

规则 参数 理由
同设备冷却期 默认 5min 避免同一事件多次触发
同站点聚合 多设备同时触发合并为一条 两个机位拍到同一次跌倒
已处置抑制 已 ack 期间不再新建同类 人已到现场
维护窗口 用户主动静默 必须强制限时(建议最长 4h)并到期前提醒

永久静默是这类系统最常见的事故成因。 静默功能的限时是硬约束,不提供"永久"选项。


10. 数据闭环需求(C9)

10.1 为什么这是 P0 而非优化项

事实 后果
公开数据集(Le2i / UR Fall 等)是演员摆拍的表演性动作 与真实场景分布不符,训出来的模型现场表现差
真实误报案例是最稀缺的训练数据 只能靠运营积累,无法采购
没有闭环,模型不会随运营时间变好 产品没有护城河

10.2 闭环设计

用户点「误报」→ 自动把 evidence(视频片段 + 结构化观测序列)推进标注队列
用户确认「有效」→ 样本进正例库
                        ↓
              定期评估 → 规则阈值调整 / 模型重训 → 灰度上线(试运行模式)

要求:从 M3 第一天就开始存,不要等到想训模型时才发现没数据。 outcome = true_positive 的样本同样是金矿。

10.3 派生的数据需求

编号 需求
FR-DAT-01 事件证据须包含结构化观测序列(关键点、包围框、track_id 时序),不只是视频
FR-DAT-02 误报标记须记录归因(遮挡/光照/宠物/坐下/其他),供分类统计
FR-DAT-03 标注队列与训练数据的导出需符合 NFR-CMP-03 的留存与脱敏要求
FR-DAT-04 每条规则的命中量、误报率可查询,作为规则质量指标

11. 数据模型(分析层)

在参考项目基础上扩展多租户与规则/事件。字段级设计见《03》,此处只给结构与关键约束。

-- ── 组织(Bell 为真相源;Sense 只读配额投影)────────
tenants(id, code, name, status, plan, created_at)
sites(id, tenant_id, code, name, scene_pack, subnet CIDR, timezone, status,
      max_video_channels INT NOT NULL DEFAULT 16 CHECK (max_video_channels BETWEEN 1 AND 128))
areas(id, site_id, name, parent_id)

-- ── 设备(不叫 cameras,为异构传感器预留)────
devices(
  id, tenant_id, site_id, area_id,
  device_type,        -- camera | radar | door | button
  serial UNIQUE,      -- ⚠️ 身份用序列号,不用 IP
  vendor, model,
  onvif_addr, onvif_user, onvif_secret,  -- secret 加密存储
  state,              -- pending_activation | active | offline | disabled
  privacy_flag,       -- 隐私区域标记,为 true 时拒绝 camera 类型
  last_seen_at
)
stream_bindings(id, device_id, mtx_instance, inference_shard, path_name, rtsp_url, profile_token, enabled,
                UNIQUE(mtx_instance, path_name))

-- ── 对账(每下游系统一行)──────────────
sync_state(binding_id, system, desired_hash, applied_hash,
           last_error, attempt, retry_after, updated_at,
           PRIMARY KEY(binding_id, system))
-- system ∈ {'mediamtx','inference','storage'}
-- 全部行 desired_hash = applied_hash 才算真正开通

-- ── 规则 ──────────────────────────────
scene_packs(id, code, name, version, spec JSONB)          -- 场景包模板
zones(id, device_id, name, geom_type, coords JSONB)        -- 画面区域,仅设备级
rules(id, tenant_id, site_id, device_id,                   -- 三级覆盖,逐级可为 NULL
      scene_pack_id, code, name, enabled, dry_run,         -- dry_run = 试运行
      spec JSONB, version, updated_by, updated_at)
rule_versions(rule_id, version, spec, updated_by, updated_at)  -- 变更审计

-- ── 事件(不可变)──────────────────────
events(
  id, tenant_id, site_id, device_id, rule_id, rule_version,
  kind, severity, confidence,
  occurred_at, detected_at,          -- 发生时刻 vs 判定时刻,两者都要
  subject JSONB,                     -- track_id / 属性 / anon_id(ReID) / identity + identity_status
  observation JSONB,                 -- 触发时的客观观测量
  evidence_uri, snapshot_uris,
  dedup_key, aggregated_into,        -- 聚合关系
  outcome,                           -- true_positive | false_positive | unknown
  outcome_reason, outcome_by, outcome_at
)

-- ── 身份识别(独立库/独立 schema,独立加密与审计)────
--    仅在租户授权后创建;未授权租户无此 schema 的任何数据
tenant_features(tenant_id, feature, enabled, authorized_by,
                authorized_at, expires_at, doc_uri)     -- feature='face_recognition'

face_libraries(id, tenant_id, site_id, name, purpose, retention_days)
-- purpose ∈ {'whitelist','watchlist','visitor'};不同 purpose 的阈值与处置策略不同

persons(id, library_id, external_ref, display_name,
        group_tags, valid_from, valid_until,            -- ⚠️ 有效期必填,到期自动失效
        consent_ref,                                    -- 知情同意留档指针
        created_by, created_at, revoked_at)

face_vectors(id, person_id, embedding VECTOR, model_ver,
             quality_score, source, created_at)         -- 默认只存向量
face_images(id, person_id, image_uri, created_at)       -- 可选,单独授权才写入

face_match_logs(id, tenant_id, site_id, device_id, at,
                person_id, score, threshold, decision,  -- matched / below_threshold / no_candidate
                event_id, reviewed_by, reviewed_at)     -- 只追加,独立审计

-- ── 预警 ──────────────────────────────
alerts(id, tenant_id, site_id, kind, severity, state,
       triggered_at, acked_by, acked_at, closed_at,
       escalation_level, contact_chain_id)
alert_events(alert_id, event_id)                            -- 多对多
contact_chains(id, site_id, level, contact_name, channels JSONB,
               active_hours, timeout_sec, UNIQUE(site_id, level))
alert_deliveries(id, alert_id, level, channel, provider,
                 sent_at, receipt_at, failed_reason)
alert_logs(id, alert_id, at, actor, from_state, to_state, detail JSONB)  -- 只追加

CREATE INDEX ON alerts(state) WHERE state NOT IN ('closed','suppressed');

关键约束复述:

  1. devices 而非 cameras——为雷达/门磁/按钮预留
  2. 设备身份用 serial——IP 会变
  3. sync_state 每系统一行——无分布式事务,中间态必须可见
  4. alert_deliveries 是独立实体——一次预警多条投递,各自有回执
  5. events 与 alert_logs 只追加——合规要求
  6. events.subject 中 anon_id(ReID)与 identity(人脸)是两个独立字段,不可互相顶替
  7. 人脸相关表独立 schema、独立加密、独立审计;persons.valid_until 必填,无"永久有效"选项
  8. sites.max_video_channels 默认 16、最大 128;配额在写入设备时校验,分片容量由运行时配置与压测决定
  9. sites.max_video_channels 由 Bell 持有,Sense 通过版本化内部 API 或只读投影校验设备新增/启用;不得跨 schema 直接写入

12. 优先级与里程碑映射

12.1 MoSCoW

级别 内容
Must 摄像头接入与台账、NAT 穿透、对账器、人体检测+跟踪+姿态、跌倒/区域入侵/停留三类规则、事件实例与证据、预警状态机与升级链、多租户与 RBAC、审计、误报反馈闭环
Should 触发式推理、ReID(匿名同一性,默认手段)、时段/日历策略、试运行模式、统计报表、边缘缓存补传、Grafana 看板
Could 人脸识别子系统(租户授权开启:底库管理、异步比对旁路、审计)、人群聚集/打架检测、非人目标(电动车/堆物)、雷达接入、国标 GB/T 28181 对接、大屏与声光联动
Won't(本期) 高空抛物、S4 园区场景、车牌识别、人脸在未成年人场景(S2)的启用(待专项合规意见)

人脸识别的排期说明:客户已确认授权,能力进入方案范围,但它不在主线关键路径上(§4.4.3 已论证比对是异步旁路)。因此定为 Could 并安排在 M5——这样 M3 的端到端主线不被合规流程与底库模块阻塞。ReID 提到 Should 并在 M4 交付,先把"同一性"类需求兜住。

12.2 里程碑与出口标准

阶段 内容 出口标准
M0 摄像头兼容性验证 + 需求定稿 可直接运行 MiBeeNvr 作为隔离实验室测试台;3–5 款型号跑通 GetProfiles/GetStreamUri/SetSystemDateAndTime,采购白名单归档;M0 代码不得作为生产基线;《01》§8 的 Q1–Q12 有答案
M1 接入骨架 + 媒体路由 MediaMTX 正式进入且不得由完整 MiBeeNvr 替代;5 路自动建 path、探活、断线重建;设备台账可用
M2 对账器 + 多租户 + 隧道 10 个站点试点,至少一个站点完成 16 路开通/停用全流程;unconverged = 0 稳定
M3 推理接入 + 规则引擎 + 事件与预警 默认 16 路端到端稳定运行;跑通一个场景的三类规则;拿到现场误报基线,反馈闭环已收数据
M4 64 路分片 + 灰度扩容 + 管理系统 64 路稳定运行;单分片故障不影响其他分片;看板、批量操作与处置流可用
M5 128 路容量验收 + 第二/第三场景包 + 触发式推理 + 人脸识别子系统 128 路通过横向分片稳定运行,扩容不改业务代码;场景包为纯配置交付;人脸能力在一个已授权租户上跑通
M6(阶段二) 异构传感器接入 + 两级判定 误报率显著下降,视频常态采集下降

M5 的出口标准是本项目的架构验收点。 如果新增场景需要改 L1–L4 的代码,说明 §2 的分层没做成,需要返工而不是继续叠加。


13. 风险清单

风险 影响 缓解
Ultralytics YOLO 商业授权未按时到位 已决策沿用 YOLO;未购授权则落在 AGPL-3.0 第 13 条,需开源整个服务端 M3 前完成采购;逃生通道:检测换 YOLOX(Apache-2.0,同属 YOLO 家族)、姿态换 RTMPose(COCO 17 点,判定算法不用改)
授权范围未覆盖全部形态 私有化实例、边缘盒子内模型、二次训练权重可能不在授权内 采购时逐项书面确认
人脸误识别造成对个人的实质伤害 无辜者被当成关注对象告警 §4.4.4 分级阈值;关注名单类规则不得自动触发对人的处置动作,只生成待人工确认事件
人脸底库泄露 生物识别信息泄露,后果与一般数据不在一个量级 独立 schema + 独立加密 + 默认只存特征向量不存原图 + 独立访问审计
底库越积越脏(毕业/搬离人员未清) 误配率上升,合规风险累积 valid_until 必填,到期自动失效,无"永久有效"选项
人脸能力拖累主线工期 M3 被合规流程阻塞 §4.4.3 比对为异步旁路;排期在 M5,不进 M3 关键路径
人脸模型权重许可与代码许可不一致 侵权 启用前逐个核对权重许可
公开数据集与真实场景脱节 模型上线后表现远低于论文指标 M3 首要产出是真实误报案例库,不是模型指标;不承诺绝对准确率
摄像头 ONVIF 实现差异 部分型号无法接入 采购前真机验证(M0),白名单管控
摄像头时钟漂移 事件时间戳全乱,审计失效 开通时校时,定期校准
NAT 隧道不稳 控制面失联 已与数据面解耦,告警但不阻断推流
path reload 踢流 用户看到卡顿 变更前比对哈希,变更集中在维护窗口
H.265 兼容性 浏览器无法原生预览 统一设为 H.264
隐私合规不过 项目无法落地 尽早引入触发式采集减少常态视频;隐私区域代码级硬约束;法务前置
推理框架绑定 NVIDIA 硬件选型受限,信创环境不可用 推理代码与框架解耦,预留 ONNX Runtime / Pipeless 备选
场景包泛化失败,变成三套代码 维护成本三倍 M5 出口标准强制验收
值班员被误报淹没后忽略全部告警 真实事件被漏 试运行模式 + 规则质量指标 + 误报率看板
客户要求"什么都能查"的全量录像 与隐私需求冲突且成本高 需求收集期即明确事件驱动采集的边界

14. 需求追溯矩阵(节选)

原始需求 分析结论 实现层 里程碑
RQ-C-02 NAT 后接入 C5 控制面/数据面分离 L1 M1/M2
RQ-C-03 序列号身份 §7.2 设备状态机 L1 M1
RQ-C-11 规则组合表达 C4 独立规则引擎,§6.2 五维度 L4 M3
RQ-C-12 三级覆盖 §6.3 覆盖语义表 L4/L5 M3
RQ-C-16 人脸按租户授权 C3 四类判定;§4.4 租户级主开关 L3 M5
RQ-FR-01 未授权租户不可见 §4.4.1 不是"看得到点不动" L0/L3 M5
RQ-FR-03 底库有效期自动失效 §4.4.2 无"永久有效" L3 M5
RQ-FR-04 只存特征不存原图 §4.4.2 L3 M5
RQ-FR-06 不可用时不得漏报 §4.3 原则 2 + FR-ID-03 on_unavailable L3/L4 M5
RQ-S3-05 陌生人徘徊 §4.3 原则 1:走 ReID,不上人脸 L3 M4
RQ-S2-04 尾随进校 同上,ReID + 门禁事件融合 L3/L4 M4
RQ-C-17 事件实例 C2 Event/Alert 分离 L4 M3
RQ-C-19 去重防抖 §9.4 四条规则 L4 M3
RQ-C-21 误报标记 C9 数据闭环 L4 M3(不可延后)
RQ-C-23 ack 与升级 C8 预警状态机 L4 M3
RQ-C-25 通道独立 §9.3 语音电话必需 L4 M3
RQ-C-28 限时静默 §9.4 硬约束,无永久选项 L4 M3
RQ-C-29 两类告警分离 §9.1 L0/L4 M2
RQ-C-30 先落库再投递 §5.3 硬约束 L4 M3
RQ-C-31 多租户 §11 强制 tenant_id 拦截 L0 M2
RQ-S1-05 隐私区域禁摄像头 NFR-CMP-05 代码级约束 L0/L1 M2
RQ-S1-08 3 分钟人工介入 §9.3 升级链,站点级配置 L5 M3
RQ-S2-08 未成年人合规 §7.3 法务阻塞项 — M0
RQ-S3-04 高空抛物 §3.1 无复用,建议独立立项 — 移出本期

本文档的分析结论(§1 的 C1–C9)是《03-通用场景应用方案》的输入约束。任何技术选型若与这些结论冲突,应先回来修改本文档,而不是在方案里悄悄绕过。