mcpField
V
vss-search-archive

vss-search-archive

github.com/nvidiaデータ・データベース3.8k1.9k 回インストール今日更新
リポジトリ

vss-search-archive について

vss-search-archiveは、自然言語でアーカイブ動画を検索し、検索用に取り込んだファイルやRTSPストリームを管理するスキルです。デプロイ済みのVSS searchプロファイルで埋め込み検索と属性検索を組み合わせます。READMEではアルファ機能とされ、本番利用は推奨されていません。

主な機能

  1. 01自然言語による動画検索
  2. 02ファイルとRTSPストリームの取り込み
  3. 03埋め込み検索と属性検索
  4. 04関連度順のタイムスタンプ付き結果
  5. 05Agentバックエンド経由のソース削除

活用シーン

  1. 01動画アーカイブから物体や行動を検索
  2. 02登録済みカメラストリームの検索
  3. 03検索前の動画クリップ取り込み
  4. 04ソースと埋め込みの削除

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nvidia/skills --skill vss-search-archive

インストール後、Claude Code で/vss-search-archiveを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
evals.json
search.json
references/
discovery_modes.md
troubleshooting.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を解放します。

動画検索ワークフロー

アルファ機能 — 本番環境での使用は推奨されません。

Cosmos Embed1の埋め込みを使用して、自然言語で動画アーカイブを検索します。検索プロファイルが必要です。vss-deploy-profile スキル(-p search)を使ってデプロイしてください。検索対象の動画ソースには、取り込んだファイルまたはRTSPストリームを指定できます。

使用する場面

  • 「フォークリフトが映っている場面をすべて検索」
  • 「立ち入り禁止区域に人が入ったのはいつですか?」
  • 「荷積み場付近にいる人を表示」
  • 「午前8時から正午までの間に車両を検索」
  • 動画アーカイブを対象とした、自然言語による検索全般
  • 「検索用に <file> を取り込んで」/「検索用にこの動画をアップロードして」
  • 「このRTSPストリームを検索用に追加して」/「検索用に <rtsp_url> を登録して」
  • 「検索対象から <file> を削除して」/「この動画と埋め込みを削除して」

デプロイの前提条件

このスキルを使用するには、ホスト上の $HOST_IP でVSSの search プロファイルが稼働している必要があります。リクエストを実行する前に、次の手順を行ってください。

  1. スタックを確認します。

    curl -sf --max-time 5 "http://${HOST_IP}:8000/docs" >/dev/null \
      && curl -sf --max-time 5 "http://${HOST_IP}:9200/" >/dev/null
    

    (2つ目の確認では、Elasticsearchが稼働していることを確認します。これはsearchプロファイル固有です。)

  2. 確認に失敗した場合は、ユーザーに尋ねます。

    「VSSの search プロファイルが $HOST_IP で稼働していません。/vss-deploy-profile スキルを -p search で使用して、今すぐデプロイしますか?」

    • はいの場合 → /vss-deploy-profile スキルに引き継ぎます。デプロイに成功したら、ここに戻ります。
    • いいえの場合 → 中止します。スタックが存在しない、または誤ったプロファイルである状態で、このスキルを実行しないでください。

    (呼び出し元から自律的なデプロイの明示的な事前承認を受けている場合 (たとえば、リクエストに「前提条件のデプロイは事前承認済み」とある場合や、 その権限を持つ非対話型の評価ハーネスで実行している場合)は、確認を省略して /vss-deploy-profile を直接呼び出してください。)

  3. 確認に成功した場合は、続行します。


取り込みの前提条件(/generate の実行前に必須)

ソースを検索可能にするには、VIOS のみを使用するのではなく、VSS エージェントのバックエンド経由で取り込む必要があります。エージェントの取り込みルートは、VIOS へのアップロード、RTVI-CV への登録、RTVI-embed のパイプラインを1つのトランザクションとして実行します。VIOS への単独の PUT ではデータが保存されるだけで、Elasticsearch への登録は行われません。

まず、ソースが VIOS に存在することを確認してください(必須ワークフローのステップ2)。存在しない場合は、/generate を実行する前に、以下のいずれかの手順で取り込んでください。取り込みが成功すると、指定した名前で sensor/list にソースが表示され、エージェントが検索ツールの分解器に渡す自然言語クエリから参照できるようになります。構造化された video_sources ペイロードを自分で作成する必要はありません。

