写了个 Skill 让 OpenClaw 自动查 AWS 账单,从此告别手动翻控制台

起因

事情是这样的。

我最近一直在用 OpenClaw 做工作自动化,用着挺爽。但有个需求它满足不了——我想让它每天自动查一下亚马逊云科技的账单,花超了就提醒我一声。

OpenClaw 自带了天气、网页摘要这些技能,但成本监控这种定制需求?不好意思,没有。

然后我发现 OpenClaw 有个叫 Skill 的扩展机制。简单来说,你写一个 Markdown 文件,告诉 AI 遇到某类问题该怎么做,它就"学会"了这个能力。

是的,就是 Markdown。不是 Python 包,不是 npm 模块,是一个 .md 文件。

当时我觉得有点不可思议,但试了一下发现真的能用。这篇文章就记录一下我从零写一个"AWS 成本监控"Skill 的过程,代码全部可以直接跑。


Skill 是什么

别把 Skill 想得太复杂。

一句话概括:Skill = 一份写给 AI Agent 的 SOP(标准操作流程)。

你在一个叫 SKILL.md 的文件里写清楚三件事:

  1. 什么时候触发(用户说了什么关键词)
  2. 具体做什么(执行哪个脚本、调用哪个 API)
  3. 输出什么(报告格式长什么样)

Agent 收到用户请求后,先扫描所有 Skill 的描述,看哪个匹配。匹配上了,读正文,照着做。就这么简单。

不需要编译,不需要注册,不需要重启。放到目录下,下次对话就生效。


目录结构


~/.openclaw/workspace/skills/aws-cost-monitor/ ├── SKILL.md # 必需:告诉 Agent 干嘛 ├── scripts/ │ └── check_cost.py # 可选:辅助脚本 └── references/ └── cost-explorer-notes.md # 可选:参考文档

只有 SKILL.md 是必需的,脚本和参考文档按需添加。

我的习惯是:能让 Agent 直接调工具完成的,就不写脚本。需要确定性输出的(比如 API 调用),才放到 scripts/ 下。


写 SKILL.md

这是核心,直接贴完整内容:


# AWS Cost Monitor ## Description 亚马逊云科技成本监控技能。自动查询当前账户的云资源费用, 生成成本报告,支持按服务维度拆分,超出预算时发送告警。 ## Triggers - 用户说"查一下我的 AWS 账单" - 用户说"这个月花了多少钱" - 用户说"AWS 成本报告" - 用户说"看看云资源开销" - 用户说"账单超了没" - 用户说"查一下这个月的费用" - 用户说"成本分析" - 用户说"哪个服务花钱多" ## Steps 1. 读取并执行 scripts/check_cost.py 获取成本数据 2. 解析脚本输出的 JSON 格式数据 3. 按以下格式生成成本报告:

💰 亚马逊云科技成本报告 | YYYY-MM-DD

📅 统计周期:YYYY-MM-01 ~ YYYY-MM-DD 💵 本月累计费用:$XXX.XX

📊 按服务拆分(Top 5):

  1. Amazon EC2 — $XX.XX
  2. Amazon S3 — $XX.XX
  3. Amazon Bedrock — $XX.XX
  4. Amazon RDS — $XX.XX
  5. Amazon Lambda — $XX.XX

📈 日均费用:X.XX📆预估月底总费用:X.XX📆预估月底总费用:XXX.XX


4. 如果预估月底总费用超过 $500(默认阈值),追加告警:

⚠️ 费用告警:预估本月总费用 XXX.XX,已超过预算阈值XXX.XX,已超过预算阈值500!


5. 如果用户指定了预算阈值,用指定值替代默认值 6. 将报告发送给用户 ## Notes - 需要本机已配置 AWS CLI 凭证 - 需要 IAM 权限:ce:GetCostAndUsage - 费用数据有 24-48 小时延迟 - 默认查询当前月份

写 Triggers 的经验

这里分享一个我踩过的坑。

一开始我只写了"查 AWS 账单"和"成本报告"两个触发条件。结果用户换个说法——"这个月云上花了多少"——Agent 就不认了。

后来我把能想到的口语化表达都加上去了。Triggers 宁可多写几条,也不要少写。 Agent 的语义理解能力不错,但你把路铺好了,它走起来更稳。


写脚本:check_cost.py

这个脚本的活儿很简单:调 Cost Explorer API → 拿数据 → 输出 JSON。


