Kiro Agent架构解析:在AWS上构建生产级Agent服务

Kiro Agent架构解析:在AWS上构建生产级Agent服务 近两年凡是跟 Agent 沾边的项目热度都不低。但说实话真正能把 Agent 落到生产环境、稳定跑起来的架构并不多见。很多团队的 Agent 还停留在“调 API 拼接 Prompt”的阶段一旦涉及多工具编排、状态持久化、权限控制整个系统就乱成一锅粥。我最近正好在 AWS 上梳理一个叫 Kiro Agent 的项目架构这个项目的特点是它不是一个玩具 Demo而是一套相对完整的 Agent 服务从用户入口到模型调用再到工具执行每一层都有清晰的边界。这篇文章我就基于自己的理解和实操经验把 Kiro Agent 的架构拆开揉碎讲清楚同时会补上大量我在 AWS 真实环境里折腾出来的细节和经验。如果你正在设计自己的 Agent 架构或者准备把 Agent 服务部署到 AWS 上这篇文章应该能帮你少踩不少坑。1. 为什么在 AWS 上构建 Agent以及 Kiro Agent 要解决什么问题1.1 Agent 开发的热潮与真正的痛点先说一个现象。过去一年里我接触过不少 Agent 项目绝大多数都死在了同一个地方不是模型不够聪明而是工程化做不下去。模型本身的推理能力已经足够强真正麻烦的是——工具调用没有统一管理。每个工具各写各的鉴权逻辑有的用 API Key有的走 IAM有的干脆把密钥硬编码在代码里。状态管理一团乱麻。Agent 的对话历史、任务上下文、工具执行中间结果散落在内存、Redis、数据库里一重启就全丢。编排逻辑硬编码在业务代码里。想调整任务流程得改代码重新部署完全谈不上灵活。权限边界模糊。Agent 能访问的资源范围说不清楚要么权限过大出安全隐患要么权限过小导致工具频繁报错。这些问题单独看都不算致命但叠加在一起Agent 系统就成了一个谁都不敢动的定时炸弹。Kiro Agent 的设计思路正是冲着这些问题去的它把 Agent 的各个能力模块化、服务化在 AWS 上借助云原生的组件来承载让整个系统可以像搭积木一样灵活演进。1.2 Kiro Agent 的定位与设计目标从架构角度看Kiro Agent 本质上是一个“以模型推理为核心、以工具执行为能力、以状态管理为底座”的智能体服务。它要做的事情可以拆成三句话接收用户请求理解意图把自然语言转化为可执行的任务。编排任务流程决定调哪些工具、按什么顺序调、遇到错误怎么处理。安全地执行工具调用并把执行结果回传给模型最终生成对用户有意义的响应。这个定位决定了它的架构不可能是一个单体的 Python 脚本。它需要区分“控制面”和“数据面”需要把“模型调用”“工具执行”“状态存储”这些职责彻底解耦。在 AWS 上这个思路对应着一套非常自然的组件选型API Gateway 做入口Lambda 做计算单元Step Functions 做编排DynamoDB 做状态存储S3 做数据落地。Kiro Agent 的架构就是围绕这套 AWS 原生能力搭建的。2. Kiro Agent 的骨架核心服务选型与职责划分2.1 入口层API Gateway 与请求接入整个 Kiro Agent 链路的起点是 API Gateway。负责接收来自 Web 端、移动端或第三方系统的请求完成身份认证、限流控制、参数校验之后再转发到后端的处理逻辑上。这里有两个容易踩坑的细节第一API Gateway 的超时时间是硬限制。默认情况下API Gateway 的集成请求超时是 30 秒REST API或 29 秒HTTP API但 Agent 的推理过程经常超过这个时间。模式化做法是API Gateway 只负责接收请求立即返回一个任务 ID真正的推理和工具执行放到异步任务链路里前端通过轮询或 WebSocket 拿到最终结果。Kiro Agent 在这一点上做得比较规范所有耗时操作都是异步化的。第二请求体大小的控制。Agent 的输入往往包含大量的上下文信息如果走 API Gateway 的 JSON 请求体会受 10MB 的 payload 限制。实际项目中大体积的上下文素材文档、图片、历史会话压缩包通常先上传到 S3API Gateway 只传对象的引用地址。这个思路在 Kiro Agent 里也体现得很明显——它把“用户直接传内容”和“用户传内容引用”两种模式做了明确区分。2.2 计算层Lambda 与 AWS SAM 的应用再往下一层是核心的计算单元。Kiro Agent 的业务逻辑并没有跑在一个常驻服务器上而是拆分成了多个独立的 Lambda 函数。这种选择的好处是显而易见的弹性伸缩天然解决。Agent 的请求量往往很不均匀白天工作时段可能是夜间的几十倍。Lambda 的按需伸缩特性让它能在几十秒内从 0 实例扩展到几百个并发不需要预先为峰值买单。成本与业务量挂钩。没有请求时Lambda 不产生任何费用。对一个 Agent 项目来说早期用户量不稳定常驻服务器就是在烧钱而 Lambda 是按调用次数和运行时长计费成本曲线平滑得多。具体实现上Kiro Agent 使用了AWS SAMServerless Application Model来定义和部署这些 Lambda 函数。SAM 的价值在于它提供了一套声明式的语法基于 CloudFormation你可以在一个template.yaml文件里描述所有函数、触发器、权限和依赖资源。一个简化的 SAM 模板片段大概长这样AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Resources: AgentEntryPoint: Type: AWS::Serverless::Function Properties: CodeUri: src/entry/ Handler: app.lambda_handler Runtime: python3.12 MemorySize: 1024 Timeout: 60 Policies: - Statement: - Effect: Allow Action: dynamodb:PutItem Resource: !GetAtt AgentStateTable.Arn Events: Api: Type: Api Properties: Path: /agent Method: POST AgentStateTable: Type: AWS::DynamoDB::Table Properties: BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: session_id AttributeType: S KeySchema: - AttributeName: session_id KeyType: HASH这里我刻意把 DynamoDB 表也定义在同一个模板里是因为 Agent 的函数往往需要访问状态表SAM 会帮我们自动生成 IAM 角色和权限省去手工配置的麻烦。用 SAM 管理 Agent 项目最大的收益就是把“基础设施即代码”这件事落地了——你可以在本地sam build sam deploy --guided一键拉起整套环境这比手动在控制台里创建资源再手工配置权限要可靠一个数量级。2.3 模型调用层多模型接入与统一抽象Agent 的核心是模型推理但 Kiro Agent 的架构里模型调用被设计成一个独立且可替换的层。它没有把某个模型 SDK 直接散落在业务代码的各处而是封装了一个统一的ModelGateway接口。这个设计的直接原因是模型迭代太快了。同样的任务上个月可能是 Claude 表现最好下个月可能就是某个国产模型或自研微调模型更合适。如果业务代码跟具体的模型 SDK 耦合每次换模型都要改一圈代码效率极低。Kiro Agent 的ModelGateway做的事情包括把不同模型的请求格式统一成内部 Schema。OpenAI 兼容格式、Claude 的 Messages 格式、甚至 AWS Bedrock 的 InvokeModel 格式都被转换成一种内部中间表示。这样上层业务逻辑永远不会关心底层模型长什么样。承载超时、重试和熔断逻辑。模型服务是最不稳定的环节动不动就超时、限流。统一的ModelGateway可以把退避重试、熔断降级这些逻辑收敛在一个地方实现。支持混合路由。比如简单的意图识别用便宜的小模型复杂的推理任务才调用大模型。这种“模型路由”策略在小规模 Agent 项目里就能带来可观的成本节约。2.4 工具执行层Agent 能力的延伸模型只负责“思考”真正的“动手”要靠工具执行层。Kiro Agent 的工具层支持两种类型的整合AWS 原生服务集成。Agent 可以直接调用 S3、DynamoDB、SQS 等 AWS 服务此时通过 IAM 角色授权不需要管理任何密钥。外部 API 集成。Agent 需要访问第三方服务比如内部 CRM、企业微信机器人、某个 SaaS 平台的 OpenAPI此时通过 Secrets Manager 统一管理凭证。这个分层里最值得点赞的设计是工具注册机制。每个工具在执行前都会向 Agent 的描述列表注册说明自己的功能、参数 Schema、调用示例。模型根据这些描述来决定“现在应该调用哪个工具、传什么参数”。Kiro Agent 把工具描述以 YAML 的形式集中管理目录结构类似这样tools/ ├── aws_s3_query/ │ ├── schema.yaml │ └── handler.py ├── internal_crm_lookup/ │ ├── schema.yaml │ └── handler.py └── web_search/ ├── schema.yaml └── handler.py每个工具的schema.yaml都定义了输入参数和输出格式handler.py负责实际执行。这种“声明式工具定义 函数式实现”的模式让工具的扩展成本降到最低。我在自己的项目里也借鉴了这套做法实测下来新加一个工具差不多只需要写一个函数加一份声明半小时内就能完成。3. 状态、记忆与任务编排Agent 的灵魂所在3.1 会话状态DynamoDB 做底座的必然选择一个 Agent 系统里状态管理是区分“Demo”和“生产级应用”的分水岭。Kiro Agent 的会话状态存储在 DynamoDB 中这个选择不是偶然。DynamoDB 在 Agent 场景下的优势体现在三个维度读写延迟稳定在毫秒级。Agent 的每个推理步骤都要读取上下文如果状态读取就要几百毫秒整个系统的响应速度会很难看。按需计费模式适合波动负载。Agent 的会话读写在一天内分布极不均匀用PAY_PER_REQUEST模式高峰不关心预置容量低谷不浪费成本。TTL 自动过期能力。会话数据默认设置 TTL比如 7 天过期后 DynamoDB 自动清理不需要专门写任务去删数据。数据建模上我的建议是采用“主表 索引”的结构。主表以session_id为分区键存储会话的基本信息和最近几轮对话历史消息可以单独放到另一个表中用GSI全局二级索引按会话和时间范围查询。Kiro Agent 的架构也是这样处理的——它是把会话元数据、消息历史、任务执行记录分表存储避免单个表过宽导致的热分区问题。3.2 记忆子系统短期与长期的分层设计Agent 的“记忆”是一个老生常谈但很少有人做好的话题。Kiro Agent 对记忆的处理是分层级的短期记忆就是当前会话窗口内的消息序列直接存在状态表中。每次模型调用时把最近的几轮对话拼接到 Prompt 里。这里要控制窗口大小否则一次请求就会打爆模型的上下文上限。长期记忆则用来沉淀跨会话的用户偏好、事实性信息。Kiro Agent 的做法是异步地在会话结束后从对话中抽取关键信息写入一个独立的“记忆库”。后续新会话启动时先查询记忆库把相关的历史信息注入到系统 Prompt 里。这个设计的精妙之处在于它把“记忆写入”和“记忆读取”从主链路中拆了出去。用户并不会因为记忆抽取变慢而感受到延迟同时记忆的查询是异步并行的不会阻塞主流程。实测中长期记忆这个模块的成功率很难做到 100%会有抽取不准、信息过时等问题。Kiro Agent 的做法是通过“记忆置信度”字段给每条记忆打分低于阈值的记忆不会被注入到新会话中。这个方法看似简单实际效果比那些“一股脑把所有历史都塞进上下文”的方案好太多了。3.3 任务编排引擎Step Functions 如何承载 Agent 的流程控制Agent 的执行流程不是线性的——模型决定调用某个工具工具返回结果模型根据结果决定下一步是继续调用还是直接回答用户。这个“循环决策”过程在代码里写起来很绕但如果状态机来编排整个逻辑会清晰很多。Kiro Agent 在任务编排上选择了AWS Step Functions它把 Agent 的一次完整任务建模成一个状态机用户请求 → 意图识别 → [调用工具A] → [判断结果] → 调用工具B / 直接回答 → 生成回复每个状态对应一个 Lambda 函数或一个分支判断条件。Step Functions 把状态之间的流转、重试、异常处理集中管理起来代码里不需要到处写try...catch状态机的定义文件本身就表达清楚了“什么时候走哪条路”。用 Step Functions 编排 Agent 有一个非常大的好处审计与调试极其直观。状态机的每一步执行都会有详细的输入输出日志在控制台里能看到整个执行轨迹——用户请求在哪个步骤被卡住了、哪个工具调用失败了、失败的原因是什么一目了然。这比看散落各处的 Lambda 日志要高效得多。4. 权限隔离与安全设计Agent 调用 AWS 资源的边界控制4.1 最小权限原则怎么在 Agent 系统里落地Agent 系统的安全设计是一个容易被忽略但必须严格对待的问题。道理很简单Agent 能用自然语言操控工具意味着任何人如果能诱导 Agent“做坏事”就能间接利用它的权限。所以在 Kiro Agent 的架构里权限隔离是从上到下贯穿的。第一层隔离是IAM 角色分离。入口函数、编排状态机、工具执行函数各自有独立的 IAM 角色。入口函数只能访问状态表和发送消息队列工具执行函数才拥有调用具体 AWS 服务的权限。这样即使某一层被攻破攻击者也无法横向移动到整个系统。第二层隔离是动态凭证。外部 API 的密钥不放在代码或环境变量里而是放在 Secrets Manager 中Lambda 运行时通过 SDK 动态获取。Kiro Agent 还配置了密钥的自动轮转避免长期持有同一个密钥带来的泄露风险。第三层隔离是参数级校验。工具函数在执行前会校验模型传入的参数是否符合 Schema 定义防止模型“即兴发挥”出一些意外参数。比如 S3 查询工具只允许访问以allowed_前缀开头的 bucket其他一概拒绝。4.2 工具调用的鉴权与审计光有权限隔离还不够每一次工具调用都应该能被追踪和追溯。Kiro Agent 在这方面的做法是每轮工具调用都会产生一条审计日志记录内容包括——用户身份和会话 ID调用方 Agent哪个 Agent工具名称和传入参数执行结果成功/失败/错误信息耗时、费用等运营数据这些日志统一写入 S3 或 CloudWatch Logs支持事后追溯。在 Agent 系统里审计日志不是可有可无的合规负担而是一个必需的调试工具。有一次我在调一个 Agent 的 bug模型总是反复调用同一个工具、陷入死循环如果没有完整的调用日志这类问题几乎不可能定位。5. 部署实测从本地开发到 AWS 上线的完整链路与踩坑记录5.1 本地开发环境的搭建前面讲了这么多架构层面的设计真正动手部署的时候又是另一套经验。Kiro Agent 的本地开发依赖 SAM CLI这是整个开发链路里我最想推荐的部分。本地开发的核心是sam local命令。它可以在你的电脑上模拟 Lambda 运行环境让你不用每次改代码都部署到云端才能验证。另外它还可以启动本地版的 API Gateway配合curl或者 Postman 直接测试 HTTP 接口。实际开发中最常用的命令组合是# 构建项目生成部署前需要的产物 sam build # 本地启动 API Gateway 和所有 Lambda 函数 sam local start-api # 如果只想单独调试某个 Lambda 函数 sam local invoke AgentEntryPoint --event event.json这里有两点需要注意一sam build是在本地做依赖安装和打包的。如果你的项目依赖了boto3之外的第三方库记得在template.yaml中声明依赖层Layer否则打出来的部署包会缺库运行时报Unable to import module。二本地环境的 Lambda 和云端一样默认是不可访问外网数据库或内网服务的。如果你在本地调试时发现 Lambda 无法连接 DynamoDB 表多半是因为本地的凭证没有配置正确需要先运行aws configure确保本地凭证指向你的 AWS 账号。这里不要用生产环境的密钥建议用 IAM 用户加最小权限的临时凭证。5.2 SAM 打包与云端部署的关键参数本地调试通过后部署上云的过程就一句话sam deploy --guided。但里面有几个参数值得细说第一个是超时时间Timeout。Lambda 函数的默认超时是 3 秒对 Agent 场景来说根本不够。我的经验是入口函数设置 10-30 秒模型网关函数设置 30-60 秒纯工具函数可以设置 15 秒左右。如果超过 60 秒建议把任务改成异步模式而不是硬撑超时。第二个是内存大小MemorySize。Lambda 的内存大小同时决定了 CPU 算力内存越大运行越快价格也越高。对 Python 实现的 Agent 项目我实测下来 512MB 是一个“够用且不浪费”的最低配置如果涉及大文档解析或者图片处理建议直接上 1024MB 或 2048MB。要注意过高的内存并不总是带来线性加速比如简单的字符串处理在 512MB 和 1024MB 下的差距微乎其微。第三个是并发限制ReservedConcurrency。Agent 的 Lambda 函数必须要设置并发上限否则一旦被调用的模型 API 卡住函数可能无限扩展费用像流水一样消耗。我给 Kiro Agent 的每个核心函数都设置了ReservedConcurrentExecutions主力函数给 50工具函数给 100。这个数字不是拍脑袋定的而是根据业务峰值预估出来的——假设峰值并发 30 个用户每个用户的一次请求最多并发 3 个工具调用预留 3 到 5 倍的缓冲区就是极限。5.3 我踩过的坑与解决办法整个部署过程中我最想分享的是三个真实踩过的坑每一个都浪费了不少时间坑一SAM 的隐式 API 与显式 API 权限差异刚开始我用template.yaml里的Events块定义 API 端点结果发现线上 API 的路径总是不对。后来才明白SAM 在这里有两种写法# 写法一隐式 API最简单 Events: Api: Type: Api Properties: Path: /agent Method: POST # 写法二显式 API更可控 AgentApi: Type: AWS::Serverless::Api Properties: StageName: prod # ...用隐式 API 时SAM 会为每个函数自动创建一个唯一的资源 IDAPI Gateway 的 URL 是自动生成的路径可能和你预期的不完全一致。显式 API 则让你完全控制网关的部署和路径。如果你对 API 的路径有严格要求建议从一开始就用显式 API。坑二工具函数循环调用导致 Step Functions 状态机卡死这是我遇到过的最诡异的 bug。一个 Agent 在执行某个任务时模型反复调用“查询订单状态”这个工具因为它从结果里看到了“处理中”就忍不住一直查。每次查询间隔几十秒状态机在一段时间里疯狂执行。解决办法有两个缺一不可在 Prompt 里加限制告知模型“同一个工具同样的参数连续调用超过 3 次必须停止”。在 Step Functions 的状态机里加循环计数检测。当某个状态的执行次数超过阈值时直接进入“放弃并回复用户”的终止状态。这是比靠 Prompt 约束更可靠的兜底方案。坑三状态表的热分区问题DynamoDB 如果分区键设计不好会出现某个分区访问量过大其他分区闲置的情况。Agent 场景下最容易出现的错误是会话表不断追加消息导致一个会话对应的分区键session_id数据量过大。Kiro Agent 后期做了一个调整把“最近 N 条消息”放在主表旧消息异步转移到 S3 或另一个冷存储表。这个改动直接让状态表的读写延迟从几百毫秒降回了几毫秒级别。6. 架构优化方向与个人使用体会6.1 从简化视角看 Kiro Agent 的可复制模式归根结底Kiro Agent 的架构价值不在于某个单点技术有多新颖而在于它把 Agent 系统应有的“标准动作”都做到位了——模块化、可观测、可扩展、权限可控。如果你要从零开始搭建一个自己的 Agent 项目我建议不要试图一次性实现所有功能。先按这样的顺序来先跑通“Lambda 模型调用 会话状态”的最小链路让 Agent 能对话、能记住上下文。接着加“工具注册与调用”机制让 Agent 能动手做事情。再上 Step Functions 做编排把多步骤任务管理起来。最后补上审计日志、权限最小化、成本控制这些“安全带”。这个顺序保证了每一步的复杂度都在可承受范围内也能让你在每一步都积累真实的运维经验而不是一次性铺开一堆组件后无法排查问题。6.2 关于成本控制的一点点经验最后聊一下很多人关心的成本问题。Agent 系统的成本大头从来不是 Lambda 的调用费而是模型 API 费用和状态存储的长尾效应。模型费用的控制核心是做“任务分级”——简单的意图识别用便宜的模型复杂的推理才用贵的大模型。另一个有效手段是缓存面向相同知识库的查询可以走语义缓存命中后直接返回结果不再调用模型。Kiro Agent 的模型网关层在实现时就预留了这个能力实测命中率在 20%-30% 时模型费用就能省下一块可观的数字。状态存储费用的控制则要关注 TTL。过期会话应及时清理长期记忆库中的数据也应有退化策略比如超过一年未访问的沉淀信息降低权重或归档。AWS 的费用看板非常适合每天查看——一旦某天费用异常上涨往往是某个工具函数进入了未预期的循环及时排查能避免月底账单带来的惊吓。Kiro Agent 这版架构在我看来已经迈入了“可生产使用”的及格线但它距离一个完善的 Agent 平台还有距离。未来如果要做面向多租户的 SaaS 化 Agent 服务租户隔离、配额管理、计费统计这些能力还需要在现有的架构上继续演进。对我个人而言这个项目的最大收获不是某段代码或某个配置而是验证了一套“在 AWS 上构建 Agent 的标准姿势”。下次再做一个 Agent 项目我应该会直接把 Kiro Agent 的骨架拿出来复用在它上面填充具体的业务逻辑就足够了。当然复用之前我会先把踩过的这些坑都记在项目的 README 里免得自己过几个月又犯同样的错误。