把 AI Agent 跑稳:Kollab 在 Amazon Bedrock AgentCore 上的工程心得

把 AI Agent 跑稳:Kollab 在 Amazon Bedrock AgentCore 上的工程心得

2026年4月25日

Kollab 团队在 AWS 上构建 AI Agent 平台的工程心得:为什么选 Amazon Bedrock AgentCore + Claude Agent SDK + S3 + LiteLLM 网关、四个生产级 Pattern、CloudWatch 与 transcript 双视角排查、本地 SDK 复刻 runtime,以及给其他 AWS 客户的五条带走。

Amazon Bedrock AgentCoreClaude Agent SDKAmazon S3AI Agent 架构Workspace 持久化模型路由LiteLLMAnthropic ClaudeAWS

作者:Kollab 工程团队

写给谁:正在用 AWS 做 AI Agent 产品、卡在"任务跑得动但跑不稳"那个阶段的工程团队

关键词:Amazon Bedrock AgentCore,Claude Agent SDK,Amazon S3,AI Agent 架构,Workspace 持久化,模型路由,Anthropic Claude


写在最前面

这篇文章不是开源项目的 README,不会把每一个文件路径、每一个环境变量、每一个内部常量名摊出来。

想分享的是在 AWS 上做 Kollab 这个 AI Agent 平台过程中真正重要的几个判断:为什么选这些 AWS 服务、它们各自解决了什么问题、给同样在做 Agent 的同行可以参考什么。

如果你正在评估要不要用 Amazon Bedrock AgentCore 跑自己的 Agent,这篇文章应该能帮你少走一些弯路。


TL;DR

只看这段也行:

  1. Agent 任务会跑十几分钟、调几十次工具、随时被销毁。架构要按"任意时刻可被杀掉、任意时刻可被复活"来设计,这和写 Web API 的心智完全不一样。
  2. AgentCore Runtime 是 ephemeral 的。把工作目录和会话 transcript 持续同步到 Amazon S3,runtime 才能真正变成无状态算力。
  3. 业务代码不要直连 Bedrock。中间放一个模型网关,你才能在模型迭代、跨 provider、计费归因这些事上有得选。
  4. 让 Skill 声明 LITE / PRO / MAX 三个档位,而不是具体的 model ID。模型每两周一代,写死 SKU 等于给三个月后的自己挖坑。
  5. 会话原始 JSONL 是排查 Agent 行为的唯一真值。被你自己代码加工过一次的日志都不算数。

下面挨个讲为什么、Kollab 是怎么做的、其他 AWS 客户怎么参考。


一、Kollab 是什么

Kollab 是一个面向团队的 AI 协作工作区。它和 ChatGPT、Claude.ai 最大的不同——不是聊天框,是把 Skill、Bot、Connector、文件工作区串起来的 Agent 平台

具体在跑哪些任务,直接看官网真实场景:

我们自己每天在用的四个真实工作流写在了 Escape the Workflow Pain:群聊 Bug→GitHub Issue、每日工作报告、读代码答疑、提交时自动关 Issue。

这些场景看起来是产品故事,但每一个背后,都是同一个工程问题。


二、最重要的认知转变:Agent 不是 HTTP 请求

这一节决定了下面所有的架构选择,先讲清楚。

写了十年 SaaS 的工程师,脑子里那个"请求-响应"模型在 Agent 时代是失效的。

举个例子。在 bug-reports-to-github 这个场景里,用户在群里抛一句"刚才那个搜索接口又挂了",Bot 要跑的步骤是这样:

🖼️ 插图:从群聊一句话到 GitHub Issue 的完整流程——意图分类、查重、起草、创建、指派、回贴

简单 bug 30 秒结束。复杂任务,比如 博客自动化管道,5 到 15 分钟。

这中间会发生什么?

Runtime 被缩容了,session 没了。

用户刷新页面,前端状态没了。

模型返回 5xx,半个任务白跑。

用户在第 8 分钟点了中断,前面 7 分钟的产出能不能保留?

