Azure Cost Management Forecast API Guardrails 实战指南:时间周期校验、训练数据要求与限流处理

原创2026-10-08 18:46:581,635 阅读

Azure Cost Management Forecast API Guardrails 实战指南:时间周期校验、训练数据要求与限流处理

本文以 packages/autoskills/skills-registry/azure-cost/cost-forecast/guardrails.md 为核心骨架,系统梳理 Azure Cost Management Forecast API 的完整校验规则与调用约束,并结合仓库内 cost-forecast 工作流、请求体 Schema、错误处理参考 及 Cost Query 工作流 进行纵深补充。读完本文,你将掌握预测请求的合法时间范围、训练数据门槛、分组限制、响应行数上限、includeActualCost/includeFreshPartialCost 依赖关系,以及 429 限流下的正确重试策略,从而在编码和 Agent 调用层面写出"一次通过校验"的 Forecast 请求。

1. 认识 Forecast API 的 Guardrails:为什么需要一套独立约束

Forecast API(POST {scope}/providers/Microsoft.CostManagement/forecast?api-version=2023-11-01)与 Cost Query API 在功能定位上完全不同:Query API 返回历史成本,而 Forecast API 返回未来预测成本。这决定了它有一套独立的、更严格的服务端校验规则——即本仓库中 azure-cost/cost-forecast/guardrails.md 记录的 "Forecast API Guardrails",其约束来源是 CCM-LUX 的 getForecastData 与 CCM-UX-MIDDLEWARE 的 Forecaster 组件。

从仓库的 主 SKILL.md 路由看,当用户表达"forecast costs / end of month estimate / how much will I spend"等意图时,应进入 Cost Forecast Workflow,而该工作流的 Step 3、Step 5 与 "Key Guardrails" 章节都会引用 guardrails 文档作为最终校验依据。理解这些规则,既能避免写出注定报 400 的请求体,也能在收到"预测不可用"这类合法但空结果的响应时正确引导用户回退到历史成本查询。

2. 时间周期校验:to 必须在未来

时间周期(timePeriod)是 Forecast 请求最容易被拒绝的字段,服务端按以下规则逐一校验:

规则 细节
to 日期必须在未来 numberOfDaysToForecast 必须 > 0;完全落在过去的时间范围会返回 CantForecastOnThePast 错误
from 可以在过去 当 from 在过去时,响应包含从 from 到今天的实际成本,以及从今天到 to 的预测成本
两个日期都必须合法 当 timePeriod 存在时,from 与 to 都必须是可解析的 ISO 8601 日期时间字符串
Monthly + includeActualCost 月粒度配合 includeActualCost=true 时必须显式提供带合法 from/to 的 timePeriod,否则报 DontContainsValidTimeRangeWhileMonthlyAndIncludeCost
最大预测周期 预测窗口最长 10 年

⚠️ 警告:如果 from 和 to 都在过去,API 直接返回 CantForecastOnThePast。至少 to 日期必须在未来。

在 request-body-schema.md 的字段参考中,timePeriod.to 被明确标注为"必须在未来",而 timePeriod.from 允许在过去以附带实际成本。对应地,workflow.md 的 Step 3 也给出了同样的要求:"to date MUST be in the future"、"from can be in the past — shows actual costs up to today, then forecast to to"。

一个常见的坑是"预测本月剩余天数"场景:from 设为月初(在过去),to 设为月末(在未来)。此时响应中的 Actual 行覆盖月初到今天的真实成本,Forecast 行覆盖剩余天数——这正是 examples.md 第一个示例的用法。而如果误把 to 也填成过去日期,则触发 CantForecastOnThePast(对应 HTTP 400)。

3. 训练数据要求:不足 28 天历史的订阅无法预测

预测模型依赖历史账单数据作为训练样本,因此存在硬性的数据门槛:

要求 值
最少历史数据 4 周(28 天)的成本数据
推荐训练窗口 最多 3 个月的历史
账单数据迟到容忍 2 天(等待账单数据到达)
新建订阅(< 28 天) 无法生成预测

⚠️ 警告:成本历史不足 28 天的新订阅无法生成预测。此时应建议改用 Cost Query 工作流(Part 1)(即 cost-query/workflow.md)获取已有的历史数据。

这条规则在 error-handling.md 中以 HTTP 424(Failed Dependency)体现:"Bad training data — forecast model cannot compute predictions"。注意区分两种表现:

  • 424 Bad training data:训练数据质量不足,属于错误响应;若 includeActualCost=true,服务端会回退到仅返回实际成本;
  • "Forecast is unavailable for the specified time period":这是合法响应(见第 6 节),表示预测模型无法在当前范围生成预测,返回空行而非错误。

4. 分组限制:grouping 字段在 Forecast 中不被接受

方面 细节
分组支持 ❌ 不支持
API 限制 这是 Forecast API 的硬性限制,请求体中不接受 grouping 字段
替代方案 如果用户请求分组预测(例如按资源组或按服务预测),应告知分组预测不可用,并建议改用 Cost Query 工作流(Part 1) 以分组方式查询历史数据

⚠️ 警告:即使通过 Cost Query 工作流(Part 1) 查询分组历史数据,ResourceId 分组也仅在订阅作用域及以下(subscription、resource group)受支持,在账单账户(billing account)、管理组(management group)及更高作用域均不支持。

这一限制在 workflow.md 的 Step 4 和"Key Differences from Query API"表格中被反复强调,并可通过 cost-query/guardrails.md 的 ResourceId 作用域矩阵交叉验证——Query API 中 ResourceId 分组同样只在订阅与资源组作用域可用,MCA/EA 的更高层级作用域一概不支持。因此在设计请求体时,Forecast 请求的 dataset 中不要包含 grouping 数组;如果确实需要按维度拆分预测,只能把预测拆成多个作用域(如逐订阅)分别请求,或先查历史分组数据作为参考。

5. 响应行数上限:40 行,日粒度请控制在 2~3 周内

约束 细节
最大行数 每次预测响应最多 40 行
日粒度反例 30 天实际 + 30 天预测 = 60 行 → 超出上限
建议 日粒度下预测周期保持在约 2~3 周
更长周期 改用月粒度以留在行数上限内

💡 提示:如果用户需要超过 2~3 周的日粒度预测,考虑拆分成多个更小的时间窗口,或改用月粒度。

这一点与 Query API 形成鲜明对比:cost-query/workflow.md 中 Query API 每页最多 5,000 行(默认 1,000 行),而 Forecast 的推荐上限是 40 行(见 workflow.md 的对比表 "Max response rows: 5,000/page vs 40 rows recommended")。由于预测响应没有分页机制,行数超限意味着数据被截断或请求不合规,因此日粒度 + 30 天窗口的组合(60 行)必然不可行,这是编写请求体时最容易踩的坑。推荐的实践是:

  • 日粒度:from 设为 2~3 周前,to 设为 2~3 周后的未来;
  • 更长窗口(如月末结算预测、季度预测):切换 Monthly 粒度,此时响应按 BillingMonth 输出月份行。

6. includeActualCost 与 includeFreshPartialCost 的依赖关系

字段 默认值 依赖
includeActualCost true 无
includeFreshPartialCost true 要求 includeActualCost=true

⚠️ 警告:仅设置 includeFreshPartialCost=true 而未设置 includeActualCost=true,会产生校验错误 DontContainIncludeActualCostWhileIncludeFreshPartialCost。两个字段必须总是显式设置。

结合 request-body-schema.md 的字段说明深入理解这两个预测专用选项:

  • includeActualCost:为 true 时,响应在 from 到今天的区间内附带历史实际成本行,与今天到 to 的预测行并列;为 false 时仅返回预测(投影)行。
  • includeFreshPartialCost:为 true 时,包含最近几天账单数据仍在到达中的部分(不完整)成本数据;它依赖 includeActualCost=true,因为部分成本行属于"实际成本"范畴。