ファイルのアップロード — 汎用の3ステップフロー

以下のタイムスタンプ付きアップロードフォームを使用してください。VSS エージェント/検索プロファイルでは、アップロードした video_file の基準タイムスタンプとして 2025-01-01T00:00:00.000Z を使用します。 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} ルートも、従来の呼び出し元向けに接続されています(エージェント主導の単一リクエスト方式)が、OpenAPI エントリーには deprecated のフラグが付いています。新しい実装では、上記の3ステップフローを使用してください。

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 は含まれません(エージェントは指定した name でストリームを識別します)。いずれかのステップが失敗すると、それ以前のステップはロールバックされます。start_embedding_generation ステップは、リクエストを受け付けて埋め込みパイプラインがバックグラウンドで実行中であることを確認するものであり、ストリームがすでに検索可能になったことを示すものではありません。Elasticsearch に十分な数のチャンクが反映されてから検索結果が表示され始めます。準備完了の目安が必要な場合は、数秒後に top_k を小さくしてクエリを実行し、状態を確認してください。

ソースの削除 — エージェント経由のクリーンアップ

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 .

検索の仕組み

  1. 取り込み — ファイルはエージェントの汎用3ステップフローから、RTSP ストリームは /api/v1/rtsp-streams/add から取り込みます。どちらのルートもソースを RTVI-CV(属性検出)と RTVI-Embed(Cosmos Embed1)に渡し、動画セグメントのベクトル埋め込みを生成します。
  2. インデックス作成 — 埋め込みは Kafka パイプライン経由で Elasticsearch に保存されます。
  3. クエリ — 自然言語クエリが埋め込まれ、類似度に基づいて保存済みのベクトルと照合されます。
  4. 結果 — 関連度順に並べられたタイムスタンプ付き動画セグメントと、クリップの再生リンクが返されます。

VSS エージェントがオーケストレーションするこの検索では、次の3つの動作が発生します。

  • 属性のみ:LLM がクエリを分解した結果、動作はなく、外見の属性のみが見つかった場合(例:「赤いジャケットを着た人」)
  • 埋め込みのみ:クエリから抽出可能な属性がない場合(例:「フォークリフトを見せて」)
  • 融合:クエリに動作と属性の両方がある場合(例:「赤いジャケットを着て走っている人」)、まず埋め込み検索を実行し、その後、属性検索を使って再ランキングします

必須のワークフロー

このスキルを使用する際は、必ず次の大まかなワークフローに従ってください。

  1. ユーザーの指示から入力を解決します — $HOST_IP が明示されていない場合は、処理を必ず停止してください。 下記の「入力の解決」を参照してください。localhost、127.0.0.1、エージェント自身の実行ホスト、その他の推測値を既定値として使用しないでください。ユーザーからエンドポイントの提示があるまで、POST http://.../generate リクエストを送信しないでください。HOST_IP/VSS エージェントのエンドポイントを尋ねる質問を 1 つだけユーザーに返し、回答を待ってください。

  2. ソースを解決します — /generate を呼び出す前に、必ず処理を停止してください。 ユーザーのクエリで特定の動画/センサー名(例:「空港の動画」、「warehouse_cam_3」、「サンプル倉庫」)が指定されている場合は、POST .../generate を実行する前に、VIOS に実際に登録されていることを確認してください。vss-manage-video-io-storage スキルを使ってソースを一覧表示してください。

    次に、以下のように進めてください。

    • 指定されたソース(または明確に部分一致する名前)が一覧にある場合 → ステップ 3 に進みます。ユーザーの自然言語クエリをそのまま転送してください。エージェント自身の検索ツールの分解器(services/agent/src/vss_agents/tools/search.py)が、利用可能なソースに基づいて文章から video_sources を抽出するため、このスキルで構造化された video sources ペイロードを作成する必要はありません。
    • 指定されたソースが一覧にない場合 → 停止してください。調査目的で /generate を実行しないでください。登録済みのソース名をユーザーに提示し、そのうちのいずれを指していたのか、不足しているソースを取り込みたいのか(取り込みの前提条件を案内し、該当するファイルまたは RTSP の手順を VIOS 単体ではなくエージェントバックエンド経由で実行してください)、それともクエリを中止するのかを尋ねてください。回答を待ってください。
    • クエリで特定のソース名が指定されていない場合(「取り込み済みの動画からフォークリフトを探す」、「すべてのソースを横断して検索する」など)→ 部分一致の確認は省略します。ただし、sensor/list が空でないことは必ず確認してください(空の場合、ソースが取り込まれていないため、処理を必ず停止してください)。
  3. 選択した方法で検索を実行します。

  4. 検索結果をユーザーのクエリに対して提示します。回答は専門的な検査レポートとして構成し、タイトルは Video Search Results としてください。 — 明確なセクション見出しを使用します。

    • 詳細な根拠を添えて、個々の結果を整理し、最後に概要をまとめます。
    • 比較に役立つ場合は表を使用します。チャットメッセージではなく、技術レポートとして記述してください。
    • criteria の結果が null でない場合は、列「Critic result」(「confirmed」 | 「rejected」 | 「skipped」)に加えて、この検索結果に対するすべての criteria を示す列「Criteria」({criteria_n}: ✓ | ✗)を含めてください。
  5. 重要:結果を検証し、その内容を簡潔にユーザーに説明してください。 検索が失敗した場合、または予期しない結果(ユーザーのクエリに一致していないと思われる動画、該当結果なし、動画の返却なし、エラーなど)が返された場合は、停止してください。結果が適切に見つかり、専門的な検査レポートとして提示されるまで、troubleshooting.md を読んで、フィードバックループを繰り返してください。

  6. 最終確認:

    • 必ず、最終確認および追加の確認を実行できることをユーザーに伝えてください。これを Verification Step として提示してください。
    • ユーザーが同意した場合に限り、検索結果(JSON results)から最も有力な候補(一致度スコアが最も高いもの)の screenshot_url を使ってスクリーンショットを /tmp にダウンロードしてください。スクリーンショットを読み込み、ユーザーのクエリに対応しているかを確認してください。