按"请求-响应"心智写的代码,上面任何一种情况都会让你的 Agent 看起来很不可信。

Agent 产品的核心问题不是"调模型",而是"对抗遗忘"。

我们最终选了 Amazon Bedrock AgentCore,不是因为它能调模型——Bedrock 自己就能调——而是因为它把"runtime 可被随时销毁"这件事变成了一等公民,逼你把架构设计对。


三、整体架构:每个 AWS 服务在这里干什么

🖼️ 插图:Kollab 整体分层架构——客户端 → AWS EKS Tokyo → AgentCore Runtime → 独立的 LiteLLM 网关 → AWS Managed 服务(Bedrock / S3 / RDS)

把每一层的选择动机讲一下,这是其他 AWS 客户参考性最强的部分:

中间还有一个独立的模型网关,这是整套架构里最容易被忽略、但回头看最重要的一个组件。下面专门讲。


四、Pattern 1:Workspace 是牲畜,S3 是真值

这是整套架构里最重要的一个设计决定。

这个模式在解决什么

AgentCore 的 runtime 会因为空闲超时、缩容、节点故障被销毁。这不是 bug,是 feature——它让你不用为闲置的 Agent 付钱。

但如果 Agent 在 runtime 内存或本地磁盘里存了任何"必须活过这次请求"的状态,这件事就会反过来咬你。我们把这条作为默认前提写进了项目规范:"AgentCore runtime 会因为空闲超时、缩容、故障等原因被销毁,新请求分配到全新 runtime"——所有 runtime 内代码都按这个前提写。

我们的解法很简单:runtime 本地的工作目录,持续双向同步到 S3,由一个统一的 workspace 管理模块维护目录策略表。把目录策略集中在一个地方,就是为了避免"runtime drift"——不同入口各自拼路径,迟早会出现不一致。

🖼️ 插图:Workspace 目录对照——runtime 本地的工作目录与 S3 上的同名前缀完全镜像,中间通过 sync 与 hydrate 双向同步

每一个 runtime 拿到 conversation_id,做的第一件事是从 S3 把对应的工作区拉下来(hydrate)。任何文件的创建、修改、删除,sync 机制写回 S3。Claude Agent SDK 的会话 transcript 也在这个目录下,所以连"模型记忆"都被一起持久化了。

顺带说一下我们对"文件"的处理:在 Kollab 里,文件的唯一真值源叫 artifact——后端有 artifact 实体,前端有对应的 store。消息里只保存 artifactId 引用,绝不复制文件元数据。这套规则保证了"工作区的文件状态"和"消息历史里看到的文件卡片"始终是同一个真相,而不是两套互相漂移的副本。

三个直接收益

会话可恢复。Claude Agent SDK 的 --resume 需要 transcript 文件,文件在 S3,新 runtime 拉下来就接着跑,模型不会失忆。

用户文件不会丢。runtime fleet 滚动重启,用户上一秒生成的草稿和 PDF 都在。

任务可以在 runtime 之间漂移。今天 runtime A,明天 runtime B,用户感知不到。

给其他 AWS 客户的启发

做长任务 Agent,第一个该选的不是模型,是状态层。S3 在这里几乎是完美的搭档:够便宜不会成瓶颈,11 个 9 的持久性,和 IAM 天然集成可以按 conversation 做 prefix 隔离,以后想做跨区容灾也是托管能力。

但有一个容易踩的坑提前告诉你:清理必须双端一致。本地 JSONL 删了、S3 上没删,下一次 hydrate 会把删掉的文件"复活"。这个 bug 在传统 Web 里不会出现,但在 runtime 可漂移的世界里,任何状态不一致都会被 runtime 重建放大。


五、Pattern 2:不要让业务代码直接调 Bedrock

最直觉的写法是 Agent 代码直接用 AWS SDK 调 Bedrock 的 InvokeModel。简单、官方、文档齐全。

