亚马逊AWS官方博客

基于Strands和AgentCore 实现Agentic Scheduler 在多Region自动编排推理GPU算力

背景与需求

在单一区域,比如新加坡区域,进行大模型推理部署与弹性扩容时,我们经常遇到 不支持GPU类型,比如G6/G6e或者G5类型。亦或GPU 实例因容量不足而启动失败(例如 InsufficientInstanceCapacity),导致扩容结果不可预测、交付周期被动拉长,线上服务的稳定性与 SLA 受到影响。传统依赖工程师手动切换可用区、跨区域反复试错的方式,不仅效率低、难以规模化,还缺乏可回溯的决策依据与标准化流程。

为解决上述问题,我们基于 Strands Agents 实现了一套跨区域 GPU 调度方案:系统接收自然语言的容量请求(实例类型、目标数量、优先区域、网络约束等),自动生成候选 Region/AZ 列表并进行打分排序,按计划逐步尝试启动;当出现容量不足、配额不足或网络/权限错误时,Agent 会依据错误分类动态调整策略(切换 AZ/Region、分批启动等),直到满足目标容量或耗尽重试预算。该调度 Agent 部署在 AgentCore Runtime 上运行,并将每次调度的输入、计划版本、尝试记录与最终结果写入 AgentCore Memory,支持按 requestId 回放与复盘,持续提升策略命中率与可运营性。

在工程实践层面,本项目全程采用 Kiro IDE 的 Specs 驱动方式,从 Requirements → Design → Implementation 将需求、架构决策与任务拆解固化为版本化资产,确保复杂 Agentic 系统在快速迭代中依然可追踪、可审计、可测试,并具备可复制的交付路径。

总体架构

整体功能亮点

1、基于 LLM 的 Agent 进行GPU 需求跨区域调控

相比传统“基于固定规则(rule-based)”的 GPU 调度与启动控制,基于 LLM 的 Agent 更适合处理云上容量波动这种高不确定性、强上下文依赖的问题。规则系统通常依赖预先写死的 if/else 与静态优先级:一旦遇到未覆盖的错误组合(容量不足叠加配额约束、AZ offerings 差异、网络路由限制、权限缺口等),要么失败退出,要么需要人工介入补规则,迭代成本高且容易形成“规则泥潭”。LLM Agent 则可以把一次启动过程视为“计划—执行—观察—再计划”的闭环:它能够理解自然语言或结构化输入中的业务意图与约束(例如优先新加坡、必须落在指定子网、允许跨区域兜底、重试预算限制),在执行中根据实时错误码与上下文动态调整策略(切换 AZ/Region、拆分批次、改变尝试顺序、给出配额/权限修复建议),并生成可解释的决策理由与最终报告。

基于 LLM 的 Agent 在扩展性上天然优于规则引擎:新增或调整 Region 往往不需要大规模改代码或堆叠 if/else,只需把新的 Region 纳入候选池,并补齐少量“环境事实”(如可用实例型、配额与网络约束)即可由 Agent 在运行时完成判断与编排。使“支持更多 Region”从一次性工程改造,变成可持续的配置化扩展与策略迭代。这种能力尤其适合容量波动明显、区域差异较大的 GPU 场景,能显著降低新 Region 上线成本并提升全局调度的适配速度。】

2、部署在 AgentCore Runtime 与 Memory 带来的额外价值

将基于 Agent 的跨区域 GPU 调配系统部署在 Amazon Bedrock AgentCore Runtime 与 AgentCore Memory 之上,可以把“调度逻辑”从一次性脚本升级为可运营、可扩展的生产级服务。

首先,AgentCore Runtime 提供托管运行环境与会话级隔离能力,使调度 Agent 能以稳定的执行上下文处理多步骤编排(候选 Region 生成、offerings/配额预检、批量启动、失败诊断与再计划),并支持按请求并发弹性伸缩,减少自建运行框架、容器治理与权限编排的运维负担。

其次,AgentCore Memory 负责保存,对话记忆,记录的是用户和 Agent 之间的交互过程。store_conversation 在每次请求/响应时把用户消息、Agent 回复、审批请求/响应等存入 AgentCore Memory 服务。此外还有 LTM(长期记忆)功能,retrieve_ltm_context 通过语义搜索提取历史调度经验,注入到 system prompt 中,让 Agent 能”记住”之前的容量调度经验(比如哪个区域经常缺货)。

