| 名称 | vss-search-archive |
| 描述 | 使用此技能对归档视频运行顶层的 VSS 融合搜索,或摄取视频文件/RTSP 流以供搜索。不要用于即席视觉问答(请使用 vss-ask-video)、实时字幕(请使用 vss-deploy-dense-captioning)或视频摘要与报告(请使用 vss-summarize-video)。 |
| 开源协议 | Apache-2.0 metadata: |
| 作者 | “NVIDIA Video Search and Summarization team” |
| 版本 | “3.2.0” github-url: “https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization” tags: “nvidia blueprint operational” |
用途
对归档视频运行顶层的 VSS 融合搜索,将新视频剪辑/RTSP 流摄取至系统中供后续搜索,并可删除已经过搜索摄取的数据源。
前提条件
- VSS 部署已激活且可以通过
$HOST_IP访问(参见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 代码块。运行 Tier-3 评估:nv-base validate <this-skill-dir> --agent-eval 可重放这些示例。
限制
- 需要匹配的 VSS profile / 微服务已部署并能从调用方访问。
- NGC 托管的模型和 NIM 可能受到速率限制、GPU 内存要求以及许可证限制。
- 并发量、GPU 内存和存储限制取决于宿主机硬件与 profile 的 compose 文件。
故障排除
- 错误:REST 调用返回 connection refused。原因:目标微服务未运行。解决方案:探测
/docs或/health;通过vss-deploy-profile或对应的vss-deploy-*skill 重新部署。 - 错误:NGC 拉取返回 HTTP 401/403。原因:缺少/过期
NGC_CLI_API_KEY。解决方案:docker login nvcr.io并重新导出密钥后重试。 - 错误:容器 OOM 或模型加载失败。原因:所选择的 profile 的 GPU 内存不足。解决方案:切换到更小的变体,或通过
docker compose down释放 GPU。
视频搜索工作流
Alpha 功能 — 不建议用于生产环境。
使用 Cosmos Embed1 嵌入,通过自然语言搜索视频档案。需要搜索 profile —— 使用 vss-deploy-profile 技能(-p search)部署。这些视频源可以是已摄取的文件或 RTSP 流。
何时使用
- “查找所有叉车实例”
- “有人什么时候进入受限区域?”
- “给我看装载码头附近的人”
- “搜索上午 8 点到中午之间的车辆”
- 对视频档案进行任何自然语言搜索
- “摄取
<file>以供搜索” / “上传此视频以供搜索” - “添加此 RTSP 流以供搜索” / “注册
<rtsp_url>以供搜索” - “从搜索中删除
<file>” / “移除此视频及其嵌入”
部署前提
本技能要求 VSS search profile 运行在 $HOST_IP 上。在任何请求之前:
-
探测栈:
curl -sf --max-time 5 "http://${HOST_IP}:8000/docs" >/dev/null \ && curl -sf --max-time 5 "http://${HOST_IP}:9200/" >/dev/null(第二次检查确认 Elasticsearch 已启动 —— search profile 特有。)
-
如果探测失败,询问用户:
"VSS
searchprofile 未在$HOST_IP上运行。我现在通过/vss-deploy-profile技能以-p search部署它吗?"- 如果同意 → 移交给
/vss-deploy-profile技能。成功后返回此处。 - 如果不同意 → 停止。不要对缺失或不匹配的 profile 栈运行此技能。
(如果你的调用方已明确预授权自动部署 —— 例如请求中带有 “pre-authorized to deploy prerequisites”,或你正在具有该权限的非交互评估环境中运行 —— 跳过确认并直接调用
/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/search profile 以 2025-01-01T00:00:00.000Z 作为上传的 video_file 基础时间戳;VIOS 存储和嵌入必须共享该时间线,否则截图 URL 和批评者帧抓取可能失败。
FILENAME="<filename.mp4>"
FILE_PATH="/path/to/${FILENAME}"
# 1. 向 agent 请求分块上传 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. 对该 VST URL 以分块 POST 上传文件(nvstreamer 协议)。
# 最后一个分块的响应携带 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. 通知 agent 上传完成 —— 这将扇出到 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 存储和搜索嵌入一起清理。
# 对视频文件:video_id 是 VIOS sensor/video UUID
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/videos/<video_id>" | jq .
# 对 RTSP 流: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,请 HARD STOP。 参见下方的“输入解析”。不要默认使用localhost、127.0.0.1、agent 自身运行的主机或任何其他猜测。在用户提供端点之前,不要发起POST http://.../generate请求。仅向用户提出一个问题,询问HOST_IP/ VSS agent 端点并等待。 -
解析数据源 — 在任何
/generate调用前 HARD STOP。 如果用户查询涉及特定视频/传感器名称(例如“机场视频”、“warehouse_cam_3”、“sample warehouse”),请通过vss-manage-video-io-storage技能列出数据源,核实其确实已在 VIOS 中注册。然后:
- 如果命名源(或明显子串匹配的名称)在列表中 → 进入步骤 3。将用户的自然语言查询原样转发 —— agent 自身的搜索工具分解器(
services/agent/src/vss_agents/tools/search.py)会基于可得源从文本中提取video_sources,因此本技能无需构建结构化的video sources负载。 - 如果命名源不在列表中 → 停止。不要将
/generate用作探测。将已注册的源名称告知用户,并询问他们是否指其中某个、是否希望摄取缺失的源(引导其前往摄取前提并运行匹配的文件或 RTSP 配方 —— 必须通过 agent 后端,而非裸 VIOS),或者放弃查询。等待澄清。 - 如果查询没有指定具体源(“在已摄取的视频中查找叉车”、“跨所有源搜索”)→ 跳过子串检查,但
sensor/list仍必须返回非空(否则没有已摄取源 → HARD STOP)。
- 如果命名源(或明显子串匹配的名称)在列表中 → 进入步骤 3。将用户的自然语言查询原样转发 —— agent 自身的搜索工具分解器(
-
通过所选方法运行搜索。
-
向用户展示查询结果。将响应格式化为专业的检查报告,但命名为
Video Search Results: — 使用清晰的章节标题- 将发现内容逐条组织并附上支持细节,最后给出总结
- 在比较有帮助时使用表格。以技术报告而不是聊天消息的方式写作。
- 如果评判标准结果非空,则除了“评判结果”(“confirmed” | “rejected” | “skipped”)列外,还包括“标准”列,用该搜索结果的全部标准描述({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 方法,除非用户另有说明。
# 默认只考虑已摄取的视频文件源
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find all instances of forklifts"}' | jq .
更多示例
需要传递结构化请求选项(如 search_source_type)时,请使用 messages 请求形式;input_message 快捷方式不接受额外字段。
# 按物体搜索
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find vehicles in the parking lot"}' | jq .
# 按动作搜索
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "show me people running"}' | jq .
# 按时间上下文搜索
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 .
# 使用 `search_source_type` 筛选只考虑 RTSP 源即实时摄像头流
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "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