但要在生产里长期跑,直连方案的问题会一个个暴露:模型升级要扫一遍所有 Skill 改 model ID;Claude Agent SDK 内部有自己的默认模型槽,会偷偷把你想用的旗舰模型换成更便宜的,业务侧难以感知;想接非 Bedrock 的模型基本不可能,代码绑死;计费数据散在 CloudWatch metric 里,要拼成"按客户、按 Skill"的账单得写一堆胶水。

我们的做法是在 Claude Agent SDK 和 Bedrock 之间,放一个 LiteLLM 网关,部署在东京独立的 EC2 上(llm.kollab.im),所有出站流量从这里走。

🖼️ 插图:Kollab 模型调用链——Agent SDK → LiteLLM 网关(EC2 独立服务)→ 同时挂 Bedrock 和其他 provider

这一层带来四个 Bedrock 直连解决不了的能力。

第一是模型升级只改网关出口,不改调用链路。Skill 声明逻辑档位(下一节讲),网关把它解析成具体的 Bedrock model ID。仓库里关于 tier 的代码注释写的就是这件事:"未来批量换代时,只改这一个文件即可,不用翻整仓搜字符串。"

第二是避免环境配置漂移。把网关收口在一处的另一个动机,是让默认档位和开发态临时切模型始终共享同一条网关与鉴权配置——避免出现"默认模型能跑、临时切模型时忘记带同一套 base_url / key"这类难以追的环境漂移。

第三是跨 provider 路由。同一个网关同时挂 Bedrock(Anthropic Claude)和其他 provider(Minimax M2.7 跑轻量档),业务代码完全感知不到。只用 Bedrock SDK 做不到这件事。

第四是计费、审计、可观测性收口。每次调用打了多少 token、属于哪个对话、归哪个组织,从网关一处写进自己的计费系统,不用去拼 CloudWatch metric。

给其他 AWS 客户的启发

长期做 Agent 产品,网关这一层早做早划算。等到你有第三个模型、第二个 provider、第十个 Skill 的时候再补,会很痛。

补一句:我们这套没做 region fallback。目前只挂了 ap-northeast-1 单区,原因是延迟和数据驻留要求。如果你对可用性要求更高,网关这层是放被动 region fallback 的好位置,但请按自己的延迟和合规要求评估,别照抄。


六、Pattern 3:模型选择按"档位",不按 SKU

承接上一节。模型迭代到了 2026 年差不多每两周一代,把 model ID 写死在业务代码里的人,都是在给三个月后的自己挖坑。

代码里只有三个 tier 常量,Skill 开发者只声明这三个之一:

这套抽象的价值不在省事,在迁移自由度:Opus 4.6 升 4.7,改一行配置,所有 max 档 Skill 自动用上新能力;想试一个全新 provider 的旗舰模型,加一行配置进入 A/B;某个模型出问题要紧急回滚,业务代码一行不动。

值得单独说一句的是,lite 档接的是 Minimax M2.7,而不是 Bedrock 上的 Claude Haiku。

这事的启发是:模型应该按任务画像选,不是按云厂商选。Bedrock 是非常好的 anchor provider,但坚持只用 Bedrock 上的模型,等于把"模型最优解"和"基础设施提供商"捆绑在一起。模型网关让我们能跨这条边界自由选。

顺带一句关于"模型能力补丁"。不同模型支持的能力不同——有的原生支持 vision,有的不支持 reasoning_effort。我们用 capability patch skill 在网关之上给缺能力的模型打补丁。这张能力表是硬编码进代码、走 PR 上线的,不走 env 开关——理由很直接:模型原生能力是二分事实,不是运维口味,新增 vision 支持这种事应该走代码 review,不应该在 prod 偷偷 flip 一个 env。


七、Pattern 4:把"会被杀掉"写进代码里

AgentCore runtime 会被随时销毁。从这件事推导出几条工程纪律,我们直接写进了仓库的 AGENTS.md,作为新工程师入职第一天必须读的部分。

第一,状态必须按 session ID 隔离。Python runtime 是常驻进程,模块级全局变量在所有 session 之间共享。多用户场景里,任何按全局 mutate 的可变状态都是串台 bug 的源头——这不是建议,是规则。

