TAO推理微服务编排Skill tao-run-inference-service

启动、查询和停止基于TAO模型的推理微服务,支持docker/brev/slurm/kubernetes等多种平台,负责容器镜像解析、作业负载构建、服务注册与请求路由,提供OpenAI兼容的推理接口。关键词:TAO、推理微服务、容器编排、模型推理、微服务生命周期、vLLM、多平台部署。

推理服务编排 0 次安装 0 次浏览 更新于 9/6/2026
名称 tao-run-inference-service
描述 > 启动、查询和停止特定网络架构的 TAO 推理微服务 ({network_arch}-inference-microservice),通过将容器执行委托给 相应的平台技能。处理容器镜像解析、作业负载 JSON 构造以及服务注册表。 当用户想要使用微服务容器对 TAO 模型检查点运行推理、 部署 TAO 推理端点,或停止正在运行的推理容器时使用。
开源协议 Apache-2.0 compatibility: 推理服务没有云存储依赖 — 模型权重来自 HuggingFace Hub(受限模型需要 HF_TOKEN 环境变量)或本地容器路径。平台先决条件由各个平台技能检查。 metadata:
作者 NVIDIA Corporation
版本 “0.1.0” allowed-tools: Read Bash Write tags: - inference - microservice - workflow

TAO 推理微服务

独立安装? 如果此会话未由 TAO 技能库插件初始化,请先运行 tao-setup 技能(主机预检、凭据、跨技能发现)。

说明

启动推理服务:

  1. 收集必需输入(第 1 节)并解析容器镜像(第 2 节)。
  2. 构建作业负载和内部命令(第 3–4.1 节);使用 references/code-templates.yamljob_payload_builder
  3. 阅读 skills/platform/<platform>/SKILL.md 并启动容器(第 4.2 节)。
  4. 写入服务注册表并轮询就绪状态(第 4.3 节);使用 references/code-templates.yamlregistry_write.<platform>readiness_check

发送推理请求:

  1. 按照第 6.0 节解析哪个服务接收请求(通过 job_id、通过 network_arch,或在运行多个服务时由用户显式选择 — 当存在多个服务时,切勿静默默认使用 "latest"),然后使用解析后的 job_idreferences/code-templates.yamlrequest.registry_read 读取端点。
  2. 在构建请求体之前,提示用户输入 vLLM 风格的采样参数(第 6.1 节)。 展示 max_tokenstop_ptemperature(以及任何架构额外的参数)及其默认值;允许用户覆盖或跳过每个参数以接受默认值。永远不要静默使用默认值。
  3. 按照第 6.2 节构建并发送请求体;按照第 6.3 节处理响应。

停止服务: 阅读 references/code-templates.yamlstop.registry_read 以解析 job_id,阅读 skills/platform/<platform>/SKILL.md,然后按照第 5 节操作。

参考数据(模式、映射、有效值 — 无指令):

  • references/service.yaml — 镜像映射、有效的 network_arch 名称、作业负载模式、环境变量名称、密钥分类。
  • references/request.yaml — 端点定义、请求字段模式、响应格式、代码示例。
  • references/code-templates.yaml — 用于负载构建、注册表写入、就绪检查以及停止/请求流程的 Python 模板。

密钥规则(适用于此技能中的每个生成的代码块)

绝不要要求用户将密钥值输入到提示中。 对于每个密钥值:

  1. 告诉用户要设置哪个环境变量(例如 export HF_TOKEN=...)。
  2. 生成使用 os.environ["VAR_NAME"] 读取该值的代码 — 永远不要硬编码、插值或提示输入该值。

密钥环境变量(完整列表见 references/service.yamlsecrets_handling): HF_TOKENWANDB_API_KEYCLEARML_API_ACCESS_KEYCLEARML_API_SECRET_KEYTAO_API_KEYTAO_USER_KEY

可在提示中安全收集: network_archmodel_pathnum_gpus、提示文本、WANDB_* 配置 URL、CLEARML_*_HOST URL。


1. 需要从用户收集的信息

