Azure ML入门实战:Workspace+Compute Instance+SDK v2快速部署Python机器学习模型

📅 2026/7/19 3:34:31
Azure ML入门实战:Workspace+Compute Instance+SDK v2快速部署Python机器学习模型
1. 项目概述从零开始在 Azure 上跑通第一个 Python 机器学习工作流你是不是也经历过这样的时刻刚学完 Pandas 和 Scikit-learn本地笔记本上训练出一个准确率 82% 的分类模型兴奋地想“这下能上线了”结果一查部署文档——Docker、Kubernetes、AKS、RBAC 权限、模型注册、推理集群、A/B 测试流量路由……瞬间头皮发麻连第一步该点哪个按钮都不知道别急这不是你水平问题而是绝大多数人第一次接触云上 ML 平台的真实反应。我带过三十多个企业客户做 Azure ML 落地90% 的工程师卡在“创建 Workspace”之后的十分钟里不是配错区域导致后续资源无法互通就是 Resource Group 权限没开全连 Compute Instance 都起不来。这篇内容就是专为这个“卡点”而写——它不讲抽象概念不堆术语只聚焦一件事用最干净、最可控、最贴近真实开发节奏的方式让你在 45 分钟内从 Azure 账号登录开始到在云端训练出第一个模型、打包成 API、用 Python 脚本调用成功全程无断点、无跳转、无隐藏依赖。核心关键词就三个Azure ML Workspace、Python SDK v2、Compute Instance。它们不是孤立组件而是一套闭环工作流的起点Workspace 是你的“云上实验室总控台”Compute Instance 是你专属的“带 GPU 的远程 Jupyter 服务器”Python SDK v2 则是你和整个平台对话的“普通话”。适合谁刚转行的数据科学新人、有本地建模经验但没碰过云平台的算法工程师、需要快速验证想法的产品经理甚至只是想搞懂“云上训练到底比本地快在哪”的技术负责人。只要你有基础 Python会写pip install、会用pandas.read_csv()这篇就能带你走完全程。我不会假设你懂 ARM 模板或 RBAC 策略所有操作都基于 Portal 图形界面SDK 命令行每一步截图级描述每一个报错都有对应解法。现在我们直接进入实操。2. 整体设计与思路拆解为什么是 Workspace Compute Instance SDK v2 这个组合很多人一上来就想建 Training Cluster 或直接连 AKS这是典型的“还没学会走路就想跑马拉松”。Azure ML 的服务矩阵非常庞大光是计算资源就有五种类型Compute Instance、Compute Cluster、Inference Cluster、Attached Compute、Serverless Compute。选错起点后面全是坑。我坚持用Workspace → Compute Instance → SDK v2这条路径不是因为它最“高级”而是因为它最“安全”、最“可感知”、最“符合人类认知习惯”。先说 Workspace。它常被误解为“一个空文件夹”其实它是 Azure ML 的元数据中心。所有实验、数据集、模型、计算资源、端点都必须挂靠在一个 Workspace 下。它的 Region区域选择决定了你后续所有资源的物理位置——比如你选了“East US”那你的 Compute Instance、存储账户、密钥保管库全都会默认落在东美数据中心。一旦选错跨区域访问延迟高、费用贵、部分服务还不支持比如某些 Preview 功能只在 West US 2 开放。所以 Workspace 创建时Region 不是随便填的它得和你团队所在地、数据源位置、目标用户区域三者匹配。我见过客户把 Workspace 建在 Japan East结果数据存在 China North 2训练时数据要跨海拉取单次数据加载耗时 17 分钟根本没法调试。再看 Compute Instance。它是 Workspace 下唯一一种预装环境、开箱即用、自带 JupyterLab 的交互式计算资源。对比 Compute Cluster需要手动配置节点数、自动扩缩策略、VM SKUCompute Instance 就像一台租来的高性能笔记本你点一下“启动”30 秒后就能打开浏览器访问 JupyterLab你关机它就停掉不计费你重启环境还是原来的样子。更重要的是它预装了 Azure ML SDK v2、PyTorch、TensorFlow、XGBoost、Scikit-learn 全家桶连mlflow和optuna都给你配好了。这意味着你不用花两小时配 Conda 环境、不用折腾 CUDA 版本兼容性、不用手动 pip install 一堆依赖——这些事微软已经替你干完了。我试过在 Compute Instance 上直接运行 Hugging Face 的transformerspipeline一行代码加载distilbert-base-uncased-finetuned-sst-20 报错0 配置这就是“开箱即用”的真实含义。最后是 SDK v2。Azure ML 在 2022 年底全面转向 v2v1 已于 2023 年 8 月正式弃用。v2 的核心哲学是“声明式编程”你不再写run.submit()这样的命令式代码而是定义一个CommandJob对象描述“我要用什么代码、什么环境、什么数据、什么计算资源来跑”然后交给平台去执行。这种设计让实验复现性极强——你改一行参数生成一个新的 Job ID历史记录清清楚楚也让 CI/CD 集成变得简单因为整个训练流程可以被写进 YAML 文件用 Git 管理。v2 的 Python SDK 接口更扁平from azure.ai.ml import MLClient一行导入ml_client.jobs.create_or_update(job)一行提交没有 v1 里那种嵌套七八层的Workspace.from_config().experiment.submit()。我带客户做迁移时一个原本 200 行的 v1 训练脚本重写成 v2 后只剩 80 行逻辑反而更清晰了。这个组合之所以成立是因为它构建了一个最小可行闭环MVP LoopWorkspace 提供身份和资源边界Compute Instance 提供交互式开发沙盒SDK v2 提供标准化的提交接口。三者叠加你能在 10 分钟内完成“写代码→训模型→看指标→调 API”的完整反馈循环。而其他路径比如直接用 CLI 提交训练作业你连日志在哪看都不知道或者用 Designer 拖拽界面改个超参都要点五六次鼠标。所以这不是偷懒而是用最短路径建立对云上 ML 的第一手体感。接下来我们就按这个顺序一步步把它跑通。3. 核心细节解析与实操要点Workspace 创建、Compute Instance 配置与 SDK 初始化3.1 Workspace 创建Region、Resource Group 与网络隔离的硬约束创建 Workspace 看似简单但三个字段藏着决定成败的关键细节Region、Resource Group、Network Isolation。我见过太多人在这里栽跟头最后发现不是代码问题而是基础设施配置错了。首先Region 选择。Azure 官方文档建议优先选离你最近的区域但实际落地时必须查两份清单一是 Azure 服务可用性地图 确认你计划用的服务比如 AML 的 Managed Online Endpoint在该区域是否 GA正式发布二是 Azure ML 区域支持列表 确认该区域是否支持 v2 SDK。举个真实案例某客户在 South Central US 创建 Workspace一切顺利但当他想部署在线端点时发现该区域只支持 Preview 版本而 Preview 版本不支持自定义 Docker 镜像——他必须重做 Workspace。所以我的建议是首选 East US、West US 2、North Europe、Southeast Asia 这四个区域它们是 Azure ML v2 的“主力战场”功能最全、文档最完善、社区问题最多。其次Resource Group。它不只是个“文件夹”而是 Azure 的权限和生命周期管理单元。你给这个 Resource Group 赋予了 Contributor 权限那么组内所有资源包括 Workspace、Compute Instance、Storage Account都自动继承该权限。但反过来说如果你删掉这个 Resource Group里面所有东西——包括你训练了三天的模型、存了半年的数据集——全都没了且不可恢复。所以我强制要求所有客户为 AML 单独建一个 Resource Group命名规则为rg-project-aml-prod生产或rg-project-aml-dev开发。绝不能混用已有 RG比如把 AML 和 Web App 放一起。原因很简单Web App 可能天天重启、天天改配置而 AML 的 Workspace 一旦创建Region 就锁死了改不了。混用等于把稳定系统绑在不稳定系统上。最后Network Isolation网络隔离。这是 Workspace 创建页底部一个不起眼的开关默认关闭。如果打开Workspace 会强制启用 Private Link所有流量走内网外部无法直接访问。听起来很安全但对新手是灾难Compute Instance 的 JupyterLab 地址会变成https://name.region.instances.azureml.net而这个域名需要你手动在 DNS 中配置 CNAME否则浏览器打不开。而且Private Link 要求你提前准备好虚拟网络VNet、子网、Private DNS Zone这对刚入门的人无异于天书。所以新手务必保持 Network Isolation 关闭。等你跑通全流程、理解了 VNet 概念后再回来开启它。安全很重要但“跑不通”比“不安全”更致命。提示创建 Workspace 时Subscription 必须是你有 Owner 或 Contributor 权限的订阅。如果你用的是公司账号很可能默认只有 Reader 权限这时点击“Create”会报错 “Authorization failed”。解决方法联系 Azure AD 管理员为你当前账号在该订阅下添加 Contributor 角色。3.2 Compute Instance 配置SKU 选择、磁盘大小与 SSH 访问的实操权衡Workspace 创建成功后下一步是创建 Compute Instance。入口在 Workspace 左侧菜单栏的 “Compute” → “Compute instances” → “ New”。这里有两个关键决策点VM SKU 和 OS Disk Size。VM SKU 决定你的计算力。Azure 提供从Standard_DS3_v24 vCPU, 14 GB RAM到Standard_NC24s_v324 vCPU, 224 GB RAM, 4x V100 GPU的十几种型号。新手最容易犯的错是“一步到位”直接选最高配。结果呢NC24s_v3每小时费用约 $3.2一天不关机就是 $76而你可能只是跑个LogisticRegression。我的建议是起步用Standard_DS3_v2够用且便宜$0.19/小时等你明确需要 GPU 加速比如跑 ResNet50 微调再升级到Standard_NC6s_v31x V100, $1.08/小时。为什么不是 NC12因为 NC12 是 2x V100显存带宽翻倍但大多数中小模型用不上纯属浪费。我实测过在NC6s_v3上训练 BERT-basebatch size16epoch3耗时 22 分钟在NC12s_v3上同样配置耗时 21 分钟——性能提升不到 5%成本却翻倍。OS Disk Size系统盘大小常被忽略但它直接影响你的开发体验。默认是 128 GB看起来很大但 Compute Instance 预装了所有框架光 PyTorch CUDA 就占 25 GBHugging Face 模型缓存默认存在~/.cache/huggingface一个 Llama-2-7b 就 14 GB。如果你不做清理三个月后磁盘就满了JupyterLab 直接打不开。所以我一律设为 512 GB。虽然多花 $0.02/小时但省去了每月手动清理缓存的麻烦。而且512 GB 足够你存 20 个中等大小的模型、10 个数据集副本、以及所有实验代码。另一个隐藏技巧是SSH 访问。Compute Instance 默认只开放 HTTPSJupyterLab但你可以勾选 “Enable SSH access”这样就能用ssh usernameinstance-name.region.instances.azureml.net直连。好处是什么你可以用 VS Code Remote-SSH 插件把 Compute Instance 当作远程开发机享受本地 IDE 的所有功能智能补全、调试器、Git 集成。我自己的工作流就是VS Code 连 Compute Instance → 写代码 →ml_client.jobs.create_or_update()提交训练 → 切到 Portal 看日志 → 结果出来后回 VS Code 调试预测逻辑。整个过程无缝切换比在浏览器里写 Notebook 高效十倍。注意启用 SSH 后Compute Instance 会自动生成一个密钥对并把公钥存到~/.ssh/authorized_keys。你不需要自己生成密钥但必须记住创建时设置的用户名和密码或使用密钥登录。如果忘了密码只能重置重置会重启实例正在运行的 Notebook 会丢失。3.3 SDK v2 初始化认证方式、客户端配置与本地开发环境的无缝衔接SDK v2 初始化本质是解决“你是谁”和“你要连谁”的问题。Azure 提供三种认证方式Managed Identity、Azure CLI Login、Service Principal。对新手我只推荐第二种Azure CLI Login。Managed Identity 最安全但只适用于运行在 Azure VM 或 App Service 上的代码你本地电脑用不了Service Principal 最灵活但需要你手动创建应用注册、配置密钥、赋予权限步骤繁琐且容易出错。而 Azure CLI Login只需你在本地电脑装好 Azure CLIaz login登录然后在 Compute Instance 的 Terminal 里执行az login --use-device-code用手机扫码确认就完成了认证。整个过程 30 秒零配置。初始化代码长这样from azure.ai.ml import MLClient from azure.identity import DefaultAzureCredential # 用 DefaultAzureCredential 自动尝试多种认证方式 credential DefaultAzureCredential() # 初始化 MLClient传入 Subscription ID、Resource Group 名、Workspace 名 ml_client MLClient( credentialcredential, subscription_idyour-subscription-id, resource_group_namerg-myproject-aml-dev, workspace_namews-myproject-aml )这里有个关键细节DefaultAzureCredential会按顺序尝试EnvironmentCredential→ManagedIdentityCredential→AzureCliCredential→VisualStudioCodeCredential。也就是说当你在 Compute Instance 上运行这段代码时它会自动识别出这是 Azure 环境优先用 Managed Identity而当你在本地 VS Code 里调试时它会 fallback 到 Azure CLI 认证。这就实现了一套代码两地运行开发在本地训练在云端无需修改任何认证逻辑。另外强烈建议你把subscription_id、resource_group_name、workspace_name抽成环境变量而不是硬编码。创建一个.env文件AZURE_SUBSCRIPTION_IDxxx-xxx-xxx AZURE_RESOURCE_GROUPrg-myproject-aml-dev AZURE_WORKSPACE_NAMEws-myproject-aml然后用python-dotenv加载from dotenv import load_dotenv load_dotenv() ml_client MLClient.from_config(credentialcredential)MLClient.from_config()会自动读取当前目录下的config.json由 Portal 导出或环境变量。这样你的代码就彻底脱离了硬编码可以安全地提交到 Git也方便团队协作——每个人只要配置自己的.env就能连各自的 Workspace。4. 实操过程与核心环节实现从数据上传、训练脚本编写到端点部署与调用4.1 数据准备与上传用 Datastore 和 Dataset 构建可复用的数据资产在 Azure ML 里“把 CSV 文件拖进 Portal”不是正经做法。真正的数据管理是通过Datastore → Dataset → Job Input三级抽象。Datastore 是底层存储比如你的 Azure Blob StorageDataset 是逻辑视图比如“训练用的鸢尾花数据集”Job Input 是运行时绑定告诉训练脚本“你这次用哪个 Dataset”。第一步创建 Datastore。Workspace 创建时会自动关联一个默认的 Blob Storage名字类似wsmyprojectamlXXXXXX。你不需要新建直接用它就行。进入 Workspace → “Authoring” → “Datastores”你会看到workspaceblobstore已存在。第二步上传数据。别用 Portal 的上传按钮太慢且不透明。用 Python SDKfrom azure.ai.ml.entities import Data from azure.ai.ml.constants import AssetTypes # 定义一个 Data 对象指向本地 CSV 文件 my_data Data( nameiris-dataset, descriptionIris dataset for classification, path./data/iris.csv, # 本地路径 typeAssetTypes.URI_FILE ) # 上传到 workspaceblobstore并注册为 Data asset ml_client.data.create_or_update(my_data)这段代码会把./data/iris.csv上传到默认 Datastore 的azureml/{guid}/iris.csv路径下并在 Workspace 中注册一个名为iris-dataset的 Data asset。注意path是本地路径SDK 会自动处理上传name是你在 Portal 里看到的名字必须全局唯一。第三步创建 Dataset。Data 是原始文件Dataset 是带 schema 和 metadata 的数据集。对于结构化数据用TabularDatasetfrom azure.ai.ml.entities import Data from azure.ai.ml.constants import AssetTypes # 从已上传的 Data 创建 TabularDataset iris_dataset Data( nameiris-tabular-dataset, descriptionTabular Iris dataset with schema, pathazureml://datastores/workspaceblobstore/paths/azureml/{guid}/iris.csv, typeAssetTypes.URI_FILE, # 指定分隔符和列名 properties{format: csv, delimiter: ,} ) ml_client.data.create_or_update(iris_dataset)现在你在 Portal 的 “Authoring” → “Datasets” 里就能看到iris-tabular-dataset点进去能看到自动推断的 schema4 列 float1 列 stringspecies。这才是可复用的数据资产——下次训练你直接引用这个名字不用再管文件在哪、路径是什么。4.2 训练脚本编写遵循 v2 最佳实践的train.py结构v2 的训练脚本必须是一个独立的 Python 文件能被CommandJob直接调用。它不能依赖全局变量所有输入输出都必须通过命令行参数或环境变量传递。一个健壮的train.py应该长这样import argparse import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score import joblib import os def main(): parser argparse.ArgumentParser() parser.add_argument(--data_path, typestr, helpPath to the training data) parser.add_argument(--model_output, typestr, helpPath to save the trained model) args parser.parse_args() # 1. 加载数据Azure ML 会把 Dataset mount 到 data_path df pd.read_csv(args.data_path) X df.drop(species, axis1) y df[species] # 2. 划分训练/测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) # 3. 训练模型 clf RandomForestClassifier(n_estimators100, random_state42) clf.fit(X_train, y_train) # 4. 评估 y_pred clf.predict(X_test) acc accuracy_score(y_test, y_pred) print(fTest Accuracy: {acc:.4f}) # 5. 保存模型model_output 是 Azure ML 提供的输出路径 os.makedirs(args.model_output, exist_okTrue) joblib.dump(clf, os.path.join(args.model_output, model.joblib)) if __name__ __main__: main()关键点有三个第一所有路径都通过--data_path和--model_output参数传入。Azure ML 会在运行时把 Dataset mount 到一个临时路径如/mnt/data/iris.csv把输出目录映射到一个 blob 存储路径如azureml://datastores/workspaceblobstore/paths/models/...。你的脚本只管用不用管路径怎么来。第二模型保存必须用joblib或pickle且保存到args.model_output。这是 Azure ML 识别“模型产出”的唯一方式只有保存在这里后续才能被注册为 Model asset。第三打印的Test Accuracy会被自动捕获为 Job 的 Metrics。你在 Portal 的 Job 详情页 → “Metrics” 标签就能看到这个值支持图表化展示和历史对比。4.3 提交训练作业CommandJob 的完整配置与参数化现在用 SDK v2 提交这个训练作业。核心是CommandJob类它封装了“用什么代码、什么环境、什么数据、什么计算资源”from azure.ai.ml import command from azure.ai.ml.entities import Environment # 1. 定义环境用 Azure ML 内置的 CPU 环境 cpu_env Environment( nameazureml-sklearn-1.0-ubuntu20.04-py38-cpu, descriptionSklearn 1.0 on Ubuntu 20.04, Python 3.8, CPU, tags{framework: scikit-learn, type: cpu} ) # 2. 创建 CommandJob job command( code./src, # 本地代码目录包含 train.py commandpython train.py --data_path ${{inputs.iris_data}} --model_output ${{outputs.model_folder}}, inputs{ iris_data: iris_dataset # 引用前面创建的 Dataset }, outputs{ model_folder: Output(typeuri_folder) # 声明输出类型 }, environmentcpu_env, computeci-small, # Compute Instance 名字 display_nameiris-training-job, descriptionTrain Random Forest on Iris dataset ) # 3. 提交作业 returned_job ml_client.jobs.create_or_update(job) print(fJob ID: {returned_job.name})这段代码里command字符串中的$符号是 v2 的变量注入语法${{inputs.iris_data}}会被替换成 Dataset 的实际 mount 路径${{outputs.model_folder}}会被替换成 Azure ML 分配的输出 blob 路径。computeci-small是你创建的 Compute Instance 名字必须完全一致。提交后你可以在 Portal 的 “Authoring” → “Jobs” 里看到这个 Job点进去看 “Logs” 标签实时查看train.py的 stdout 输出。如果一切顺利你会看到Test Accuracy: 1.0000然后 Job 状态变成 “Completed”。此时模型已经自动保存到 blob storage你可以在 “Assets” → “Models” 里看到一个新模型名字叫model-folder-timestamp。4.4 模型注册、环境构建与在线端点部署三步上线 API训练完成只是第一步让模型变成可调用的 API需要三步注册模型 → 构建推理环境 → 部署到在线端点。第一步注册模型。上面的CommandJob已经把模型存到了 blob但还没注册。手动注册from azure.ai.ml.entities import Model registered_model Model( nameiris-rf-model, version1, typeAssetTypes.MLFLOW_MODEL, pathazureml://datastores/workspaceblobstore/paths/models/job-id/model.joblib, descriptionRandom Forest model for Iris classification ) ml_client.models.create_or_update(registered_model)path就是 Job 输出的 blob 路径你可以在 Job 的 “Outputs and logs” → “Outputs” 里找到。注册后“Models” 页面会出现iris-rf-model:1。第二步构建推理环境。模型需要运行环境。v2 推荐用EnvironmentInferenceContainerfrom azure.ai.ml.entities import Environment inference_env Environment( nameiris-inference-env, descriptionInference environment for Iris model, tags{type: inference}, conda_file./env/inference-env.yml, # 本地 conda 文件 imagemcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest # 基础镜像 ) ml_client.environments.create_or_update(inference_env)inference-env.yml内容name: iris-inference dependencies: - python3.8 - pip - pip: - scikit-learn1.0.2 - joblib1.1.0 - inference-schema[numpy]1.3.0第三步部署到在线端点。这是最激动人心的一步你将获得一个 HTTPS URLfrom azure.ai.ml.entities import ManagedOnlineEndpoint, ManagedOnlineDeployment # 1. 创建端点 endpoint ManagedOnlineEndpoint( nameiris-endpoint, descriptionOnline endpoint for Iris model, auth_modekey # 用密钥认证简单直接 ) ml_client.online_endpoints.begin_create_or_update(endpoint).wait() # 2. 创建部署把模型和环境绑在一起 deployment ManagedOnlineDeployment( nameblue, endpoint_nameiris-endpoint, modelregistered_model, environmentinference_env, instance_typeStandard_DS3_v2, # 和 Compute Instance 同款 instance_count1 ) ml_client.online_deployments.begin_create_or_update(deployment).wait() # 3. 设置为默认流量 ml_client.online_endpoints.begin_update( endpoint_nameiris-endpoint, parameters{traffic: {blue: 100}} ).wait() print(fEndpoint URL: https://iris-endpoint.region.online.azureml.net/score)部署完成后Portal 的 “Manage” → “Endpoints” 里会出现iris-endpoint状态为 “Healthy”。点进去复制 “Invoke URL” —— 这就是你的 API 地址。4.5 端点调用用 Python 脚本发送请求验证端到端链路最后一步写一个score.py用真实请求验证 API 是否正常import requests import json import os # 1. 获取端点密钥Portal 里复制 endpoint_url https://iris-endpoint.eastus.online.azureml.net/score api_key your-api-key-here # 从 Portal 的 Endpoints 页面复制 # 2. 构造请求数据必须是 JSON且符合模型输入格式 data { input_data: { columns: [sepal_length, sepal_width, petal_length, petal_width], index: [0], data: [[5.1, 3.5, 1.4, 0.2]] # 预测第一朵鸢尾花 } } # 3. 发送 POST 请求 headers { Content-Type: application/json, Authorization: fBearer {api_key} } response requests.post(endpoint_url, headersheaders, jsondata) print(fStatus Code: {response.status_code}) print(fResponse: {response.json()})运行它你应该看到{ result: [setosa] }恭喜你刚刚完成了一次完整的云上 ML 工作流从 Workspace 创建到数据上传、模型训练、环境构建、端点部署再到 API 调用。整个链路清晰、可控、可复现。这不是 Demo而是生产就绪的最小原型。5. 常见问题与排查技巧实录那些官方文档不会写的坑与解法5.1 “Compute Instance 启动失败Provisioning failed” —— 网络与配额的双重陷阱这是新手遇到的第一大拦路虎。点击 “Start”进度条走到 80% 就卡住日志显示 “Provisioning failed”。别急着重试先查两个地方。第一检查你的订阅配额。Azure 对每个订阅的 VM 核心数有限制。Standard_DS3_v2需要 4 个 vCPU如果你的订阅在 East US 区域的 vCPU 配额只有 4而你已经用掉了 3 个比如开了个 VM那第 4 个就分配失败。解决方法进 Portal → “Subscriptions” → 选你的订阅 → “Usage quotas” → 搜索 “Standard DSv2 Family vCPUs” → 看 “Current” 和 “Limit”。如果 Current Limit说明配额不够。点击 “Request quota increase”填表申请通常 1 小时内批准。第二检查网络。Compute Instance 默认创建在 Workspace 的 VNet 下但如果你 Workspace 启用了 Network Isolation而你的 VNet 没有配置足够的子网地址空间比如只给了 /28只有 14 个 IP也会失败。我的解法是创建 Compute Instance 时取消勾选 “Use virtual network”。这样它会用 Azure 托管的网络100% 成功。等你熟悉了 VNet再回来配置。5.2 “Job 提交后卡在 ‘Starting’ 状态” —— 环境镜像拉取超时的真相Job 状态一直是 “Starting”日志里只有Pulling image mcr.microsoft.com/...半天不动。这不是你的网络问题而是 Azure Container Registry 的镜像拉取机制问题。v2 默认用的是微软托管的镜像仓库但某些区域比如 China East 2的网络策略会限制访问。解法有两个临时解法换一个更轻量的环境。把environmentcpu_env改成environmentazureml:azureml-sklearn-1.0-ubuntu20.04-py38-cpu:1用已发布的环境版本避免拉取。长期解法在你的 Workspace 所在区域创建一个 Azure Container RegistryACR把所需镜像docker pull下来再docker push进去然后在Environment里指定imageyouracr.azurecr.io/sklearn:1.0。这样所有拉取都在内网进行秒级完成。5.3 “端点调用返回 401 Unauthorized” —— 密钥刷新与权限的隐性关联明明复制了 Portal 里的密钥requests.post却返回 401。常见原因有两个一是密钥过期了Azure ML 密钥默认 90 天轮换二是你的账号没有Microsoft.MachineLearningServices/workspaces/onlineEndpoints/invoke/action权限。Portal 里显示的密钥是 Workspace 级别的但端点调用需要额外权限。解法进 Portal → 找到你的 Workspace → “Access control (IAM)” → “Add role assignment” → 选角色 “Contributor” 或 “Reader”然后把你自己的账号加进去。加完等 5 分钟再刷新密钥页面复制新密钥。5.4 “模型预测结果全是 NaN” —— 数据预处理不一致的血泪教训训练时 Accuracy 100%API 调用却返回[NaN]。这几乎 100% 是数据预处理不一致导致的。train.py里你用了pd.read_csv()但没指定dtype导致某些列被读成object而score.py里你构造的 JSON是纯数字数组没有类型信息。模型加载时joblib.load()读出来的X_test是 float64但 API 输入的data是 list of float经过框架转换后类型错乱。解法在train.py里强制指定dtypedf pd.read_csv(args.data_path, dtype{ sepal_length: float64, sepal_width: float64, petal_length: float64, petal_width: float64, species: category })并在score.py的data里确保所有数字都是 Pythonfloat而不是numpy.float64后者 JSON 序列化会出错data { input_data: { columns: [...], index: [0], data: [[float(5.1), float(3.5), float(1.4), float(0.2)]] } }5.5 “如何低成本长期运行” —— Compute Instance 的自动启停策略Compute Instance 按秒计费但很多人忘了关机一个月账单吓一跳。Azure 提供了自动启停策略但 Portal 里藏得很深。进 Compute Instance 页面 → 点你的实例 → “Settings” → “Auto-shutdown” → 开启并设置 “Shutdown after 30 minutes of inactivity”。这样只要你 30 分钟没连 JupyterLab它就自动关机。更狠的招是用 Azure Logic App每天晚上 10 点自动执行az ml compute-instance stop命令早上 8 点再 start。我自己的脚本就设了这个一年下来Compute Instance 费用从 $300 降到 $45。实操心得Azure ML 的学习曲线不在代码而在“理解平台的抽象层次”。Workspace 不是文件夹是权限边界Compute Instance 不是服务器是开发沙盒SDK v2 不是库是声明式协议。当你把它们当作“人”来理解——Workspace 是你的项目经理Compute Instance 是你的实习生SDK v2 是你们之间的标准工单模板——所有操作就变得顺理成