| 名称 | 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 节)并解析容器镜像(第 2 节)。
- 构建作业负载和内部命令(第 3–4.1 节);使用
references/code-templates.yaml→job_payload_builder。 - 阅读
skills/platform/<platform>/SKILL.md并启动容器(第 4.2 节)。 - 写入服务注册表并轮询就绪状态(第 4.3 节);使用
references/code-templates.yaml→registry_write.<platform>和readiness_check。
发送推理请求:
- 按照第 6.0 节解析哪个服务接收请求(通过
job_id、通过network_arch,或在运行多个服务时由用户显式选择 — 当存在多个服务时,切勿静默默认使用"latest"),然后使用解析后的job_id从references/code-templates.yaml→request.registry_read读取端点。 - 在构建请求体之前,提示用户输入 vLLM 风格的采样参数(第 6.1 节)。 展示
max_tokens、top_p、temperature(以及任何架构额外的参数)及其默认值;允许用户覆盖或跳过每个参数以接受默认值。永远不要静默使用默认值。 - 按照第 6.2 节构建并发送请求体;按照第 6.3 节处理响应。
停止服务: 阅读 references/code-templates.yaml → stop.registry_read 以解析 job_id,阅读 skills/platform/<platform>/SKILL.md,然后按照第 5 节操作。
参考数据(模式、映射、有效值 — 无指令):
references/service.yaml— 镜像映射、有效的network_arch名称、作业负载模式、环境变量名称、密钥分类。references/request.yaml— 端点定义、请求字段模式、响应格式、代码示例。references/code-templates.yaml— 用于负载构建、注册表写入、就绪检查以及停止/请求流程的 Python 模板。
密钥规则(适用于此技能中的每个生成的代码块)
绝不要要求用户将密钥值输入到提示中。 对于每个密钥值:
- 告诉用户要设置哪个环境变量(例如
export HF_TOKEN=...)。 - 生成使用
os.environ["VAR_NAME"]读取该值的代码 — 永远不要硬编码、插值或提示输入该值。
密钥环境变量(完整列表见 references/service.yaml → secrets_handling):
HF_TOKEN、WANDB_API_KEY、CLEARML_API_ACCESS_KEY、CLEARML_API_SECRET_KEY、TAO_API_KEY、TAO_USER_KEY。
可在提示中安全收集: network_arch、model_path、num_gpus、提示文本、WANDB_* 配置 URL、CLEARML_*_HOST URL。
1. 需要从用户收集的信息
| 输入 | 作用 |
|---|---|
network_arch |
选择容器镜像、每个架构的内部命令形状(references/service.yaml → container_commands.<network_arch>)以及适用时作业 JSON 中的 neural_network_name。必须与 references/service.yaml 中 valid_network_arch_config_basenames 的基名匹配(例如 cosmos-rl、cosmos-predict2.5)。 |
model_path |
训练好的模型检查点。有效形式:hf_model://<org>/<model>(HuggingFace Hub — 为受限模型设置 HF_TOKEN)或本地容器文件系统路径。不支持云 URI(s3://、gs://、az://) — 推理服务没有云存储依赖。始终询问用户;永远不要替换占位符。参见 references/service.yaml → model_path_protocols。 |
platform |
计算平台:local-docker、brev、slurm 或 kubernetes。 |
num_gpus |
默认为 1;推理最小为 1。 |
2. 镜像解析
每个 network_arch 都有一个名为 {network_arch}.config.json 的边车配置文件。按如下方式解析容器镜像:
- 读取
{network_arch}.config.json并获取api_params.image(例如COSMOS_RL)。这是指向references/service.yaml中docker_image_defaults.mapping的键。 - 在映射中查找该键。如果宿主机环境变量
IMAGE_<KEY>已设置(例如IMAGE_COSMOS_RL),则覆盖映射默认值。 - 映射值通常是指向仓库根目录
versions.yaml清单的点分键(例如tao_toolkit.cosmos_rl)。通过查找versions.yaml→images.<group>.<name>将其解析为具体的nvcr.io/...镜像 URI。绝对 URI 不变地通过,因此包含完整 URI 的IMAGE_<KEY>环境变量覆盖仍然有效。相关的 Python 辅助函数位于references/code-templates.yaml。 - 如果配置文件缺失或
api_params.image为空,则回退到COSMOS_RL键。
配置文件还有 spec_params.inference.model_path,它决定文件夹 vs 文件路径语义:如果值包含子字符串 folder,容器会将路径视为目录。
3. 环境变量(无回调)
在编码 env_json 之前,在 env_payload 中设置这些变量。不要设置 TAO_LOGGING_SERVER_URL 或 TAO_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=all和NVIDIA_VISIBLE_DEVICES=<ids>。 - 标准 x86 + nvidia-container-toolkit:使用 Docker
device_requests。平台技能会处理此问题。
4. 跨平台执行
作业负载和内部命令(第 1–3 节)是平台无关的。对于每个平台,在生成任何执行代码之前,阅读 skills/platform/<name>/SKILL.md 以了解预检和凭据。
4.1 构建内部命令(每个架构)
内部命令的形状是每个 network_arch 特定的 — 没有统一模板。在 references/service.yaml → container_commands.<network_arch> 中查找每个架构的条目;如果不存在,则该架构不受支持 — 停止并询问。选择 references/code-templates.yaml → job_payload_builder.<network_arch> 中匹配的子块。在命令前加上 umask 0 &&,并使其在平台之间保持一致(local-docker、brev、slurm、kubernetes)。
跨架构通用:
job_id:新的uuid.uuid4()— 成为容器名称和注册表键。image:按第 2 节解析。- 密钥(
access_key、secret_key、HF_TOKEN等)在运行时从环境变量读取 — 永远不要硬编码、不要记录或打印。
架构相关说明(完整细节见 references/service.yaml → container_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_ID、CLOUD_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_id 和 workspace_group_id — 参见 skills/platform/tao-run-on-brev/SKILL.md |
| slurm | partition 和 account — 检查 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.yaml → registry_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.yaml → readiness_check。容器在后台加载模型;在返回 200 之前不要发送请求。
5. 停止推理服务
询问用户要停止的 job_id。如果他们不提供,默认使用 state["latest"] 并确认要停止的 job_id。使用 references/code-templates.yaml → stop.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.yaml → stop.registry_cleanup。
6. 发送推理请求
6.0 解析哪个服务接收此请求(必需)
每个请求必须路由到运行匹配模型的特定服务。路由通过 job_id 进行 — 注册表为每个条目存储 network_arch,因此当用户命名模型而不是 job_id 时,你可以按架构解析目标。按顺序应用这些规则:
- 用户提供了明确的
job_id→ 使用它。验证它存在于state中。 - 用户命名了
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;不要自动选择。 - 没有匹配 → 停止并告知用户没有该架构的服务在运行。
- 没有
job_id且没有network_arch→ 统计state中非"latest"的条目:- 正好一个正在运行的服务 → 使用它。
- 两个或更多 → 不要静默默认为
state["latest"]。向用户显示完整列表(job_id、network_arch、host_url)并要求明确选择。"latest"指针是单服务工作流的便利,而不是多个服务共存时的路由回退。 - 零个 → 停止并告诉用户先启动一个服务。
解析后,从注册表读取端点(references/code-templates.yaml → request.registry_read),将解析的 job_id 作为 user_provided_job_id 传递。向用户确认:“正在发送到 job_id=… arch=… url=…”。如果服务可能仍在加载,首先轮询就绪状态(references/code-templates.yaml → readiness_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 风格的采样参数。不要静默应用默认值。使用结构化提示,每个字段一个问题:
- 列出每个适用字段及其类型和默认值。
- 允许用户跳过 / 接受任何字段以采用该字段的默认值 — 输入值从来不是必需的。
- 在一轮中收集所有字段。
提示后,逐字应用每个用户输入的值,并为任何跳过的字段替换默认值。不要凭空发明值或静默收敛。
字段列表、默认值和每个架构的适用性: references/request.yaml → chat_completions_request_body(基本采样字段:max_tokens、top_p、temperature)和 network_arch_constraints.<network_arch>(对于 cosmos-predict2.5,还有架构特定的覆盖和额外字段,如 guidance/num_steps/seed/negative_prompt)。如果某个字段标记为对当前架构不支持,请不要提示它,也不要包含在请求体中。
6.2 请求格式
向 {BASE_URL}/v1/chat/completions 发送 POST,Content-Type: application/json,超时时间至少 300 秒。请求体与 OpenAI 兼容(vLLM chat completions);参见 references/request.yaml → chat_completions_request_body 了解完整字段模式以及内容项格式(text / image_url / video_url),以及 code_examples 了解可立即运行的 Python 和 curl 示例。
约束: 只处理第一条用户消息。请求体中不得包含密钥值。每个网络的约束(例如 cosmos-rl 要求每个请求包含图像或视频;cosmos-rl 拒绝 data: URI)位于 references/request.yaml → network_arch_constraints。
6.3 响应处理
| HTTP 状态 | 含义 | 操作 |
|---|---|---|
| 200 | 成功 — choices[0].message.content 包含生成的文本 |
读取结果 |
| 202 | 服务器仍在初始化或模型仍在加载 | 延迟后重试 |
| 503 | 初始化失败、模型加载失败或模型尚未就绪 | 检查 error.type:model_not_ready → 重试;initialization_error / model_load_error → 放弃并检查日志 |
| 400 | 缺少或空的 JSON 请求体 | 修复请求 |
| 500 | 推理期间未处理的异常 | 检查容器日志 |
对于 202 和 503,响应体包含 {"error": {"type": "<error_type>", "message": "<reason>"}}。参见 references/request.yaml 中的 container_response_shapes 以获取错误类型字符串。