输入 作用
network_arch 选择容器镜像、每个架构的内部命令形状(references/service.yamlcontainer_commands.<network_arch>)以及适用时作业 JSON 中的 neural_network_name。必须与 references/service.yamlvalid_network_arch_config_basenames 的基名匹配(例如 cosmos-rlcosmos-predict2.5)。
model_path 训练好的模型检查点。有效形式:hf_model://<org>/<model>(HuggingFace Hub — 为受限模型设置 HF_TOKEN)或本地容器文件系统路径。不支持云 URI(s3://gs://az://) — 推理服务没有云存储依赖。始终询问用户;永远不要替换占位符。参见 references/service.yamlmodel_path_protocols
platform 计算平台:local-dockerbrevslurmkubernetes
num_gpus 默认为 1;推理最小为 1

2. 镜像解析

每个 network_arch 都有一个名为 {network_arch}.config.json 的边车配置文件。按如下方式解析容器镜像:

  1. 读取 {network_arch}.config.json 并获取 api_params.image(例如 COSMOS_RL)。这是指向 references/service.yamldocker_image_defaults.mapping 的键。
  2. 在映射中查找该键。如果宿主机环境变量 IMAGE_<KEY> 已设置(例如 IMAGE_COSMOS_RL),则覆盖映射默认值。
  3. 映射值通常是指向仓库根目录 versions.yaml 清单的点分键(例如 tao_toolkit.cosmos_rl)。通过查找 versions.yamlimages.<group>.<name> 将其解析为具体的 nvcr.io/... 镜像 URI。绝对 URI 不变地通过,因此包含完整 URI 的 IMAGE_<KEY> 环境变量覆盖仍然有效。相关的 Python 辅助函数位于 references/code-templates.yaml
  4. 如果配置文件缺失或 api_params.image 为空,则回退到 COSMOS_RL 键。

配置文件还有 spec_params.inference.model_path,它决定文件夹 vs 文件路径语义:如果值包含子字符串 folder,容器会将路径视为目录。


3. 环境变量(无回调)

在编码 env_json 之前,在 env_payload 中设置这些变量。不要设置 TAO_LOGGING_SERVER_URLTAO_ADMIN_KEY

TAO_EXECUTION_BACKEND — 必须与平台匹配:

平台 TAO_EXECUTION_BACKEND
local-docker local-docker
brev local-docker
slurm slurm
kubernetes local-k8s

CLOUD_BASED — 此技能始终为 "False"(禁用向 TAO_LOGGING_SERVER_URL 发布回调)。

GPU 环境变量 — 仅当平台技能不自动处理 GPU 注入时才需要:

  • Tegra / Jetson:使用 --runtime=nvidia 以及 NVIDIA_DRIVER_CAPABILITIES=allNVIDIA_VISIBLE_DEVICES=<ids>
  • 标准 x86 + nvidia-container-toolkit:使用 Docker device_requests。平台技能会处理此问题。

4. 跨平台执行

作业负载和内部命令(第 1–3 节)是平台无关的。对于每个平台,在生成任何执行代码之前,阅读 skills/platform/<name>/SKILL.md 以了解预检和凭据。

4.1 构建内部命令(每个架构)

内部命令的形状是每个 network_arch 特定的 — 没有统一模板。在 references/service.yamlcontainer_commands.<network_arch> 中查找每个架构的条目;如果不存在,则该架构不受支持 — 停止并询问。选择 references/code-templates.yamljob_payload_builder.<network_arch> 中匹配的子块。在命令前加上 umask 0 &&,并使其在平台之间保持一致(local-docker、brev、slurm、kubernetes)。

跨架构通用:

  • job_id:新的 uuid.uuid4() — 成为容器名称和注册表键。
  • image:按第 2 节解析。
  • 密钥(access_keysecret_keyHF_TOKEN 等)在运行时从环境变量读取 — 永远不要硬编码、不要记录或打印。

架构相关说明(完整细节见 references/service.yamlcontainer_commands):

  • cosmos-rl — 单个 --job '<JOB_JSON>' --docker_env_vars '<ENV_JSON>' blob;json.dumps(...) + shlex.quote(...)env_payload 携带 TAO_EXECUTION_BACKEND(根据第 3 节表格)、TAO_API_JOB_IDCLOUD_BASED=False。推理服务没有云存储依赖;HF_TOKEN 是唯一适用的凭证环境变量(用于受限的 HuggingFace 模型)。
  • cosmos-predict2.5 — 标志风格 cosmos_predict inference_microservice start ... --port 8080(无 setup. 前缀;使用 tyro.conf.OmitArgPrefixes)。接受 --job/--docker_env_vars。将 model_path 转换为 --checkpoint-path(本地路径)或 --model <registered_key>hf_model://);拒绝云 URI。唯一适用的凭证环境变量是用于受限 HuggingFace 模型的 HF_TOKEN。每个请求的参数(prompt、inference_type、num_output_frames、guidance、seed、num_steps、negative_prompt)在请求体中提供,而不是在启动时。TAO_EXECUTION_BACKEND/TAO_API_JOB_ID/CLOUD_BASED 不使用,可以省略。