第二,工具调用必须幂等。一个工具可能因为 runtime 漂移被重放,"发飞书消息"这种工具不幂等,用户会收到两条一样的。这一点对 Kollab Bot 4 工作流 里"提交时自动关 issue"那种自动化流尤其要紧。

第三,Transcript JSONL 是唯一真值AGENTS.md 里写得很硬:"涉及 AgentCore 真实执行轨迹时,必须优先检查 transcript JSONL,而不是只看 qa_message、前端文案或被脱敏后的 SSE 文本。"原始 JSONL 里有真实的 assistant / tool_use / tool_result / API Error 事件,这是唯一能区分"模型说错话了"和"我们的代码解析坏了"的地方。

第四,清理一致性/clear(remove_history)不仅要删本地 JSONL,还要同步删除 S3 上的文件,防止 runtime 重建时旧文件被恢复回来。Pattern 1 里讲过这个坑,这里把它升级成纪律。

四条都很基础,但工程纪律 > 架构选型:架构可以换,纪律一旦没建立,同一类 incident 会反复出现。


八、看一个真实任务把上面的设计串起来

博客自动化管道 在 Kollab 上的完整执行轨迹长这样:

🖼️ 插图:博客自动化管道任务的完整执行流程——用户触发 → S3 hydrate → PRO 档跑趋势收集 → MAX 档+xhigh 跑草稿撰写 → MCP 写入 Notion → S3 sync → 完成

注意几个关键节点:

  • 任务进来第一件事是 hydrate,按 conversation_id 从 S3 拉回上次的 transcript。用户三天前发起过任务,这次拉回来就是三天前那个会话的全部上下文(Pattern 1 的体现)
  • 中间走了两次不同 tier 的模型:意图轻的趋势收集走 pro 档,逻辑重的正文撰写走 max 档加 xhigh reasoning。这是 Claude Opus 4.7 升级博客 里详细写过的能力(Pattern 2 + Pattern 3 的体现)
  • transcript 在每次重要事件后 sync 回 S3(Pattern 1),即使 runtime 在写 Notion 后被销毁,下一次拉回来还能看到全部历史

这就是上面四个 Pattern 在生产里的样子,它们不是孤立的设计,是同一套"对抗遗忘"哲学的不同侧面。


九、把它跑起来:可观测性与本地复现

讲完架构和真实任务,还有两个生产层面的事,任何用 AgentCore 的客户都会遇到。

1. CloudWatch + S3 Transcript 是两套互补视角

AgentCore Runtime 的运行日志默认进 CloudWatch,路径是 /aws/bedrock-agentcore/runtimes/,按 runtime ID 和时间区间过滤——这是排查"runtime 在某次执行里做了什么"的第一站。

但 CloudWatch 看不到模型层的对话内容,只能看 runtime 进程的输出。要看模型真实说了什么,必须去 S3 上的 transcript JSONL(Pattern 1)。两套日志要配着用:

  • 用户报"AI 答错了" → 先看 transcript JSONL,定位到具体的 tool_use / assistant 事件
  • 用户报"Agent 卡住了" / "服务挂了" → 先看 CloudWatch,看 runtime 进程是不是异常退出
  • 两边对不上 → 通常是中间某一层(网关、SDK)出问题,顺着对照很快能锁住

如果你的模型网关也部署在 EC2 上,建议用 SSM Session Manager 而不是 SSH 进机器排查。理由很简单:网关只需要对外开 HTTPS,根本不必把 22 暴露出去。SSM 走出站连接,无需开放入站,IAM 直接控制权限——这是更干净的默认。

2. 用 Claude Agent SDK 在本地复刻 runtime 行为

AgentCore Runtime 里跑的就是 Claude Agent SDK。这意味着——任何模型层面的行为问题,都可以在开发者笔记本上用同一份 SDK 复现,不需要 deploy、不需要等 runtime cold start。

