Instructions
Suivez la table de routage, puis les étapes numérotées. Exécutez chaque étape dans l'ordre lors d'une première exécution ; pour une réexécution sur un déploiement déjà indexé, allez directement à l'étape 5. Le matériel de référence se trouve dans references/, le runner dans scripts/.
Purpose
Répond à deux questions sur un déploiement de profil de recherche : la récupération trouve-t-elle les bonnes vidéos, et où passe le temps d'une requête. Il pilote le CLI vss — le même chemin que celui utilisé par le produit, puisque l'adaptateur agent exécute vss search run <mode> --raw pour chaque recherche — les chiffres décrivent donc ce qui est livré plutôt qu'un endpoint REST qui est en cours de retrait.
Quand ne pas utiliser cette compétence
- Pour une question de recherche de vidéo isolée, utilisez
vss-search-archive. - Pour un benchmark de bout en bout de la route OpenClaw chat, ce runner ne mesure pas ce chemin ; ne présentez pas les délais CLI comme des délais chat.
- Pour un benchmark historique de l'endpoint REST search agent retiré, utilisez le legacy externe
run_eval.pynoté dansreferences/troubleshooting.md.
Routing
| Situation | Action |
|---|---|
| L'utilisateur demande de benchmarker la route OpenClaw chat | Ce runner ne la mesure pas ; expliquez l'écart au lieu de présenter les délais CLI comme des délais chat |
| L'utilisateur demande de benchmarker l'endpoint REST search agent retiré | Ce runner ne le mesure pas ; pour une comparaison historique, utilisez le legacy externe run_eval.py noté dans references/troubleshooting.md |
| Aucun profil de recherche déployé dans cette session | Utilisez vss-build-vision-ai pour déployer le profil de recherche stock avec son API REST agent en pile et son LLM conservé. Nommez explicitement les deux conditions dans la demande de build pour qu'il ignore la question du harness (qui retirerait l'agent et éventuellement le LLM) ; ne sélectionnez pas un harness NemoClaw uniquement ou CLI uniquement. Enregistrez l'endpoint agent accessible et l'origine unifiée, puis revenez ici. Vérifiez l'agent /health et le LLM /v1/models, exécutez l'étape 3 pour inspecter les indices, et complétez l'ingestion de l'étape 4 et sa sonde d'index avant notation |
| L'utilisateur n'a pas fourni d'endpoint | Demandez-le. Ne devinez pas, et ne défaut à localhost |
L'endpoint utilise localhost ou 127.0.0.1 |
C'est valide quand le runner est sur l'hôte de déploiement. Vérifiez que l'URL clip VST réelle est joignable depuis RT-VLM avant de faire confiance aux métriques filtrées par le critic |
| L'utilisateur n'a pas donné de dataset | Demandez quel dataset et où se trouve son --data-dir. N'en inventez pas |
Elasticsearch n'a pas d'indices mdx-* |
L'ingestion n'est pas terminée. Exécutez l'étape 4 ; ne signalez pas des scores zéro comme un résultat de qualité |
| L'utilisateur demande de réutiliser ce qui est déjà ingéré | Ajoutez --skip-ingest. Cela ne peut pas être combiné avec --clear ou --only-dataset |
| L'utilisateur demande d'analyser un fichier résultat existant | Allez à l'étape 6 ; lisez le JSON, n'exécutez rien |
| Chaque requête retourne 0 résultat | Arrêtez. Diagnostiquez avec l'étape 3 avant de signaler quoi que ce soit — c'est presque toujours des indices manquants, pas une mauvaise récupération |
Les métriques filtrées par le critic sont toutes NA |
Le critic n'a jamais exécuté. Vérifiez la condition préalable clip-URL ci-dessous avant de conclure quoi que ce soit sur la qualité de vérification |
The default run
À moins que l'utilisateur n'en dise autrement, c'est l'exécution. Demandez quel dataset utiliser et, s'il manque, quel endpoint de déploiement cibler.
uv run --with requests python3 scripts/run_eval_flows.py --endpoint http://HOST:8000 \
--data-dir /path/to/datasets --dataset DATASET \
--skip-download --skip-existing --name RUN_NAME
Cinq défauts, chacun porteur de charge :
-
--skip-existingest non-destructif et évite les uploads en doublon sur un déploiement partagé.--only-datasetet--clearsont des modes de maintenance explicitement destructifs. Les deux nécessitent--confirm-deletedans la même invocation ; il n'y a pas d'invite interactive. Utilisez l'un d'eux seulement quand l'utilisateur a demandé la suppression, et signalez l'inventaire de suppression imprimé. -
La décomposition en direct est activée par défaut. L'origine LLM est dérivée de
--endpoint(même hôte, port 30081), donc il n'y a pas de flag à oublier. Chaque requête est décomposée de la façon dont l'agent déployé la décompose, et ce choix sélectionne le chemin de récupération. Remplacez par--llm-url/--llm-port; désactivez avec--no-decompose(rejoue les routes stockées) ou--fixed-search-path(ignore les routes stockées pour une baseline à chemin unique).Si le NIM est inaccessible, l'exécution rejoue les routes du dataset si présentes ; sinon, elle revient à
embed, qui n'a besoin que du texte de requête. La fallback enregistreflow.query.live_decomposition.fell_back_todans le fichier résultat. Vérifiez ce champ etSearch paths:avant de citer des chiffres.--no-decomposerejoue aussi les routes du dataset si présentes ; il ne force pas un chemin. Utilisez--fixed-search-pathseulement pour une baseline à chemin unique délibéré. Rien d'autre n'est déduit : un sidecardevset_provenance.jsonn'est jamais chargé automatiquement. Pour l'utiliser comme réponse clé, passez son chemin complet avec--decompositions; la notation contre un routage parfait est une expérience différente de celle de scorer le décomposeur en direct. -
La question pré-décomposition est envoyée avec chaque requête comme
--original-query. La récupération l'ignore ; le critic la vérifie au lieu d'une question que la bibliothèque reconstruit à partir de--queryet--attribute. Sans elle, le critic du CLI est posé une question différente de celui du flux REST, donc les taux de rejet des deux flux ne sont pas comparables — et sur le cheminobjectil n'y a pas du tout de question, donc la vérification est sautée d'emblée. Désactivez-la seulement avec--no-original-query, et seulement pour reproduire un fichier résultat capturé avant que cela n'existe.Un
vssplus ancien que le flag est détecté par une sonde--helpunique au démarrage et l'exécution continue sans elle, avec un avertissement. Ne citez pas les métriques filtrées par le critic d'une exécution qui a imprimé cet avertissement. -
L'ingestion est
vst-direct: téléchargez vers VIOS, laissez ses webhooks piloter la perception. C'est ce que fait l'UI — elle a arrêté d'appeler l'API d'ingestion de l'agent — et c'est le seul flux qui déclenche aussi l'étiquetage RT-VLM. L'ancre d'horodatage se trouve dans les métadonnées de téléchargement, pas dans quoi que ce soit que/completefasse, les scores restent donc comparables avec les baselinesagent-3step.Ce que
agent-3stepdonnait gratuitement c'était la preuve :/completeretournechunks_processed, et un zéro échouait le téléchargement.vst-directn'a pas cette étape, donc une sonde d'index post-ingestion la remplace — une requête embed, retentée, avant le début de l'exécution réelle. Enregistré dans VST n'est pas la même chose qu'indexé dans Elasticsearch, et sans cette vérification un déploiement non indexé scores 0.0 partout et se lit comme un effondrement de récupération.Si la sonde abandonne une exécution, vérifiez la config de notification VIOS déployée et que
RTVI_EMBED_MODELcorrespond à la chaîne de modèle du webhook — RT-Embed répond à une discordance avec HTTP 200 etinference: false. Les profils de recherche Docker et Helm activent les webhooks ; les defaults du chart VIOS générique peuvent ne pas le faire. Si les webhooks déployés sont désactivés, utilisez--ingest-flow agent-3step. Ne passez jamais--skip-index-probesur une exécution dont vous avez l'intention de citer les chiffres. -
La concurrence reste à 1 (le défaut du script). Les requêtes concurrentes se disputent les mêmes services VLM et embedding, donc les latences par étape s'enflent et cessent de décrire une seule requête.
Déviatez seulement sur demande : --skip-ingest pour réutiliser ce qui est là, --clear pour effacer tout le déploiement, --subset pour réduire la tranche, --concurrency N pour échanger la fidélité de latence contre temps mur, --no-decompose pour rejouer les routes stockées, ou --fixed-search-path pour une baseline à chemin unique.
N'ajoutez jamais l'un ou l'autre override de décomposition à une exécution que l'utilisateur a appelée eval de routage en direct. Les deux mesurent un flux différent ; le résultat enregistre le mode de routage.
Prerequisites
| Requirement | How to check |
|---|---|
| Agent profil de recherche joignable | curl -sf --connect-timeout 5 --max-time 10 ${ENDPOINT}/health retourne 200 |
| Origine HAProxy unifiée route les services | curl -sf --connect-timeout 5 --max-time 10 ${ORIGIN}/vst/api/v1/sensor/version retourne 200. ORIGIN est généralement l'hôte endpoint sur le port 7777 ; utilisez-le pour vss configure et la sonde Elasticsearch de l'étape 3. Le runner dérive séparément l'ingress direct de VST sur le port 30888 (défaut --vst-port) ; ne passez pas le port HAProxy comme --vst-port |
Le CLI vss s'exécute depuis ce checkout |
vss search run --help sort 0 |
| Le CLI pointe vers la bonne origine | vss configure show rapporte l'ORIGIN ci-dessus |
| Dataset présent localement | test -f ${DATA_DIR}/${DATASET}/dataset.json — layout dans references/dataset-format.md |
Python 3.10+ pour ce runner ; Python 3.13–3.14 pour un CLI vss installé séparément |
python3 --version pour le runner ; utilisez un environnement Python 3.13 ou 3.14 lors de l'installation de libs/vss/core et libs/vss/cli (leur requires-python est >=3.13,<3.15), puis vérifiez vss search run --help là-bas |
| LLM joignable (sinon l'exécution revient et le dit) | curl -sf --connect-timeout 5 --max-time 10 http://HOST:30081/v1/models retourne 200 |
| Modèle LLM sélectionné sans ambiguïté | Si /v1/models liste plusieurs IDs, passez --llm-model correspondant au modèle de l'agent déployé |
| URL clip Critic joignable depuis RT-VLM | Inspectez une videoUrl VST retournée et testez cette URL exacte depuis le conteneur RT-VLM. Le CLI utilise video_url_scope="internal" ; ORIGIN du CLI peut légalement être localhost sur l'hôte |
L'agent /health confirme que le processus est joignable, pas que VIOS et les indices de recherche sont prêts. L'étape 3 et la sonde d'index post-ingestion sont les gates de préparation de récupération.
Step 1 — Configure the CLI
Le CLI lit ~/.vss/config.json, qui est un état séparé de --endpoint et pointe vers un port différent : il découvre les services par préfixe de chemin sur l'origine unifiée, que le port agent ne route pas. Mal faire cela fait que chaque requête sort 4.
vss configure --base-url http://HOST:7777
vss configure show
localhost est valide ici quand le runner s'exécute sur l'hôte de déploiement. Cette URL contrôle où le CLI atteint les services ; elle ne détermine pas l'URL clip envoyée à RT-VLM. Si la vérification échoue, inspectez la videoUrl retournée par VST et testez cette adresse exacte depuis le conteneur RT-VLM.
Step 2 — Dry run
Rapporte ce qui se passerait et ne contacte rien.
uv run --with requests python3 scripts/run_eval_flows.py --endpoint http://HOST:8000 \
--data-dir /path/to/datasets --dataset DATASET --dry-run
Step 3 — Verify the deployment is actually indexed
L'enregistrement avec VST n'est pas l'ingestion. Un déploiement peut lister chaque capteur et avoir quand même un Elasticsearch vide, auquel cas chaque requête retourne zéro résultats et chaque métrique lit 0.0000 — ce qui ressemble à une qualité de récupération catastrophique et ne l'est pas.
curl -s --connect-timeout 5 --max-time 10 "http://HOST:7777/elasticsearch/_cat/indices?h=index,docs.count"
Attendez mdx-embed-filtered-*, mdx-behavior-* et mdx-raw-* avec des compteurs non-zéro. mdx-behavior-* est ce que les chemins attribute et fusion lisent ; s'il manque, seul embed peut scorer. Si les indices sont absents, allez à l'étape 4.
Step 4 — Ingest
Le flux vst-direct défaut télécharge vers VIOS et laisse ses webhooks déclencher la perception. Il n'appelle pas l'endpoint /complete de l'agent ni ne reçoit un compte chunks_processed. Le runner attend l'enregistrement VST, puis sonde l'index de recherche avant notation. Utilisez --ingest-flow agent-3step seulement quand le déploiement ne peut pas exécuter le flux webhook ; voir references/troubleshooting.md.
uv run --with requests python3 scripts/run_eval_flows.py --endpoint http://HOST:8000 \
--data-dir /path/to/datasets --dataset DATASET --skip-download --skip-existing
Attendez-vous à ce que ce soit lent pendant que le pipeline webhook indexe les vidéos :
- Une source enregistrée n'est pas nécessairement indexée. La sonde d'index post-ingestion doit passer avant de traiter les zéro résultats comme un résultat de récupération.
- Si les webhooks sont désactivés, sélectionnez
--ingest-flow agent-3stepexplicitement. Ce flux appelle/complete, qui peut retourner un transient 502 et est retente. --skip-existingest le défaut : ingérez ce qui manque et ne supprimez rien.--only-datasetsupprime les sources étrangères seulement quand explicitement demandé avec--confirm-delete; signalez son inventaire candidat avant qu'il s'exécute.--clear --confirm-deletesupprime chaque source y compris celles d'autres gens. Utilisez-le seulement sur demande explicite.--clearet--only-datasetlistent les sources via--vst-urlmais suppriment via l'endpoint agent. Si ces URLs ont des hôtes différents, vérifiez qu'elles appartiennent au même déploiement avant suppression ; sinon les IDs source d'une pile pourraient être envoyés à une autre.
Puis réexécutez l'étape 3. Les indices sont lazy ; ils apparaissent après le traitement webhook, pas immédiatement après le téléchargement. Voir references/flags.md pour les options d'ingestion.
Step 5 — Run the benchmark
uv run --with requests python3 scripts/run_eval_flows.py --endpoint http://HOST:8000 \
--data-dir /path/to/datasets --dataset DATASET --subset SUBSET \
--skip-download --skip-ingest --name RUN_NAME
--skip-ingest réutilise un dataset déjà indexé ; il ne peut pas être combiné avec --clear ou --only-dataset. Voir references/flags.md avant de changer les flags qui affectent le sens de l'exécution.
La décomposition n'a besoin d'aucun flag. Un LLM transforme la phrase en {query, attributes, has_action, ...} et cela décide quel chemin s'exécute — le même appel que celui fait par l'agent déployé. Le script dérive l'origine NIM de --endpoint ; s'il ne peut pas l'atteindre l'exécution revient plutôt que de s'arrêter, et dit quel fallback elle a pris.
fusion ne peut pas être un fallback. Il a besoin d'un attribut par requête et il n'y a rien pour en fournir un sans décomposition — et le nourrir avec la requête entière comme son attribut est l'échec que cette eval a déjà mesuré : mAP −25%, HIT@1 divisé par deux, latence +59%.
Laissez --concurrency tranquille à moins qu'on vous le demande. Il défaut à 1 parce que les requêtes concurrentes se disputent les mêmes services VLM et embedding, ce qui gonfle chaque latence par étape du rapport.
--name rend le fichier résultat trouvable ; sans lui le nom est <dataset>_<subset>_<timestamp>.
Step 6 — Report
Les résultats se retrouvent dans scripts/cli_eval_result/<name>.json.
Signalez Recall et HIT@k comme le signal de qualité. Precision et mAP sont dominés par --top-k — cinq résultats contre environ un segment pertinent les maintiennent bas quelle que soit la qualité de récupération — donc ils comparent les exécutions ; ils ne notent pas un déploiement.
Énoncez ceux-ci à côté de tout chiffre, parce que chacun change ce qu'il signifie :
- Quels chemins se sont exécutés.
Search paths:dans le résumé. Une exécution qui était touteembedne dit rien surattribute. - Si la décomposition était en direct. Si oui, donnez sa part du temps de requête et ce vers quoi elle
Routed to:— un changement de routage change ce qui a été mesuré. - Si le critic s'est exécuté. Les métriques filtrées par le critic impriment
NAquand la réponse ne contenait pas de bloc de vérification.NAn'est pas0.
Lisez references/reading-results.md lors de l'interprétation des latences par étape ou des métriques. Lisez references/flags.md quand un flag pourrait changer la comparabilité. Lisez references/troubleshooting.md quand l'ingestion échoue ou que le CLI sort non-zéro. Lisez references/dataset-format.md quand validez le layout d'un dataset.
Error handling
Une sortie CLI non-zéro abandonne l'exécution. Une enveloppe résultat manquante marque cette requête comme sans réponse et abandonne par défaut ; --tolerate-unanswered permet une exécution partielle explicite qui exclut ces requêtes de la notation. Ne les comptez jamais comme des misses. Diagnostiquez une exécution tout-zéro avec l'étape 3 avant de signaler la qualité. NA filtré par le critic signifie que la vérification n'était pas disponible, pas une qualité zéro. Utilisez references/troubleshooting.md pour l'échec spécifique et les étapes de récupération.
Conventions
- Ne signalez jamais 0.0000 comme un résultat de qualité sans vérifier d'abord l'étape 3. Un déploiement non indexé et un récupérateur cassé sont identiques dans les métriques et ne sont pas la même conclusion.
- Une sortie CLI non-zéro abandonne l'exécution plutôt que de noter 0.0. Un virtualenv stale sort 1 à chaque invocation, et noter cela comme "pas de résultats" signalez un environnement cassé comme une régression d'accuracy.
- Les requêtes ne fusionnent pas les fenêtres adjacentes par défaut. La fusion en amont moyenne les scores des fenêtres fusionnées et change le dénominateur de précision, donc une exécution fusionnée n'est pas comparable à une baseline non-fusionnée.
- Le critic est un LLM et n'est pas déterministe. Les métriques brutes se répètent exactement ; les métriques filtrées par le critic bougent quelques points entre les exécutions. Gate sur le brut.
- La décomposition en direct n'est pas déterministe non plus. La même requête peut router différemment entre les exécutions, donc comparez
Routed to:avant de comparer les scores.