#!/usr/bin/env python3 """ AWS Cost Monitor — 查询亚马逊云科技账户成本数据 依赖:boto3(pip install boto3) 权限:需要 IAM 策略 ce:GetCostAndUsage """ import json import sys from datetime import datetime, timedelta import boto3 def get_month_range(year: int = 0, month: int = 0) -> tuple[str, str]: """获取指定月份的起止日期。""" today = datetime.utcnow() if year == 0 or month == 0: year = today.year month = today.month start = f"{year:04d}-{month:02d}-01" if month == 12: end_date = datetime(year + 1, 1, 1) else: end_date = datetime(year, month + 1, 1) # 当前月用明天作为 End(Cost Explorer 的 End 是排他的) if year == today.year and month == today.month: end_date = today + timedelta(days=1) end = end_date.strftime("%Y-%m-%d") return start, end def query_total_cost(client, start: str, end: str) -> float: """查询总费用。""" resp = client.get_cost_and_usage( TimePeriod={"Start": start, "End": end}, Granularity="MONTHLY", Metrics=["UnblendedCost"], ) total = 0.0 for result in resp["ResultsByTime"]: amount = result["Total"]["UnblendedCost"]["Amount"] total += float(amount) return round(total, 2) def query_cost_by_service(client, start: str, end: str) -> list[dict]: """按服务维度查询费用。""" resp = client.get_cost_and_usage( TimePeriod={"Start": start, "End": end}, Granularity="MONTHLY", Metrics=["UnblendedCost"], GroupBy=[{"Type": "DIMENSION", "Key": "SERVICE"}], ) services = {} for result in resp["ResultsByTime"]: for group in result["Groups"]: name = group["Keys"][0] amount = float(group["Metrics"]["UnblendedCost"]["Amount"]) services[name] = services.get(name, 0.0) + amount sorted_services = sorted( services.items(), key=lambda x: x[1], reverse=True ) return [ {"service": name, "amount": round(amount, 2)} for name, amount in sorted_services if amount > 0.01 ] def estimate_monthly_total(total_so_far: float, start: str) -> float: """预估月底总费用。""" today = datetime.utcnow() start_date = datetime.strptime(start, "%Y-%m-%d") days_passed = (today - start_date).days if days_passed <= 0: return total_so_far if start_date.month == 12: next_month = datetime(start_date.year + 1, 1, 1) else: next_month = datetime(start_date.year, start_date.month + 1, 1) total_days = (next_month - start_date).days daily_avg = total_so_far / days_passed return round(daily_avg * total_days, 2) def main(): """主函数。""" year, month = 0, 0 if len(sys.argv) >= 3: year = int(sys.argv[1]) month = int(sys.argv[2]) start, end = get_month_range(year, month) client = boto3.client("ce", region_name="us-east-1") total = query_total_cost(client, start, end) services = query_cost_by_service(client, start, end) today = datetime.utcnow() start_date = datetime.strptime(start, "%Y-%m-%d") days_passed = (today - start_date).days daily_avg = round(total / max(days_passed, 1), 2) estimated_total = estimate_monthly_total(total, start) result = { "period": {"start": start, "end": end}, "total_cost": total, "daily_average": daily_avg, "estimated_monthly_total": estimated_total, "days_passed": days_passed, "top_services": services[:10], "query_time": today.strftime("%Y-%m-%d %H:%M:%S UTC"), } print(json.dumps(result, indent=2, ensure_ascii=False)) if __name__ == "__main__": main()

代码不长,核心就三个函数:

  • query_total_cost:查总费用
  • query_cost_by_service:按服务拆分
  • estimate_monthly_total:根据日均预估月底开销

安装 & 测试

放文件

mkdir -p ~/.openclaw/workspace/skills/aws-cost-monitor/scripts mkdir -p ~/.openclaw/workspace/skills/aws-cost-monitor/references # 把三个文件分别放到对应位置,然后: chmod +x ~/.openclaw/workspace/skills/aws-cost-monitor/scripts/check_cost.py

先手动测一下脚本

pip install boto3 python3 ~/.openclaw/workspace/skills/aws-cost-monitor/scripts/check_cost.py

应该能看到一段 JSON 输出,包含费用数据。如果报错,大概率是 AWS 凭证没配(aws configure)或者 IAM 权限不够。

在 OpenClaw 里测

文件放好后不用重启。直接在 Slack 里说:

查一下我的 AWS 账单

Agent 应该能识别到 Skill 并执行。效果类似:


💰 亚马逊云科技成本报告 | 2026-03-19 📅 统计周期:2026-03-01 ~ 2026-03-19 💵 本月累计费用:$127.35 📊 按服务拆分(Top 5): 1. Amazon EC2 — $52.10 2. Amazon Bedrock — $35.20 3. Amazon S3 — $18.05 4. Amazon RDS — $12.80 5. AWS Lambda — $9.20 📈 日均费用:$6.70 📆 预估月底总费用:$207.70

看到这个输出的时候我挺开心的。从动手到跑通,前后不到一小时。


踩坑记录

分享几个我实际开发中碰到的问题。

坑 1:Cost Explorer 只认 us-east-1

这个坑了我大概二十分钟。脚本里 region_name 写的是 ap-northeast-1(因为我的资源大部分在东京),一直报错。后来查文档才发现 Cost Explorer API 只能通过 us-east-1 调用,和你的资源在哪个 Region 无关。

坑 2:End 日期是排他的

Cost Explorer 的 TimePeriod.End 是排他的,也就是说 End: "2026-03-19" 实际上查的是到 3 月 18 日的数据。要想包含今天,End 得写明天的日期。脚本里的 today + timedelta(days=1) 就是为了解决这个问题。

坑 3:数据延迟 24-48 小时

新账户或者刚开始产生费用的时候,可能查出来全是零。别以为脚本有 bug,等一两天数据就有了。


进阶玩法

定时巡检

在 OpenClaw 的 HEARTBEAT.md 里加一行:


- [ ] 每天早上 9:00(UTC+8),执行 AWS 成本监控,推送报告

Agent 心跳检查时会主动触发。

Skill 嵌套

如果你有个"飞书通知"Skill,可以在成本监控的 Steps 里引用它:


6. 费用超过阈值时,使用"飞书通知"Skill 发送告警到团队群

Agent 会自动串联两个 Skill。

和 Amazon Bedrock 配合

查完账单只是第一步。更进阶的玩法是把成本数据丢给 Amazon Bedrock,让它分析增长趋势、找出异常、给优化建议。在 Steps 里加一步就行:


7. 将成本数据发给 Amazon Bedrock 分析趋势和异常

我现在每天早上看到的不光是一堆数字,还有一段"这个月 EC2 比上月多了 30%,建议检查是否有闲置实例"之类的分析。挺有用的。


发布到 ClawHub

觉得自己写的 Skill 不错?可以发布到 ClawHub,让其他人也用上。

  1. 确保 SKILL.md 描述完整
  2. 脚本里别硬编码敏感信息
  3. 用打包工具生成 .skill 文件
  4. 提交到 ClawHub

社区共建,少造轮子。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