4.2 将执行委托给平台技能

阅读 skills/platform/<platform>/SKILL.md 并按照它启动容器。

基本参数(所有平台):

参数
image 解析后的容器镜像(第 2 节)
command inner — 在第 4.1 节中构建的 shell 字符串
gpu_count num_gpus
env_vars env_payload
作业 / 容器名称 job_id — 必须等于 4.1 中的 UUID,以便注册表可以引用它
host_port (local-docker、brev) 绑定到容器端口 8080 的主机端口。默认 8080,但在并发服务之间必须唯一 — 请参阅下面的端口分配规则。

平台特定的附加输入:

平台 附加输入
local-docker 除基本参数外无
brev instance_id(可选 — 重用现有实例);多凭证 / 多工作区账户在首次创建时还需要 cloud_cred_idworkspace_group_id — 参见 skills/platform/tao-run-on-brev/SKILL.md
slurm partitionaccount — 检查 SLURM_PARTITION/SLURM_ACCOUNT 环境变量;如果未设置,询问用户
kubernetes namespace(默认:default);image_pull_secret(对于 nvcr.io 镜像必需)

端口绑定(local-docker 和 brev): 使用直接 docker run(不是 DockerSDK),以便可以传递 -p <host_port>:8080 并且容器名称严格等于 job_id

端口分配规则(local-docker 和 brev,并发服务必需): 在启动服务之前,读取注册表(/tmp/tao-inf-ms-state.json)并收集同一平台上每个现有条目的 host_port 值集合(对于 brev,还要求同一 instance_id)。选择从 8080 开始的最低空闲端口,该端口不在该集合中 — 例如 host_port = next(p for p in range(8080, 8200) if p not in used_ports)。默认 8080 仅在没有任何其他服务运行时适用。这使“启动 3 个服务,每个服务可通过不同的 host_url 访问”成为可能;否则,服务 2 和 3 将因 bind: address already in use 失败。SLURM 和 kubernetes 通过自己的平台机制获得不同的端点,不需要此步骤。

4.3 启动后:服务注册表和端点

平台确认容器正在运行后,立即写入服务注册表。注册表(/tmp/tao-inf-ms-state.json)以 job_id 为键;"latest" 始终指向最近启动的服务。

参见 references/code-templates.yamlregistry_write.<platform> 获取 Python 模板。

平台 host_url platform_job_id 写入前的额外步骤
local-docker http://localhost:{host_port}
brev http://{brev_ip}:{host_port} brev ls → 获取实例 IP(远程虚拟机上 localhost 无效)
slurm http://localhost:{host_port} SLURM 调度程序作业 ID 等待 Running;SSH 端口转发 localhost:{host_port}→{node}:8080
kubernetes http://{external_ip}:8080 k8s 作业名称 kubectl expose job … --type=LoadBalancer;等待外部 IP

写入注册表后,打印 job_id 和 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.")

然后轮询就绪状态 — 参见 references/code-templates.yamlreadiness_check。容器在后台加载模型;在返回 200 之前不要发送请求。


5. 停止推理服务

询问用户要停止的 job_id。如果他们不提供,默认使用 state["latest"] 并确认要停止的 job_id。使用 references/code-templates.yamlstop.registry_read 读取注册表,然后阅读 skills/platform/<platform>/SKILL.md 并使用其取消 / 停止机制。

平台 传递的标识符 额外清理
local-docker job_id_to_stop — 容器名称
brev job_id_to_stop — 容器名称
slurm entry["platform_job_id"] — SLURM 作业 ID pkill -f "ssh.*-L.*{entry['host_port']}"
kubernetes entry["platform_job_id"] — k8s 作业名称 kubectl delete svc {entry["platform_job_id"]} -n <namespace>

其中 entry = state[job_id_to_stop]。停止后,清理注册表:references/code-templates.yamlstop.registry_cleanup


6. 发送推理请求

