1. 项目到底在解决什么问题从大海捞针变成毫秒找人先说说这个项目的出身。我在安防和商业智能领域做了不少年最常被客户问到的一个问题是几千路摄像头摆在那里天天录真出事或者要找人的时候靠人肉盯屏幕翻录像这根本盯不过来。传统的视频监控系统本质上是一个事后取证系统录像存在硬盘里等你想查的时候面对的是成百上千路摄像头几天甚至几十天的素材就算快进也是大海捞针。人脸库毫秒检索和跨摄像头轨迹追踪就是要解决这个大海捞针的问题。通俗点讲就是把所有摄像头抓拍到的有效人脸实时提取成特征向量存到一个底库里然后不管你给人脸还是给一张照片系统都能在百万级的数据里瞬间告诉你这个人是谁、在哪个摄像头出现过、几点几分哪进哪出。再进一步把同一个人在不同摄像头下的出现记录按时间和空间串成一条线就是轨迹。这个能力在安防布控、园区访客管理、连锁门店客流分析、校园安全管理等场景里需求相当旺盛。这个项目的技术组合很有意思Java提供后端工程化的稳定骨架IoT层解决海量设备接入和视频流采集AI负责把人脸变成机器能检索的特征向量。三样东西单独拿出来都不新鲜但真正把它们接成一条低延迟、高可用的全链路需要解决一堆工程问题。这篇文章就是我自己从零把一个Java IoT AI的人脸检索与轨迹追踪系统搭起来的全过程记录包括架构选型、关键算法细节、参数计算、踩过的坑和最后调通之后的性能表现希望能给正在做或者准备做类似项目的同学一些足够硬核的参考。先说清楚适合谁看如果你正在规划一个实时人脸检索系统或者你手上有Java后端团队但没有AI背景、却被领导安排做跨摄像头轨迹追踪这种听起来很AI的项目这篇文章会很有用。我会把AI部分尽量包装成Java工程师能理解并落地的方案而不是丢给你一个需要自己啃两周的深度学习论文。2. 整体架构设计Java、IoT、AI三块怎么分工做这种系统最容易犯的错误是上来就写代码结果设备接不进来、算法容量不够、后端扛不住并发全链路到处漏水。我先花了几天时间把架构捋清楚把数据从哪来、到哪去、在哪个环节变成什么这件事彻底想明白才开始动手。2.1 系统拓扑从摄像头到轨迹还原的数据流我的最终系统分成四层每一层的职责非常单一设备接入层IoT层负责对接各种品牌、各种协议的摄像头拉取视频流做解码。这层不关心人脸是谁只关心有没有画面、流稳不稳定。智能分析层AI层订阅视频帧做人脸检测、跟踪、质量过滤把检测到的人脸裁剪出来用深度模型提取成特征向量。这层是纯计算密集型的我用独立的GPU服务承载和Java后端完全解耦。后端服务层Java层接收AI层上报的特征向量和抓拍图负责写底库、做检索、维护轨迹数据对外提供REST API给业务方调用。数据存储层MySQL存结构化业务数据设备表、人表、轨迹记录对象存储MinIO/OSS存抓拍图片和底图向量数据库存人脸特征向量Redis做热点缓存和布控任务缓存。数据流大概是这样的摄像头通过RTSP协议把视频流推到边缘网关边缘网关对视频帧做初步解码后帧率控制把关键帧送给AI分析服务AI服务把检测到的人脸区域截出来提取成128维浮点特征向量连同摄像头编号、时间戳、抓拍图URL一起推给Java后端的消息队列Java后端消费消息先做一次底库检索判断这个人是已知人员还是陌生人然后决定是否更新它的轨迹记录同时把这一条抓拍记录写进库里。这个设计的核心逻辑是计算尽量前移数据尽量集中。人脸检测和特征提取在AI层完成Java后端拿到的已经是高度结构化的小数据——一条记录加起来不到1KB这比直接传图片再后端做人脸识别要高效得多消息队列的带宽压力也小得多。2.2 Java后端的技术选型为什么是Spring Boot而不是别的Java这个选择其实没什么好犹豫的。项目需要长期演进团队核心人员都是Java背景而且这个系统要和现有的业务系统比如员工管理系统、门禁系统深度集成用Spring Boot是最稳妥的选择。我这边的具体选型是Spring Boot 3.2 JDK 17Web层用Spring MVC参数校验和统一异常处理直接交给框架。MyBatis-Plus操作MySQL没有用JPA因为这类系统SQL复杂特别是轨迹查询经常要按时间范围、设备列表、区域做各种组合过滤MyBatis-Plus写动态SQL更顺手。RocketMQ做消息队列。选它而不是Kafka是因为它有完善的Java客户端、支持按Tag过滤消息而且我对它的RocketMQ Dashboard运维更熟悉。消息量在这个场景下并不算大处理吞吐量是每秒几千条Kafka有点大材小用。Redis Cluster做缓存。热点是布控库也就是要重点关注的黑名单人员这个库通常只有几千到几万人每个人的特征向量可以常驻Redis只靠这个布控缓存就能扛掉大量实时检索请求。之所以把这套选型拿出来说是因为很多做AI算法的团队习惯用Python把整个系统写通但一旦涉及到和硬件设备、业务系统、权限体系对接Java的稳定性和生态优势就体现出来了。人脸检索系统不是一个模型调通了就跑的项目它需要长期在边缘机房、弱网环境、高并发请求下稳定运行这是Java最擅长的事情。2.3 向量检索选型百万级人脸库为什么不能靠遍历硬扛传统Java工程师的第一反应可能是把特征向量存MySQL然后用自定义函数算余弦相似度。百万条记录每条512维float数组全表扫描一次要算上亿次浮点运算MySQL根本扛不住。这种方案只适合几万条数据的Demo上了生产环境必然崩。我最终选了Milvus作为向量数据库原因有三个它原生支持余弦相似度检索接口简单Java SDK成熟。内置IVF_PQ这类近似最近邻索引能在大规模数据下把检索控制在毫秒级。支持热数据与历史数据分层、动态扩容和Java后端集成非常自然。如果不方便部署独立向量库也可以选FAISS或者hnswlib这种进进程内嵌的库。但我这边因为底库规模达到百万级且未来要扩展到千万级独立部署一个向量检索引擎更合适。Milvus的安装运维不算复杂Docker一键起Java后端只管调gRPC接口。2.4 IoT接入层设计设备标准化是纯体力活IoT层是整个系统里最容易被低估的部分。摄像头品牌太多了有的支持ONVIF国际标准有的只提供私有SDK还有老旧的摄像头连RTSP推流都不稳定。我在项目里做了一层设备接入抽象定义了一个统一的虚拟设备接口不管底层是海康SDK还是ONVIF还是GB28181国标到了后端都收敛成同一个模型设备编号、RTSP地址、GPS坐标如果是固定点位就是静态坐标、所属区域、状态在线/离线。这个抽象特别重要因为后面的轨迹追踪算法完全依赖设备的空间位置关系一个人从A摄像头走到B摄像头如果业务侧不能给出这两个摄像头的物理距离和拓扑关系那算法再牛也是瞎猜。所以我在设备表里为每个摄像头维护了坐标和区域字段还手工维护了一张摄像头邻接关系表记录哪些摄像头在物理上是相邻的、路径上可以直达。这张表在轨迹追踪阶段发挥了很大作用。3. 核心链路实现从人脸检测到毫秒级检索架构定完之后最核心的就是把从摄像头到检索结果这条链路跑通。这一节我从设备接入开始一直讲到最终Java接口返回检索结果把每一步的关键细节和参数都摊开说。3.1 设备接入与视频帧拉取Java也不是不行设备接入这一块很多团队会选择写一个Python脚本单独跑但我这边统一用Java做了流媒体网关。用Java处理RTSP流听起来有点冷门实际上用JavaCVFFmpeg的Java封装非常成熟。每路摄像头一个独立线程通过拉流地址获取帧按AI分析能力限制做帧率控制——比如我的AI服务算力大概是单路摄像头每秒分析2帧那网关就按需推送不白费带宽。建议把视频流拉取和分析解耦。摄像头RTSP地址作为源头网关解码后把帧塞进一个内存队列AI服务通过gRPC流式接口来拿帧。这样摄像头断流、重连、码率波动都只在网关层面处理AI服务感知不到后端就更感知不到了。这里有个Java实现细节JavaCV的FrameGrabber在拉流断线时经常抛异常需要自己实现重连逻辑。我的做法是每路摄像头维护一个连续失败计数超过3次就标记为离线同时每30秒尝试重连一次。另外Spring的Async线程池务必单独配置别用默认的SimpleAsyncTaskExecutor那玩意儿每来一个任务就new一个线程几百路摄像头同时重连时服务器必挂。3.2 特征提取的工程化封装AI服务与Java的桥接AI层的人脸检测和特征提取我用了独立部署的Python服务原因很简单人脸模型生态基本都在Python这边论精度和效率目前都是最优解。模型方案是SCRFD做人脸检测EfficientNet或ArcFace风格的模型做人脸特征提取输出128维归一化特征向量。为什么是128维比512维内存小4倍精度在百万级底库上并没有明显掉点检索速度还快对工程代价友好。Java后端和AI服务之间用gRPC通信接口定义很简单输入图片字节流输出检测框数组和特征向量数组。gRPC比HTTP轮询高效太多而且支持双向流式做视频帧的持续预测非常方便。为了容错我加了一个HTTP Fallback接口gRPC连接异常时自动切换为HTTP短连接调用保证AI服务发版重启时人脸抓拍链路不至于断掉。Java这边定义了一个统一的FeatureClient接口屏蔽gRPC和HTTP两种实现。这个设计后来帮了大忙——AI服务从GPU服务器迁移到另一台更强的机器时我只改了配置中心的一个地址业务代码一行没动。3.3 特征向量索引的构建百万级底库的关键参数底库的质量和量级决定了检索的延迟而索引参数则决定了检索在快与准之间的平衡。我用的算法是IVF_PQ大致拆解一下IVF倒排索引把向量库聚类成nlist个组检索时只扫描和查询向量最近的nprobe个组。PQ乘积量化把向量切成M段每段用少量码字代替向量体积从原来的512×4字节压缩到M个字节。我的底库规模是100万人脸特征特征维度128维float精度4字节裸数据量是100万×128×4≈512MB。如果做暴力检索每查询一次就要全量算一遍余弦相似度实测单次耗时约70毫秒QPS上不去更别提并发时内存带宽直接被打满。加了索引之后参数如下参数我的取值说明nlist16384聚类中心数约0.016 × 底库规模经验值nprobe32检索扫描的聚类中心数越高召回越好但越慢metricIP内积人脸特征做过归一化后IP等价于余弦相似度PQ M值32特征切成32段每段量化成一个字节压缩后数据量约100MB100万×32字节内存占用降了80%以上为什么nlist取16384而不是65536因为nlist太大时平均每个聚类桶里的向量太少导致索引构建变慢、检索时聚类中心距离计算开销变大。实践中16384在百万级人脸底库上单向量查询耗时大约在8到15毫秒召回率在95%以上。如果想进一步压延迟可以把nprobe降到16速度能提升到大约4到6毫秒代价是召回率下降到92%左右。我这边对召回率要求比较高所以留在了32只针对部分业务场景开了低延迟配置。索引构建的过程分三步先把历史人脸图片批量跑一遍特征提取得到向量后写入Milvus的collection然后手动触发flush和build_index底库不是一次建完就完事的平时增量写入实时抓拍的新人脸Milvus会自动维护索引不需要每次重建。这里必须注意Milvus在HNSW索引下才支持增量不重建的快速插入IVF_PQ这种索引如果增量写入过大会导致未索引数据膨胀检索性能会明显劣化所以我的做法是定时任务每天凌晨做一次紧凑化compact操作。3.4 检索接口的具体实现Java SDK与缓存策略Milvus的Java SDK用起来不复杂pom引依赖、connect、search整段代码不长。核心检索逻辑如下public SearchResp search(float[] queryVector, int topK) { ListFloat vector new ArrayList(128); for (float v : queryVector) vector.add(v); SearchParam param SearchParam.newBuilder() .withCollectionName(face_collection) .withMetricType(MetricType.IP) .withOutFields(Arrays.asList(person_id, camera_id, capture_time)) .withTopK(topK) .withVectors(Collections.singletonList(vector)) .withParams({\nprobe\:32}) .build(); return milvusClient.search(param); }这个接口本身很简单真正决定线上性能的是两件事。第一是连接池MilvusClient内部实现了连接池但要注意它是基于gRPC的默认的连接复用策略在Java线程并发较高时容易打满需要配置合适的keepAlive和线程池参数。第二是缓存策略检索接口不是每次都要查向量库的如果我要查的这个人头像它的特征向量和我刚才某次检索过的结果完全一样就没必要再去查一遍。我在Redis里给每个查询向量的第一候选结果做了一份短期缓存TTL设3秒减少对向量库的重复压力。更要紧的是布控库的实时比对逻辑。实时抓拍进了一条特征我先用Redis里的布控库做一次暴力扫描——布控库一般只有几千到几万人Redis内存里的浮点数组不算多扫描一遍也就几毫秒。只有当布控库里没命中才走Milvus查全量底库。这个设计让实时抓拍链路的平均延迟从15毫秒降到了5毫秒左右效果非常明显。4. 跨摄像头轨迹追踪的核心算法与落地人脸检索做通之后轨迹追踪是这个项目里最大的硬骨头。检索解决的是这个人是谁轨迹要解决的是这个人从哪来、到哪去。看起来只差一步实际是两种不同的问题。4.1 为什么跨镜头追踪这么难先想一个问题同一个摄像头画面里一个人从头走到尾属于同一轨迹这个相对容易但如果他从A摄像头的画面左边消失了10秒后出现在500米外B摄像头的画面里你怎么知道这是同一个人人脸特征理论上可以帮他对暗号但如果他的脸侧过去了、帽子压低了、光线变暗了AI提取的特征和刚才那一帧很可能匹配不上。更麻烦的是不是所有摄像头都能拍清人脸——很多交通卡口的相机主要拍的是行人和车辆的全身人脸只是一小团模糊图。所以跨镜头追踪不能只依赖人脸特征必须结合时间和空间的约束来做推理。4.2 轨迹片段生成单镜头内的连续刻画我做轨迹追踪的第一步不是直接跨镜头匹配而是先把单摄像头内部的连续出现记录串起来形成一个轨迹片段。AI层的人脸检测器自带轻量级追踪能力同一张脸在同一个摄像头画面里连续出现的帧会被打上同一个trackId我把它作为一个轨迹片段的雏形。对于一个轨迹片段我会维护这样一个记录对象字段含义track_id轨迹片段唯一IDcamera_id摄像头编号first_seen / last_seen第一次/最后一次出现时间head_feature这段轨迹里质量最好的一帧人脸特征body_feature质量最好的一帧人体特征若支持ReIDframes抓拍图URL列表enter_time / exit_time进入和离开该摄像头范围的准确时间head_feature的选取很关键。我写了一个简单质量评分函数人脸检测框的尺寸越大、人脸角度越正、清晰度越高分数越高。质量最好的一帧特征就是这段轨迹的代表人脸特征后续底层判断这个人是谁、是不是某个人都用这个特征。4.3 跨摄像头特征匹配与时空约束现在有了大量轨迹片段接下来是把它们拼成一整条完整轨迹。我的做法是特征相似度 时空可达性的联合判定缺一不可。先看特征相似度两条轨迹片段的head_feature做余弦相似度如果超过阈值通常0.65到0.75说明两张脸可能来自同一个人。只看特征相似度是绝对不够的——在大型园区里长相相似的两个人被误判为同一个人的概率不低尤其是灯光昏暗时不同人的特征也会很接近。再看时空可达性两条轨迹片段要能拼接必须满足它们出现的时空是合理的。我用摄像头邻接关系表 两个摄像头的物理距离结合判定当轨迹片段A在camera1的last_seen时间为T1轨迹片段B在camera2的first_seen为T2如果camera1和camera2是相邻或连通的步行可达并且T2 - T1在3到120秒之间就认为满足时空约束。这段时间差窗口我特意设的比较宽因为人有走快走慢、可能在中途停留卡的太死容易断轨迹卡得太宽则容易把不同人串到一起。拼接判定逻辑如下从轨迹片段池里取一条未归属的片段S尝试和所有已有轨迹的尾部片段做匹配。若特征相似度 ≥ 0.7且时空可达性通过则S拼接到该轨迹更新轨迹的last_seen和当前位置。若最高相似度 0.7但时空可达性极强比如同一摄像头相邻时间出现、或相邻摄像头极短时间内出现则降级为软匹配——加上一个待定标记积累两三条片段后再确认。若都不满足则S作为一条新轨迹单独开始。这套流程里有几个巧妙的地方。软匹配这个降级机制非常重要因为实际场景中人脸模糊、特征匹配失败的次数比我们想象中多得多。很多时候靠这个人刚从这个路口消失、一分钟后从隔壁路口出现这一条时空信息就足以确定是同一个人人脸特征反而只是辅助。我用一个具体的例子来说明。园区里有个访客从南门进走到了1号楼大厅然后又去了2号楼会议室。这个过程中经过5个摄像头其中两个角度不好只拍到了侧脸特征相似度比较低。但因为相邻摄像头的物理距离和时间差都合理系统先把这5条片段软拼接起来等访客在2号楼会议室门口的正脸被抓拍到后才确认这条轨迹完整成立再回溯更新前面所有片段的归属。这个先假设、后验证的思路在实际运行中把轨迹还原率提高了将近20%。4.4 轨迹的可视化与查询接口轨迹串好之后对外暴露一个查询接口就可以返回完整的轨迹链路了。我的接口大概是这样的GET /api/v1/tracks/person?person_idxxxstart_time...end_time...返回结果是一个按时间排序的事件列表每个事件包含摄像头编号、摄像头名称、区域、进出时间、抓拍图URL、经纬度。数据结构类似这样[ { trackId: TK001, events: [ { cameraId: CAM01, name: 南门, time: 2025-01-12 08:23:10, imgUrl: ... }, { cameraId: CAM05, name: 1号楼大厅, time: 2025-01-12 08:25:43, imgUrl: ... }, { cameraId: CAM08, name: 2号楼会议室, time: 2025-01-12 08:30:02, imgUrl: ... } ] } ]前端拿到这个结构直接在地图上按坐标打点连线就能看到一条人走的路线。我还在后台加了一个轨迹回放功能按时间推进播放抓拍图片看起来就像在顺着摄像头跟这个人走。这个功能对安防研判、客流动线分析特别实用。5. 实施细节与避坑实录这些坑我替你们踩过了这一节是全篇含水量最低的部分。我把自己在项目上线前后遇到的最典型的坑和排查思路整理出来大多数问题是网上查不到的脏活苦活希望你们不用再走一遍。5.1 底库冷启动与增量更新策略别把底库搞烂底库的初始化方式直接决定系统上线后会不会崩溃。上线第一天客户导入了80万张历史照片如果一股脑全提特征入库你的AI服务要连续跑几十个小时期间任何风吹草动都可能让任务失败。我的做法是做了个批量导入任务系统用消息队列把80万张照片分批下发每批1000张由多台AI服务节点并行处理。处理完一批就写一批Milvus同时记录每张照片的处理状态积攒到一定数量后统一触发索引构建。这样即使中途有机器挂了未完成的任务会重新进入队列不会丢数据。增量更新的策略更要小心。实时抓拍的人脸如果每张都往底库里塞底库很快就会被低质量样本污染。我设了两道闸质量分数不足60分的人脸只做比对、不入底库已经能在底库里匹配到同一个人相似度 ≥ 0.8的照片也不入底库只更新原样本的最新抓拍时间。只有全新的、质量足够好的面孔才会被新增为底库成员。这个机制非常关键实际操作中80%的抓拍人脸其实都是重复出现的人这样做一方面保证底库规模可控另一方面也保障了检索精度不因噪声样本而劣化。5.2 检索性能的持续优化从能跑到扛得住项目实测时发现检索链路在低并发下很流畅一旦QPS升高Milvus的gRPC连接就开始出现超时。排查后确认不是Milvus本身性能不够而是Java端的MilvusClient对连接池的复用不够合理。优化措施有几条照着做性能有明显提升将MilvusClient做成单例注入Spring容器全局只维持少量长连接不要每次请求都new。把查询向量优先做一次L2归一化因为Milvus的IP相似度对向量模长敏感Java代码里手动做归一化比让Milvus内部处理更可控。对高频检索的Top结果做Redis缓存特别是布控库的比对结果TTL设置在3到5秒。检索请求加独立的线程池隔离避免和其他业务的线程争抢资源超时则快速失败返回空结果不能拖垮整个后端。优化完之后的实测数据百万级底库下单次检索P95耗时稳定在12毫秒以内并发100路实时抓拍比对时后端服务整体无超时。这个成绩客户很满意毕竟之前他们用的是别家的方案单次检索要300多毫秒完全不是一个量级。5.3 轨迹断裂与误串调参哲学轨迹追踪上线后出现两类问题一类是断裂一个人明明走了一长串路系统只还原了一半另一类是误串两条不同人的轨迹被错误拼接在一起。这两类问题还是同一组参数引起的互相矛盾调参是个取舍活。轨迹断裂的最常见原因是我前面说的时间差窗口设得太短了。比如一个访客出了A号楼在楼下抽了根烟再走到B号楼中间隔了5分钟如果我的窗口只设了60秒这条轨迹必断。后来我把相邻摄像头间的合理时间差从摄像头部署点位之间的步行时间推导出来先用地图算出两摄像头间的路程再按人的步行速度除以一个容差系数得到最大允许间隔。比如500米的路程按1.2米/秒的速度理论耗时约420秒我把窗口设为700秒这样既不会断得离谱也不会把半小时后路过的人串进来。误串的高发场景是商场这种人流密集场所人脸相似度高的人太多。我的解法是引入一个旁证机制如果两个人在同一时间段出现在两个摄像头的画面里即使特征高度相似也不能拼成一个人。比如A和B长得像双胞胎但系统同时抓到了A在1号店、B在3号店那它们的轨迹片段就不能拼接。我让轨迹拼接算法必须检查两条片段在重叠时间内是否与其他抓拍记录冲突。冲突检测把误串率从4.7%降到了0.8%代价是部分真实轨迹会被漏判但在这个业务场景里漏判是可接受的串错人是不可接受的。5.4 常见问题速查表线上突发事件排查手册现象可能原因排查方法检索结果出现大量特征向量完全一致Milvus索引构建失败或压缩未完成查看Milvus日志执行compact或重建索引摄像头离线状态频繁网关拉流线程溢出或RTSP地址过期检查JavaCV重连逻辑确认地址可用性线程池是否被打满轨迹还原率突然下降特征模型版本升级导致新老特征不能直接比较重新用当前模型对底库全量特征进行刷一次或做特征空间映射对齐实时比对延迟飙升后回落布控库或者Redis缓存过期导致大面积穿透预热布控库存量特征到Redis错峰更新缓存消息队列积压AI服务处理速度跟不上或某张图片处理异常反复重投检查AI服务GPU利用率异常消息做隔离重试不要无限走队列这张表在我项目交付后转交给运维团队他们对这套排查手册反馈最多的一句话是还好有这张表不然第一晚值班肯定慌。5.5 跨摄像头时间同步问题这个是所有人都提但几乎所有人都会踩一遍的坑。很多摄像头自身时钟不准有的差几秒有的差几分钟如果直接用摄像头自带的时间戳做轨迹时间线还原出来的轨迹会不伦不类。比如一个摄像头时间快了2分钟一个人刚从A画面消失B画面出现的时间居然比A还早轨迹拼不上。我的处理方式是在IoT网关层做统一时间矫正。网关拉流时每帧都打上网关服务器自己的时间戳替换掉摄像头SDK给的时间同时定期对所有摄像头做NTP校准。如果某个摄像头无法通过NTP校准就在设备表里记录一个固定偏移量消息消费时统一修正。这一步不做后面所有时间相关的逻辑都会出错到时候排查起来比写代码痛苦一百倍。6. 一些补充分享这套系统的下一步演进整个系统从设计到上线大约花了两个月核心团队成员四个人。回头看这个项目最难的不是某个算法而是把三个技术栈的工程耦合点处理干净IoT层别和AI层纠缠在一起AI层别和后端业务耦合起来每层之间的接口定义清楚后面扩展就是搭积木。对这套系统的下一步我有几个已经验证过思路的扩展方向。第一是把跨镜头追踪从行人/人脸扩展到车辆ReID核心逻辑完全兼容只要换特征提取模型轨迹拼接和时空约束的功能不需要大改第二是引入时序知识图谱把人员的轨迹和站点、区域事件做关联分析形成行为画像这会让系统从被动检索走向主动告警分析第三是替换掉我在demo阶段用的最大排序逻辑在Java后端做一个轻量级特征聚类服务可以把批量轨迹挖掘的计算量分摊到业务服务上降低对GPU服务的依赖。最后再分享一个经验。这套系统的底库检索阈值、轨迹拼接相似度阈值都不是上线时一次调好的我准备了至少一年份的抓拍数据每天跑离线回归测试对比线上的检索结果和人工标注结果持续调整参数和模型。人脸识别和轨迹追踪这类系统本质上是个高置信度比例的问题上线只是开始之后每周都要看这些指标底库检索召回率、轨迹还原率、误串率、平均检索延迟。指标波动直接反映出模型漂移、数据质量和硬件状态的变化。这不是AI项目的特殊要求而是所有感知 决策型系统的通病宁可把它当成一部需要长期养护的车也别当成一台卖出去就不管的家电。
阅读完成 · 觉得有帮助?