AI 视频分析任务的范围拆解与现实收敛:原型要的九项 API 都不支持
一个 AI 视频分析的「基本功能开发」任务,原型画得很完整:区域入侵、徘徊侦测、灵敏度调节、多边形绘制……真去对接上游 AI 网关的 API,发现原型要的九项能力一个都不支持。这篇记录任务范围怎么从「基本闭环」一步步收敛到「能跑的最小集」,以及三个联动(弹窗、信息屏、语音播报)各自的现实卡点。
任务范围
按原型(告警规则设置页)先跑通基本闭环:
- 规则只做入侵检测;
- 触发联动只做三个:平台弹窗、信息屏发布、语音播报,其余模块后续再处理;
- 后端子任务拆解:
- 3.1 确认入侵检测 API 支持 / 不支持的参数;
- 3.2 平台弹窗(多路摄像头都要推送,前端暂定 socket);
- 3.3 信息屏发布(旧版已有,需调试是否可用);
- 3.4 语音播报 / 广播(旧版已有,需调试是否可用);
- 3.5 其余联动(录像 / 消息通知 / 喊话对讲 / 联动报警),待 3.1~3.4 完成后再做。
平台架构:Spring Cloud Alibaba 微服务(security = 综合安防、warning = 告警、smart = 智慧、through = 便捷通行、integrate-iot = 物联网接入)。AI 算法上游是 Vplat 平台(AI 网关 / 盒子),信息发布屏上游是大华信发平台。
监控任务既有闭环(背景知识)
后续开发都挂在下面这条存量链路上:
1 | flowchart TD |
前端监控任务结果列表按天看异常数、详情弹窗看时间 + 截图 + 感知设备,工单在 BPM 侧处置即闭环。这条链路是后面三个联动的地基。
3.1 入侵检测 API:原型要的九项都不支持
上游 Vplat AI 网关策略接口封装在 integrate-iot 的 AiClientImpl.java:
| 操作 | 接口 |
|---|---|
| 新增策略 | POST /api/vplat/VplatDeviceStrategyService |
| 更新策略 | POST .../saveUpdate |
| 删除策略 | POST .../saveMultiDelete |
| 查询策略 | GET .../pageQueryList |
| 告警拉取 | GET .../VplatDeviceStrategyResultService/pageQueryAlarmList(平台轮询,设备不主动推送) |
支持的参数:devId(一策略一摄像头)、enable 启用开关、name 策略名、strategyType(1 = 越线、3 = 人脸、13 = 安全帽、15 = 工作服;入侵检测 = 1 越线)、strategyInfo.rectInfo 矩形检测区域(归一化 0~1,现只下全屏)、strategyInfo.linePoints 越界线画点(归一化,最多 5 个点)、action 抓拍 / 录像开关、timeTemplate 布防时间(星期几 × 整点时段)、固定联动参数 linkedTime=10 / linkedVideo=0 / snapshot=1。
原型要求但 API 不支持(请求模型无字段,共 9 项):

