Alibaba MCP Core 提供了 RunScript 能力,用来帮助 Agent 处理多步骤的云资源操作。它允许 Agent 提交一段受控 Python 脚本,在 sandbox 中通过结构化 call_cli 调用阿里云 OpenAPI,并把最终结果以结构化数据返回。
这类能力看起来只是“多调几次 API”,但在实际运维场景里很有必要。因为很多云上任务并不是一次 API 调用可以完成的。
例如:
- 统计多个地域的 ECS、VPC、交换机和 NAT 网关使用情况;
- 检查一批 ECS 的安全组、磁盘、标签和备份配置;
- 变更前核对实例状态、网络配置、RAM 权限和资源策略;
- 排查一次 OSS 访问失败,需要同时检查 bucket、object、policy、ACL 和调用身份;
- 对一组资源做巡检,输出可复核的证据和异常列表。
这些任务都有一个共同点:步骤多,中间数据多,还容易受分页、参数名、权限、资源状态影响。如果拆成多轮工具调用,Agent 每一轮都要读上一步结果、拼下一步参数,再把新结果继续传下去。轮次越多,漏资源、漏分页、重复操作和误判的概率就越高。
RunScript 的目标就是把这类任务收敛成一次可控执行。
问题:Agent 会调用 API,但细节容易出错
Agent 通常知道“应该调用哪个 API”。真正容易出问题的是执行细节。
最常见的是分页。很多 List 或 Describe 接口默认只返回第一页,在小规模测试里看起来正常,到了真实账号里就会漏掉后面的资源。另一个常见问题是把 List 结果当成完整详情。List 通常只返回资源摘要,要判断加密、标签、策略、生命周期、绑定关系等属性,往往还需要继续调用 Describe 或 Get。
参数也是高频问题。OpenAPI 参数名、CLI 参数名、SDK 示例里的字段名不一定完全一致。比如有的接口要求 RegionId,有的对象参数要放在 body 下面,OSS 相关接口又有 bucket、key 等字段。如果 Agent 按经验猜参数,代码可能看起来合理,但实际调用会失败,或者更麻烦:调用成功了,但查的不是你想查的内容。
这些问题不是模型“聪不聪明”的问题,而是云资源操作本身就需要稳定的执行过程。RunScript 把分页、批量查询、并发、错误处理和结果聚合放在同一段脚本里完成,可以减少多轮调用带来的不确定性。
RunScript 适合做什么
可以用一个简单规则判断:如果任务超过一次 API 调用,优先考虑 RunScript。
查单台 ECS 的基本信息,用单步工具就够了。要检查一个账号下多个地域的 ECS 配置、VPC 关系、安全组规则和标签情况,就更适合用 RunScript。它能把“先列资源,再逐个查详情,最后汇总结果”的过程放进一次执行里。
典型场景包括:
- 多地域资源盘点;
- 安全组、磁盘、标签、备份策略巡检;
- RAM 权限和资源策略证据采集;
- 变更前资源状态核对;
- 故障排查时批量收集上下文;
- 需要审批和审计的写操作前置检查。
这里的重点不是让 Agent 写更长的脚本,而是让一次运维任务有清楚的执行边界。
常见错误一:只查第一页
下面是一个经常出现的问题:脚本调用了 DescribeInstances,但没有处理分页。
resp = await call_cli( product="Ecs", action="DescribeInstances", params={"RegionId": "cn-hangzhou"} ) result = resp["Instances"]["Instance"]
这段代码在资源很少时可能看不出问题,但在真实账号里很容易漏数据。更稳的写法是显式处理分页:
instances = [ ] page = 1 while True: resp = await call_cli( product="Ecs", action="DescribeInstances", params={ "RegionId": "cn-hangzhou", "PageNumber": page, "PageSize": 100 } ) items = resp.get("Instances", {}).get("Instance", [ ]) instances.extend(items) if len(items) < 100: break page += 1 result = { "count": len(instances), "instanceIds": [item["InstanceId"] for item in instances] }
生产环境里的巡检、盘点、权限分析,都应该默认考虑分页。否则结果很容易“看起来正确”,但实际少了一部分资源。
常见错误二:List 之后不继续查详情
另一个常见问题是拿 List 结果直接下结论。
比如要检查一批资源是否开启了某个配置,List 接口可能只返回资源 ID、名称和基础状态。真正的配置字段可能在 Describe、Get 或某个专项接口里。此时脚本应该先把资源列出来,再逐个补齐详情。
RunScript 比较适合做这类 List 到 Describe 的编排:
regions_resp = await call_cli(product="Ecs", action="DescribeRegions", params={}) regions = [r["RegionId"] for r in regions_resp["Regions"]["Region"]] async def list_region(region_id): resp = await call_cli( product="Ecs", action="DescribeInstances", params={"RegionId": region_id, "PageSize": 100} ) return resp.get("Instances", {}).get("Instance", [ ]) responses = await asyncio.gather( *[list_region(region) for region in regions], return_exceptions=True ) result = { region: response if isinstance(response, list) else {"error": str(response)} for region, response in zip(regions, responses) }
这个例子仍然是简化版,真实巡检里还可以继续对每个实例调用更多详情接口。关键是把“列出资源、补齐详情、记录失败项”放在同一次任务里完成。
常见错误三:参数靠经验猜
RunScript 里的 call_cli 接收结构化 OpenAPI 参数,不接收 aliyun ... 命令字符串。
result = await call_cli( product="Ecs", action="DescribeInstances", params={"RegionId": "cn-hangzhou"} )
这里最重要的是 params。顶层字段要按 OpenAPI 元数据来写,不建议从 CLI 参数、SDK 示例或历史经验里猜。对于不熟悉的 API,先查 API 定义,再写脚本。遇到参数错误,也先回到 API 定义确认字段名、类型和层级。
几个经验规则:
RegionId、PageNumber、PageSize这类字段按 API 定义写,不要随意改大小写;- 对象参数按元数据放到对应字段,比如
body; - 数组参数和 JSON 字符串参数不要混用;
- OSS 相关接口尤其要注意
bucket、key、body等字段; version、region、endpoint是call_cli的顶层参数,不要混进params。
这部分看起来细,但它决定了 Agent 生成的脚本是“能跑一次”,还是“能稳定跑很多次”。
写操作要保留同一个任务状态
云上操作不只有查询,也会有创建、修改和删除。涉及写操作时,RunScript 的状态机制很重要。
RunScript 启动后,如果任务很快完成,可以直接返回结果。如果任务仍在执行,或者触发人工审批,会返回 processID 和下一步动作。后续应该使用同一个 processID 调用 GetTask 继续等待,而不是重新提交同一段脚本。
这点在生产环境里很关键。重复提交读操作,最多是浪费时间;重复提交写操作,可能就是重复创建资源、重复修改配置,或者重复触发审批。
一个比较稳的流程是:
- 脚本先收集要操作的资源、当前状态和影响范围;
- 如果涉及高风险或写操作,进入审批;
- 审批通过后,继续推进同一个
processID; - 任务失败时,保留失败 API、参数摘要和错误信息,便于复盘。
这样处理后,一次云资源操作就有了完整链路:提交、审批、执行、结果、错误,都围绕同一个任务展开。
安全边界不能只靠提示词
Agent 接入真实云账号后,安全边界必须落到运行时里。
RunScript 的执行环境是受控 sandbox。脚本不能随意访问网络,访问阿里云 OpenAPI 只能通过 sandbox 内置的 call_cli。凭证不直接暴露给脚本,而由本地 executor 持有。这样做的目的很明确:脚本可以完成云资源编排,但必须走受控出口。
配合静态校验、基于 OpenAPI 元数据的风险判断、HITL 审批、结果脱敏和任务审计,RunScript 才适合进入真实运维流程。否则 Agent 只是“能调用 API”,还不能说“能安全地操作云资源”。
如何开始使用
建议从只读场景开始。只读场景风险低,也最能看出 RunScript 的价值。
可以先选这些任务:
- 多地域资源盘点;
- 安全组和公网暴露面巡检;
- ECS、VPC、OSS、RAM 资源配置核查;
- 变更前资源状态确认;
- 故障排查时批量收集上下文。
脚本写法上,可以先遵守几条简单规则:
- 一个任务一段脚本,不把中间 ID 拿回对话里再拼下一段;
- List 接口默认处理分页;
- 判断属性前先确认是否需要 Describe 或 Get;
- 返回原始证据和汇总结果,不要只返回一句结论;
- 涉及写操作时,围绕同一个
processID继续推进。
RunScript 的价值不在于让 Agent 多写几行 Python,而在于让 Agent 能把真实云资源操作做完整:拿全数据、保留证据、减少重复调用,并在需要时进入审批和审计链路。
对于 Agent Toolkit 来说,这是从“会调用工具”走向“能承担云上任务”的关键一步。