autoskills 实战:Azure Cost Management Forecast API 预测请求示例与 Scope URL 完整指南

原创2026-10-08 18:45:431,974 阅读

autoskills 实战:Azure Cost Management Forecast API 预测请求示例与 Scope URL 完整指南

导读

本篇文章基于 autoskills 仓库中 azure-cost 技能包(skills-registry/azure-cost)下的成本预测(cost-forecast)模块编写,系统讲解 Microsoft Cost Management Forecast API 的典型请求体(request body)写法、Scope URL 拼装规则、响应解读与边界约束。读完本文,你将掌握:如何用一条 az rest 命令预测当月剩余成本、预测未来 3 个月账单、在资源组与计费账户等不同 Scope 下发起预测请求,以及如何规避 40 行响应上限、28 天训练数据要求等关键 Guardrails。所有示例均可在安装了 autoskills 的环境中直接落地使用。


一、Forecast API 是什么:与 Query API 的本质区别

在动手写请求体之前,先明确 Forecast API 的定位。autoskills 的 azure-cost/SKILL.md 将成本管理拆成三条工作流:查询历史成本(Cost Query)、优化成本(Cost Optimization)、预测未来成本(Cost Forecast)。当用户提出"本月月底大概要花多少钱""未来三个月的账单趋势"这类问题时,应进入第三条工作流,其入口即 cost-forecast/workflow.md。

Forecast API 与 Query API 的关键差异如下表(摘自 workflow.md):

方面 Query API Forecast API
用途 历史成本数据 预测未来成本
时间范围 仅过去日期 必须包含未来日期
分组(Grouping) 最多 2 个维度 不支持
includeActualCost 不适用 在预测旁附带历史实际成本
响应列 Cost、Date、Currency Cost、Date、CostStatus、Currency
每页最大响应行数 5,000 行 建议 40 行以内
Timeframe 多种预设 + Custom 通常仅 Custom

⚠️ 注意:如果用户要的是历史成本数据,应走 Cost Query Workflow;如果要省钱,应走 Cost Optimization Workflow。Forecast API 只回答"未来会花多少"。


二、请求前的准备:Scope、角色与执行命令

2.1 权限要求

调用 Forecast API 需要在目标 Scope 上具备 Cost Management Reader 角色(或更高权限)。缺少该角色时 API 返回 403 Forbidden(详见 error-handling.md)。这也是 SKILL.md 中列出的 Required Role:Cost Management Reader + Monitoring Reader + Reader on scope。

2.2 端点与执行方式

Forecast API 端点与 Query API 结构一致,仅资源类型不同:

POST {scope}/providers/Microsoft.CostManagement/forecast?api-version=2023-11-01

autoskills 的最佳实践是使用 az rest 携带 JSON 请求体执行(比 az costmanagement forecast 子命令更可靠,且需带上 ClientType: GitHubCopilotForAzure 请求头):

# 先创建存放请求体的目录
New-Item -ItemType Directory -Path "temp" -Force

# 执行预测请求(以订阅 Scope 为例)
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'

完整的七步工作流(确定 Scope → 选择报告类型 → 设置时间范围 → 配置 dataset → 设置预测专属选项 → 构造并执行 → 解读响应)见 cost-forecast/workflow.md。


三、四种常见预测请求体(核心示例)

以下示例直接继承自 cost-forecast/examples.md,并补充了字段说明,可直接复制使用。

示例 1:预测当月剩余成本(按天粒度)

这是最常见的场景:想知道"这个月到目前为止花了多少、月底预计总共花多少"。将 from 设为本月第一天,to 设为本月最后一天,响应中会包含从月初到今天的历史 Actual 行,以及今天到月末的 Forecast 行。

{
  "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
}

💡 Tip:把 from 设为月初,响应就会包含到今天为止的 Actual 行与剩余天数的 Forecast 行,天然构成"实际 + 预测"的完整月度视图。

示例 2:预测未来 3 个月(按月粒度)

月度粒度的预测适合做中长期账单规划。注意按月粒度时排序字段要使用 BillingMonth 而非 UsageDate。

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

💡 Tip:Monthly 粒度下,响应中的日期列名为 BillingMonth(参见 request-body-schema.md)。

示例 3:资源组 Scope 预测

Scope 是通过 URL 层级控制的,请求体本身无需任何 scope 字段。若只想预测某个资源组的成本,把 URL 中的 scope 段替换为资源组即可:

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

💡 Tip:Scope 设在 URL 层。使用资源组 Scope URL 即可把预测范围限定在该资源组内。

示例 4:计费账户(Billing Account)Scope 预测