两者都是 Forecast API 独有字段(request-body-schema.md 的对比表显示 Query API 不适用这两个字段),且默认值均为 true。在 workflow.md 的 Step 5 中,推荐的默认组合就是同时显式设置 includeActualCost: true 与 includeFreshPartialCost: true,既保证响应包含可用于对照的实际成本,也避免字段缺省引发的隐式行为。

7. "Forecast is unavailable":不是错误,而是合法空响应

当满足以下任一条件时,API 会返回 "Forecast is unavailable for the specified time period":

条件 细节
空/空值响应行 响应没有任何数据行
训练数据不足 作用域成本历史不足 28 天
无成本历史 作用域从未产生任何成本数据

⚠️ 警告:这不是错误——它是表示预测模型无法生成预测的合法响应。不要重试,而应建议改用 Cost Query 工作流(Part 1) 获取任何可用的历史数据。

这条规则对 Agent 自动化特别重要:很多自动化流程会把"无数据响应"当作故障反复重试,但在这里重试是无意义的——问题出在训练数据而非请求本身。在 error-handling.md 的"Forecast-Specific Scenarios"表中,这一场景被明确标注为"Valid response with null/empty rows",对应动作是引导用户使用 Cost Query 工作流。判断要点是响应状态码:200 + 空行 → 合法空预测;424 → 训练数据错误(可能回退实际成本);400 CantForecastOnThePast → 时间周期配置错误。

8. 限流:与 Cost Query API 共享的配额体系

8.1 限流阈值

Forecast API 与 Cost Query API 共享同一套限流配额:

限制 值
每用户(Per User) 每分钟 20 次请求
每作用域(Per Scope) 每分钟 4 次请求
每租户(Per Tenant) 每 10 秒 12 次、每分钟 60 次、每小时 600 次
每客户端类型(Per Client Type) 每分钟 2,000 次请求

⚠️ 警告:每作用域限制(4 次/分钟)是最严格的。对同一订阅、资源组或账单账户的连续查询共享这一配额。

8.2 限流响应头

发生限流时,响应携带以下 retry-after 头,分别对应不同的限流维度:

响应头 描述
x-ms-ratelimit-microsoft.costmanagement-qpu-retry-after 基于 QPU 的限流,等待秒数
x-ms-ratelimit-microsoft.costmanagement-entity-retry-after 实体/作用域级限流的等待秒数
x-ms-ratelimit-microsoft.costmanagement-tenant-retry-after 租户级限流的等待秒数

补充背景:QPU 配额存在层级差异——cost-query/guardrails.md 显示 Premium 层级(EA、MCA 企业级)拥有更高的 QPU 配额,非 Premium 层级(MOSP、试用)配额更低。

8.3 处理 429 响应的正确姿势

收到 429 响应时,必须检查响应中出现的所有 retry-after 头——多个头可能同时返回。取其中的最大值,并且在该时长完全经过之前不要重试。

⚠️ 警告:不要在 retry-after 时长耗尽前重试。过早重试会被拒绝,并可能延长限流时间。

这一策略在 SKILL.md 的最佳实践 和 error-handling.md 的重试策略 中完全一致:429 是唯一允许重试的状态码,且最多重试 3 次;其余状态码(400/401/403/404/424/503)一律不要重试,必须先修复请求或环境再重新发起。综合来看,调用预测接口时应按"小步慢走"策略组织:同一作用域的预测请求保持每分钟 ≤ 4 次,必要时把大窗口拆分为多个作用域或错峰提交。

9. 组合实战:构造一个"一次通过校验"的预测请求

把上述 Guardrails 汇总到 workflow.md 的请求体模板中,一个合规的预测请求应同时满足:to 在未来、from 可选在过去、至少 28 天历史、无 grouping、行数 ≤ 40(日粒度窗口 ≤ 2~3 周)、显式设置两个 include 字段:

{
  "type": "ActualCost",
  "timeframe": "Custom",
  "timePeriod": {
    "from": "<first-of-month>",
    "to": "<last-of-month>"
  },
  "dataset": {
    "granularity": "Daily",
    "aggregation": {
      "totalCost": { "name": "Cost", "function": "Sum" }
    },
    "sorting": [{ "direction": "Ascending", "name": "UsageDate" }]
  },
  "includeActualCost": true,
  "includeFreshPartialCost": true
}

执行命令(PowerShell):

New-Item -ItemType Directory -Path "temp" -Force

az rest --method post `
  --url "/subscriptions/<subscription-id>/providers/Microsoft.CostManagement/forecast?api-version=2023-11-01" `
  --headers "ClientType=GitHubCopilotForAzure" `
  --body '@temp/cost-forecast.json'

响应行的 CostStatus 列区分数据性质:Actual 表示历史实际成本(includeActualCost: true 时出现),Forecast 表示模型预测的未来成本;日粒度对应 UsageDate 列,月粒度对应 BillingMonth 列(详见 request-body-schema.md)。若需要更长窗口的月粒度示例(如未来 3 个月)、资源组作用域或账单账户作用域的完整请求体,可直接参考 examples.md。

10. 校验错误速查表

当请求被 400 拒绝时,从响应中的校验错误码即可定位问题。下表来自 error-handling.md,与 Guardrails 文档中的规则一一对应:

错误码 描述 修复
EmptyForecastRequestBody 请求体为空或 null 提供包含 type、timeframe、timePeriod、dataset 的完整请求体
InvalidForecastRequestBody 请求体 JSON 结构非法 检查 JSON 语法——括号、逗号、字段名
DontContainsDataSet 缺少 dataset 字段 添加包含 granularity 与 aggregation 的 dataset 对象
DontContainsValidTimeRangeWhileContainsPeriod 存在 timePeriod 但 from 或 to 非法 确保两个日期都是合法 ISO 8601 字符串
DontContainsValidTimeRangeWhileMonthlyAndIncludeCost 月粒度 + includeActualCost=true 但缺少合法 timePeriod 显式添加带合法 from/to 的 timePeriod
DontContainIncludeActualCostWhileIncludeFreshPartialCost includeFreshPartialCost=true 但 includeActualCost 未开启 设置 includeActualCost=true,或将 includeFreshPartialCost 设为 false
CantForecastOnThePast from 与 to 都在过去 确保 to 日期在未来

11. 小结:Guardrails 决策清单

在调用 Forecast API 之前,对照以下清单逐项自检,即可把大部分校验错误消灭在请求发出之前:

  1. 时间周期:to 必须在未来(numberOfDaysToForecast > 0);from 在过去时响应会附带实际成本;窗口不超过 10 年。
  2. 训练数据:作用域至少 28 天成本历史;新订阅请改用 Cost Query 工作流。
  3. 分组:Forecast 请求不带 grouping;分组需求回退到历史查询(ResourceId 分组仅限订阅及以下作用域)。
  4. 行数:响应上限 40 行;日粒度窗口约 2~3 周,更长用月粒度。
  5. 字段依赖:includeActualCost 与 includeFreshPartialCost 显式成对设置,默认均为 true。
  6. 空预测:"Forecast is unavailable" 是合法响应,不要重试,回退到历史查询。
  7. 限流:共享 Cost Query 配额(每作用域 4 次/分钟最严);429 时取所有 retry-after 头的最大值等待,最多重试 3 次,其余状态码不重试。

完整的校验规则原稿见 guardrails.md,其与 workflow.md、request-body-schema.md、error-handling.md、examples.md 共同构成 azure-cost 技能中完整的 Forecast 预测能力闭环。

登录后查看全文
autoskills