图 1:原型要求的能力逐项对照 API,全部打叉——需要产品决策砍需求还是找设备侧其他能力。
| # | 原型要求 | API 现状 |
|---|---|---|
| 1 | 区域入侵 / 进入区域 / 离开区域 / 徘徊侦测 | 入侵类只有越线一种 |
| 2 | 目标类型筛选(人体 / 车辆 / 非机动车) | 无字段 |
| 3 | 多边形绘制 | 只有矩形 + 越线 |
| 4 | 灵敏度 1-10 级 | 无字段 |
| 5 | 停留时间阈值 | 无字段 |
| 6 | 去重间隔 | 无字段 |
| 7 | 目标尺寸过滤 | 无字段 |
| 8 | 置信度阈值 | 告警回报里有 confidence,但创建策略无法设阈值 |
| 9 | 布防计划的自定义日期范围 / 跨次日 | 只有「每天」或「按周几勾选」两种 |
| 10 | 分钟级时段 | timeTemplate.value 是 int[] 小时数组,下发时 .split(":")[0] 直接丢分钟 |
第 10 项尤其值得注意:它不是「待实测」,而是代码层面就不支持。
MonitoringServiceImpl.java:148下发时把时段字符串按:切分只取小时位,分钟位被直接丢弃。即便原型只配了整点时段,这个限制也得记进文档,避免后续误以为能配09:30-10:00。
结论建议:入侵检测闭环用 strategyType=1(越线)+ linePoints/rectInfo + timeTemplate 即可跑通;不支持的 9 项需产品确认砍需求还是找设备侧其他能力。
3.2 平台弹窗:发送链路在,订阅下架
详细的前后端实现另见这篇,这里只记结论。
- 后端发送链路在:warning 暴露 STOMP 端点,告警触发且处理器开关打开 → 推
/topic/1024/alarmPopup。 - 前端订阅下架:现役
src/layout无任何 SockJS/STOMP,订阅代码只在废弃副本里且initWebSocket()被注释。 - VO 字段精简:旧
AlarmingPopupVO没有deviceCode、alarmImg,前端拿不到设备编号和告警截图。
方案分两档:第一档文字弹窗闭环(前端重写订阅 + 队列);第二档带视频 + 权限(VO 补字段 + 园区隔离)。实际两轮都做了。
3.3 信息屏发布:卡在中间件 500
「旧版已有相关功能」属实——链路完整、前后端模块齐全。线上实测锁定卡点:中间件 10.152.64.7:9120 已配、网络通,但该中间件所有 /dh/* 接口返 500。不是代码问题,是中间件层故障。
链路 5 跳:
1 | flowchart LR |
只有大华(factory=2)有实现,海康 / 明景分支为空。
线上实测锁定卡点的四步排查
从「点同步报系统繁忙」开始,把锅从代码一路摘干净、钉到中间件:
- smart 同步报「系统繁忙」 → 查代码:
ScreenInfoServiceImpl.syncMJScreenDeviceList(明景)无 try-catch,崩了掩盖大华真实结果;switchScreen大华路径result.getData().success()没 null 检查,NPE 把大华的错吞成笼统「系统繁忙」。 - 改测大华专用路径(只走大华不走明景)→ 仍「系统繁忙」→ 确认大华链路也断。
- 查 integrate-iot 日志:
operateDevice和queryPageDeviceList都ResourceAccessException: HTTP 500,上游http://10.152.64.7:9120。 - 服务器直接 curl 中间件:响应体是 Spring Boot 标准 500 格式(
timestamp/status/error/path),无 auth/token 字样;/actuator/health、/返 404(进程活着、actuator 没暴露)。
结论:10.152.64.7:9120 是个 Spring Boot 中间件(大华信发网关,与 Vplat AI 网关 :9002 同机),进程活着(404 正常)但所有 /dh/* 业务接口返 500。host 已配、网络已通、请求已发出、不是鉴权问题——是中间件内部故障。
修正之前的误判:原写「host 全渠道未配置」——线上其实配了,dev 没配但线上有。卡点不是「地址没配」,是「配的中间件坏了」。
附带发现的两个代码 bug
ScreenInfoServiceImpl.syncMJScreenDeviceList无 try-catch——明景一崩,整个同步接口「系统繁忙」,掩盖大华结果。switchScreenresult.getData().success()没 null 检查——大华失败时 NPE,把真实错误吞成笼统「系统繁忙」,排查极费劲。
这两个 bug 的形态和显示屏推送排查里那个「失败零日志」是同一类病:错误被笼统化吞掉,现场丢失。
3.4 语音播报:骨架四截全断
详细拆解另见这篇,结论:「旧版已有」的是一副骨架,设备能力层可复用,Feign、触发、配置、素材持久化四层全断,当前完全不可用,需要补开发。
底层探活的一个间接证据:实时监控能看画面,说明视频平台活着、鉴权通;广播接口和视频流共一套鉴权,大概率也活。所以 3.4 的底层风险远低于 3.3(3.3 是整个中间件 500,3.4 平台已证实活着)。真卡点收窄到设备喇叭(哪台设备能发声)+ 广播接口是否单独启用。
进度状态总览
| 子项 | 状态 | 说明 |
|---|---|---|
| 3.1 入侵检测 API 参数确认 | ✅ 已交付 | 结论发在任务评论 |
| 3.2 平台弹窗 | ✅ 两轮完成 | 文字弹窗 + 视频弹窗 + 接收人定向 + 本地录像截图 |
| 3.3 信息屏发布 | ⚠️ 线上实测闭合 | 链路代码完整;卡在中间件 /dh/* 全 500,甩给中间件维护方 |
| 3.4 语音播报 | ⚠️ 部分前置 | Feign + 数据层已写,触发 stub + 前端保存仍断 |
| 3.5 其余联动 | 🔒 暂缓 | 联动报警(报警主机)全库为零 |

图 2:三个联动三种命运——弹窗已转通、信息屏被中间件卡住、语音播报碎成四段。
IoT 联动的设计要点(API 文档提炼)
这次还顺带梳理了安防视频 API 的几个模块(录像、截图、摄像头预置位),其中两个设计点值得记下来。
预置位的事务一致性——IoT 下发与本地落库在同一事务:先下发、后落库、失败回滚。
| 操作 | 流程 | 失败行为 |
|---|---|---|
| 新增 | 先下发 presetSet 到 IoT 平台 → 成功后落库 |
IoT 失败 → 抛异常,事务回滚,本地不记录 |
| 修改 | 先下发 presetSet(覆盖同槽位)→ 成功后更新本地 |
同上,整体回滚 |
| 删除 | 逐条下发 presetDel → 全部成功后软删本地 |
任一失败 → 整体回滚,本地也不删 |
因此「本地有记录」⟹「IoT 侧一定设置成功」;反向不保证。这是一个「指令先行、本地为主」的可靠模式:避免本地有记录而设备上不存在。
录像 / 截图的数据隔离——非超管按 create_id + park_id + tenant_id 三元组隔离,只能看自己创建的;超管查全量。
| 角色 | 分页可见范围 | 查看 / 改名 / 删除 |
|---|---|---|
| 普通用户 | 仅自己创建(三元组匹配) | 仅自己的记录,越权整体拒绝 |
| 超管 | 全量(可用 createId 再过滤) |
任意记录 |
小结
这个任务最大的教训是「原型 ≠ 能力」。原型画出来的功能,不一定上游 API 真的支持;「旧版已有」也不等于「能用」。几个收敛方法:
- API 能力要逐项对照原型,把「支持 / 不支持 / 待实测」三类列清楚,不支持的就是要产品决策的。
- 「待实测」和「代码层面不支持」要分开:
timeTemplate丢分钟是代码写死的,不是「接上真实设备也许行」。 - 「旧版已有」要逐层探活:信息屏是中间件坏了,语音播报是四层全断,弹窗是订阅下架——三个「旧版已有」三种病。
- 错误别笼统化:
syncMJScreenDeviceList吞异常、switchScreenNPE、pushScreenDevice失败零日志,都是同一类病——把真实错误吞成「系统繁忙」,排查代价极高。
三个联动的现实卡点各不相同:弹窗是代码要重写、信息屏是中间件要修、语音播报是四层要重建。同一个「基本闭环」任务,三套完全不同的工作量和依赖方,这是任务描述「调通是否可用」六个字完全没法覆盖的复杂度。