opción
HogarHogar Skill DevOps y CI/CD tao-run-inference-service

tao-run-inference-service

NVIDIA/skills NVIDIA/skills

Iniciar, consultar y detener un microservicio de inferencia TAO para una arquitectura de red específica, delegando la ejecución del contenedor a la función de la plataforma adecuada.

...Expandir todo
1
Tiempo actualizado 27 de septiembre de 2026

Microservicio de inferencia TAO

Instrucciones

Para iniciar un servicio de inferencia:

  1. Recopila los datos de entrada necesarios (sección 1) y resuelve la imagen del contenedor (sección 2).
  2. Compila la carga útil del trabajo y el comando interno (Secciones 3–4.1); utiliza references/code-templates.yaml → job_payload_builder.
  3. «Read» skills/platform//SKILL.md e inicie el contenedor (Sección 4.2).
  4. Escriba en el registro de servicios y compruebe el estado de disponibilidad (Sección 4.3); utilice references/code-templates.yaml → registry_write. y readiness_check.

Para enviar una solicitud de inferencia:

  1. Determina qué servicio recibe la solicitud según la sección 6.0 (mediante job_id, mediante network_arch, o mediante la elección explícita del usuario cuando se ejecutan varios servicios —nunca se utilice de forma silenciosa el valor por defecto "latest" cuando exista más de un servicio—; a continuación, lea el punto final de references/code-templates.yaml → request.registry_read con el job_id.
  2. Antes de crear el cuerpo de la solicitud, solicita al usuario los parámetros de muestreo al estilo vLLM (sección 6.1). Presenta max_tokens, top_p, temperature (y cualquier elemento adicional específico de la arquitectura) con sus valores por defecto; permita que el usuario modifique cada uno de ellos o se salte ese paso para aceptar el valor por defecto. Nunca utilice los valores por defecto de forma silenciosa.
  3. Crea y envía el cuerpo según la sección 6.2; gestiona la respuesta según la sección 6.3.

Para detener un servicio: lee references/code-templates.yaml → stop.registry_read para resolver el job_id, lea skills/platform//SKILL.mdy, a continuación, siga la sección 5.

Datos de referencia (esquemas, asignaciones, valores válidos —sin instrucciones—):

  • references/service.yaml — asignaciones de imágenes, network_arch , esquema de la carga útil del trabajo, nombres de variables de entorno, clasificación de secretos.
  • references/request.yaml — Definición de puntos finales, esquema de campos de solicitud, formatos de respuesta, ejemplos de código.
  • references/code-templates.yaml — Plantillas de Python para la creación de la carga útil, escrituras en el registro, comprobaciones de disponibilidad y flujos de parada/solicitud.

Regla sobre secretos (se aplica a todos los bloques de código generados en esta habilidad)

Nunca pidas al usuario que introduzca un valor secreto en un mensaje de solicitud. Para cada valor secreto:

  1. Indica al usuario qué variable de entorno debe configurar (p. ej., export HF_TOKEN=...).
  2. Genera código que lo lea con os.environ["VAR_NAME"] — nunca codifiques de forma fija, interpoles ni solicites el valor mediante un mensaje.

Variables de entorno secretas (lista completa en references/service.yaml → secrets_handling): HF_TOKEN, WANDB_API_KEY, CLEARML_API_ACCESS_KEY, CLEARML_API_SECRET_KEY, TAO_API_KEY, TAO_USER_KEY.

Se pueden recopilar de forma segura en la ventana de solicitud: network_arch, model_path, num_gpus, texto de la solicitud, WANDB_* URL de configuración, CLEARML_*_HOST URL.

1. Qué datos recopilar del usuario

Entrada Rol
network_arch Selecciona la imagen del contenedor, la forma del comando interno por arquitectura (references/service.yaml → container_commands.) y neural_network_name en el JSON del trabajo cuando sea aplicable. Debe coincidir con un nombre base en valid_network_arch_config_basenames en references/service.yaml (p. ej., cosmos-rl, cosmos-predict2.5).
model_path El punto de control del modelo entrenado. Formatos válidos: hf_model:/// (HuggingFace Hub — establecer HF_TOKEN para modelos con acceso restringido) o una ruta del sistema de archivos de un contenedor local. NO se admiten las URI en la nube (s3://, gs://, az://) NO son compatibles: el servicio de inferencia no depende de ningún almacenamiento en la nube. Pregunta siempre al usuario; nunca sustituyas por un marcador de posición. Véase references/service.yaml → model_path_protocols.
platform Plataforma de computación: local-docker, brev, slurm, o kubernetes.
num_gpus El valor por defecto es 1; mínimo 1 para la inferencia.

2. Resolución de la imagen

Cada network_arch tiene un archivo de configuración sidecar llamado {network_arch}.config.json. Configura la imagen del contenedor de la siguiente manera:

  1. Lee {network_arch}.config.json y toma api_params.image (p. ej., COSMOS_RL). Se trata de una clave en docker_image_defaults.mapping en references/service.yaml.
  2. Busca esa clave en la tabla de correspondencias. Si la variable de entorno del host IMAGE_ está definida (p. ej. IMAGE_COSMOS_RL), anula el valor predeterminado asignado.
  3. El valor asignado suele ser una clave con puntos en el versions.yaml (p. ej., tao_toolkit.cosmos_rl). Resuélvela en un nvcr.io/... buscando versions.yaml → images... Las URI absolutas se transmiten sin cambios, por lo que una IMAGE_ sobrescritura de variable de entorno que contenga una URI completa seguirá funcionando. La función auxiliar de Python para esto se encuentra en references/code-templates.yaml.
  4. Si falta el archivo de configuración o api_params.image está vacío, se recurre a la COSMOS_RL clave.

El archivo de configuración también contiene spec_params.inference.model_path que determina la semántica entre rutas de carpeta y de archivo: si el valor contiene la subcadena folder, el contenedor trata la ruta como un directorio.

3. Variables de entorno (sin funciones de devolución de llamada)

Configúralas en env_payload antes de la codificación env_json. No las establezcas TAO_LOGGING_SERVER_URL ni TAO_ADMIN_KEY.

TAO_EXECUTION_BACKEND — deben coincidir con la plataforma:

Plataforma TAO_EXECUTION_BACKEND valor
local-docker local-docker
brev local-docker
slurm slurm
Kubernetes local-k8s

CLOUD_BASED — siempre "False" para esta habilidad (desactiva el envío de callbacks a TAO_LOGGING_SERVER_URL).

variables de entorno de la GPU — solo es necesario cuando la habilidad de la plataforma no gestiona automáticamente la inyección de la GPU:

  • Tegra / Jetson: --runtime=nvidia con NVIDIA_DRIVER_CAPABILITIES=all y NVIDIA_VISIBLE_DEVICES=.
  • x86 estándar + nvidia-container-toolkit: utiliza Docker device_requests. La habilidad de plataforma se encarga de ello.

4. Ejecución en distintas plataformas

La carga útil del trabajo y el comando interno (secciones 1-3) son independientes de la plataforma. Para cada plataforma, consulta skills/platform//SKILL.md para conocer las comprobaciones previas y las credenciales antes de generar cualquier código de ejecución.

4.1 Crear el comando interno (por arquitectura)

La estructura del comando interno se rige por network_arch; no existe una plantilla uniforme. Busca la entrada correspondiente a cada arquitectura en references/service.yaml → container_commands.; si no aparece, significa que esa arquitectura no es compatible: detente y consulta. Elige el subbloque correspondiente en references/code-templates.yaml → job_payload_builder.. Añade el prefijo umask 0 && y manténlo idéntico en todas las plataformas (local-docker, brev, slurm, kubernetes).

Común a todas las arquitecturas:

  • job_id: fresh uuid.uuid4() — se convierte en el nombre del contenedor y la clave del registro.
  • image: resuélvelo según la sección 2.
  • Los secretos (access_key, secret_key, HF_TOKEN, etc.) se leen de las variables de entorno en tiempo de ejecución; nunca los codifiques de forma estática, ni los registres ni los imprimas.

Notas específicas de la arquitectura (detalles completos en references/service.yaml → container_commands):

  • cosmos-rl — un único --job '' --docker_env_vars '' blob; json.dumps(...) + shlex.quote(...). env_payload contiene TAO_EXECUTION_BACKEND (según la tabla de la sección 3), TAO_API_JOB_ID, CLOUD_BASED=False. El servicio de inferencia no depende de ningún almacenamiento en la nube; HF_TOKEN es la única variable de entorno de credenciales que se aplica (para los modelos de HuggingFace con acceso restringido).
  • cosmos-predict2.5 — estilo bandera cosmos_predict inference_microservice start ... --port 8080 (sin setup. prefijo; no se aceptan tyro.conf.OmitArgPrefixes). --job/--docker_env_vars no se aceptan. Traduce model_path a --checkpoint-path (ruta local) o --model (hf_model://); se rechazan las URI en la nube. La única variable de entorno de credenciales que se aplica en algún caso es HF_TOKEN para los modelos de HuggingFace con acceso restringido. Los parámetros por solicitud (prompt, inference_type, num_output_frames, guidance, seed, num_steps, negative_prompt) van en el cuerpo de la solicitud, no al iniciar el programa. TAO_EXECUTION_BACKEND/TAO_API_JOB_ID/CLOUD_BASED no se utilizan y pueden omitirse.

4.2 Delegar la ejecución a la habilidad de la plataforma

Lee skills/platform//SKILL.md y sigue las instrucciones para iniciar el contenedor.

Parámetros básicos (todas las plataformas):

Parámetro Valor
image imagen del contenedor resuelta (Sección 2)
command inner — la cadena de shell creada en la sección 4.1
gpu_count num_gpus
env_vars env_payload
nombre del trabajo o del contenedor job_id — debe coincidir con el UUID de la sección 4.1 para que el registro pueda hacer referencia a él
host_port (local-docker, brev) puerto del lado del host que se vinculará al puerto 8080 del contenedor. Por defecto 8080, pero debe ser único para cada servicio simultáneo — véase la regla de asignación de puertos más abajo.

Entradas adicionales específicas de la plataforma:

Plataforma Entradas adicionales
local-docker Ninguna más allá de la básica
brev instance_id (opcional — reutilizar una instancia existente); en cuentas con múltiples credenciales o múltiples espacios de trabajo, también cloud_cred_id y workspace_group_id para la primera creación — véase skills/platform/tao-run-on-brev/SKILL.md
slurm partition y account — comprueba SLURM_PARTITION/SLURM_ACCOUNT las variables de entorno; preguntar al usuario si no están definidas
kubernetes namespace (por defecto: default); image_pull_secret (obligatorio para nvcr.io imágenes)

Enlace de puertos (local-docker y brev): utiliza «docker run» directamente (no DockerSDK) para que -p :8080 se pueda pasar y el nombre del contenedor coincida job_id exactamente.

Regla de asignación de puertos (local-docker y brev, OBLIGATORIA para servicios simultáneos): antes de iniciar un servicio, lee el registro (/tmp/tao-inf-ms-state.json) y recopila el conjunto de host_port valores de cada entrada existente en la misma plataforma (y, para brev, la misma instance_id). Elige el puerto libre más bajo a partir del 8080 que no esté en ese conjunto —p. ej., host_port = next(p for p in range(8080, 8200) if p not in used_ports). El valor por defecto 8080 solo se aplica cuando no hay ningún otro servicio en ejecución. Esto es lo que hace que «iniciar 3 servicios, cada uno accesible en un host_url»; sin ello, los servicios 2 y 3 fallan con bind: address already in use. SLURM y Kubernetes obtienen puntos finales distintos a través de sus propios mecanismos de plataforma y no necesitan este paso.

4.3 Tras el inicio: registro de servicios y punto final

Escribe el registro de servicios inmediatamente después de que la plataforma confirme que el contenedor está en ejecución. El registro (/tmp/tao-inf-ms-state.json) se indexa mediante job_id; "latest" apunta siempre al servicio iniciado más recientemente.

Véase references/code-templates.yaml → registry_write. para ver la plantilla en Python.

Plataforma host_url platform_job_id Paso adicional antes de escribir
local-docker http://localhost:{host_port} — Ninguno
brev http://{brev_ip}:{host_port} — brev ls → obtener la IP de la instancia (localhost no es válido en una máquina virtual remota)
slurm http://localhost:{host_port} ID de trabajo del programador SLURM Esperar hasta que esté en ejecución; reenvío de puertos por SSH localhost:{host_port}→{node}:8080
kubernetes http://{external_ip}:8080 Nombre del trabajo de k8s kubectl expose job … --type=LoadBalancer; espera a la IP externa

Tras escribir en el registro, muestra el job_id y la URL:

print(f"Inference service started.")
print(f"  Job ID : {job_id}")
print(f"  Arch   : {network_arch}")
print(f"  URL    : {state[job_id]['host_url']}/v1/chat/completions")
print(f"Use this Job ID to send requests or stop the service.")

A continuación, comprueba si está listo —véase references/code-templates.yaml → readiness_check. El contenedor carga el modelo en segundo plano; no envíes solicitudes antes de que devuelva un 200.

5. Detener el servicio de inferencia

Pide al usuario el job_id que se va a detener. Si no proporciona ninguno, utiliza por defecto state["latest"] y confirma qué job_id se va a detener. Lee el registro utilizando references/code-templates.yaml → stop.registry_read, a continuación, consulta skills/platform//SKILL.md y utiliza su mecanismo de cancelación o detención.

Identificador de Identificador a pasar Limpieza adicional
local-docker job_id_to_stop — nombre del contenedor Ninguno
brev job_id_to_stop — nombre del contenedor Ninguno
slurm entry["platform_job_id"] — ID de trabajo de SLURM pkill -f "ssh.*-L.*{entry['host_port']}"
kubernetes entry["platform_job_id"] — Nombre del trabajo de k8s kubectl delete svc {entry["platform_job_id"]} -n

donde entry = state[job_id_to_stop]. Tras detenerlo, limpia el registro: references/code-templates.yaml → stop.registry_cleanup.

6. Envío de solicitudes de inferencia

6.0 Determinar qué servicio recibe esta solicitud (OBLIGATORIO)

Cada solicitud debe enrutarse al servicio específico que ejecuta el modelo correspondiente. El enrutamiento se realiza mediante job_id — el registro almacena network_arch por entrada, por lo que puedes determinar un destino por arquitectura cuando el usuario especifica un modelo en lugar de un job_id. Aplica estas reglas en este orden:

  1. El usuario ha proporcionado un job_id explícito → utilízalo. Comprueba que exista en state.
  2. El usuario ha especificado un network_arch (p. ej., «enviar esto al servicio cosmos-rl») → busca las entradas que coincidan: candidates = [j for j, e in state.items() if j != "latest" and isinstance(e, dict) and e["network_arch"] == arch].
    • Exactamente una coincidencia → utilízala.
    • Varias coincidencias → mostrar al usuario las opciones job_idy sus started_at; no la elijas automáticamente.
    • Sin coincidencias → detenerse e informar al usuario de que no hay ningún servicio en ejecución para esa arquitectura.
  3. Si no hay «job_id» ni «network_arch» → cuenta las entradas que no"latest" entradas en state:
    • Exactamente un servicio en ejecución → utilízalo.
    • Dos o más → no establecer «state["latest"]» como valor predeterminado de forma silenciosa. Mostrar al usuario la lista completa (job_id, network_arch, host_url) y exigir una elección explícita. El "latest" puntero es una comodidad para flujos de trabajo con un solo servicio, no una alternativa de enrutamiento cuando coexisten varios servicios.
    • Ninguno → detén el proceso e indica al usuario que inicie primero un servicio.

Tras la resolución, lee el punto final del registro (references/code-templates.yaml → request.registry_read), pasando el job_id como user_provided_job_id. Confirma al usuario: «Enviando a job_id=… arch=… url=…». Si el servicio aún pudiera estar cargándose, comprueba primero si está listo (references/code-templates.yaml → readiness_check).

Comprueba antes de enviar: si el cuerpo de la solicitud proporcionado por el usuario contiene campos específicos de la arquitectura (p. ej., guidance / num_steps / seed / negative_prompt → cosmos-predict2.5; elementos de contenido obligatorios image_url/video_url elementos de contenido → cosmos-rl), comprueba que sean coherentes con state[job_id]["network_arch"]. En caso de discrepancia, detén el proceso y solicita aclaración: enviar un cuerpo de cosmos-predict2.5 a un servicio de cosmos-rl provocará un error en el contenedor con un código 4xx/5xx que es más difícil de diagnosticar que detectarlo aquí.

6.1 Parámetros de muestreo: solicitud OBLIGATORIA al usuario antes de cada solicitud

Antes de construir el cuerpo de la solicitud, DEBES solicitar explícitamente al usuario los parámetros de muestreo al estilo vLLM. No apliques los valores por defecto de forma silenciosa. Utiliza una solicitud estructurada, una pregunta por campo, que:

  1. Enumere todos los campos aplicables con su tipo y valor por defecto.
  2. Permita al usuario omitir o aceptar cualquier campo para adoptar su valor por defecto; nunca es obligatorio introducir un valor.
  3. Recopile todos los campos de una sola vez.

Tras la solicitud, aplique cada valor introducido por el usuario tal cual y sustituya cualquier campo omitido por su valor por defecto. No invente valores ni limite los valores de forma silenciosa.

Lista de campos, valores por defecto y aplicabilidad por arquitectura: references/request.yaml → chat_completions_request_body (campos de muestreo base: max_tokens, top_p, temperature) y network_arch_constraints. (sobrescrituras específicas por arquitectura y elementos adicionales como guidance/num_steps/seed/negative_prompt para cosmos-predict2.5). Si un campo está marcado como no compatible con la arquitectura activa, no se solicite su introducción y no se incluya en el cuerpo.

6.2 Formato de la solicitud

Envía un POST a {BASE_URL}/v1/chat/completions con Content-Type: application/json y un tiempo de espera de al menos 300 s. El cuerpo es compatible con OpenAI (completados de chat vLLM); consulta references/request.yaml → chat_completions_request_body para consultar el esquema completo de campos y los formatos de los elementos de contenido (text / image_url / video_url), y code_examples aquí para ver ejemplos listos para ejecutar en Python y curl.

Restricciones: solo se procesa el primer mensaje del usuario. No se admiten valores secretos en el cuerpo de las solicitudes. Restricciones específicas de cada red (por ejemplo, cosmos-rl requiere que cada solicitud incluya una imagen o un vídeo; cosmos-rl rechaza data: URI) se recogen en references/request.yaml → network_arch_constraints.

6.3 Gestión de respuestas

Estado HTTP Significado Acción
200 Éxito — choices[0].message.content contiene el texto generado Resultado de la lectura
202 El servidor sigue inicializándose o el modelo sigue cargándose Vuelve a intentarlo tras un tiempo de espera
503 Error en la inicialización, error al cargar el modelo o el modelo aún no está listo Comprobar error.type: model_not_ready → vuelve a intentarlo; initialization_error / model_load_error → abandonar y consultar los registros
400 Cuerpo JSON ausente o vacío Corregir la solicitud
500 Excepción no gestionada durante la inferencia Comprueba los registros del contenedor

En los códigos 202 y 503, el cuerpo contiene {"error": {"type": "", "message": ""}}. Véase container_response_shapes en references/request.yaml para ver las cadenas de tipo de error.

Ver en GitHub
---
name: tao-run-inference-service
description: Start, query, and stop a TAO inference microservice for a specific network architecture by delegating container execution to the appropriate platform skill.
license: Apache-2.0
---

# TAO Inference Microservice

## Instructions

**To start an inference service:**
1. Collect required inputs (Section 1) and resolve the container image (Section 2).
2. Build the job payload and inner command (Sections 3–4.1); use `references/code-templates.yaml` → `job_payload_builder`.
3. Read `skills/platform/<platform>/SKILL.md` and start the container (Section 4.2).
4. Write the service registry and poll readiness (Section 4.3); use `references/code-templates.yaml` → `registry_write.<platform>` and `readiness_check`.

**To send an inference request:**
1. Resolve which service receives the request per Section 6.0 (by `job_id`, by `network_arch`, or by explicit user choice when multiple services run — **never silently default to `"latest"` when more than one service exists**), then read the endpoint from `references/code-templates.yaml` → `request.registry_read` with the resolved `job_id`.
2. **Before building the request body, prompt the user for the vLLM-style sampling parameters (Section 6.1).** Present `max_tokens`, `top_p`, `temperature` (and any per-arch extras) with their defaults; let the user override or skip each one to accept the default. Never silently use defaults.
3. Build and send the body per Section 6.2; handle the response per Section 6.3.

**To stop a service:** Read `references/code-templates.yaml` → `stop.registry_read` to resolve the job_id, read `skills/platform/<platform>/SKILL.md`, then follow Section 5.

**Reference data** (schemas, mappings, valid values — no instructions):
- **`references/service.yaml`** — image mappings, valid `network_arch` names, job payload schema, env var names, secrets classification.
- **`references/request.yaml`** — endpoint definition, request field schema, response shapes, code examples.
- **`references/code-templates.yaml`** — Python templates for payload building, registry writes, readiness checks, and stop/request flows.

---

## Secrets rule (applies to every generated code block in this skill)

**Never ask the user to type a secret value into a prompt.** For every secret value:
1. Tell the user which environment variable to set (e.g. `export HF_TOKEN=...`).
2. Generate code that reads it with `os.environ["VAR_NAME"]` — never hard-code, interpolate, or prompt for the value.

**Secret env vars** (full list in `references/service.yaml` → `secrets_handling`):
`HF_TOKEN`, `WANDB_API_KEY`, `CLEARML_API_ACCESS_KEY`, `CLEARML_API_SECRET_KEY`, `TAO_API_KEY`, `TAO_USER_KEY`.

**Safe to collect in the prompt:** `network_arch`, `model_path`, `num_gpus`, prompt text, `WANDB_*` config URLs, `CLEARML_*_HOST` URLs.

---

## 1. What to collect from the user

| Input | Role |
|--------|------|
| **`network_arch`** | Chooses container image, the per-arch inner command shape (`references/service.yaml` → `container_commands.<network_arch>`), and `neural_network_name` in the job JSON when applicable. Must match a basename in `valid_network_arch_config_basenames` in `references/service.yaml` (e.g. `cosmos-rl`, `cosmos-predict2.5`). |
| **`model_path`** | The trained model checkpoint. Valid forms: `hf_model://<org>/<model>` (HuggingFace Hub — set `HF_TOKEN` for gated models) or a local container filesystem path. Cloud URIs (`s3://`, `gs://`, `az://`) are NOT supported — the inference service has no cloud-storage dependency. Always ask the user; never substitute a placeholder. See `references/service.yaml` → `model_path_protocols`. |
| **`platform`** | Compute platform: `local-docker`, `brev`, `slurm`, or `kubernetes`. |
| **`num_gpus`** | Defaults to **1**; minimum **1** for inference. |

---

## 2. Image resolution

Each `network_arch` has a sidecar config file named `{network_arch}.config.json`. Resolve the container image as follows:

1. Read `{network_arch}.config.json` and take `api_params.image` (e.g. `COSMOS_RL`). This is a key into `docker_image_defaults.mapping` in `references/service.yaml`.
2. Look up that key in the mapping. If the host env var `IMAGE_<KEY>` is set (e.g. `IMAGE_COSMOS_RL`), it overrides the mapped default.
3. The mapped value is normally a dotted key into the repo-root `versions.yaml` manifest (e.g. `tao_toolkit.cosmos_rl`). Resolve it to a concrete `nvcr.io/...` image URI by looking up `versions.yaml` → `images.<group>.<name>`. Absolute URIs pass through unchanged, so an `IMAGE_<KEY>` env-var override that contains a full URI still works. The Python helper for this lives in `references/code-templates.yaml`.
4. If the config file is missing or `api_params.image` is empty, fall back to the `COSMOS_RL` key.

The config file also has `spec_params.inference.model_path` which drives **folder vs file** path semantics: if the value contains the substring `folder`, the container treats the path as a directory.

---

## 3. Environment variables (no callbacks)

Set these in `env_payload` before encoding `env_json`. Do **not** set `TAO_LOGGING_SERVER_URL` or `TAO_ADMIN_KEY`.

**`TAO_EXECUTION_BACKEND`** — must match the platform:

| Platform | `TAO_EXECUTION_BACKEND` value |
|----------|-------------------------------|
| local-docker | `local-docker` |
| brev | `local-docker` |
| slurm | `slurm` |
| kubernetes | `local-k8s` |

**`CLOUD_BASED`** — always `"False"` for this skill (disables callback posting to `TAO_LOGGING_SERVER_URL`).

**GPU env vars** — only needed when the platform skill does not handle GPU injection automatically:
- Tegra / Jetson: `--runtime=nvidia` with `NVIDIA_DRIVER_CAPABILITIES=all` and `NVIDIA_VISIBLE_DEVICES=<ids>`.
- Standard x86 + nvidia-container-toolkit: use Docker `device_requests`. The platform skill handles this.

---

## 4. Executing across platforms

The job payload and inner command (Sections 1–3) are **platform-agnostic**. For each platform, read **`skills/platform/<name>/SKILL.md`** for preflight checks and credentials **before** generating any execution code.

### 4.1 Build the inner command (per arch)

The inner-command shape is **per `network_arch`** — there is no uniform template. Look up the per-arch entry in `references/service.yaml` → `container_commands.<network_arch>`; if not present, the arch is unsupported — stop and ask. Pick the matching sub-block in `references/code-templates.yaml` → `job_payload_builder.<network_arch>`. Prefix the command with `umask 0 &&` and keep it **identical across platforms** (local-docker, brev, slurm, kubernetes).

Common across arches:

- `job_id`: fresh `uuid.uuid4()` — becomes the container name and registry key.
- `image`: resolve per Section 2.
- Secrets (`access_key`, `secret_key`, `HF_TOKEN`, etc.) are read from env vars at runtime — never hard-code, never log or print.

Arch-specific notes (full details in `references/service.yaml` → `container_commands`):

- **`cosmos-rl`** — single `--job '<JOB_JSON>' --docker_env_vars '<ENV_JSON>'` blob; `json.dumps(...)` + `shlex.quote(...)`. `env_payload` carries `TAO_EXECUTION_BACKEND` (per Section 3 table), `TAO_API_JOB_ID`, `CLOUD_BASED=False`. The inference service has no cloud-storage dependency; `HF_TOKEN` is the only cred env var that ever applies (for gated HuggingFace models).
- **`cosmos-predict2.5`** — flag-style `cosmos_predict inference_microservice start ... --port 8080` (no `setup.` prefix; uses `tyro.conf.OmitArgPrefixes`). `--job`/`--docker_env_vars` are **not** accepted. Translate `model_path` to `--checkpoint-path` (local path) or `--model <registered_key>` (`hf_model://`); cloud URIs are rejected. The only cred env var that ever applies is `HF_TOKEN` for gated HuggingFace models. Per-request params (prompt, inference_type, num_output_frames, guidance, seed, num_steps, negative_prompt) go in the request body, not at startup. `TAO_EXECUTION_BACKEND`/`TAO_API_JOB_ID`/`CLOUD_BASED` are unused and may be omitted.

### 4.2 Delegate execution to the platform skill

Read **`skills/platform/<platform>/SKILL.md`** and follow it to start the container.

**Base parameters (all platforms):**

| Parameter | Value |
|-----------|-------|
| `image` | resolved container image (Section 2) |
| `command` | `inner` — the shell string built in Section 4.1 |
| `gpu_count` | `num_gpus` |
| `env_vars` | `env_payload` |
| job / container name | `job_id` — must equal the UUID from 4.1 so the registry can reference it |
| `host_port` *(local-docker, brev)* | host-side port to bind to container port 8080. Default `8080`, but **must be unique per concurrent service** — see the port-allocation rule below. |

**Platform-specific additional inputs:**

| Platform | Additional inputs |
|----------|------------------|
| **local-docker** | None beyond base |
| **brev** | `instance_id` (optional — reuse an existing instance); on multi-credential / multi-workspace accounts also `cloud_cred_id` and `workspace_group_id` for first-create — see `skills/platform/tao-run-on-brev/SKILL.md` |
| **slurm** | `partition` and `account` — check `SLURM_PARTITION`/`SLURM_ACCOUNT` env vars; ask user if unset |
| **kubernetes** | `namespace` (default: `default`); `image_pull_secret` (required for `nvcr.io` images) |

**Port binding (local-docker and brev):** use **direct docker run** (not DockerSDK) so that `-p <host_port>:8080` can be passed and the container name equals `job_id` exactly.

**Port allocation rule (local-docker and brev, REQUIRED for concurrent services):** Before starting a service, read the registry (`/tmp/tao-inf-ms-state.json`) and collect the set of `host_port` values from every existing entry on the same platform (and, for brev, the same `instance_id`). Pick the **lowest free port starting from 8080** that is not in that set — e.g. `host_port = next(p for p in range(8080, 8200) if p not in used_ports)`. The default `8080` only applies when no other service is running. This is what makes "start 3 services, each reachable at a distinct `host_url`" work; without it, services 2 and 3 fail with `bind: address already in use`. SLURM and kubernetes get distinct endpoints from their own platform mechanisms and do not need this step.

### 4.3 After start: service registry and endpoint

Write the service registry immediately after the platform confirms the container is running. The registry (`/tmp/tao-inf-ms-state.json`) is keyed by `job_id`; `"latest"` always points to the most recently started service.

See `references/code-templates.yaml` → `registry_write.<platform>` for the Python template.

| Platform | `host_url` | `platform_job_id` | Extra step before writing |
|----------|-----------|-------------------|--------------------------|
| **local-docker** | `http://localhost:{host_port}` | — | None |
| **brev** | `http://{brev_ip}:{host_port}` | — | `brev ls` → get instance IP (`localhost` is invalid on remote VM) |
| **slurm** | `http://localhost:{host_port}` | SLURM scheduler job ID | Wait until Running; SSH port-forward `localhost:{host_port}→{node}:8080` |
| **kubernetes** | `http://{external_ip}:8080` | k8s job name | `kubectl expose job … --type=LoadBalancer`; wait for external IP |

After writing the registry, print the job_id and URL:

```python
print(f"Inference service started.")
print(f"  Job ID : {job_id}")
print(f"  Arch   : {network_arch}")
print(f"  URL    : {state[job_id]['host_url']}/v1/chat/completions")
print(f"Use this Job ID to send requests or stop the service.")
```

Then poll for readiness — see `references/code-templates.yaml` → `readiness_check`. The container loads the model in the background; do not send requests before it returns 200.

---

## 5. Stopping the inference service

Ask the user for the `job_id` to stop. If they don't provide one, default to `state["latest"]` and confirm which job_id is being stopped. Read the registry using `references/code-templates.yaml` → `stop.registry_read`, then read **`skills/platform/<platform>/SKILL.md`** and use its cancellation / stop mechanism.

| Platform | Identifier to pass | Extra cleanup |
|----------|--------------------|---------------|
| **local-docker** | `job_id_to_stop` — container name | None |
| **brev** | `job_id_to_stop` — container name | None |
| **slurm** | `entry["platform_job_id"]` — SLURM job ID | `pkill -f "ssh.*-L.*{entry['host_port']}"` |
| **kubernetes** | `entry["platform_job_id"]` — k8s job name | `kubectl delete svc {entry["platform_job_id"]} -n <namespace>` |

where `entry = state[job_id_to_stop]`. After stopping, clean up the registry: `references/code-templates.yaml` → `stop.registry_cleanup`.

---

## 6. Sending inference requests

### 6.0 Resolve which service receives this request (REQUIRED)

Each request must be routed to the **specific** service that runs the matching model. Routing happens by `job_id` — the registry stores `network_arch` per entry, so you can resolve a target by arch when the user names a model instead of a `job_id`. Apply these rules in order:

1. **User provided an explicit `job_id`** → use it. Verify it exists in `state`.
2. **User named a `network_arch`** (e.g. "send this to the cosmos-rl service") → look up matching entries: `candidates = [j for j, e in state.items() if j != "latest" and isinstance(e, dict) and e["network_arch"] == arch]`.
   - Exactly one match → use it.
   - Multiple matches → **prompt the user** with the candidate `job_id`s and their `started_at`; do not auto-pick.
   - No match → stop and tell the user no service for that arch is running.
3. **No `job_id` and no `network_arch`** → count non-`"latest"` entries in `state`:
   - Exactly one running service → use it.
   - Two or more → **do not silently default to `state["latest"]`**. Prompt the user with the full list (`job_id`, `network_arch`, `host_url`) and require an explicit choice. The `"latest"` pointer is a convenience for single-service workflows, not a routing fallback when multiple services coexist.
   - Zero → stop and tell the user to start a service first.

After resolving, read the endpoint from the registry (`references/code-templates.yaml` → `request.registry_read`), passing the resolved `job_id` as `user_provided_job_id`. Confirm to the user: "Sending to job_id=… arch=… url=…". If the service may still be loading, poll readiness first (`references/code-templates.yaml` → `readiness_check`).

**Cross-check before sending:** if the user-supplied request body contains arch-specific fields (e.g. `guidance` / `num_steps` / `seed` / `negative_prompt` → cosmos-predict2.5; required `image_url`/`video_url` content items → cosmos-rl), verify they are consistent with `state[job_id]["network_arch"]`. On mismatch, stop and ask — sending a cosmos-predict2.5 body to a cosmos-rl service will fail at the container with a 4xx/5xx that is harder to diagnose than catching it here.

### 6.1 Sampling parameters — REQUIRED user prompt before each request

Before constructing the request body, you **MUST** explicitly prompt the user for the vLLM-style sampling parameters. Do **not** silently apply defaults. Use a structured prompt, one question per field, that:

1. Lists every applicable field with its **type** and **default value**.
2. Lets the user skip / accept any field to take that field's default — entering a value is never required.
3. Collects all fields in one round.

After the prompt, apply each user-entered value verbatim and substitute the default for any skipped field. Do not invent values or silently clamp.

**Field list, defaults, and per-arch applicability:** `references/request.yaml` → `chat_completions_request_body` (base sampling fields: `max_tokens`, `top_p`, `temperature`) and `network_arch_constraints.<network_arch>` (per-arch overrides and extras such as `guidance`/`num_steps`/`seed`/`negative_prompt` for `cosmos-predict2.5`). If a field is marked unsupported for the active arch, do **not** prompt for it and do **not** include it in the body.

### 6.2 Request format

Send a `POST` to `{BASE_URL}/v1/chat/completions` with `Content-Type: application/json` and a timeout of **at least 300 s**. The body is OpenAI-compatible (vLLM chat completions); see `references/request.yaml` → `chat_completions_request_body` for the full field schema and content-item shapes (text / image_url / video_url), and `code_examples` for ready-to-run Python and curl samples.

**Constraints:** only the first user message is processed. No secret values in request bodies. **Per-network constraints** (e.g. cosmos-rl requires every request to include an image or video; cosmos-rl rejects `data:` URIs) are in `references/request.yaml` → `network_arch_constraints`.

### 6.3 Response handling

| HTTP status | Meaning | Action |
|-------------|---------|--------|
| **200** | Success — `choices[0].message.content` has the generated text | Read result |
| **202** | Server still initializing or model still loading | Retry after a delay |
| **503** | Initialization failed, model load failed, **or model not yet ready** | Inspect `error.type`: `model_not_ready` → retry; `initialization_error` / `model_load_error` → give up and check logs |
| **400** | Missing or empty JSON body | Fix request |
| **500** | Unhandled exception during inference | Check container logs |

For 202 and 503, the body contains `{"error": {"type": "<error_type>", "message": "<reason>"}}`. See `container_response_shapes` in `references/request.yaml` for error type strings.

Instalar tao-run-inference-service

Descarga y descomprime los archivos de habilidades en tu directorio .claude/skills/.

Descargar ZIP

Clona el repositorio y copia los archivos de la habilidad a tu proyecto.

git clone https://github.com/NVIDIA/skills/tree/main/skills/tao-run-inference-service # Copy SKILL.md to your .claude/skills/ directory

Copiar Copiar
Configuración rápida: Copia la carpeta de la habilidad en .claude/skills/ Claude detectará y utilizará automáticamente la habilidad
Repositorio NVIDIA/skills

Habilidades relacionadas

klingai-upgrade-migration
Tiempo actualizado 3 de julio de 2026
Verification &amp; Quality Assurance
Tiempo actualizado 29 de junio de 2026
base44-cli
Tiempo actualizado 29 de junio de 2026
Railway CLI Management
Tiempo actualizado 2 de julio de 2026
OR