3、DynamoDB — 业务数据存储,记录的是 GPU 实例的生命周期。

每次启动实例后,dynamodb_put_instances 写入一条记录(PK=request_id, SK=region#instance_id),包含实例类型、IP、AZ、启动时间等。删除实例时,ec2_delete_instances 会把对应记录的 status 更新为 “terminated” 并写入 terminated_at。查询时 dynamodb_query_instances 可以按 region、instance_type、status 等条件检索历史。同时为Agentic 应用提供可供扩展的查询分析功能。

4、大模型边界限制的多层防御

项目用了一个很典型的”纵深防御”策略,不是只靠 prompt 约束大模型,而是在多个层面同时设防:

第一层:Prompt 层(软约束)SYSTEM_PROMPT 里明确写了:

  • 只允许 g4dn/g5/g5g/g6/g6e 系列,遇到非 GPU 类型必须立即拒绝
  • 必须遵守 fallback_groups 的地理边界,get_region_order 返回 error 时必须拒绝
  • 查询实例只能走 DynamoDB,不能直接查 EC2

这部分是通过提示词要求大模型遵守规则,但大模型可能会犯错,所以还需要硬约束。

第二层:Pydantic 模型层(硬约束) schemas.py 里 Plan 模型的 instance_type 字段挂了 @field_validator,调用 validate_gpu_instance_type。这个函数用正则 ^g(4dn|5g?|6e?)\..*$ 做校验。即使大模型生成了一个包含 m7i.xlarge 的 Plan,Pydantic 反序列化时就会直接抛 ValueError,Plan 根本无法构造成功。

:Pydantic 是 Python 的数据验证和序列化库。核心思路通过定义一个继承 BaseModel 的类,声明字段和类型,Pydantic 在实例化时自动做类型校验、类型转换和约束检查。可以参考官方文档

第三层:工具执行层(硬约束)ec2_launch_instances 工具函数的第一件事就是调用 validate_gpu_instance_type。即使前两层都被绕过了,到了真正要调 AWS API 的时候,非 GPU 类型会被拦截,返回 ERROR + INVALID_INSTANCE_TYPE,不会有任何 RunInstances 调用发出去。

第四层:区域配置层(硬约束)regions.yaml 的 fallback_groups 定义了地理合规边界。ConfigLoader.get_allowed_regions() 在代码层面强制执行:

  • 如果请求的 consumer_region 不在任何 fallback group 里,直接抛 ValueError
  • get_region_order 工具会把这个错误返回给 Agent,Agent 被 prompt 要求必须拒绝

第五层:配置白名单(硬约束)regions.yaml 的 regions 列表本身就是一个白名单。只有列在里面的区域才有 subnet、AMI、key pair 等配置。即使大模型试图在一个未配置的区域启动实例,工具层拿不到必要的参数,调用也会失败。

核心功能模块

1、Probe-and-Fill 启动策略,这是系统的核心算法:

  • 将大请求拆分为小批次(默认 batch_max=4)
  • 在每个 Region 内按 Subnet 轮转(Round-Robin)
  • 遇到 InsufficientInstanceCapacity 时二分退让(batch 减半)
  • 每次 RunInstances 调用携带唯一 client_token 保证幂等性
  • 返回标准化 StepResult(FULL / PARTIAL / NONE / ERROR)

二分退让,核心逻辑在 ec2_launch_instances 的内层 while 循环里。

假设要在 ap-northeast-1 启动 8 台 g5.xlarge,batch_max=4,有 3 个 subnet。

正常流程:

subnet-A: 尝试 4 台 → 成功 → remaining=4

subnet-A: 尝试 4 台 → 成功 → remaining=0, 结束

遇到容量不足时的二分退让:

subnet-A: 尝试 4 台 → InsufficientInstanceCapacity

batch 减半 → 2

subnet-A: 尝试 2 台 → 成功 → remaining=6

batch 恢复 → min(4, 6) = 4

subnet-A: 尝试 4 台 → InsufficientInstanceCapacity

batch 减半 → 2

subnet-A: 尝试 2 台 → InsufficientInstanceCapacity

batch 减半 → 1

subnet-A: 尝试 1 台 → InsufficientInstanceCapacity

batch=1 还失败 → break, 换下一个 subnet

subnet-B: 尝试 4 台 → 成功 → remaining=2

subnet-B: 尝试 2 台 → 成功 → remaining=0, 结束

这个策略的好处是在容量紧张时尽可能”榨干”剩余容量。比如某个 AZ 只剩 3 台的容量,直接请求 4 台会失败,但退让到 2 台就能成功,再请求 2 台又能拿到 1 台,最终拿到 3 台而不是 0 台。配合外层的多 subnet 轮转和跨 region fallback,形成了完整的 Probe-and-Fill 策略

2、地理合规回退

通过 fallback_groups 配置定义地理合规边界:

消费者 Region 允许回退到
southeast_asia ap-southeast-1 (新加坡) 新加坡 → 孟买 → 东京 → 首尔
japan ap-northeast-1 (东京), ap-northeast-3 (大阪) 仅东京  大阪
其他 如 us-west-2 直接拒绝

get_region_order 工具使用 Haversine 公式按地理距离排序候选 Region,同时严格遵守 fallback group 边界。

3、Orchestrator 状态机,驱动完整的调度循环:

Init → Preflight(Offerings检查) → Launch(Probe-and-Fill) → Describe(补全) → DDB Write(持久化) → Decide(Agent决策) →下一Region/重试/完成/中止

关键状态保证:

  • remaining 单调递减(只减不增)
  • cursor 单调递增(不回退到已尝试的 Region)
  • request_id 全局唯一,防止重复调度

错误分类策略:CAPACITY/QUOTA → 跳过 Region,THROTTLE → 指数退避重试(最多3次),CONFIG → 中止。

注:cursor 就是 regions 列表的索引指针,指向当前正在尝试的候选区域。

4、调度模式

  • multi_region(默认):按优先级逐 Region 尝试,直到满足需求或候选耗尽
  • single_region:仅在指定 Region 启动,容量不足直接返回 PARTIAL/FAILED,不跨 Region 回退

5、Human-in-the-Loop 审批

基于 Strands BeforeToolCallEvent Hook,三种触发条件:

  • 批量阈值:target_count > batch_threshold(dev=50, staging=20, prod=10)
  • 地理边界:region 不属于 allowed_geo_regions
  • 工具黑名单:指定工具始终需要审批
  • 删除操作通过 Strands tool_context.interrupt() 实现两步审批流程。

注:Strands 的 BeforeToolCallEvent 是 Agent 执行工具之前触发的拦截点。实现一个 HookProvider,在 register_hooks 里把回调注册到 BeforeToolCallEvent,Strands 就会在每次 LLM 决定调用工具、但还没真正执行之前,运行回调。具体可以参考官方文档

6、数据持久化

  • DynamoDB 表设计:PK=request_id, SK=region#instance_id
  • 记录字段:goal_region, region, instance_type, instance_id, az, private_ip, public_ip, status, launched_at, terminated_at
  • 查询工具自动计算运行时长(duration_seconds + duration_human)
  • 删除实例后自动更新 DynamoDB 状态为 terminated

7、AgentCore 部署入口 (agent_entrypoint.py)

  • Session 级 Agent 缓存(同一 session 复用 Agent 实例)
  • 中断状态跨请求保存/恢复(解决 AgentCore 两次 HTTP 请求间 _InterruptState 丢失问题)
  • JWT 认证 → 请求路由(prompt vs approval_responses)→ Agent 调用 → 响应构建

注:因为 HTTP 请求是无状态的,审批需要跨两次请求完成:

第一次请求(用户发 prompt 要求删除):

invoke() 收到 prompt,调用 agent.stream_async(prompt)

Agent 调用 ec2_delete_instances,工具内部触发 interrupt

_build_response() 检测到 stop_reason == “interrupt”

调用 _save_interrupt_state() 把 agent 的中断状态序列化到 _session_interrupt_cache

返回 AgentResponse(status=”approval_required”, interrupts=[…]) 给前端

第二次请求(用户确认/拒绝):

前端发送 payload = {“approval_responses”: [{“interrupt_id”: “…”, “decision”: “approved”}]}

invoke() 走 approval_responses 分支

调用 _restore_interrupt_state() 从缓存恢复中断状态到 agent 上

构造 interruptResponse,把 decision 映射为 “y” 或 “n”

调用 agent(interrupt_responses) 恢复执行

如果用户批准,工具继续执行 terminate_instances,然后更新 DynamoDB 状态为 terminated

如果没有新的 interrupt,调用 _clear_interrupt_state() 清理状态

8、Memory 集成

  • 短期记忆(STM):对话历史存储到 AgentCore Memory
  • 长期记忆(LTM):通过语义检索获取过去发生过的调度经验,把返回的检索信息作为System Prompt提交给大语言模型
  • 所有 Memory 操作 fail-safe,失败不阻塞主流程

注:同时 AgentCore LTM 如下代码方式整合到系统提示词中,Agent 的 system prompt 为代码结构大致是:

******

def retrieve_ltm_context(max_results=5, max_chars=1000) -> str:

memories = search_ltm(

query=”GPU instance capacity scheduling experience and region availability“,

max_results=max_results,

)

# 格式化为编号列表,拼成 “## Historical Knowledge (from Long-Term Memory)” 段落

# 总字符数不超过 max_chars,防止 prompt 膨胀

******

[SYSTEM_PROMPT 基础指令]

[config_context 区域/DynamoDB/批次配置]

[LTM context — 如果有的话]

## Historical Knowledge (from Long-Term Memory)

  1. ap-northeast-1 在周五下午经常 ICE 错误…
  2. ap-southeast-1 的 g5.xlarge 容量较充足…

重要的设计思路:

  • LTM 查询是在 build_agent() 时一次性执行的,不是每次对话都查。也就是说 LTM 内容在 Agent 创建时就固定了,同一个 session 内不会更新。
  • 查询语句是硬编码的,不会根据用户当前请求动态调整。这意味着它拿到的始终是”GPU 调度经验”这个大方向的记忆,不是针对性的。
  • max_chars=1000 的限制比较保守,确保 LTM 不会吃掉太多 context window。
  • 整个 LTM 链路是 fail-safe 的:Memory 服务不可用时返回空字符串,system prompt 正常工作,只是没有历史经验加持。

具体可以阅读Github中的原始代码。

9、配置管理

  • 本地开发:YAML 文件(yaml + config/environments/*.yaml)
  • 部署环境:SSM Parameter Store(支持动态更新,无需重新部署)
  • 开发和生产环境隔离:dev(宽松审批)、staging(中等)、prod(严格审批 + WARNING 日志级别)

数据流总结

以客户请求流程为例,按照如下详细步骤进行数据的流转。

1、用户提交请求

用户发起:“在新加坡启动 4 台xlarge”。

2、Agent 解析意图并确定调度模式

Agent 解析用户意图,识别为 multi-region 调度场景,并将 consumer_region 设为 ap-southeast-1。

3、生成候选 Region 尝试顺序

调用 get_region_order(ap-southeast-1),得到候选 Region 列表:[新加坡、孟买、东京、首尔]。

  • 排序规则:按距离排序
  • 约束条件:受 fallback_group 约束

4、生成执行 Plan

Agent 基于上述候选列表生成 Plan(对应流程的第 3–8 步),用于指导后续执行与重试策略。

5、Orchestrator 开始按 Region 循环执行:Region 1(新加坡)

  • offerings 校验通过
  • 执行 launch(4 台, batch=4)
  • 启动结果为 PARTIAL(2 台):仅成功 2 台
  • 将本次尝试结果写入 DynamoDB
  • 决策:continue(继续尝试下一 Region 填补缺口)

6、Orchestrator 继续:Region 2(孟买)

  • offerings 校验通过
  • 针对剩余缺口执行 launch(2 台, batch=4)
  • 启动结果为 FULL(2 台):成功补齐 2 台
  • 将本次尝试结果写入 DynamoDB
  • 决策:done(目标已满足,结束循环)

7、汇总与输出(finalize)

系统汇总所有 Region 的执行结果并返回:
{status: SUCCESS, total: 4/4, gpu_list: […], gap: 0}

  • status: SUCCESS:整体成功
  • total: 4/4:满足 4 台目标容量
  • gpu_list: […]:已启动实例/GPU 列表
  • gap: 0:无剩余缺口

用 Kiro Specs 驱动构建跨区域 GPU 调度 Agent

跨区域 GPU 调度系统的本质,不是“写一个能跑的脚本”,而是把一个多约束、多分支、多失败路径的系统工程,做成可交付、可维护、可复用的产品级能力:输入自然语言、调度策略要可解释、失败要能自愈、还要能在不同 Region 间做一致化治理,并且为后续优化沉淀“可学习的经验”。

在实现过程中采用 Spec-driven development:在 Kiro 中把工作拆成三个始终保持一致的规格化资产——requirements.md、design.md、tasks.md,由此把“需求—设计—实现”串成可追踪链路,降低返工与漂移风险。Kiro 的 Specs 工作流也明确强调:需求用用户故事+验收标准组织,设计文档承载架构/序列图/关键决策,实现计划拆解为可跟踪任务。有关 Kiro IDE specs 开发,可以参考官方文档作者在这里不再赘述,但是将一些总结的经验做一下简单的分享:

如图,在使用 Kiro IDE 的过程中,采用“分步、渐进、可验证”的工程化路线推进。

第一步先在本地完成最小闭环:实现 gpu-cross-region-scheduler 的核心能力(解析用户请求、生成跨 Region 候选顺序、按批次启动 GPU 实例、处理 PARTIAL/FULL 结果并返回汇总)。随后用模拟容量、故障注入与回归用例覆盖异常分支,确保调度策略不会跑偏。

第二步在核心稳定后,引入基于 DynamoDB 的 instance-query-and-deletion,补齐运维闭环:把每次启动的实例信息、Region、状态与时间戳落表,并提供查询/删除接口;通过单测与端到端测试验证幂等性、一致性与权限控制。

第三步利用 Kiro 的 powers,将各模块按 AgentCore Runtime 规范完成云上融合部署,统一依赖、环境变量与 IAM 边界。

结合整个项目使用的技术栈,所以引入了两个 Kiro 的Power, “Build an agent with Strands SDK” 和 “Build an agent with Amazon Bedrock AgentCore” 有关 Kiro Power的介绍,可以参考官方文档。通过引入这两个Power 将 Strands 和 AgentCore 的能力整合到Kiro中。

第四步用 AgentCore CLI 做多轮会话测试,验证调用路径、日志与历史记录可回溯。最后在全部验证通过后,再上线 Web Dashboard,将调度结果与实例生命周期可视化,形成从本地验证到云上落地的完整交付。

总结

本项目围绕“单一 Region GPU 容量与供给不确定”这一典型痛点,构建了一套可生产化的跨 Region 推理算力自动编排能力:当新加坡等目标区域出现 GPU 类型不支持或容量不足(如 InsufficientInstanceCapacity)时,系统能够自动生成候选 Region/AZ 顺序,按“探测-填充(Probe-and-Fill)”策略分批启动实例,并根据容量/配额/限流/配置等错误分类动态调整计划,直至补齐目标容量或触达重试预算。调度过程部署在 AgentCore Runtime 上运行,关键输入、计划版本、尝试记录与最终结果写入 AgentCore Memory,支持按 requestId 回放复盘,为后续策略优化沉淀可学习的运营数据。

工程实现上,项目全程采用 Kiro Specs 的“Requirements→Design→Tasks”驱动方式,把需求、架构决策与任务拆解固化为版本化资产,并按“本地最小闭环→DynamoDB 运维闭环→AgentCore 融合部署→CLI 多轮测试→Web Dashboard”渐进推进;每一步都通过单测与端到端验证,确保行为可追踪、可审计、可测试。相比传统手工试错与一次性集成,Specs 工作流显著加速了开发与部署节奏,减少返工与偏航风险,大幅提升研发效率并缩短交付周期。

具体代码说明以及安装步骤,可以参考Github

附录

1、具体代码说明以及安装步骤,可以参考Github

2、功能演示:

(1)查询AgentCore 工作状态:

(2)启动Web Dashboard ,打开登陆界面,输出如下:

登录之后查询当前正在运行的GPU实例。

界面登陆之后,左边红框默认保存了最近对话的记录,这部分内容取自 AgentCore Memory 中。

查看 AWS 区域支持的GPU 实例类型,如下美西2 区域可以查询,但是明确边界,表示美西区域不在支持范围之内:

查看首尔区域支持的GPU实例类型:

主要功能性测试,尝试从新加坡区域启动 G6 类型实例:

说明:以上是一个极端情况,但是清晰说明了当尝试从新加坡区域启动 g6 类型实例的时候,GPU 调度系统会尝试按照一定的顺序,先尝试孟买,孟买容量不够的时候,继续尝试东京区域,最终在首尔区域启动成功。 上图显示了界面的回复,下图显示日志中记录的整个启动过程。

类似的,当尝试在新加坡区域内启动 g4dn 类型的实例,由于该区域本身支持该类型GPU,则直接启动。如下图:

对应,当需要删除正在运行的实例时,需要人为接入审批流程,如下:

同样,由于系统的限制,当希望在美西区域启动GPU,或者其他需求的时候,系统会进行拦截:

结合大语言模型的识别能力,能够从各个维度对现有数据进行查询,而不用预先设置,如下展示:

3、网络延迟测试

以新加坡区域为核心,通过亚马逊云科技自有网络,网络延迟测试结果如下:

## 实际测试结果

测试环境:t3.micro 实例,100MB文件传输

| 路径 | 延迟 (RTT) | 传输耗时 | 平均速度 |

|——|———–|———|———|

| 新加坡(AZ1) → 新加坡(AZ2) | **0.76 ms** | **0.10秒** | **999.9 MB/s** |

| 新加坡 → 东京 | 70.7 ms | 0.61秒 | 163.4 MB/s |

| 新加坡 → 大阪 | 75.9 ms | 0.66秒 | 150.4 MB/s |

| 新加坡 → 孟买 | 62.7 ms | 0.57秒 | 174.6 MB/s |

| 新加坡 → 首尔 | 69.8 ms | 0.61秒 | 164.4 MB/s |

### 数据传输成本分析

基于 AWS 定价(以100MB传输为例):

| 传输类型 | 单价 | 100MB成本 | 1GB成本 | 相对跨AZ倍数 |

|———|——|———-|——–|————-|

| 同区域跨AZ | $0.01/GB | $0.001 | $0.01 | 1x (基准) |

| 跨区域 (TGW Peering) | $0.02/GB | $0.002 | $0.02 | 2x |

**成本说明:**

– **同区域跨AZ**:EC2之间跨AZ传输 $0.01/GB(双向各计费)

– **跨区域传输**:TGW Peering数据处理费 $0.02/GB

– 跨区域传输成本是跨AZ的 **2倍**

**大规模传输成本估算:**

| 数据量 | 跨AZ成本 | 跨区域成本 | 差额 |

|——-|———|———–|——|

| 100GB | $1 | $2 | +$1 |

| 1TB | $10 | $20 | +$10 |

| 10TB | $100 | $200 | +$100 |

### Transit Gateway 固定费用

TGW 本身按小时计费,与数据传输量无关:

| 费用项 | 单价 | 本项目配置 | 每小时费用 | 每月费用(730h) |

|——-|——|———–|———–|—————|

| TGW Attachment | $0.05/小时/附件 | 5个VPC附件 | $0.25 | $182.50 |

| TGW Peering Attachment | $0.05/小时/附件 | 4个Peering | $0.20 | $146.00 |

| **合计** | | | **$0.45/小时** | **$328.50/月** |

**注意:** TGW固定费用较高,适合持续大流量场景。短期测试建议及时清理资源。

### 结果分析

– **同区域跨AZ**:延迟极低(<1ms),100MB传输仅需0.1秒,速度接近1GB/s

– **跨区域延迟排序**:孟买(62ms) < 首尔(70ms) < 东京(71ms) < 大阪(76ms)

– **跨区域传输速度排序**:孟买(174.6) > 首尔(164.4) > 东京(163.4) > 大阪(150.4) MB/s

– 延迟越低,文件传输速度越快,符合预期

*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。

本篇作者

李京

亚马逊云科技解决方案架构师,负责亚马逊云科技云计算方案咨询和设计。目前主要专注在现代化应用改造和机器学习领域的技术研究和实践。曾就职于 F5,甲骨文,摩托罗拉等多家公司,有丰富的实践经验。


AWS 架构师中心:云端创新的引领者

探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用