做法是:把生产的 transcript 从 S3 拉下来,用 SDK 的 --resume 在本地接着跑同一个会话。模型会读到完全一样的上下文,行为基本可复现(剩下的不可复现部分是模型自身的非确定性)。

这个能力把"修一个 Agent bug"的循环从"改代码 → 部署 → 等用户复现"压缩到了"改代码 → 本地一行命令复现"。如果你在做 Agent 产品,无论用不用 AgentCore,都建议把"基于真实 transcript 在本地重放"做成标准开发工具——这是省排查时间最划算的一笔投资。


十、给其他 AWS 客户的五条带走

如果你在用 AWS 做 Agent 产品,这是我们最希望你能从这篇文章带走的五件事。

一,选基础设施前先想清楚:你做的是 SaaS 还是 Agent。SaaS 对抗的是延迟和并发,Agent 对抗的是遗忘——这两件事会推导出完全不同的架构选择。如果你按 SaaS 那套去搭 Agent,会在第三个月的某个深夜被一个 incident 教做人。

二,把 AgentCore 当 Bedrock 的补集而不是替代。Bedrock 给你模型,AgentCore 给你 runtime 生命周期管理。做问答机器人 Bedrock 直连就够;做长任务、多工具、多用户的 Agent,AgentCore 帮你免去自己维护一个 ephemeral fleet 的工作量。

三,把 S3 当 Agent 状态层用,不只是文件存储。Workspace 和会话 transcript 都放 S3,AgentCore runtime 真正的"即用即销"价值才发挥得出来。

四,在 Bedrock 之上加一个模型网关,越早越好。模型升级自由度、跨 provider 能力、计费可观测性,这三件事是它带来的。

五,让 Skill 声明档位,不声明 SKU。模型迭代速度只会越来越快,任何写死的 model ID 都是债。

更宏观的产品层观察可以读这几篇:


十一、FAQ

Q:Amazon Bedrock AgentCore 适合什么场景?

A:任务长、状态多、需要工具调用、需要多用户隔离的 Agent。问答机器人用 Bedrock 直连就够,AgentCore 的价值在 runtime 生命周期管理。

Q:在 Bedrock 之上加一层模型网关,是不是过度工程?

A:看你的时间维度。做一个 demo 确实多余。要长期运营、支持多个 Skill、面对每两周一代的模型迭代,网关层是抗熵增的关键。

Q:Claude Agent SDK 的会话怎么持久化?

A:SDK 把 transcript 写到 $CLAUDE_CONFIG_DIR/.claude-sessions/projects/*.jsonl。把这个目录双向同步到 S3,SDK 的 --resume 拉回来就能复活会话。

Q:多用户共享 Python runtime 怎么避免串台?

A:把"状态必须按 session ID 隔离"作为硬规则写进项目文档,而不是个别函数自己处理。不要全局 mutate os.environ 或模块级变量。任何按全局共享的可变状态都会变成串台 bug 的源头。

Q:为什么不依赖 Bedrock 的多区高可用,自己做 region fallback?

A:我们目前没做。跨区延迟和数据驻留是主要原因,这是 trade-off。其他 AWS 客户可以按自己的延迟和合规要求评估。

Q:Kollab 上的 Skill 列表在哪里看?

A:产品维度可以看 Skills 页和 /use-cases,版本节奏可以看 /changelog


十二、最后

回过头看,这一整套架构——AgentCore 的 runtime、S3 的工作区、模型网关、Claude Agent SDK 的对话——都是在回答同一个问题:

当机器随时可能消失,我们要怎么让一段持续了三十分钟的对话,觉得自己从未被打断过?

这件事如果做对了,用户其实什么都感觉不到。而这,大概就是基础设施工程最迷人的地方:

它最高的成就,是让人忘记它的存在。

如果你想看看这些设计跑出来的产品长什么样,欢迎到 kollab.im 注册,或者直接看 /use-cases 上挂的真实场景。


相关链接

Kollab 产品

Kollab 官方博客(本文引用)

AWS 服务

第三方