关于 vss-search-archive
vss-search-archive 是用于 NVIDIA VSS 视频档案自然语言检索的技能,可搜索已归档视频,也可接入文件或 RTSP 流并管理检索来源。它通过属性检索与 Cosmos Embed1 向量检索组合查找片段;该功能处于 Alpha 阶段,不建议用于生产环境。
主要功能
- 01自然语言搜索视频档案
- 02接入视频文件与 RTSP 流
- 03生成并索引视频向量嵌入
- 04融合属性与向量检索
- 05删除来源及其搜索数据
适用场景
- 01查找档案中的特定对象或活动
- 02按时间与地点筛选视频片段
- 03将新视频或 RTSP 源加入搜索
- 04移除来源及相关嵌入数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ promptingcompany/ nv-skills --skill vss-search-archive安装后在 Claude Code 中输入/vss-search-archive确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
BENCHMARK.mdskill-card.mdskill.oms.sigevals/evals.jsonsearch.jsonreferences/discovery_modes.mdtroubleshooting.md详细介绍
目的
在已归档视频中运行顶层 VSS 融合搜索,摄取新的视频片段 / RTSP 流以供搜索,并删除已摄取用于搜索的源。
前置条件
- 可通过
$HOST_IP访问正在运行的 VSS 部署(参见vss-deploy-profile和references/)。 - 已安装
vss-manage-video-io-storage技能(用于在搜索前列出和管理视频源)。 - 如需拉取任何镜像,需在
$NGC_CLI_API_KEY和$NVIDIA_API_KEY中提供 NGC 凭据。 - 调用方可使用
curl、jq和 Docker。
说明
按照以下路由表和分步工作流操作。每个以 workflow、quick start 或 flow 结尾的部分都应从上到下执行。详细参考资料位于 references/ 中。
示例
端到端示例保存在 evals/ 下(每个 *.json 清单都包含一个可运行场景),也以内联形式列在下方各工作流的 curl 代码块中。运行 nv-base validate <this-skill-dir> --agent-eval 可重放这些示例并进行 Tier-3 评估。
限制
- 需要部署与之匹配且可从调用方访问的 VSS 配置文件 / 微服务。
- NGC 托管的模型和 NIM 可能受速率限制、GPU 内存要求和许可证限制。
- 并发、GPU 内存和存储限制取决于主机硬件和配置文件的 compose 文件。
故障排除
- 错误:REST 调用返回连接被拒绝。原因:目标微服务未运行。解决方案:检查
/docs或/health;通过vss-deploy-profile或匹配的vss-deploy-*技能重新部署。 - 错误:从 NGC 拉取时收到 HTTP 401/403。原因:缺少或已过期的
NGC_CLI_API_KEY。解决方案:运行docker login nvcr.io,然后重新导出密钥再试。 - 错误:容器发生 OOM,或模型加载失败。原因:所选配置文件的 GPU 内存不足。解决方案:切换到较小的变体,或通过
docker compose down释放 GPU。
视频搜索工作流
Alpha Feature — 不建议用于生产环境。
使用 Cosmos Embed1 嵌入向量,通过自然语言搜索视频档案。需要搜索配置文件 — 使用 vss-deploy-profile 技能(-p search)进行部署。这些视频源可以是已摄取的文件或 RTSP 流。
适用场景
- “查找所有出现叉车的实例”
- “有人是什么时候进入限制区域的?”
- “显示装卸区附近的人员”
- “搜索上午 8 点到中午之间的车辆”
- 对视频档案进行任何自然语言搜索
- “摄取
<file>以供搜索” / “上传此视频以供搜索” - “添加此 RTSP 流以供搜索” / “注册
<rtsp_url>以供搜索” - “从搜索中删除
<file>” / “移除此视频及其嵌入向量”
部署前提条件
此技能需要在 $HOST_IP 上运行 VSS search 配置文件。执行任何请求前:
-
检查服务栈:
curl -sf --max-time 5 "http://${HOST_IP}:8000/docs" >/dev/null \ && curl -sf --max-time 5 "http://${HOST_IP}:9200/" >/dev/null(第二项检查用于确认 Elasticsearch 已启动,这是搜索配置文件独有的检查。)
-
如果检查失败,请询问用户:
“VSS
search配置文件未在$HOST_IP上运行。是否要使用/vss-deploy-profile技能和-p search立即部署?”- 如果是 → 转交给
/vss-deploy-profile技能。部署成功后返回此处。 - 如果否 → 停止。不要在缺少服务栈或配置文件错误的情况下运行此技能。
(如果调用方已明确预先授权你自主部署 — 例如请求中写明“已预先授权部署前置条件”,或你正在具有该权限的非交互式评估环境中运行 — 则跳过确认,直接调用
/vss-deploy-profile。) - 如果是 → 转交给
-
如果检查通过,则继续。
摄取前提条件(任何 /generate 调用前均为必需)
要使来源可供搜索,必须通过 VSS Agent 后端摄取,而不能仅通过 VIOS 摄取。Agent 的摄取路由将 VIOS 上传、RTVI-CV 注册和 RTVI-embed 管道作为一个事务处理;单独执行 VIOS PUT 只会存储字节,不会将其接入 Elasticsearch。
请先确认来源存在于 VIOS 中(必需工作流第 2 步)。如果来源不存在,请在调用 /generate 前使用以下任一方案摄取。摄取成功后,来源会以你提供的名称显示在 sensor/list 中,并可在 Agent 转发给搜索工具分解器的自然语言查询中引用——你无需自行构造结构化的 video_sources 负载。
文件上传——通用三步流程
使用下面带时间戳的上传表单。VSS Agent/搜索配置使用
2025-01-01T00:00:00.000Z 作为上传的 video_file 基础时间戳;
VIOS 存储和嵌入必须使用相同的时间线,否则
截图 URL 和 critic 帧获取可能会失败。
FILENAME="<filename.mp4>"
FILE_PATH="/path/to/${FILENAME}"
# 1. Ask the agent for the chunked-upload URL
UPLOAD_URL=$(curl -s -X POST "http://${HOST_IP}:8000/api/v1/videos" \
-H "Content-Type: application/json" \
-d "{\"filename\":\"${FILENAME}\"}" | jq -r .url)
# 2. Chunked POST the file to that VST URL (nvstreamer protocol).
# The final-chunk response carries sensorId.
IDENTIFIER=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid)
UPLOAD_RESPONSE=$(curl -s -X POST "${UPLOAD_URL}" \
-H "nvstreamer-chunk-number: 1" \
-H "nvstreamer-total-chunks: 1" \
-H "nvstreamer-is-last-chunk: true" \
-H "nvstreamer-identifier: ${IDENTIFIER}" \
-H "nvstreamer-file-name: ${FILENAME}" \
-F "mediaFile=@${FILE_PATH};filename=${FILENAME}" \
-F "filename=${FILENAME}" \
-F 'metadata={"timestamp":"2025-01-01T00:00:00"}')
# 3. Tell the agent the upload finished — this fans out to RTVI-CV + RTVI-embed
SENSOR=$(printf '%s' "${UPLOAD_RESPONSE}" | jq -r .sensorId)
[ -z "${SENSOR}" ] || [ "${SENSOR}" = "null" ] \
&& { echo "Upload failed: no sensorId in response: ${UPLOAD_RESPONSE}"; exit 1; }
printf '%s' "${UPLOAD_RESPONSE}" \
| jq --arg filename "${FILENAME}" '. + {filename: $filename}' \
| curl -s -X POST "http://${HOST_IP}:8000/api/v1/videos/${SENSOR}/complete" \
-H "Content-Type: application/json" \
-d @- | jq .
等待 /complete 响应(嵌入写入后会返回 chunks_processed > 0)。只有在此之后,视频才可供搜索。
已弃用的
PUT /api/v1/videos-for-search/{filename}路由也已接入,供旧版调用方使用(单次请求,由 Agent 驱动),但其 OpenAPI 条目标记为deprecated。新工作请优先使用上述三步流程。
RTSP 流——单个端点
curl -s -X POST "http://${HOST_IP}:8000/api/v1/rtsp-streams/add" \
-H "Content-Type: application/json" \
-d '{
"sensorUrl": "rtsp://<host>:<port>/<path>",
"name": "<sensor-name>",
"username": "",
"password": "",
"location": "",
"tags": ""
}' | jq .
响应格式为 {status, message, error}——不包含 sensorId(Agent 使用你提供的 name 作为流的键)。任何步骤失败时,之前的步骤都会回滚。start_embedding_generation 步骤采用触发后验证的方式:2xx 表示请求已被接受且嵌入管道正在后台运行,并不表示流已可供搜索。只有在足够多的分块写入 Elasticsearch 后,搜索结果才会开始出现——如果需要确认是否就绪,可以在几秒后使用较小的 top_k 值轮询查询。
删除来源——通过 Agent 清理
请通过 Agent 后端删除,而不要直接通过 VIOS 删除,以便同时清理 VIOS 存储和搜索嵌入。
# For video files: video_id is the VIOS sensor/video UUID
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/videos/<video_id>" | jq .
# For RTSP streams: name is the registered source name
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/rtsp-streams/delete/<name>" | jq .
搜索原理
- 摄取——文件通过 Agent 的通用三步流程接入;RTSP 流通过
/api/v1/rtsp-streams/add接入。两种路由都会将来源交给 RTVI-CV(属性检测)和 RTVI-Embed(Cosmos Embed1),后者会为视频片段生成向量嵌入。 - 索引——嵌入通过 Kafka 管道存储在 Elasticsearch 中。
- 查询——自然语言查询会被转换为嵌入,并通过相似度与已存储的向量进行匹配。
- 结果——按相关性排序的带时间戳视频片段,并附带片段播放链接。
VSS Agent 编排的这种搜索可以产生 3 种行为:
- 仅属性搜索:当 LLM 分解查询后,只找到外观属性而没有动作时(例如“穿红色夹克的人”)
- 仅嵌入搜索:当查询没有可提取的属性时(例如“给我看看叉车”)
- 融合搜索:当查询同时包含动作和属性时(例如“穿红色夹克跑步的人”),先运行嵌入搜索,再使用属性搜索重新排序
强制工作流程
使用此技能时,始终遵循以下高级工作流程:
-
根据用户指示解析输入——如果未明确提供
$HOST_IP,则立即停止。 请参阅下方的 § 输入解析。不要默认使用localhost、127.0.0.1、Agent 自身运行所在的主机或任何其他猜测值。在用户提供端点之前,不要发送POST http://.../generate请求。向用户只提出一个问题,询问HOST_IP/ VSS Agent 端点,然后等待。 -
解析来源——在调用
/generate之前立即停止。 如果用户的查询提到特定视频 / 传感器名称(例如“机场视频”“warehouse_cam_3”“sample warehouse”),请在发送POST .../generate之前,确认它确实已在 VIOS 中注册。使用vss-manage-video-io-storage技能列出来源。然后:
- 如果命名的来源(或明显包含该名称的来源)在列表中 → 继续执行第 3 步。逐字转发用户的自然语言查询——Agent 自带的搜索工具分解器(
services/agent/src/vss_agents/tools/search.py)会根据提供的可用来源从文本中提取video_sources,因此此技能无需构造结构化的video sources载荷。 - 如果命名的来源不在列表中 → 停止。不要调用
/generate进行探测。向用户回复已注册的来源名称,并询问他们指的是其中某个来源、想要摄取缺失来源(指引他们参阅摄取前提条件,并通过Agent 后端而非直接调用 VIOS 来运行匹配的文件或 RTSP 方案),还是想要放弃此查询。等待澄清。 - 如果查询未命名特定来源(“在已摄取的视频中查找叉车”“搜索所有来源”)→ 跳过子字符串检查,但
sensor/list仍必须返回非空结果(否则没有摄取任何来源 → 立即停止)。
- 如果命名的来源(或明显包含该名称的来源)在列表中 → 继续执行第 3 步。逐字转发用户的自然语言查询——Agent 自带的搜索工具分解器(
-
使用选定的方法运行搜索
-
根据用户的查询向用户呈现结果。将回复格式设为专业的检查报告,标题命名为
Video Search Results: — 使用清晰的章节标题- 逐项整理发现,并提供支持细节,最后以摘要收尾
- 在比较有帮助时使用表格。采用技术报告的写法,而非聊天消息的语气。
- 如果 criteria 结果非空,除包含“Critic result”(“confirmed” | “rejected” | “skipped”)列外,还要包含“Criteria”列,其中列出此搜索结果的全部标准({criteria_n}: ✓ | ✗)
-
关键:验证结果并简明地向用户说明验证情况。 如果搜索失败,或返回意外结果(即与用户查询不匹配的视频、零条匹配结果、返回零个视频、出错等),请停止。必须先阅读 troubleshooting.md,通过反馈循环反复处理,直到找到并呈现正确结果,且格式符合专业检查报告的要求。
-
最终验证:
- 始终告知用户可以运行最终验证和后续验证。将此内容作为
Verification Step呈现 - 仅当用户同意时,才使用搜索命中项(JSON 结果)中最佳候选项(相似度得分最高)的
screenshot_url,将截图下载到/tmp。读取截图并验证其是否符合用户查询
- 始终告知用户可以运行最终验证和后续验证。将此内容作为
输入解析
仅根据对话或用户查询推断这些输入(除非用户提供,否则不要使用其他文件)。如果无法推断其中某些输入,请立即询问用户:
- $HOST_IP:VSS Agent 后端的运行位置
注意事项
- 一旦发生任何意外情况,立即进入工作流中的故障排查步骤,并阅读 troubleshooting.md
- 使用具体的视觉描述(物体、动作、位置)查询效果最佳。必要时补充用户查询,以提升问题质量并拓展可能的细节
- 此技能假设视频源已通过 Agent 后端完成摄取(请参阅 摄取前提)。用户明确提出请求时(“为搜索摄取
<file>”、“添加<rtsp_url>以供搜索”),可以运行由 Agent 支持的摄取配方;但不会搜索用户未指定的本地文件系统文件,也不会使用裸 VIOS PUT 路径(不会生成嵌入向量)。工作流第 2 步仍将确认“此源存在于 VIOS 中”作为执行/generate的硬性前提。 - 使用
vss-query-analytics技能,将搜索结果与事件/警报数据交叉对照
通过 REST API 搜索
除非用户另有指定,否则默认使用此 REST API 方式。
# Consider only ingested video file sources by default
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find all instances of forklifts"}' | jq .
更多示例
# Search by object
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find vehicles in the parking lot"}' | jq .
# Search by action
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "show me people running"}' | jq .
# Search by time context
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "what happened at the entrance between 2pm and 3pm?"}' | jq .
# Consider only RTSP sources with `search_source_type` filter i.e. live camera streams
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find all instances of forklifts", "search_source_type": "rtsp"}' | jq .
高级控制选项
如果用户的查询有歧义、用户需要更多指导,或需要精细控制,请通过纯文本明确指出特定选项,补充用户的 input_message,并引导 Agent 按期望方向执行。可用的控制维度:
| 维度 | 类型 | 默认值 | 说明 |
|---|---|---|---|
video sources | string[] | null | 限定特定摄像头或传感器名称 |
top k | int | 10 | 最大结果数 |
minimum similarity | float | 0.0 | 最低相似度阈值;提高阈值(例如 0.3)可过滤噪声 |
critic usage | bool | true | VLM 验证每个结果并移除误报 |
description | string | null | 如果元数据可用,则按摄像头元数据(例如位置、类别)筛选 |
选择部分调优选项,并根据用户的情况和查询进行调整。 有关使用这些选项的发现模式示例,请参阅 discovery_modes.md。
通过 Agent UI 搜索
打开 http://${HOST_IP}:3000/ 并输入自然语言查询:
find all instances of forklifts
show me people near the loading dock
when did a truck arrive at the gate?
find someone wearing a red jacket
结果包括带时间戳的片段及其相似度分数。
bump:2