入力の解決

これらの入力は会話またはユーザーのクエリからのみ推測してください(ユーザーから提供された場合を除き、その他のファイルは使用しないでください)。推測できない項目がある場合は、すぐにユーザーに尋ねてください。

  • $HOST_IP:VSS エージェントのバックエンドが実行されている場所

注意事項

  • 予期しないことが起きた場合は、必ずワークフローのトラブルシューティングの手順に直ちに進み、troubleshooting.mdを読んでください
  • クエリは、具体的な視覚的描写(物体、動作、場所)を含めると最も効果的です。必要に応じてユーザーのクエリを補足し、質問の質を高めるために詳細を追加してください
  • このスキルでは、動画ソースはエージェントのバックエンドを通じてすでに取り込まれていることを前提としています(取り込みの前提条件を参照)。ユーザーが明示的に依頼した場合(「検索用に <file> を取り込む」「検索用に <rtsp_url> を追加する」など)は、エージェント経由の取り込みレシピを実行することがあります。ただし、ユーザーが名前を指定していないファイルをローカルファイルシステムから検索することはなく、bare-VIOS PUT パスも使用しません(埋め込みは生成されません)。ワークフローのステップ 2 では、/generate の前提条件として「このソースが VIOS に存在する」ことの確認が引き続き必須です。
  • 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_source_type などの構造化されたリクエストオプションを渡す場合は、messages リクエスト形式を使用してください。input_message のショートカットでは、追加フィールドを受け付けません。

# 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 '{"messages": [{"role": "user", "content": "find all instances of forklifts"}], "search_source_type": "rtsp"}' | jq .
高度な制御オプション

ユーザーのクエリが曖昧な場合、ユーザーがより詳しいガイダンスを求めている場合、または細かな制御が必要な場合は、特定のオプションをプレーンテキストで明示してユーザーの input_message に追加し、エージェントを望ましい方向へ誘導してください。使用できる制御項目は次のとおりです。

項目型デフォルト説明
video sourcesstring[]null特定のカメラまたはセンサー名に絞り込みます
top kint10結果の最大数
minimum similarityfloat0.0類似度の最小しきい値。ノイズを除外するには値を上げます(例:0.3)
critic usagebooltrueVLM が各結果を検証し、誤検出を除外します
descriptionstringnullメタデータがある場合、カメラのメタデータ(例:場所、カテゴリ)で絞り込みます

これらの調整オプションから必要なものを選び、ユーザーの状況やクエリに応じて調整してください。 これらを利用する探索モードの例については、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

コメント