企业级场景下,财务团队往往需要在计费账户层面预测整体支出。此时 URL 使用 /providers/Microsoft.Billing/billingAccounts/<id>/... 前缀,并建议使用 Monthly 粒度(行数更少、更符合财务汇报周期):

{
  "type": "ActualCost",
  "timeframe": "Custom",
  "timePeriod": {
    "from": "<start-date>",
    "to": "<end-date>"
  },
  "dataset": {
    "granularity": "Monthly",
    "aggregation": {
      "totalCost": { "name": "Cost", "function": "Sum" }
    },
    "sorting": [
      { "direction": "Ascending", "name": "BillingMonth" }
    ]
  },
  "includeActualCost": true,
  "includeFreshPartialCost": true
}

💡 Tip:URL 模式为 /providers/Microsoft.Billing/billingAccounts/<id>/...。计费账户级预测推荐使用 Monthly 粒度。


四、Scope URL 参考表与拼接规则

以下 Scope URL 模式表直接继承自 cost-forecast/examples.md:

Scope URL 模式
订阅 Subscription /subscriptions/<subscription-id>/providers/Microsoft.CostManagement/forecast
资源组 Resource Group /subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.CostManagement/forecast
计费账户 Billing Account /providers/Microsoft.Billing/billingAccounts/<id>/providers/Microsoft.CostManagement/forecast

⚠️ 注意:上表只是路径片段(path-only patterns),不是完整 URL。构造完整请求地址时,需要在末尾追加查询参数 ?api-version=2023-11-01,并配合 az rest --url 或完整 HTTPS 地址使用。

主技能 SKILL.md 还提供了完整的 Scope 路径参考(共五种 Scope),可供交叉引用:

Scope URL 模式
订阅 /subscriptions/<subscription-id>
资源组 /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>
管理组 /providers/Microsoft.Management/managementGroups/<management-group-id>
计费账户 /providers/Microsoft.Billing/billingAccounts/<billing-account-id>
计费档案 /providers/Microsoft.Billing/billingAccounts/<billing-account-id>/billingProfiles/<billing-profile-id>

五、请求体字段逐项解析

为了写出可预测、可调试的请求体,需要吃透 request-body-schema.md 中的字段表。以下是完整字段参考(继承自原文档):

字段 类型 必填 取值 说明
type string ✅ ActualCost、AmortizedCost、Usage 预测的成本类型
timeframe string ✅ Custom 预测请求必须为 Custom
timePeriod object ✅ — 预测窗口的起止日期
timePeriod.from string ✅ ISO 8601 日期时间 起始日期;可以在过去(用于包含实际成本)
timePeriod.to string ✅ ISO 8601 日期时间 结束日期;必须为未来日期
dataset object ✅ — 预测的 dataset 配置
dataset.granularity string ✅ Daily、Monthly 预测结果的时间粒度
dataset.aggregation object ✅ — 应用的聚合函数
dataset.aggregation.totalCost.name string ✅ Cost 要聚合的列名
dataset.aggregation.totalCost.function string ✅ Sum 聚合函数
dataset.sorting array 可选 — 结果的排序方式
dataset.sorting[].direction string 可选 Ascending、Descending 排序方向
dataset.sorting[].name string 可选 UsageDate 排序所依据的列
dataset.filter object 可选 — 过滤表达式(dimensions/tags)
includeActualCost boolean 可选 true、false 是否在预测旁包含历史实际成本,默认 true
includeFreshPartialCost boolean 可选 true、false 是否包含最近几天尚未结算完全的"部分成本"数据,默认 true,依赖 includeActualCost=true

5.1 预测专属字段:includeActualCost

  • 类型:boolean,默认 true;
  • 为 true 时,响应包含从 from 日期到今天的历史实际成本行(CostStatus=Actual),以及从今天到 to 日期的预测行(CostStatus=Forecast);
  • 为 false 时,只返回预测(projected)行。

5.2 预测专属字段:includeFreshPartialCost

  • 类型:boolean,默认 true;
  • 为 true 时,会包含最近几天计费数据仍在到达中的部分成本数据;
  • ⚠️ 依赖约束:设置 includeFreshPartialCost=true 而 includeActualCost=false 会产生校验错误 DontContainIncludeActualCostWhileIncludeFreshPartialCost。

5.3 可选过滤:dataset.filter

当预测范围太大(如整个订阅)而只想看某个资源组时,除了在 URL 层切换 Scope,还可以在请求体内加过滤。完整的带过滤请求体示例:

{
  "type": "ActualCost",
  "timeframe": "Custom",
  "timePeriod": {
    "from": "2024-01-01T00:00:00Z",
    "to": "2024-03-31T00:00:00Z"
  },
  "dataset": {
    "granularity": "Daily",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    },
    "sorting": [
      {
        "direction": "Ascending",
        "name": "UsageDate"
      }
    ],
    "filter": {
      "dimensions": {
        "name": "ResourceGroupName",
        "operator": "In",
        "values": ["my-resource-group"]
      }
    }
  },
  "includeActualCost": true,
  "includeFreshPartialCost": true
}

filter 支持 dimensions(内置维度,如 ResourceGroupName、ServiceName)与 tags(资源标签)两种目标类型,以及 In、Equal、Contains、LessThan、GreaterThan、NotEqual 等比较运算符(完整枚举见 cost-query/request-body-schema.md)。


六、响应结构解读:CostStatus 是关键

6.1 响应列

列 类型 说明
Cost Number 成本金额(实际或预测)
UsageDate / BillingMonth Datetime 成本所在日期
CostStatus String 标识该行是历史还是预测
Currency String 货币代码(如 USD、EUR)

6.2 CostStatus 取值

值 含义
Actual 历史实际成本(已发生)
Forecast 预测的未来成本(模型预测)

6.3 粒度与日期列映射

粒度 日期列
Daily UsageDate
Monthly BillingMonth

💡 Tip:响应的解读要点——如果 includeActualCost=true,同一份响应里 Actual 行帮你核对已发生支出,Forecast 行给你模型预测,"实际 + 预测"共同构成对账单周期的完整估计。


七、必须遵守的 Guardrails(边界约束)

预测请求比查询请求有更多硬性约束,全部细节见 cost-forecast/guardrails.md。核心规则如下:

7.1 时间范围校验

规则 细节
to 日期必须在未来 预测天数必须 > 0;全部为过去日期的区间会返回 CantForecastOnThePast 错误
from 可以在过去 from 在过去时,响应包含从 from 到今天的历史实际成本与从今天到 to 的预测
两个日期都必须合法 timePeriod 存在时,from、to 必须是可解析的 ISO 8601 日期时间字符串
Monthly + includeActualCost Monthly 粒度配合 includeActualCost=true 时必须显式给出合法 timePeriod,否则报 DontContainsValidTimeRangeWhileMonthlyAndIncludeCost
最大预测区间 最多 10 年

7.2 训练数据要求(28 天门槛)

要求 值
最少历史数据 4 周(28 天)的成本数据
推荐的训练窗口 最多 3 个月历史
计费数据晚到容忍度 2 天
新订阅(< 28 天) 无法生成预测

⚠️ Warning:历史不足 28 天的新订阅无法生成预测。此时 API 会返回 "Forecast is unavailable for the specified time period"——这不是错误,是模型数据不足的合法响应,不要重试,应改用 Cost Query Workflow 获取已有的历史数据。

7.3 分组(Grouping)不支持

Forecast API 不接受 grouping 字段,这是硬性限制。如果用户想要"按资源组/服务分组的预测",应告知其不可用,并建议改用 Query API 查询带分组的历史数据。

7.4 响应行数上限:40 行

约束 细节
最大行数 每次预测响应 40 行
Daily 反例 30 天实际 + 30 天预测 = 60 行 → 超限
建议 Daily 粒度下预测窗口控制在 2~3 周以内
更长区间 改用 Monthly 粒度以保持在行数上限内

💡 Tip:如果需要超过 2~3 周的按天预测,可以把请求拆成多个较小的时间窗口,或切换为 Monthly 粒度。

7.5 速率限制(Rate Limiting)

Forecast API 与 Query API 共享同一套速率限制:

限制 值
每用户 每分钟 20 个请求
每 Scope 每分钟 4 个请求
每租户 每 10 秒 12 个、每分钟 60 个、每小时 600 个
每客户端类型 每分钟 2,000 个请求

⚠️ Warning:per-scope 限制(4 请求/分钟)最严格。对同一订阅、资源组或计费账户的连续查询共享该限制。

遇到 429 响应时,检查响应中所有 x-ms-ratelimit-microsoft.costmanagement-*-retry-after 头(qpu-retry-after、entity-retry-after、tenant-retry-after),取最长的值等待,在时长完全过去之前不要重试,最多重试 3 次。


八、错误处理速查

8.1 HTTP 状态码

