
做 Azure OpenAI 项目踩过的最大的坑不是模型效果不好而是月底账单出来的时候你根本看不懂钱到底花在了哪。尤其当业务量上来之后一个没加任何控制的部署就能让你在几天内用掉预算的大半。Azure OpenAI 的费用管控和全维度监控是每一个架构师都绕不开的必修课。这篇文章就把我自己的实操经验完整地捋一遍包括成本拆解、预算配额、监控指标、日志分析、告警配置以及踩过的那些坑希望对正在做相关架构设计的你有帮助。注意文中所有查询语句和配置步骤均基于我个人的实际项目经验整理不同环境下的字段名和入口位置可能略有差异建议结合你自己的资源组实际情况做适配。1. 为什么 Azure OpenAI 费用这么难控1.1 计费模型拆解先搞清楚我们是在为什么付钱。Azure OpenAI 的核心计费维度有两个一个是按 Token 数量计费一个是按预留吞吐量计费。按 Token 计费很好理解就是每次调用时输入多少 Token、输出多少 Token分别按模型单价累计。这里的关键在于输入和输出价格不一样输出 Token 通常比输入 Token 贵不少所以“模型话痨”直接决定成本。另一个维度是预留吞吐Provisioned Throughput UnitPTU。PTU 是包小时计费的类似云数据库的预购算力适合对延迟和吞吐有稳定要求的生产环境。它的好处是费用可控、可预期但坏处是即便没有任何请求每个小时也在花钱。还有一个容易被忽略的点Token 不是按“字数”算的而是按 Token 数算的。中文字符在切词器里通常一个字就要吃一两个 Token一段 1000 字的中文 prompt 产生的 Token 数远高于同长度的英文。所以同样一套参数中文场景的实际费用可能比英文场景高出 30% 到 50%。1.2 费用失控的典型场景我接手过不少“账单惊吓”案例几乎无一例外都踩了这些坑。第一没有限制max_tokens。默认配置下模型会一直生成到满足条件为止一个简单问答输出 5000 个 Token 也是常有的事。用户问一句“帮我介绍下这个产品”结果模型在那边洋洋洒洒写作文钱翻着倍地涨。第二上下文无限制累加。很多同学做多轮对话时把所有历史消息全部每次都发给模型。userId 稍微多几个同一会话聊半小时每条消息的上下文可能已经膨胀到几万 Token而这个开销是不知不觉累加的。第三重试机制造成的放大效应。SDK 默认遇到限流会重试如果部署的配额设得很低团队又习惯性把重试次数拉满一次业务峰会直接打爆配额而且每次重试都会重新计费。我见过一个白天的流量高峰因为 429 导致重试 4 次单次请求翻了 5 倍成本。第四模型选型太贵。很多场景明明 GPT-4o mini 就能搞定却统一用了旗舰模型。我们后来做过统计只要把文本分类、信息抽取这类任务切换到更经济的模型成本直接降下来七成。所以费用管控的第一原则就是先搞清楚钱是怎么流失的再谈怎么堵住漏洞。2. 费用管控预算、配额与限流三板斧2.1 预算设置让账单提早预警Azure 原生提供的成本管理工具Cost Management里可以创建预算Budget。预算的作用不是“限制消费”而是“提前通知”。我建议你至少在订阅级别或者资源组级别设置两层预算一层是月度总预算比如 5 万另一层是按模型的成本预算比如 GPT-4o 这个部署月费用不能超过 2 万。预算可以设置多个阈值例如 50%、80%、100%、120%每个阈值都可以绑定不同的操作组。操作组的配置很关键。预算告警默认只是发邮件但企业环境里最好把行动组接到 Webhook 或者 ITSM 工单系统让相关责任人第一时间收到通知。我曾经因为只发了邮件结果告警躺在运维邮箱里一个星期没人看等到发现的时候预算已经超了 40%。预算本身不拦请求它只是感知层。但感知层做到位了配合下面的配额和代码层控制才能形成完整的闭环。2.2 配额管理从源头限制消耗Azure OpenAI 的配额有两类值得关注一个是模型部署的每分种请求数Requests per MinuteRPM另一个是每分种 Token 数Tokens per MinuteTPM。很多人用默认配额觉得“没关系反正够用”。实际上默认配额往往偏高而且不设配额的结果就是某个下游脚本失控时单分钟就能烧掉整天的预算。正确的做法是每个部署根据预估流量设置一个合理的 TPM。怎么估算拿生产环境举例假设你预估高峰期每分钟有 100 个用户请求每个请求平均输入 1500 Token、输出 800 Token那你需要的就是每分钟 (100 × 1500 100 × 800) 23 万 Token 的处理能力。但考虑到输出 Token 是按增量逐步计费的配额模型里输入和输出共享 TPM 额度所以我会在这个基础上乘一个 1.2 的冗余系数把 TPM 设置到 27.6 万左右。这样做的价值在于即使代码层失控配额也会像保险丝一样自动熔断最多影响一段时间的请求成功率但不会让你一夜回到解放前。2.3 代码层限流客户端兜底配额是平台侧的保险丝代码层还得有一个节流阀。为什么因为 429 限流一旦触发如果客户端没有兜底用户看到的错误会直接上升到生产事故。我们项目的做法是在调用层做两层控制第一层是内存令牌桶限制每个用户每分钟最多能调 10 次第二层是队列缓冲超过阈值的请求直接排队而不是立即重试。这相当于在云平台限流之前我们自己先做了一轮流量整形。写到这儿顺便提一句那个重试策略一定要设置上限而且重试遇到 429 时要加指数退避和抖动。否则限流时你疯狂重试不仅消耗请求次数还会因为重试期间的重复计算增加 Token 消耗。2.4 成本分析看懂账单的钱花在哪儿Azure 门户的 Cost Analysis 里可以看到按资源、按服务、按标记聚合的消费明细。我强烈建议给每个 OpenAI 部署打上清晰的标签例如appcustomer-service、modelgpt-4o-mini、envprod。不打标签的云资源费用分析就是一锅粥。用标签聚合之后你能一眼看出哪个应用是花钱大头。我们之前就发现一个内部工具一个月只被三个人用结果占了 OpenAI 费用的 23%。后来做了一次模型降级和调用频次限制这块费用从 23% 降到了 4%。想再进一步还可以启用 Azure 成本管理的“按资源组导出”功能把成本明细每天自动导出到存储账号再丢进 Power BI 或者自家报表平台做多维度分析。这个习惯一旦建立起来月底复盘就变得非常轻松。3. 全维度监控体系总览与搭建3.1 监控的三个层次费用管控是“果”真正的“因”在于你能不能实时掌握调用行为。我把 Azure OpenAI 的监控拆成三个层次第一层是平台指标Metrics。Azure AI 服务在 Azure Monitor 里自带一组指标例如“处理过的推理 Token 数”“生成补全 Token 数”“Token 交易次数”“客户端缓存命中数”“延迟”“异常数”等。这些指标通过监控面板就能看不需要额外开发适合做一线告警。第二层是诊断日志Diagnostic Logs。开启诊断设置之后每个请求的调用详情会流入 Log Analytics、存储账号或事件中心。这层数据最全能看到谁在调、调了哪个模型、Token 消耗多少、返回码是什么是成本归因和故障排查的核心数据源。第三层是应用追踪Application Insights。平台日志反映的是“平台视角”但如果你想导出每个用户端的提示词、响应内容、或者是微服务调用链里的延迟分布就得靠 App Insights 或 OpenTelemetry 埋点。这层数据能回答“哪些业务流程在调用 AI”“调用前后的业务转化如何”是优化成本结构的终极依据。这三层数据各司其职缺一不可。只做第一层的项目遇到问题只能仰卧起坐干瞪眼三层全做的项目连某个模型在某天某个时段的 Token 消耗趋势都能翻出来。3.2 开启平台指标与诊断日志实际操作时你只需要在 Azure 门户找到 AI 服务资源进入“诊断设置”然后新建一条诊断配置把日志流向 Log Analytics 工作区即可。建议勾选Audit和RequestResponse两类日志前者记录管理操作后者记录每个请求和响应的详细元数据。这个过程有几个人容易忽略的细节第一日志要和工作区放在同一个区域跨区域传输会额外产生网络费用虽然不多但没必要。第二建议把“资源日志”里所有类别先全部勾上跑几天再从实际数据里筛选真正有用的类别。Azure OpenAI 相关的日志类别本身不多漏掉某个类别后面再想补数据只能从开启那天重新积累。第三不要只留一个日志目的地。Log Analytics 负责查询和分析存储账号负责长期归档事件中心负责对接外部 SIEM。至少要有前两个否则等审计需求来了才想起来数据早就过了保留期。3.3 Application Insights 埋点实战平台日志有了但如果你是做企业级应用你大概率还需要知道“是哪个用户发起了调用”。这个需求平台日志满足不了因为 AI 服务的日志里只有客户端 IP 和调用方标识不会暴露业务侧的用户信息。在我做过的项目里最稳妥的埋点方式是通过 SDK 侧的自定义事件上报。每一次调用之前生成一个ConversationId随请求一起传入调用结束之后把ConversationId、模型名、输入 Token 数、输出 Token 数、耗时、错误码作为自定义维度写入 App Insights。这样你在做成本分析时可以直接按业务维度聚合比如“全部客户咨询消耗了多少 Token”“某个大客户贡献了多少成本”。这一点对后续做成本分摊和产品定价极其重要。埋点时不光要记录成功请求失败请求的 Token 消耗也要记录。别以为失败就不花钱很多时候重试的失败请求消耗的 Token 比一次成功请求还多。4. 用 KQL 把调用行为“打捞”出来4.1 AzureDiagnostics 基础查询日志都进了 Log Analytics之后就轮到 KQL 出场了。Azure OpenAI 的请求类日志一般落在AzureDiagnostics表里我以一个最常用的总览查询作为模板AzureDiagnostics | where ResourceProvider MICROSOFT.COGNITIVESERVICES | where Category RequestResponse | where OperationName has openai | extend model tostring(parse_json(properties_s).configuration.model) | extend prompt_tokens toint(parse_json(properties_s).usage.prompt_tokens) | extend completion_tokens toint(parse_json(properties_s).usage.completion_tokens) | extend total_tokens toint(parse_json(properties_s).usage.total_tokens) | project TimeGenerated, OperationName, ResultSignature, model, prompt_tokens, completion_tokens, total_tokens, Uri | order by TimeGenerated desc | take 100这个查询能把最近 100 次调用的模型、Token 消耗、返回状态全部拉出来。由于日志里部分字段是 JSON 结构需要用parse_json和extend把它们展开成独立列。不同 SDK 版本上报的字段名可能不一样建议先跑一条不带extend的原始查询看清properties_s里实际有哪些字段再根据实际字段名调整。4.2 按模型和时段聚合成本总览查询只是热身真正能帮你管钱的是聚合查询。我一般会做下面这个“按小时、按模型”的 Token 消耗统计AzureDiagnostics | where ResourceProvider MICROSOFT.COGNITIVESERVICES | where Category RequestResponse | where OperationName has openai | extend model tostring(parse_json(properties_s).configuration.model) | extend total_tokens toint(parse_json(properties_s).usage.total_tokens) | where total_tokens 0 | summarize totalTokenCount sum(total_tokens), requestCount count(), avgTokensPerRequest avg(total_tokens) by bin(TimeGenerated, 1h), model | order by totalTokenCount desc这个查询的结果可以直接画成时间序列图能立刻看出哪个模型在哪个时段消耗异常。我遇到过一种典型情况白天一切正常晚上某个定时任务开始批量处理历史数据Token 消耗一路狂飙而这个任务其实并不需要调用旗舰模型。这种问题不看按小时聚合的报表根本发现不了。再进阶一点按用户维度聚合也很实用只需要在extend部分把ConversationId或者自定义字段加进来。但前提是你在诊断日志里写入了这些字段。如果之前没做那就只能回到 App Insights 的数据里查。4.3 关联其他系统日志做根因定位成本监控不只是看 Token 本身还得跟系统行为关联起来。比如某个时段延迟飙升可能不是 OpenAI 的问题而是你业务系统的并发线程池打满了。这时候可以把 App Insights 的requests表和 Log Analytics 的AzureDiagnostics表做一个关联查询let aiRequests cluster(ai-log-workspace).database(AppInsights).requests | where timestamp ago(1d) | summarize count() by bin(timestamp, 5min), operation_Name; AzureDiagnostics | where TimeGenerated ago(1d) | where Category RequestResponse | summarize latencyP95 percentile(DurationMs, 95), requestCount count() by bin(TimeGenerated, 5min) | join kindinner aiRequests on $left.TimeGenerated $right.timestamp | project TimeGenerated, requestCount, latencyP95, aiRequests跨资源查询的语法在不同环境里略有差异核心思路就是把两边的时间戳对齐看业务请求量和平台延迟是否同步涨落。这一步能帮你区分到底是模型变慢了还是你自己的应用变慢了。5. 告警设置与推送把问题消灭在爆发前5.1 指标告警盯住关键阈值指标告警是最灵敏的一层。我会在 Azure Monitor 里围绕以下几个指标各建一条告警规则Processed Inference Tokens超过预设的分钟阈值例如每分钟超过 10 万 Token说明有突发流量或者代码失控。Throttled Requests大于 0代表平台开始限流需要立刻排查是配额设太低还是调用异常。Latency的 P95 超过 3 秒说明用户体验可能受损。告警阈值不是拍脑袋定的我建议先用一周时间采集基线数据再以“正常峰值的 120%”作为阈值。比如正常情况下每分钟 Token 峰值为 6 万那告警阈值就设在 7.2 万既不会天天误报也能在异常出现时及时提醒。5.2 日志告警用 KQL 捕捉异常模式有一些问题无法用天然指标覆盖比如“某个模型部署突然没有请求了”“错误码 400 的比例飙升”。这些场景就用日志搜索告警。我做过一个很经典的日志告警用来检测“连续失败请求”。查询逻辑如下AzureDiagnostics | where ResourceProvider MICROSOFT.COGNITIVESERVICES | where Category RequestResponse | where ResultSignature 429 | summarize blockedCount count() by bin(TimeGenerated, 5min), Deployment tostring(parse_json(properties_s).configuration.deployment) | where blockedCount 50当 5 分钟内某个部署的 429 超过 50 次就触发告警。这种告警比指标告警多一层上下文能直接告诉你故障点是哪个部署、哪个模型。把告警绑定到行动组后可以选邮件、短信、Webhook 三种通道。微信/钉钉/飞书的应用机器人通过 Webhook 接入是最常用的做法配置一次之后告警能直接推送到工作群响应速度明显比邮件快。5.3 告警噪音治理告警配置完了紧接着就是噪音治理。这方面我交过不少学费敲几个重点第一避免“单人告警”。所有告警至少发给三个人否则某个人请假时故障就石沉大海。第二区分严重级别。比如 P95 延迟超过 3 秒只能算“警告”429 比例超过 10% 才算“严重”。分级的意义在于控制响应优先级避免所有告警都半夜拉人起来而疲惫不堪。第三设置告警抑制。当同一种告警在短时间内反复触发时只发一条通知即可后续通知等冷却期结束再发。否则一个故障就能炸出几十条消息真正的关键信息反而被淹没。6. 常见问题与排查技术实录6.1 预算超了但一个告警都没收到这个坑我踩过不止一次。预算告警配置在成本管理模块里但成本数据的刷新频率很低通常要到第二天才能看到前一天的消费。这意味着你看到的“预算未超”往往是昨天的数据今天可能已经超了。解决办法是不要把预算告警当成唯一防线。预算告警之外还必须叠加指标告警和日志告警做到“分钟级感知”。预算负责粗粒度地控制月度总盘子指标告警负责实时拦截异常尖峰。6.2 诊断日志里面没有 Token 字段很多人开了诊断日志之后兴冲冲跑去 Log Analytics 查 Token 消耗结果发现日志里压根没有usage字段。我最早也遇到过这个问题后来才明白这是因为部分 AI 服务资源的诊断日志默认类别里RequestResponse日志并不会记录所有请求的响应体而是只记录请求行的一些元数据。解决的办法有两个方向一是升级到新版 AI 服务资源类型新版资源在RequestResponse日志里通常具备更完整的请求/响应信息二是在应用层自己埋点把 SDK 返回的usage数据显式写入customEvents。如果预算允许也可以直接启用 OpenAI 服务自带的“内容与指标输出”配置定期导出 Prompts 和 Completions 的分析结果但这些功能的开启路径随服务版本而异需要按实际资源版本确认。6.3 配额突然降了全站请求 429置信度最高的锅往往是“谁偷偷调低了配额”。我经历过一次生产事故排查到最后发现是有同事在门户上调整部署的 TPM 限额从 30 万调到了 5 万结果第二天高峰全线超限。这种问题根因是权限管控太松。Azure 的资源权限模型里建议把“能够调整 OpenAI 配额”的权限收敛到架构师或者运维负责人角色普通开发只给“贡献者”级别但不要给配额修改权限。另外在做变更之前先看看这个部署的最近 7 天峰值是多少调整后的 TPM 必须覆盖 1.5 倍峰值流量否则一改一个准。6.4 日志保留期太短回溯无从下手Log Analytics 的默认日志保留期可能是 30 天但如果你的项目有审计需求这个保留期根本不够。查询的时候发现半年前的调用日志早就被清了那叫一个无奈。建议在 Log Analytics 工作区里单独配置数据保留策略重要工作区可以按年保留同时把诊断日志导出到存储账号做冷备。存储账号的成本很低一年的归档成本可能还不如几十万 Token 调用贵。7. 实操中的几个通用心得做完这一整套费用管控和监控体系之后我最大的感受是不要试图一次性把所有东西全部配齐而要像剥洋葱一样一层层地来。第一步先把预算和配额设好。这一步能最大程度避免账单失控属于保命级别。第二步开启平台指标和诊断日志。先把能看到的看全再把 KQL 查询模板跑通。第三步做应用层埋点和告警推送。这一步开始深入到业务维度能支撑成本分摊和容量规划。最后一步把常见的查询固化成仪表盘和定期报表让团队形成月底复盘的习惯。仪表盘我建议至少放四个图按日 Token 消耗总览、按模型消耗占比、P95 延迟趋势、429 错误率。这四个图能覆盖日常运维的绝大部分场景。把这套东西沉淀到团队里之后阿里那种“月底才发现超预算”的被动局面就不会再出现了。再分享一个小技巧KQL 查询模板一定要用 Azure 工作簿Workbooks保存下来并且共享给团队。我见过很多人每次排查问题都现场写查询效率很低。把“按小时聚合”“按模型聚合”“按用户聚合”“错误排查”这几个模板固化到工作簿里新同学入职第二天就能自己上手排查不必拉着老人反复问。这套运维资产的价值比写多少篇文档都实在。