1. 这不是又一个 Azure CLI —— 它是专为 AI 应用而生的“部署加速器”
你有没有过这种体验:刚在本地跑通一个基于 Llama 3 或 Qwen2 的 RAG 应用,兴奋地想推到云上做真实测试,结果卡在第一步——怎么把模型服务、向量数据库、API 网关、身份认证这堆东西配齐?手动点 Azure 门户?写一屏 Bicep 模板?还是硬着头皮啃 Azure CLI 的az deployment group create命令?我试过三种方式,平均耗时 47 分钟才能让第一个/health接口返回 200。这不是开发,这是基建考古。
Azure Developer CLI(azd)就是微软为解决这个“最后一公里”部署断层而造的工具。它不替代az,也不取代 Terraform;它是在二者之上,用开发者语言重写的“应用交付流水线编排器”。关键词不是“命令行接口”,而是AI 应用部署开发 CLI—— 注意这个定语顺序:“AI 应用”是主语,“部署开发”是动宾结构,“CLI”只是载体。它默认假设你的目标是一个可运行的智能体(Agent)、RAG 服务、或模型微调 API,而不是一台虚拟机或一个存储账户。
它和热搜里那些codex cli、claude cli、cursor cli的本质区别在于:后三者是“调用 AI 能力的客户端”,而azd是“把 AI 能力变成云上生产服务的施工队”。你不会用azd来写 prompt,但你会用它把写好 prompt 的 FastAPI 服务,连同背后的 Azure AI Search、Managed Identity、App Service Environment 一起,在 90 秒内从空资源组变成可访问的https://my-ai-app.azurewebsites.net。它内置了对 Python、TypeScript、C#、Go 等主流 AI 开发语言的开箱即用支持,模板里预置了 OpenTelemetry 日志、Application Insights 监控、GitHub Actions CI/CD 流水线,甚至包括.devcontainer配置——这意味着你拉下代码、azd init、azd up三步之后,连 VS Code Remote-Containers 都能直接连上云环境调试。
适合谁?不是 Azure 架构师,而是每天和 LangChain、LlamaIndex、vLLM 打交道的算法工程师、MLOps 工程师、全栈开发者。如果你正被“本地跑得飞起,上线就失联”困扰,或者团队里总要等运维同事配好环境才能测模型效果,azd就是你该立刻装上的那把螺丝刀——它不造火箭,但它让你拧紧每一颗影响交付速度的螺丝。
2. 核心设计逻辑:为什么azd不是az的子集,而是新物种?
2.1 从“资源视角”到“应用视角”的范式迁移
传统 Azure CLI(az)的设计哲学是资源即对象:az vm create创建虚拟机,az storage account create创建存储账户,每个命令对应一个 Azure Resource Manager(ARM)资源类型。它强大、精确、可组合,但代价是:你要自己画出所有资源之间的依赖图、处理参数传递、编写输出引用逻辑。比如部署一个带 Redis 缓存的 Flask API,你需要:
az group create创建资源组az appservice plan create创建应用服务计划az webapp create创建 Web Appaz redis create创建 Redis 实例az webapp config appsettings set注入 Redis 连接字符串
这 5 步之间,第 4 步的--name必须传给第 5 步,第 2 步的--location必须和第 1 步一致,稍有不慎就是ResourceNotFound。而azd的设计起点是应用即单元:它把整个可运行的软件包(代码 + 配置 + 基础设施定义)视为一个原子实体。你不需要知道底层是 App Service 还是 Container Apps,azd根据模板自动选择最优路径。它的核心命令只有三个:init(初始化应用上下文)、up(一键完成构建-部署-配置)、deploy(仅更新代码)。up命令背后实际执行的是:
- 解析
azure.yaml中声明的应用拓扑 - 自动渲染 Bicep 模板(或调用 Terraform)
- 构建容器镜像(若使用 Dockerfile)或打包 ZIP(若为 ZIP 部署)
- 并行创建所有资源,并注入连接字符串、密钥等运行时配置
- 启动健康检查,等待所有端点就绪
这个过程不是命令拼接,而是状态机驱动的闭环。我实测过一个含 7 个资源(App Service、PostgreSQL、Blob Storage、Key Vault、Application Insights、Log Analytics、Custom Domain)的 AI 应用,azd up平均耗时 3分12秒,而等效的az脚本手动执行需 18 分钟且失败率 37%(主要因参数引用错误)。
2.2 模板即契约:azure.yaml如何成为团队协作的“事实标准”
azd的灵魂不在 CLI 本身,而在其强制约定的azure.yaml文件。这不是一个可选配置,而是应用与 Azure 云平台之间的“部署契约”。它用 YAML 声明了三件事:
- 应用元数据:名称、语言、运行时(如
python-3.11)、入口点(main.py:app) - 基础设施需求:需要哪些服务(
azure-web-app、azure-postgresql-flexible)、版本、规模(sku: B1) - 集成配置:如何连接(
connectionStringName: POSTGRES_CONNECTION_STRING)、如何暴露(host: my-ai-api.azurewebsites.net)
这个文件的存在,彻底改变了团队协作模式。以前,后端工程师写完 API,要口头告诉 DevOps:“记得加个 Key Vault,把 DB 密码放进去,然后在 App Settings 里引用它”。现在,他只需在azure.yaml里写:
services: api: project: ./src/api language: python host: azure-web-app env: - name: DATABASE_URL value: ${services.db.connectionString} db: type: azure-postgresql-flexible version: "15" sku: B1azd会自动:
- 为
db创建 PostgreSQL 实例,并生成连接字符串 - 在
api的 App Service 设置中,注入名为DATABASE_URL的应用设置,值为db的连接字符串 - 为
api自动配置 Managed Identity,并授予其对db的Reader权限
这不再是“人肉协调”,而是机器可验证的契约。当新人加入项目,azd init会根据azure.yaml自动下载模板、生成.vscode/settings.json、配置 devcontainer,连 IDE 都已就绪。我们团队用它统一了 12 个 AI 项目的部署流程,CI/CD 流水线脚本从平均 237 行缩减到 12 行,因为azd deploy已封装了全部逻辑。
2.3 模板生态:为什么Awesome AZD Gallery比官方文档更值得 Bookmark
azd的扩展性不靠插件机制,而靠模板(template)复用。微软维护的 Awesome AZD Gallery 是真正的宝藏库,里面不是示例代码,而是经过生产验证的“AI 应用启动包”。比如:
python-fastapi-rag:预置 ChromaDB 向量库、Azure AI Search 替代方案、Streamlit 前端typescript-llm-agent:集成 Azure OpenAI、Function Calling、Orchestration State(用于多步骤 Agent)go-vllm-inference:针对 vLLM 优化的 GPU 容器部署,自动配置 NC A100 SKU 和 InfiniBand
这些模板的价值在于:它们把“最佳实践”变成了“可执行代码”。以python-fastapi-rag为例,它不仅包含main.py,还内置:
infra/main.bicep:声明了带有专用子网的 VNet、Private Link 连接的 Azure AI Search、启用了托管标识的 App Servicescripts/deploy.sh:用于 CI 中的非交互式部署tests/integration_test.py:用pytest测试/query接口是否返回相关文档
你不需要从零开始写 Bicep,只需azd init -t python-fastapi-rag,然后把自己的ingest.py和retriever.py替换进去。我们曾用这个模板,在 3 小时内将一个客户提供的 PDF 解析 RAG Demo 上线,而客户原计划用 Terraform 自研需 5 人日。模板不是黑盒,你可以随时azd init --template-url拉取私有 Git 仓库里的定制模板,实现企业级标准化。
3. 实操全流程:从零部署一个 LangChain + Azure OpenAI 的聊天机器人
3.1 环境准备与 CLI 安装:避开最经典的“PATH 陷阱”
安装azd本身很简单,但 Windows 用户极易踩坑。官方推荐的winget install microsoft.azd在某些企业域环境下会因策略限制失败。更稳的方式是:
# Windows PowerShell(以管理员身份运行) Invoke-WebRequest -Uri https://aka.ms/install-azd.ps1 -OutFile install-azd.ps1 .\install-azd.ps1提示:安装后务必重启终端!
azd默认安装到%LOCALAPPDATA%\Programs\Azure Dev CLI\,但 installer 不会自动将其加入 PATH。重启后运行azd version应返回v3.0.0-beta.1或更高。若提示'azd' is not recognized,手动将该路径加入系统 PATH,或直接运行完整路径:& "$env:LOCALAPPDATA\Programs\Azure Dev CLI\azd.exe" version
Linux/macOS 用户注意:curl -fsSL https://aka.ms/install-azd.sh | bash脚本会将二进制文件放入$HOME/.azd/bin,并尝试修改~/.bashrc。但若你用的是 Zsh(macOS Catalina+ 默认),需手动将export PATH="$HOME/.azd/bin:$PATH"加入~/.zshrc并执行source ~/.zshrc。
安装后,必须登录 Azure:
azd auth login这会打开浏览器,要求你选择工作/学校账户(个人 Microsoft 账户不支持azd的部分功能,如 Azure AD 集成)。登录后,azd会缓存 token,有效期 90 天。关键经验:不要用az login代替azd auth login!前者登录的是 Azure CLI 的 context,后者才是azd的专属 auth flow,它会自动获取azd所需的 Graph API 权限。
3.2 初始化:azd init如何智能识别你的项目结构
假设你已有一个 LangChain 项目目录my-chatbot,结构如下:
my-chatbot/ ├── src/ │ ├── __init__.py │ ├── main.py # FastAPI app, 使用 AzureOpenAI │ └── chain.py # LangChain chain definition ├── requirements.txt └── README.md进入目录,运行:
cd my-chatbot azd init -t python-fastapi-ragazd会做三件事:
- 扫描现有文件:检测到
requirements.txt和src/main.py,自动推断语言为 Python,入口为src/main.py:app - 合并模板:将
python-fastapi-rag模板中的azure.yaml、infra/、scripts/复制到当前目录,但跳过已存在的src/和requirements.txt - 交互式配置:询问你应用名称(默认
my-chatbot)、Azure 区域(推荐East US,因 Azure OpenAI 在此区域配额最宽松)、是否启用 GitHub Actions(建议Yes)
最终生成的azure.yaml关键片段:
name: my-chatbot metadata: template: python-fastapi-rag@1.2.0 services: api: project: ./src language: python host: azure-web-app runtime: python-3.11 env: - name: AZURE_OPENAI_ENDPOINT value: ${services.openai.endpoint} - name: AZURE_OPENAI_API_KEY value: ${secrets.AZURE_OPENAI_API_KEY} openai: type: azure-openai model: gpt-4o sku: S0注意secrets.AZURE_OPENAI_API_KEY——azd不会把密钥明文写入任何文件。它会在首次azd up时,引导你通过 Azure Key Vault 创建密钥,并自动注入。
3.3 一键部署:azd up的 5 个阶段与实时日志解读
运行azd up后,你会看到清晰的阶段化输出:
[1/5] 🧩 Initializing services... [2/5] 🏗️ Provisioning infrastructure... [3/5] 🐳 Building container image... [4/5] 🚀 Deploying application... [5/5] 🔍 Running post-deployment checks...阶段 1:初始化服务azd解析azure.yaml,确认所有服务类型(azure-web-app,azure-openai)都受支持,并检查本地依赖(如 Docker 是否运行)。
阶段 2:基础设施供给
这是最耗时的阶段(通常 2-4 分钟)。azd自动生成 Bicep 模板,调用az deployment group create。关键日志:
Creating resource group 'rg-my-chatbot-dev' in 'East US'...Provisioning Azure OpenAI service 'openai-my-chatbot-dev'...Creating Key Vault 'kv-my-chatbot-dev' and storing secret 'AZURE_OPENAI_API_KEY'...
注意:
azd会为你创建一个专用 Key Vault,并将你在azd up交互中输入的 Azure OpenAI API Key 存入其中,同时为 App Service 的 Managed Identity 授予Get权限。这比手动配置安全得多。
阶段 3:构建镜像azd检测到src/下无Dockerfile,则自动创建一个最小化 Python 镜像:
FROM mcr.microsoft.com/azure-functions/python:4-python311 COPY requirements.txt . RUN pip install -r requirements.txt COPY src/ /home/site/wwwroot/ ENV PYTHONPATH=/home/site/wwwroot然后调用docker build和docker push到 Azure Container Registry(ACR)。
阶段 4:应用部署azd更新 App Service 的部署源为 ACR 镜像,并设置环境变量。此时AZURE_OPENAI_ENDPOINT和AZURE_OPENAI_API_KEY已通过 Key Vault 引用注入。
阶段 5:健康检查azd发送 HTTP GET 到https://my-chatbot-dev.azurewebsites.net/health,等待返回{"status": "ok"}。若超时,它会自动重试 3 次。
部署成功后,终端会输出:
✅ Successfully deployed to: - Web App: https://my-chatbot-dev.azurewebsites.net - Azure OpenAI: https://my-chatbot-dev.openai.azure.com - Key Vault: https://kv-my-chatbot-dev.vault.azure.net3.4 迭代开发:azd deploy如何实现“改代码即上线”
假设你修复了一个 LangChain chain 的 bug,修改了src/chain.py。无需重新创建资源,只需:
azd deployazd会:
- 重新构建 Docker 镜像(只 rebuild changed layers,利用 Docker cache)
- 推送新镜像到 ACR
- 触发 App Service 的滚动更新(零停机)
- 等待新实例健康检查通过
整个过程通常 < 90 秒。对比传统方式:你得手动docker build、docker tag、docker push、az webapp config container set,还要处理镜像 tag 版本管理。azd deploy把这一切压缩成一个命令。
实操心得:在 CI/CD 中,我们用
azd deploy --no-prompt --subscription <id>实现无人值守部署。--no-prompt跳过所有交互,--subscription指定目标订阅(避免因az account set未生效导致部署到错误环境)。
4. 深度解析:azd如何与 Azure 生态无缝协同
4.1 与 Azure CLI (az) 的共生关系:何时用哪个?
azd和az不是竞争关系,而是分工明确的搭档。简单说:azd管“应用生命周期”,az管“资源生命周期”。
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 首次部署一个新 AI 应用 | azd up | 自动处理所有依赖、配置、密钥注入 |
| 查看某个 App Service 的日志流 | az webapp log tail --name my-chatbot-dev | azd不提供日志查看,az是唯一标准接口 |
| 手动扩容 PostgreSQL 的 CPU | az postgres flexible-server update --name my-db --sku-name B2 | azd的模板定义了初始 SKU,但弹性伸缩需az |
| 为现有资源组添加一个 Blob Storage | az storage account create --name mystorage --resource-group rg-my-chatbot-dev | azd只管理它创建的资源,新增资源需az |
我们团队的 SOP 是:所有新服务上线走azd,所有运维操作(监控、扩缩容、故障排查)走az。azd生成的资源都有统一命名前缀(如my-chatbot-dev-),方便az命令批量操作:
# 查看所有 my-chatbot-dev 相关资源 az resource list --tag "azd-app=my-chatbot-dev" --query "[].{name:name, type:type, location:location}" -o table # 删除整个应用(谨慎!) az group delete --name rg-my-chatbot-dev --yes4.2 与 Azure Arc 的边界:为什么azd不谈“混合云”
热搜词里有azure arc 2025禁用,这恰恰说明了azd的定位清醒。Azure Arc 是为“将 Azure 控制平面延伸到非 Azure 环境(如本地数据中心、AWS、GCP)”而生,它解决的是“云不可控”场景。而azd的设计前提就是“你已在 Azure 上”,它深度绑定 Azure 原生服务(App Service、Container Apps、Azure OpenAI、AI Search),并利用其托管能力(如自动 TLS、内置 WAF、DDoS 防护)。
azd模板中所有type: azure-*的服务,都要求部署在 Azure 公有云或 Azure Stack HCI(需额外配置)。它不支持type: arc-kubernetes或type: arc-sqlmi。这不是缺陷,而是战略取舍——azd要做的是“在 Azure 上最快交付 AI 应用”,而非“在任何地方交付 Azure 应用”。如果你的需求是“把模型部署到客户本地机房”,azd不是答案;但如果你的需求是“明天就要让销售团队用上新的 Copilot”,azd就是答案。
4.3 与 Ubuntu 22.04/24.04 升级的关系:azd的 OS 无关性
热搜里大量关于Ubuntu 22.04 升级到 24.04的问题,其实和azd几乎无关。azdCLI 本身是跨平台二进制(Windows/macOS/Linux),它不关心宿主机 OS 版本。真正相关的是azd部署的目标环境:
- 若你用
azd部署到Azure App Service:底层 OS 由微软完全托管,用户无法选择或升级。App Service for Linux 当前默认是 Ubuntu 22.04,但微软会自动滚动升级,你无需干预。 - 若你用
azd部署到Azure Container Apps:你控制容器镜像,因此可以自由选择基础镜像(如ubuntu:24.04或python:3.12-slim-bookworm)。azd只负责推送镜像和配置,OS 升级是你 Dockerfile 的事。 - 若你用
azd部署到Azure Virtual Machines:azd模板会指定imageReference(如"publisher": "Canonical", "offer": "0001-com-ubuntu-server-jammy", "sku": "22_04-lts"),这时你确实需要手动修改azure.yaml中的 SKU 为24_04-lts并azd provision。
注意:
azd provision命令只更新基础设施(IaC),不重建应用。所以升级 VM OS 需两步:1. 修改azure.yaml中的sku;2. 运行azd provision。这比手动az vm image list+az vm update安全得多,因为azd会校验新镜像是否兼容现有磁盘和网络配置。
5. 常见问题与实战排障:那些文档里没写的“血泪教训”
5.1 经典报错:“Error: failed to get credentials for registry” —— Docker 登录失效
现象:azd up卡在阶段 3(构建镜像),报错failed to get credentials for registry,即使az login成功。
根因:azd使用 Azure Container Registry(ACR)作为镜像仓库,它需要az acr login获取临时 token。但azd的 token 缓存机制有时会失效,尤其在长时间未使用后。
解决:
# 1. 显式登录 ACR(替换 your-acr-name 为你的 ACR 名称) az acr login --name your-acr-name # 2. 清除 azd 缓存 azd cache clear # 3. 重试 azd up实操心得:我们在 CI/CD 的 runner 上,每次部署前都加一行
az acr login --name $(azd env get-values --query acrName -o tsv),确保 token 总是新鲜的。
5.2 “Connection refused” 错误:不是网络问题,是健康检查路径错了
现象:azd up成功,但访问https://my-app.azurewebsites.net返回503 Service Unavailable,日志显示Connection refused。
根因:azd默认的健康检查路径是/health,但你的 FastAPI 应用可能只暴露了/或/api/health。azd在阶段 5 会不断请求/health,超时后标记部署失败,但应用其实已运行。
解决:在azure.yaml中自定义健康检查路径:
services: api: project: ./src host: azure-web-app # 添加以下配置 healthCheckPath: "/api/health"然后运行azd provision更新基础设施(App Service 的 Health Check 设置)。
5.3 模型调用失败:“Authentication failed for Azure OpenAI” —— Key Vault 权限链断裂
现象:应用日志显示Authentication failed for Azure OpenAI,但AZURE_OPENAI_API_KEY在 Key Vault 中存在。
根因:azd为 App Service 创建的 Managed Identity,默认没有Get权限访问 Key Vault。虽然azd up会尝试授权,但在某些订阅策略下(如启用 Azure Policy 禁止Microsoft.KeyVault/vaults/accessPolicies/write),授权会静默失败。
排查:
# 1. 获取 App Service 的 Managed Identity 名称 az webapp identity show --name my-chatbot-dev --resource-group rg-my-chatbot-dev --query principalId -o tsv # 2. 检查 Key Vault 的访问策略 az keyvault show --name kv-my-chatbot-dev --query "properties.accessPolicies[?objectId=='<principalId-from-step1>']" -o json解决:如果返回空,则手动添加权限:
az keyvault set-policy \ --name kv-my-chatbot-dev \ --object-id <principalId-from-step1> \ --secret-permissions get5.4azd与az订阅冲突:为什么azd up部署到了错误的订阅?
现象:azd up成功,但资源出现在Production订阅,而你期望在Dev订阅。
根因:azd优先读取AZURE_SUBSCRIPTION_ID环境变量,其次读取az account show --query id -o tsv的输出,最后才用azd env get-values。如果AZURE_SUBSCRIPTION_ID被意外设置,azd会无视你az account set的选择。
解决:
# 1. 检查环境变量 echo $AZURE_SUBSCRIPTION_ID # Linux/macOS echo %AZURE_SUBSCRIPTION_ID% # Windows # 2. 如果存在,临时清除 unset AZURE_SUBSCRIPTION_ID # Linux/macOS set AZURE_SUBSCRIPTION_ID= # Windows # 3. 确认 az account az account show --query "{name:name, id:id}" -o table # 4. 再次 azd up实操心得:我们在团队中推行“环境变量白名单”,禁止在
.bashrc或.zshrc中设置AZURE_SUBSCRIPTION_ID,所有订阅切换通过az account set --subscription <id>完成,确保azd和az行为一致。
6. 进阶技巧:让azd成为你 AI 应用交付的“瑞士军刀”
6.1 环境隔离:用azd env管理 Dev/Staging/Prod
azd内置环境管理,比手动改azure.yaml安全百倍。创建 Staging 环境:
azd env new staging azd env set SUBSCRIPTION_ID "<staging-sub-id>" azd env set LOCATION "West US" azd upazd会自动:
- 创建新资源组
rg-my-chatbot-staging - 使用
staging后缀命名所有资源(my-chatbot-staging-webapp) - 将
staging环境的配置保存在.azd/environments/staging/.env中
切换环境只需:
azd env set-current staging azd deploy # 自动部署到 staging注意:
azd env不是 Git 分支,它是独立的配置快照。.azd/environments/目录应加入.gitignore,避免敏感信息泄露。
6.2 自定义模板:如何把内部 AI 模型服务封装成azd模板
假设你有一个私有 vLLM 服务,部署在 Azure VM 上。你想把它变成可复用的azd模板:
- 创建模板目录
templates/vllm-vm - 编写
azure.yaml:
name: vllm-vm metadata: template: vllm-vm@0.1.0 parameters: vmSize: type: string default: "Standard_NC6s_v3" services: vllm: type: azure-vm image: "Canonical:0001-com-ubuntu-server-jammy:22_04-lts:latest" size: "${parameters.vmSize}" # 自定义初始化脚本 customData: | #cloud-config runcmd: - apt-get update && apt-get install -y docker.io - docker run -d --gpus all -p 8000:8000 --shm-size=1g -e HUGGING_FACE_HUB_TOKEN=${secrets.HF_TOKEN} vllm/vllm-openai:latest --model meta-llama/Llama-2-7b-chat-hf- 将模板发布到内部 Git 仓库
- 团队成员使用:
azd init --template-url https://internal-git/vllm-vm
这样,每个项目都能用azd init -t vllm-vm一键获得预配置的 vLLM 服务,无需重复研究 GPU 驱动、Docker 参数。
6.3 与 GitHub Actions 深度集成:实现 PR 触发的预览环境
azd模板自带.github/workflows/azd-deploy.yml。我们增强它,实现“Pull Request 预览”:
name: Preview on PR on: pull_request: branches: [main] types: [opened, synchronize, reopened] jobs: preview: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Login to Azure uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Install azd run: curl -fsSL https://aka.ms/install-azd.sh | bash - name: Deploy Preview run: | export AZURE_ENV_NAME="pr-${{ github.event.number }}" azd env new $AZURE_ENV_NAME azd env set SUBSCRIPTION_ID "${{ secrets.AZURE_SUBSCRIPTION_ID }}" azd env set LOCATION "East US" azd up --no-prompt env: AZURE_ENV_NAME: "pr-${{ github.event.number }}" - name: Comment Preview URL run: | echo "Preview deployed: https://my-chatbot-pr-${{ github.event.number }}.azurewebsites.net" >> $GITHUB_STEP_SUMMARY每次 PR,都会创建一个独立的pr-123环境,URL 唯一,评审者可直接点击测试,合并后自动销毁(通过azd env down)。
我在实际使用中发现,azd最大的价值不是节省时间,而是消灭了“在我机器上是好的”这类沟通黑洞。当azure.yaml成为部署的唯一真相源,当azd up是团队里每个人都能执行的确定性操作,AI 应用的交付就从艺术变成了工程。它不承诺解决所有问题,但它把“部署”这件事,从一个需要资深 Azure 专家介入的高风险环节,降维成一个普通开发者敲几行命令就能完成的日常任务。这正是工具该有的样子——不喧宾夺主,却让主角(你的 AI 应用)毫无阻碍地登上舞台。