状态 错误 原因 补救
400 Bad Request 请求体非法、缺少 dataset、日期全在过去、字段依赖组合非法 检查请求体结构;确保 to 在未来;核对 includeActualCost/includeFreshPartialCost 依赖
401 Unauthorized 认证失败——令牌缺失或过期 重新 az login 或刷新访问令牌
403 Forbidden Scope 上权限不足 确保身份在目标 Scope 上具有 Cost Management Reader 角色
404 Not Found Scope URL 非法——订阅、资源组或计费账户不存在 核对 Scope URL 路径与资源 ID
424 Failed Dependency 训练数据质量差——预测模型无法计算 若 includeActualCost=true 则回退为实际成本;否则建议走 Query 工作流
429 Too Many Requests 被限流——QPU、entity 或 tenant 配额超限 检查所有 x-ms-ratelimit-microsoft.costmanagement-*-retry-after 头,等待最长值后重试
503 Service Unavailable 服务临时不可用 检查 Azure 服务状态页

8.2 校验错误码参考

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

8.3 重试策略

状态 是否重试 策略
429 ✅ 是 读取全部 retry-after 头,取最长值,等待完全过去后再试;最多 3 次
400 ❌ 否 依据校验错误码修复请求体
401 ❌ 否 重新认证
403 ❌ 否 授予 Cost Management Reader 角色
404 ❌ 否 修正 Scope URL
424 ❌ 否 训练数据问题,重试无意义;回退实际成本或走 Query 工作流
503 ❌ 否 检查服务状态,稍后重试

⚠️ Warning:除 429 外,其他错误都不要重试——它们都表示需要在重发请求前修复的问题(完整说明见 error-handling.md)。


九、在 autoskills 中如何运用这些示例

autoskills 仓库以"One command. Your entire AI skill stack. Installed."为理念,azure-cost 技能包由主入口 SKILL.md 与三条工作流组成,其中 cost-forecast 目录下包含:

  • workflow.md —— 七步预测工作流总纲(Scope 确定、报告类型、时间设置、dataset 配置、预测选项、执行、响应解读);
  • request-body-schema.md —— 请求体完整字段表与响应结构;
  • examples.md —— 本文讲解的四类典型请求体;
  • guardrails.md —— 时间、训练数据、行数、限流等全部边界规则;
  • error-handling.md —— 状态码、校验错误码与重试策略。

这些文档经 scripts/validate-registry.mjs 校验后进入技能注册表,随 autoskills 一并安装分发。你在使用 Agent 时,只需说出"预测我本月月底的 Azure 花费"这类意图,技能路由(见 SKILL.md 的意图路由表)就会自动选择 Cost Forecast Workflow,并参照本文示例构造 az rest 请求。

一个可直接套用的完整调用序列

# 1. 构造请求体(预测当月剩余,按天粒度)
#    写入 temp/cost-forecast.json,内容即"示例 1"

# 2. 创建临时目录并执行
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'

# 3. 解读响应
#    CostStatus=Actual   -> 已发生的实际成本
#    CostStatus=Forecast -> 模型预测的未来成本
#    将两者相加即可得到本月底的预计总支出

十、常见问题速览(FAQ)

Q1:为什么我的请求返回 "CantForecastOnThePast"? from 和 to 都在过去。Forecast API 要求 to 必须在未来(guardrails.md)。

Q2:为什么返回 "Forecast is unavailable for the specified time period"? 这不是错误,是模型因历史数据不足(少于 28 天)而无法预测的合法响应。不要重试,改用 Cost Query Workflow 取历史数据。

Q3:想按资源组分组预测,为什么报错? Forecast API 不支持 grouping 字段。改用 Query API 查询带分组的历史数据。

Q4:Daily 粒度的预测区间为什么不能太长? 每次响应上限 40 行。Daily 粒度下 30 天实际 + 30 天预测即 60 行超限,建议 Daily 窗口控制在 2~3 周,更长用 Monthly 粒度或拆分窗口。

Q5:includeFreshPartialCost 报依赖错误? 该字段依赖 includeActualCost=true,必须同时显式设置,否则返回 DontContainIncludeActualCostWhileIncludeFreshPartialCost。


总结

Azure Cost Management Forecast API 是"月底账单估算"与"未来支出规划"的核心工具。掌握四类典型请求体(当月剩余按天、未来三月按月、资源组 Scope、计费账户 Scope)、Scope URL 拼接规则(路径片段 + ?api-version=2023-11-01)、40 行响应上限与 28 天训练数据门槛,就能在 autoskills 的 azure-cost 技能包支持下,稳定产出"实际 + 预测"的完整成本视图。所有字段细节、边界规则与错误码,均可在仓库内 cost-forecast 目录的配套文档中随时查阅。

登录后查看全文
autoskills