6.0 解析哪个服务接收此请求(必需)

每个请求必须路由到运行匹配模型的特定服务。路由通过 job_id 进行 — 注册表为每个条目存储 network_arch,因此当用户命名模型而不是 job_id 时,你可以按架构解析目标。按顺序应用这些规则:

  1. 用户提供了明确的 job_id → 使用它。验证它存在于 state 中。
  2. 用户命名了 network_arch(例如“将此发送到 cosmos-rl 服务”)→ 查找匹配的条目:candidates = [j for j, e in state.items() if j != "latest" and isinstance(e, dict) and e["network_arch"] == arch]
    • 正好一个匹配 → 使用它。
    • 多个匹配 → 提示用户候选的 job_id 及其 started_at;不要自动选择。
    • 没有匹配 → 停止并告知用户没有该架构的服务在运行。
  3. 没有 job_id 且没有 network_arch → 统计 state 中非 "latest" 的条目:
    • 正好一个正在运行的服务 → 使用它。
    • 两个或更多 → 不要静默默认为 state["latest"]。向用户显示完整列表(job_idnetwork_archhost_url)并要求明确选择。"latest" 指针是单服务工作流的便利,而不是多个服务共存时的路由回退。
    • 零个 → 停止并告诉用户先启动一个服务。

解析后,从注册表读取端点(references/code-templates.yamlrequest.registry_read),将解析的 job_id 作为 user_provided_job_id 传递。向用户确认:“正在发送到 job_id=… arch=… url=…”。如果服务可能仍在加载,首先轮询就绪状态(references/code-templates.yamlreadiness_check)。

发送前交叉检查: 如果用户提供的请求体包含特定于架构的字段(例如 guidance / num_steps / seed / negative_prompt → cosmos-predict2.5;必需的 image_url/video_url 内容项 → cosmos-rl),请验证它们与 state[job_id]["network_arch"] 一致。不匹配时,停止并询问 — 将 cosmos-predict2.5 请求体发送到 cosmos-rl 服务将在容器中以 4xx/5xx 失败,比在这里捕获更难诊断。

6.1 采样参数 — 每个请求之前必需的用户提示

在构建请求体之前,你必须明确提示用户输入 vLLM 风格的采样参数。不要静默应用默认值。使用结构化提示,每个字段一个问题:

  1. 列出每个适用字段及其类型默认值
  2. 允许用户跳过 / 接受任何字段以采用该字段的默认值 — 输入值从来不是必需的。
  3. 在一轮中收集所有字段。

提示后,逐字应用每个用户输入的值,并为任何跳过的字段替换默认值。不要凭空发明值或静默收敛。

字段列表、默认值和每个架构的适用性: references/request.yamlchat_completions_request_body(基本采样字段:max_tokenstop_ptemperature)和 network_arch_constraints.<network_arch>(对于 cosmos-predict2.5,还有架构特定的覆盖和额外字段,如 guidance/num_steps/seed/negative_prompt)。如果某个字段标记为对当前架构不支持,请不要提示它,也不要包含在请求体中。

6.2 请求格式

{BASE_URL}/v1/chat/completions 发送 POSTContent-Type: application/json,超时时间至少 300 秒。请求体与 OpenAI 兼容(vLLM chat completions);参见 references/request.yamlchat_completions_request_body 了解完整字段模式以及内容项格式(text / image_url / video_url),以及 code_examples 了解可立即运行的 Python 和 curl 示例。

约束: 只处理第一条用户消息。请求体中不得包含密钥值。每个网络的约束(例如 cosmos-rl 要求每个请求包含图像或视频;cosmos-rl 拒绝 data: URI)位于 references/request.yamlnetwork_arch_constraints

6.3 响应处理

HTTP 状态 含义 操作
200 成功 — choices[0].message.content 包含生成的文本 读取结果
202 服务器仍在初始化或模型仍在加载 延迟后重试
503 初始化失败、模型加载失败或模型尚未就绪 检查 error.typemodel_not_ready → 重试;initialization_error / model_load_error → 放弃并检查日志
400 缺少或空的 JSON 请求体 修复请求
500 推理期间未处理的异常 检查容器日志

对于 202 和 503,响应体包含 {"error": {"type": "<error_type>", "message": "<reason>"}}。参见 references/request.yaml 中的 container_response_shapes 以获取错误类型字符串。