Objectif
Exécuter la recherche de fusion VSS au niveau supérieur sur les vidéos archivées, ingérer de nouveaux clips / flux RTSP pour la recherche, et supprimer les sources ingérées pour la recherche.
Prérequis
- Déploiement VSS actif accessible sur
$HOST_IP(voirvss-deploy-profileetreferences/). - Skill
vss-manage-video-io-storageinstallée (utilisée pour lister et gérer les sources vidéo avant la recherche). - Identifiants NGC dans
$NGC_CLI_API_KEYet$NVIDIA_API_KEYpour toute extraction d'images. curl,jq, et Docker disponibles sur l'appelant.
Instructions
Suivez les tables de routage et les flux de travail étape par étape ci-dessous. Chaque section se terminant par workflow, quick start, ou flow est destinée à être exécutée de haut en bas. La documentation de référence détaillée se trouve dans references/.
Exemples
Des exemples fonctionnels de bout en bout sont conservés dans evals/ (chaque manifeste *.json contient un scénario exécutable) et en ligne dans les blocs curl par flux de travail ci-dessous. Exécutez une évaluation Tier-3 avec nv-base validate <this-skill-dir> --agent-eval pour les rejouer.
Limitations
- Nécessite que le profil VSS / microservice correspondant soit déployé et accessible depuis l'appelant.
- Les modèles hébergés sur NGC et les NIMs peuvent être soumis à des limites de débit, des exigences de mémoire GPU et des restrictions de licence.
- Les limites de concurrence, de mémoire GPU et de stockage dépendent du matériel hôte et du fichier compose du profil.
Dépannage
- Erreur : l'appel REST retourne connection refused. Cause : le microservice cible n'est pas en cours d'exécution. Solution : sondez
/docsou/health; redéployez viavss-deploy-profileou la skillvss-deploy-*correspondante. - Erreur : HTTP 401/403 depuis les extractions NGC. Cause :
NGC_CLI_API_KEYmanquante/expirée. Solution :docker login nvcr.ioet réexportez la clé avant de réessayer. - Erreur : OOM du conteneur ou le modèle ne se charge pas. Cause : mémoire GPU insuffisante pour le profil sélectionné. Solution : basculez vers une variante plus petite ou libérez les GPUs via
docker compose down.
Flux de travail de recherche vidéo
Fonctionnalité Alpha — non recommandée pour une utilisation en production.
Recherchez des archives vidéo en langage naturel en utilisant les embeddings Cosmos Embed1. Nécessite le profil de recherche — déployez avec la skill vss-deploy-profile (-p search). Ces sources vidéos peuvent être des fichiers ingérés ou des flux RTSP.
Quand l'utiliser
- « Trouver toutes les instances de chariots élévateurs »
- « Quand quelqu'un a-t-il pénétré dans la zone restreinte ? »
- « Montrez-moi les personnes près du quai de chargement »
- « Rechercher des véhicules entre 8h et midi »
- Toute recherche en langage naturel dans les archives vidéo
- « Ingérer
<file>pour la recherche » / « télécharger cette vidéo pour la recherche » - « Ajouter ce flux RTSP pour la recherche » / « enregistrer
<rtsp_url>pour la recherche » - « Supprimer
<file>de la recherche » / « supprimer cette vidéo et les embeddings »
Condition préalable au déploiement
Cette skill nécessite le profil VSS search en cours d'exécution sur l'hôte à $HOST_IP. Avant toute demande :
-
Sondez la pile :
curl -sf --max-time 5 "http://${HOST_IP}:8000/docs" >/dev/null \ && curl -sf --max-time 5 "http://${HOST_IP}:9200/" >/dev/null(La deuxième vérification confirme qu'Elasticsearch est actif — unique au profil de recherche.)
-
Si le sondage échoue, demandez à l'utilisateur :
« Le profil VSS
searchn'est pas en cours d'exécution sur$HOST_IP. Dois-je le déployer maintenant en utilisant la skill/vss-deploy-profileavec-p search? »- Si oui → passez la main à la skill
/vss-deploy-profile. Revenez ici une fois qu'elle réussit. - Si non → arrêtez. N'exécutez pas cette skill contre une pile manquante ou avec un profil incorrect.
(Si votre appelant vous a accordé une pré-autorisation explicite pour déployer de manière autonome — par exemple, la demande dit « pré-autorisé à déployer les prérequis », ou vous êtes en cours d'exécution dans un harnais d'évaluation non interactif avec cette permission — ignorez la confirmation et invoquez
/vss-deploy-profiledirectement.) - Si oui → passez la main à la skill
-
Si le sondage réussit, procédez.
Condition préalable à l'ingestion (requise avant tout /generate)
Pour qu'une source soit consultable, elle doit être ingérée via le backend de l'agent VSS, pas uniquement via VIOS. Les routes d'ingestion de l'agent possèdent le pipeline VIOS upload + RTVI-CV register + RTVI-embed comme une seule transaction ; un simple PUT VIOS stocke uniquement les octets et ne les câble jamais dans Elasticsearch.
Confirmez d'abord que la source existe dans VIOS (Étape 2 du flux de travail obligatoire). Si elle est manquante, ingérez-la avec l'une des recettes ci-dessous avant de déclencher /generate. Après la réussite de l'ingestion, la source apparaît dans sensor/list sous le nom que vous avez fourni et peut être référencée à partir de la requête en langage naturel que l'agent transmet à son décomposeur d'outil de recherche — vous n'avez PAS besoin de construire vous-même une charge utile structurée video_sources.
Upload de fichier — flux universel en trois étapes
Utilisez le formulaire de téléchargement horodaté ci-dessous. L'agent VSS/profil de recherche utilise 2025-01-01T00:00:00.000Z comme timestamp de base pour le video_file téléchargé ; le stockage VIOS et les embeddings doivent partager cette chronologie, sinon les URLs de capture d'écran et les extractions de cadre du critique peuvent échouer.
FILENAME="<filename.mp4>"
FILE_PATH="/path/to/${FILENAME}"
# 1. Demandez à l'agent l'URL de téléchargement en morceaux
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. Envoyez en POST le fichier par morceaux à cette URL VST (protocole nvstreamer).
# La réponse du dernier morceau porte le 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. Dites à l'agent que le téléchargement est terminé — cela se démultiplexe vers 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 .
Attendez la réponse /complete (elle retourne chunks_processed > 0 une fois que les embeddings atterrissent). C'est seulement à ce moment que la vidéo est consultable.
L'ancienne route
PUT /api/v1/videos-for-search/{filename}est également câblée pour les appelants hérités (coup unique, piloté par l'agent), mais son entrée OpenAPI est marquéedeprecated. Préférez le flux en trois étapes ci-dessus pour les nouveaux travaux.
Flux RTSP — point de terminaison unique
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 .
La forme de réponse est {status, message, error} — pas de sensorId (l'agent indexe le flux par le name que vous avez fourni). Sur l'échec de n'importe quelle étape, les étapes antérieures font l'objet d'une annulation. L'étape start_embedding_generation est fire-and-verify : un 2xx confirme que la demande a été acceptée et le pipeline d'embedding s'exécute en arrière-plan, pas que le flux est consultable. Les résultats de recherche commencent à apparaître seulement après que suffisamment de morceaux arrivent dans Elasticsearch — interrogez avec une requête à faible top_k quelques secondes plus tard si vous avez besoin d'un signal de disponibilité.
Supprimer source — nettoyage soutenu par l'agent
Supprimez via le backend de l'agent, pas le VIOS nu, afin que le stockage VIOS et les embeddings de recherche soient nettoyés ensemble.
# Pour les fichiers vidéo : video_id est l'UUID du capteur/vidéo VIOS
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/videos/<video_id>" | jq .
# Pour les flux RTSP : name est le nom de la source enregistrée
curl -s -X DELETE "http://${HOST_IP}:8000/api/v1/rtsp-streams/delete/<name>" | jq .
Comment fonctionne la recherche
- Ingestion — Les fichiers arrivent via le flux universel en trois étapes de l'agent ; les flux RTSP via
/api/v1/rtsp-streams/add. Les deux routes remettent la source à RTVI-CV (détection d'attributs) et RTVI-Embed (Cosmos Embed1) qui génère des embeddings vectoriels pour les segments vidéo. - Indexation — Les embeddings sont stockés dans Elasticsearch via le pipeline Kafka.
- Requête — Les requêtes en langage naturel sont intégrées et mises en correspondance avec les vecteurs stockés par similarité.
- Résultats — Segments vidéo horodatés classés par pertinence, avec liens de lecture de clip.
Cette recherche orchestrée par l'agent VSS peut conduire à 3 comportements :
- Attributs uniquement : quand le LLM décompose la requête et ne trouve que des attributs d'apparence sans action (par exemple, « personne portant une veste rouge »)
- Embedding uniquement : quand la requête n'a pas d'attributs extractibles (par exemple, « montrez-moi des chariots élévateurs »)
- Fusion : quand la requête a à la fois une action et des attributs (par exemple, « personne en veste rouge courant »), elle exécute d'abord la recherche d'embedding, puis reclasse en utilisant la recherche d'attributs
Flux de travail obligatoire
Lors de l'utilisation de cette skill, SUIVEZ TOUJOURS ce flux de travail de haut niveau :
-
Résolvez les entrées à partir des instructions de l'utilisateur — ARRÊT OBLIGATOIRE si
$HOST_IPn'est pas explicitement fourni. Voir § Résolution des entrées ci-dessous. Ne METTEZ PAS par défautlocalhost,127.0.0.1, l'hôte sur lequel l'agent lui-même s'exécute, ou toute autre supposition. Ne lancez PAS une demandePOST http://.../generatejusqu'à ce que l'utilisateur ait fourni un point de terminaison. Répondez à l'utilisateur avec une seule question demandantHOST_IP/ le point de terminaison de l'agent VSS et attendez. -
Résolvez la source — ARRÊT OBLIGATOIRE avant tout appel
/generate. Si la requête de l'utilisateur référence une vidéo / un nom de capteur spécifique (par exemple, « la vidéo de l'aéroport », « warehouse_cam_3 », « sample warehouse »), vérifiez qu'il est réellement enregistré dans VIOS avant de déclencherPOST .../generate. Listez les sources via la skillvss-manage-video-io-storage.Puis :
- Si la source nommée (ou un nom clairement correspondant à une sous-chaîne) EST dans la liste → procédez à l'étape 3. Transmettez la requête en langage naturel de l'utilisateur verbatim — le décomposeur d'outil de recherche propre de l'agent (
services/agent/src/vss_agents/tools/search.py) extraitvideo_sourcesde la prose compte tenu des sources disponibles, la skill n'a donc PAS besoin de construire elle-même une charge utile structuréevideo_sources. - Si la source nommée N'est PAS dans la liste → ARRÊTEZ. Ne lancez PAS
/generateen tant que sonde. Répondez à l'utilisateur avec les noms de sources enregistrées et demandez s'il en a voulu l'un d'eux, souhaite ingérer la source manquante (pointez-le vers Condition préalable à l'ingestion et exécutez la recette de fichier ou RTSP correspondante via le backend de l'agent, pas le VIOS nu), ou souhaite abandonner la requête. Attendez la clarification. - Si la requête ne nomme pas de source spécifique (« trouver des chariots élévateurs dans les vidéos ingérées », « rechercher dans toutes les sources ») → ignorez la vérification de sous-chaîne, mais
sensor/listdoit quand même retourner non vide (sinon aucune source n'est ingérée → ARRÊT OBLIGATOIRE).
- Si la source nommée (ou un nom clairement correspondant à une sous-chaîne) EST dans la liste → procédez à l'étape 3. Transmettez la requête en langage naturel de l'utilisateur verbatim — le décomposeur d'outil de recherche propre de l'agent (
-
Exécutez la/les recherche(s) via l'approche choisie
-
Présentez les résultats à la requête de l'utilisateur. Formatez la réponse comme un rapport d'inspection professionnel mais nommez-le
Résultats de la recherche vidéo: — Utilisez des en-têtes de section clairs- Organisez les conclusions individuellement avec les détails à l'appui, et terminez par un résumé
- Utilisez des tableaux où les comparaisons aident. Écrivez comme un rapport technique, pas un message de chat.
- Si les résultats des critères ne sont pas nuls, alors en plus d'une colonne « Résultat du critique » (« confirmé » | « rejeté » | « ignoré »), incluez une colonne « Critères » avec tous les critères de ce résultat de recherche ({criteria_n}: ✓ | ✗)
-
CRITIQUE : Vérifiez les résultats et expliquez-le à l'utilisateur de manière concise. Si la recherche échoue, ou retourne des résultats inattendus (c.-à-d. des vidéos qui ne semblent pas correspondre à la requête utilisateur, zéro correspondance, zéro vidéos retournées, erreur, etc.), ARRÊTEZ. Ne procédez pas sans lire troubleshooting.md pour itérer avec des boucles de rétroaction jusqu'à ce que les résultats appropriés soient trouvés et présentés comme un rapport d'inspection professionnel.
-
Vérifications finales :
- INFORMEZ TOUJOURS l'utilisateur que des vérifications finales et supplémentaires peuvent être exécutées. Présentez cela comme une
Étape de vérification - UNIQUEMENT SI l'utilisateur accepte, téléchargez les captures d'écran en utilisant la
screenshot_urldes meilleurs candidats (scores de similarité les plus élevés) des résultats de recherche (résultats JSON) vers/tmp. Lisez-les et vérifiez s'ils correspondent à la requête de l'utilisateur
- INFORMEZ TOUJOURS l'utilisateur que des vérifications finales et supplémentaires peuvent être exécutées. Présentez cela comme une
Résolution des entrées
Déduisez ces entrées uniquement de la conversation ou de la requête de l'utilisateur (aucun autre fichier sauf s'il est fourni). Si certaines ne peuvent pas être déduites, demandez immédiatement à l'utilisateur :
- $HOST_IP : où le backend de l'agent VSS s'exécute
Pièges
- ALLEZ TOUJOURS à l'étape de dépannage du flux de travail immédiatement si quelque chose d'inattendu se produit, lisez troubleshooting.md
- Les requêtes fonctionnent mieux avec des descriptions visuelles concrètes (objets, actions, emplacements). Augmentez les requêtes de l'utilisateur si nécessaire pour améliorer la qualité des questions, en élargissant les détails potentiels
- La skill suppose que les sources vidéo sont déjà ingérées via le backend de l'agent (voir Condition préalable à l'ingestion). Elle PEUT exécuter les recettes d'ingestion soutenues par l'agent quand l'utilisateur le demande explicitement (« ingérer
<file>pour la recherche », « ajouter<rtsp_url>pour la recherche ») ; elle ne recherche PAS le système de fichiers local pour les fichiers que l'utilisateur n'a pas nommés, et elle n'utilise PAS le chemin nu-VIOS PUT (aucun embedding n'est généré). L'étape 2 du flux de travail rend toujours confirmer « cette source existe dans VIOS » une précondition obligatoire avant/generate. - Utilisez la skill
vss-query-analyticspour croiser les résultats de recherche avec les données d'incident/d'alerte
Recherche via REST API
Utilisez par défaut cette approche REST API, sauf si l'utilisateur en spécifie une autre.
# Considérez par défaut uniquement les sources de fichiers vidéo ingérés
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find all instances of forklifts"}' | jq .
Autres exemples
Utilisez la forme de requête messages lors du passage d'options de requête structurées telles que search_source_type ; le raccourci input_message n'accepte pas de champs supplémentaires.
# Rechercher par objet
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find vehicles in the parking lot"}' | jq .
# Rechercher par action
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "show me people running"}' | jq .
# Rechercher par contexte temporel
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 .
# Considérez uniquement les sources RTSP avec le filtre `search_source_type` c.-à-d. les flux de caméra en direct
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 .
Boutons de commande avancés
Si la requête utilisateur est ambiguë, l'utilisateur souhaite plus de conseils ou quand un contrôle fin est nécessaire, augmentez le input_message utilisateur en appelant explicitement certaines options en texte brut et en orientant l'agent dans la direction souhaitée. Axes de commande disponibles :
| Axes | Type | Défaut | Description |
|---|---|---|---|
video sources |
string[] | null | Filtrer par des caméras ou noms de capteurs spécifiques |
top k |
int | 10 | Max de résultats |
minimum similarity |
float | 0,0 | Seuil de similarité min ; augmentez (par exemple 0,3) pour filtrer le bruit |
critic usage |
bool | true | VLM vérifie chaque résultat et supprime les faux positifs |
description |
string | null | Filtrer par métadonnées de caméra (par exemple, localisation, catégorie) si les métadonnées sont disponibles |
Choisissez et sélectionnez certaines de ces options d'ajustement. Ajustez-les au besoin selon la situation et la requête de l'utilisateur. Pour des exemples de modes de découverte exploitant ceux-ci, voir discovery_modes.md.
Recherche via l'interface utilisateur Agent
Ouvrez http://${HOST_IP}:3000/ et tapez des requêtes en langage naturel :
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
Les résultats incluent des clips horodatés avec des scores de similarité.
bump:2