Objectif
Exécuter la recherche de fusion VSS au niveau supérieur sur des vidéos archivées et ingérer de nouveaux clips / flux RTSP pour la recherche.
Prérequis
- Déploiement VSS actif accessible sur
$HOST_IP(voirvss-deploy-profileetreferences/). - Identifiants NGC dans
$NGC_CLI_API_KEYet$NVIDIA_API_KEYpour les tirages d'images. curl,jqet 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. Le matériel de référence détaillé se trouve dans references/ et les scripts d'aide se trouvent dans scripts/ — appelez-les via run_script quand le skill pointe vers un script par nom.
Exemples
Les exemples complets travaillés sont conservés sous evals/ (chaque manifeste *.json contient un scénario exécutable) et en ligne dans les blocs curl par workflow ci-dessous. Exécutez une évaluation Tier-3 avec nv-base validate <this-skill-dir> --agent-eval pour les relire.
Limitations
- Nécessite que le profil VSS correspondant / le microservice 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 connexion refusée. Cause : microservice cible non exécuté. Solution : sondez
/docsou/health; redéployez viavss-deploy-profileou le skillvss-deploy-*correspondant. - Erreur : HTTP 401/403 à partir des tirages NGC. Cause :
NGC_CLI_API_KEYmanquante/expirée. Solution :docker login nvcr.ioet ré-exportez la clé avant de réessayer. - Erreur : conteneur OOM ou le modèle ne charge pas. Cause : mémoire GPU insuffisante pour le profil sélectionné. Solution : passez à une variante plus petite ou libérez les GPU via
docker compose down.
Flux de travail de recherche vidéo
Fonctionnalité Alpha — non recommandée pour la production.
Recherchez des archives vidéo en langage naturel en utilisant les embeddings Cosmos Embed1. Nécessite le profil de recherche — déployez avec le skill vss-deploy-profile (-p search). Ces sources vidéo peuvent être des fichiers ingérés ou des flux RTSP.
Quand l'utiliser
- « Trouver tous les cas de chariots élévateurs »
- « Quand quelqu'un a-t-il accédé à la zone restreinte ? »
- « Montrez-moi les gens près du quai de chargement »
- « Chercher les véhicules entre 8h et 12h »
- Toute recherche en langage naturel sur les archives vidéo
- « Ingérer
<fichier>pour la recherche » / « charger cette vidéo pour la recherche » - « Ajouter ce flux RTSP pour la recherche » / « enregistrer
<rtsp_url>pour la recherche »
Prérequis de déploiement
Ce 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, posez à l'utilisateur :
« Le profil VSS
searchn'est pas en cours d'exécution sur$HOST_IP. Dois-je le déployer maintenant en utilisant le skill/vss-deploy-profileavec-p search? »- Si oui → remettez au skill
/vss-deploy-profile. Revenez ici une fois qu'il réussit. - Si non → arrêtez. N'exécutez pas ce skill contre une pile manquante ou avec le mauvais profil.
(Si l'appelant vous a accordé une pré-autorisation explicite de déployer de façon autonome — par exemple la demande dit « pré-autorisé à déployer les prérequis », ou vous exécutez un harnais d'évaluation non-interactif avec cette permission — ignorez la confirmation et invoquez
/vss-deploy-profiledirectement.) - Si oui → remettez au skill
-
Si le sondage réussit, procédez.
Prérequis d'ingestion (requis avant tout /generate)
Pour qu'une source soit interrogeable, 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 chargement VIOS + l'enregistrement RTVI-CV + le pipeline RTVI-embed comme une seule transaction ; un PUT VIOS nu ne stocke que les octets et ne les câble jamais dans Elasticsearch.
Confirmez d'abord que la source existe dans VIOS (étape 2 obligatoire du flux de travail). S'il manque, ingérez-la avec l'une des recettes ci-dessous avant de lancer /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écompositeur d'outil de recherche — vous n'avez PAS besoin de construire vous-même une charge utile video_sources structurée.
Chargement de fichier — flux universel à trois étapes
# 1. Demandez à l'agent l'URL de chargement par morceaux
URL=$(curl -s -X POST "http://${HOST_IP}:8000/api/v1/videos" \
-H "Content-Type: application/json" \
-d '{"filename": "<filename.mp4>"}' | jq -r .url)
# 2. POST par morceaux le fichier vers cette URL VST (l'interface diffuse les morceaux ; à partir d'un shell,
# un POST multipart unique convient). La réponse du morceau final porte sensorId.
SENSOR=$(curl -s -X POST "$URL" \
-F "file=@/path/to/<filename.mp4>;type=video/mp4" | jq -r .sensorId)
# 3. Dites à l'agent que le chargement est terminé — cela se déploie vers RTVI-CV + RTVI-embed
curl -s -X POST "http://${HOST_IP}:8000/api/v1/videos/${SENSOR}/complete" \
-H "Content-Type: application/json" \
-d '{"filename": "<filename.mp4>"}' | jq .
Attendez la réponse /complete (elle retourne chunks_processed > 0 une fois les embeddings arrivés). C'est seulement à ce moment que la vidéo est interrogeable.
La route
PUT /api/v1/videos-for-search/{filename}dépréciée 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 à trois étapes ci-dessus pour les nouveaux travaux.
Flux RTSP — endpoint unique
curl -s -X POST "http://${HOST_IP}:8000/api/v1/rtsp-streams/add" \
-H "Content-Type: application/json" \
-d '{
"sensor_url": "rtsp://<host>:<port>/<path>",
"name": "<sensor-name>",
"username": "",
"password": "",
"location": "",
"tags": ""
}' | jq .
La forme de la réponse est {status, message, error} — pas de sensorId (l'agent indexe le flux par le name que vous avez fourni). En cas d'échec à une étape, les étapes antérieures sont annulées. L'étape start_embedding_generation est envoi-et-vérification : 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 interrogeable. Les résultats de recherche commenceront à apparaître seulement après que suffisamment de morceaux arrivent dans Elasticsearch — interrogez avec une requête top_k faible après quelques secondes si vous avez besoin d'un signal de disponibilité.
Comment fonctionne la recherche
- Ingestion — Les fichiers arrivent via le flux universel à 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 les 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 des liens de lecture de clips.
Cette recherche orchestrée par l'agent VSS peut mener à 3 comportements :
- Attributs uniquement : quand le LLM décompose la requête et trouve uniquement des attributs d'apparence sans action (par ex. « personne portant une veste rouge »)
- Embed uniquement : quand la requête n'a pas d'attributs extractibles (par ex. « montrez-moi les chariots élévateurs »)
- Fusion : quand la requête a à la fois une action et des attributs (par ex., « personne en veste rouge qui court »), elle exécute d'abord la recherche embed, puis ré-classe à l'aide de la recherche d'attributs
Flux de travail obligatoire
En utilisant ce skill, TOUJOURS suivez ce flux de travail de haut niveau :
-
Résolvez les entrées à partir des instructions utilisateur — ARRÊT FERME si
$HOST_IPn'est pas explicitement fourni. Voir § Résolution des entrées ci-dessous. NE PAS choisir 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 PAS émettre une requêtePOST http://.../generatejusqu'à ce que l'utilisateur ait fourni un endpoint. Répondez à l'utilisateur avec une seule question demandantHOST_IP/ l'endpoint de l'agent VSS et attendez. -
Résolvez la source — ARRÊT FERME avant tout appel
/generate. Si la requête utilisateur référence un nom de vidéo / capteur spécifique (par ex. « la vidéo de l'aéroport », « warehouse_cam_3 », « sample warehouse »), vérifiez qu'il est réellement enregistré dans VIOS avant de lancerPOST .../generate:curl -s "http://${HOST_IP}:30888/vst/api/v1/sensor/list" | jq '.[].name'Ensuite :
- Si la source nommée (ou un nom correspondant clairement à la sous-chaîne) EST dans la liste → procédez à l'étape 3. Transmettez la requête en langage naturel de l'utilisateur littéralement — le propre décompositeur d'outil de recherche de l'agent (
services/agent/src/vss_agents/tools/search.py) extraitvideo_sourcesde la prose donnée les sources disponibles, donc le skill n'a PAS besoin de construire une charge utilevideo_sourcesstructurée. - Si la source nommée N'EST PAS dans la liste → ARRÊTEZ. NE lancez PAS
/generatecomme sondage. Répondez à l'utilisateur avec les noms des sources enregistrées et demandez s'il en signifiait une, s'il souhaite ingérer la source manquante (pointez-le vers Prérequis d'ingestion et exécutez la recette de fichier ou RTSP correspondante via le backend de l'agent, pas VIOS nu), ou s'il souhaite abandonner la requête. Attendez la clarification. - Si la requête ne nomme aucune source spécifique (« trouver les chariots élévateurs dans les vidéos ingérées », « chercher sur toutes les sources ») → ignorez la vérification de sous-chaîne, mais
sensor/listdoit toujours retourner non-vide (sinon aucune source n'est ingérée → ARRÊT FERME).
- Si la source nommée (ou un nom correspondant clairement à la sous-chaîne) EST dans la liste → procédez à l'étape 3. Transmettez la requête en langage naturel de l'utilisateur littéralement — le propre décompositeur d'outil de recherche de l'agent (
-
Exécutez la/les recherche(s) via l'approche choisie
-
Présentez les résultats à la requête utilisateur. Formatez la réponse comme un rapport d'inspection professionnel mais nommez-le
Résultats de recherche vidéo: — Utilisez des en-têtes de section clairs- Organisez les constatations individuellement avec détails de soutien, 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 sont non-nuls, alors en plus d'une colonne « Résultat 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 cela à l'utilisateur de manière concise. Si la recherche échoue, ou retourne des résultats inattendus (par ex. vidéos qui ne semblent pas correspondre à la requête utilisateur, zéro correspondances, 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 :
- TOUJOURS informez l'utilisateur que les vérifications finales et ultérieures peuvent être exécutées. Présentez ceci comme une
Étape de vérification - UNIQUEMENT SI l'utilisateur accepte, téléchargez les captures d'écran en utilisant le
screenshot_urldes meilleurs candidats (scores de similarité les plus élevés) à partir des résultats de recherche (résultats JSON) vers/tmp. Lisez-les et vérifiez s'ils correspondent à la requête utilisateur
- TOUJOURS informez l'utilisateur que les vérifications finales et ultérieures peuvent être exécutées. Présentez ceci comme une
Résolution des entrées
Déduisez ces entrées uniquement à partir de la conversation ou de la requête utilisateur (aucun autre fichier sauf s'il est fourni). Si certaines ne peuvent pas être déduites, demandez à l'utilisateur immédiatement :
- $HOST_IP : où s'exécute le backend de l'agent VSS
Pièges
- TOUJOURS entrez dans 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, lieux). Augmentez les requêtes utilisateur si nécessaire pour améliorer la qualité des questions, en élargissant les détails potentiels
- Le skill suppose que les sources vidéo sont déjà ingérées via le backend de l'agent (voir Prérequis d'ingestion). Il PEUT exécuter les recettes d'ingestion soutenues par l'agent quand l'utilisateur demande explicitement (« ingérer
<fichier>pour la recherche », « ajouter<rtsp_url>pour la recherche ») ; il ne cherche PAS le système de fichiers local pour les fichiers que l'utilisateur n'a pas nommés, et il n'utilise PAS le chemin PUT nu-VIOS (aucun embedding n'est généré). L'étape 2 du flux de travail fait toujours de la confirmation « cette source existe dans VIOS » une précondition ferme avant/generate. - Utilisez le skill
vss-query-analyticspour croiser les résultats de recherche avec les données d'incident/alerte
Recherche via API REST
Préférez cette approche API REST par défaut, sauf si l'utilisateur spécifie autrement.
# Considérez uniquement les sources vidéo fichier ingérées par défaut
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "find all instances of forklifts"}' | jq .
Plus d'exemples
# Chercher 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 .
# Chercher par action
curl -s -X POST http://${HOST_IP}:8000/generate \
-H "Content-Type: application/json" \
-d '{"input_message": "show me people running"}' | jq .
# Chercher 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érer uniquement les sources RTSP avec le filtre `search_source_type`, c'est-à-dire les flux de caméra en direct
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 .
Boutons de contrôle avancés
Si la requête utilisateur est ambiguë, l'utilisateur veut 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 guidant l'agent dans la direction souhaitée. Axes de contrôle disponibles :
| Axes | Type | Défaut | Description |
|---|---|---|---|
video sources |
string[] | null | Filtrer vers des caméras ou noms de capteurs spécifiques |
top k |
int | 10 | Résultats max |
minimum similarity |
float | 0,0 | Seuil de similarité min ; augmentez (par ex. 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 ex. localisation, catégorie) si les métadonnées sont disponibles |
Choisissez et sélectionnez certaines de ces options d'ajustement. Ajustez-les selon les besoins pour la situation et la requête de l'utilisateur. Pour des exemples de modes de découverte exploitant ces options, voir discovery_modes.md.
Recherche via l'interface utilisateur de l'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 scores de similarité.
bump:1