跳到正文
AWS Machine Learning Blog· Thiago Verney·· 1 小时前精选AI 评分64

如何在 AgentCore 与 OpenClaw 上构建具备上下文记忆的 AI 助手

Building a context-aware AI assistant on AgentCore and OpenClaw

AI 导读

AWS 官方博客介绍如何在 Amazon Bedrock AgentCore 运行时上运行开源智能体系统 OpenClaw,构建能跨会话积累上下文的个人助手。方案用 AgentCore memory 的短期事件与长期抽取两层结构,配置 USER_PREFERENCE、SEMANTIC、SUMMARIZATION 三种抽取策略,并按用户 chat ID 划分命名空间隔离记忆。

推荐理由

原文给出可复用的 AgentCore 记忆架构与提示词缓存排序方法,读者可据此搭建带长期记忆的智能体。

正文 · AI 翻译

现成的 AI 助手能很好地回答单个问题,但在另一个维度上却表现不佳:连续性。向一个无状态的助手询问你今天花园的情况,它完全不知道你三周前提到过排水良好的高架花坛,不知道你只用有机肥料,也不知道你的矮牵牛花正艰难地熬过一场热浪。每次对话都从零开始,重新解释上下文的负担落在了用户身上。

问题不在于答案的质量,而在于助手对你没有记忆。本文展示如何构建一个能够积累上下文的个人助手,使用 OpenClaw——一个开源智能体系统,运行在 AgentCore runtime 上,这是 Amazon Bedrock AgentCore 的一项能力。AgentCore memory 是 Amazon Bedrock AgentCore 的一项能力,它把一次性的聊天转化为持久的知识。你还将看到如何为这些记忆打上结构化元数据标签,以便检索与当前问题相关的记录。

我们的示例是 Sprout,一个园艺助手,但该架构与领域无关。只需更换角色设定和技能清单,同一套流水线就能服务于支持机器人、健身教练或内部帮助台。整个系统位于单个 AWS CloudFormation 模板中,用一条命令即可部署,并采用按用量计费的模式,轻度个人使用每月只需几美元。在此过程中,我们分享一些设计准则,你可以将其应用于在此技术栈上构建的助手。

解决方案概述

AgentCore 是一个平台,可使用任意框架或模型大规模构建、连接和优化智能体。下图展示了端到端的请求流程,从入站 Telegram webhook 经过 AgentCore runtime,及其支持的 AWS 服务。

图 1:Telegram webhook 和 Amazon EventBridge 计划任务都会调用同一个 AgentCore runtime 智能体,该智能体协调 OpenClaw 网关、AgentCore memory 和 Amazon Bedrock

两个入口汇聚到一个智能体。Telegram 消息通过 Amazon API Gateway 和一个 webhook AWS Lambda 函数到达,而诸如早晨浇水提醒之类的计划任务则通过 Amazon EventBridge Scheduler 和一个 cronjob Lambda 函数到达。两者都调用 AgentCore runtime 上的 InvokeAgentRuntime API,在那里一个轻量的 server.py 进程协调 OpenClaw 网关、AgentCore memory 和 Amazon Bedrock Converse API。Amazon Simple Storage Service(Amazon S3)提供工作区存储,AWS Key Management Service(AWS KMS)负责加密,AWS Secrets Manager 保存机器人令牌,Amazon CloudWatch 捕获日志和指标。

先决条件

要使用 Launch Stack 按钮或 scripts/deploy.sh(在“自行扩展”一节中描述)部署你自己的版本,你需要:

  • Amazon Bedrock AgentCore 访问权限,包括 AgentCore runtime 和 AgentCore memory。
  • 为你计划路由到的模型授予模型访问权限:文本使用 Claude Haiku 4.5,视觉使用 Claude Sonnet 4.5(或你账户中可用的等效模型)。
  • 支持 linux/arm64 构建的 Docker,以及配置好的 AWS Command Line Interface(AWS CLI)。仅当你计划构建并推送自己的镜像时才需要。
  • 一个 Telegram 机器人令牌(来自 BotFather),作为助手的前门。
  • 对智能体编排概念和 CloudFormation 有基本了解。

架构:AgentCore runtime 上的无服务器智能体

每个组件都位于单个 CloudFormation 模板中,启动无需任何构建工具。以下各节将逐一介绍关键决策。

AgentCore 运行时:只为活跃计算付费

智能体运行在 AgentCore 运行时的容器中,采用基于用量的定价。你只需为智能体实际消耗的计算付费,而不是按墙钟运行时间计费,等待模型响应等 I/O 的时间也不收费。对于短时使用的个人助理来说,这就是每月约 1–2 美元基线成本与每月约 35 美元常开 Amazon Elastic Compute Cloud(Amazon EC2)实例之间的差别。这些数字是截至 2026 年 7 月轻量个人使用的估算值。当前费率请参阅 AgentCore 定价。

运行时强制执行一个最小容器契约:监听端口 8080,并暴露 GET /ping 用于健康检查,暴露 POST /invocations 作为智能体入口点。我们的容器是 linux/arm64,基于官方 OpenClaw 镜像加一个 Python 层进行多阶段构建。

OpenClaw 作为智能体基座

OpenClaw 提供智能体循环、工具使用和技能系统。它运行一个包装器(server.py),将其适配到 AgentCore HTTP 协议契约:

  • 容器启动时,server.py 将 openclaw gateway run 作为子进程启动并对其进行健康检查。
  • GET /ping 很快返回健康状态,因此 AgentCore 就绪探针通过。
  • POST /invocations 完成实际工作:解析负载、检索记忆、组装上下文、将本轮请求转发到网关,并持久化结果。有一点需要注意:AgentCore 可以解冻一个子进程已退出的冻结容器。因此调用路径不假设网关存活,它会调用一个 ensure_openclaw_ready() 辅助函数,在转发本轮请求之前重新检查健康状态(并在需要时重启网关)。

这种包装器模式可推广到其他用例。任何作为本地进程运行的智能体框架都可以用同样的方式适配到 AgentCore 运行时,而无需修改框架本身。

两个模型,按任务路由

文本聊天和图像理解在成本和质量上各有取舍,因此助理将它们路由到 Bedrock 上不同的 Claude 模型:

  • 文本使用 Claude Haiku 4.5: 对于占据日常使用大部分的高频对话轮次,它快速且便宜。
  • 视觉使用 Claude Sonnet 4.5: 对于从照片诊断植物这一频率较低但难度更高的任务,它具有更强的多模态推理能力。

文本轮次流经 OpenClaw 网关,从而获得技能和会话状态。图像轮次直接从 server.py 调用 Bedrock 上的大语言模型(LLM),将图像字节作为多模态内容块传入。我们有意让图像绕过网关:容器内 OpenClaw 构建在内容到达 Bedrock 之前丢弃了 image_url 内容部分,因此直接从 server.py 调用 Converse API 可确保模型看到实际像素。两条路径共享相同的系统提示(人设加记忆),因此体验保持一致。

模型 ID 是环境变量(MODEL_ID、VISION_MODEL_ID),因此你可以在每次部署时更换模型,而无需重新构建镜像。

技能作为可复用的能力单元

能力在 community-skills.json 清单中声明为技能。部署时脚本会在镜像构建之前将它们物化到容器中,并在 OpenClaw 配置中注册。在本文发布时,Sprout 随附天气、提醒和植物笔记技能。更换清单,同一流水线即可服务于不同领域。这正是让整个方案成为可复用模式、而不仅仅是一个机器人的原因。

Telegram 作为无服务器前门

Telegram 是个人助理的一个实用渠道,因为它基于 webhook,并且让一切保持无服务器。它不需要客户端开发,可在用户已拥有的每台设备上运行,并通过简单的 bot API 支持文本、图像和富格式。BotFather 签发一个 bot token,该 token 存储在 Secrets Manager 中。部署会注册一个 webhook,将 Telegram 指向 API 网关端点。当用户发送消息时,Telegram 将其投递到 webhook Lambda 函数,以验证负载并调用 InvokeAgentRuntime。回复通过 telegram bot API 返回。

一个值得注意的格式教训:Telegram 的旧版 markdown 模型对未转义字符毫不宽容,模型响应中一个多余的单个下划线就可能导致整条消息发送失败。将回复渲染为 HTML 是可靠的,因此助理在发送前会将模型输出转换为 Telegram 安全的 HTML。

记忆:将一次性聊天转化为持久知识

到目前为止描述的架构是一个功能强大、成本低廉、无服务器的代理,但仅凭它自身,它仍会在对话之间忘记你。记忆正是改变这一点的东西。想象一下,几周前你提到自己进行有机园艺,而今天助理推荐了一种处理方法,并自行补充说它选择了有机方案,因为你不使用合成肥料。无状态模型做不到这一点。

心智模型:短期事件,长期提取

AgentCore 记忆有两层。短期记忆通过 CreateEvent 将每个对话轮次存储为事件,以 actorId(Telegram 聊天 ID)和 sessionId 为键。这是原始记录。长期记忆由托管提取策略异步生成,形成持久、结构化的记录。我们配置了三种策略:

  • USER_PREFERENCE:园丁明确陈述的选择(“我只使用有机肥料”)。
  • SEMANTIC:推断出的事实(“在 Corten 钢制高架花坛中种植墨西哥牵牛花”)。
  • SUMMARIZATION:情景式会话摘要(“在热浪期间讨论了下部叶片发黄”)。

命名空间:每位园丁一个花园

Sprout 将记录归档到按用户划分的命名空间中,因此任何两个聊天都不会混淆:

  • sprout/{chat_id}/long_term:偏好和语义事实。
  • sprout/{chat_id}/episodic/{session_id}:会话摘要。

聊天 ID 是唯一的可变片段,这使得隔离易于推理和测试:每位独特的园丁恰好映射到一个命名空间,任何两位园丁都不会冲突。

检索、组装和注入流水线

在每一轮中,代理检索相关的长期记录,对其进行排序,并将其注入系统提示。以下是每条消息在 server.py 内发生的情况:

  • 检索。针对 sprout/{chat_id}/long_term 调用 RetrieveMemoryRecords,使用用户的消息作为搜索查询,结果上限为 50 条,时间预算为 3 秒。如果检索超时或出错,我们会优雅降级,在没有记忆的情况下回答,而不是失败。
try:
    records = memory_client.retrieve_memory_records(
        memoryId=MEMORY_ID,
        namespace=f'sprout/{chat_id}/long_term',
        searchCriteria={
            'searchQuery': user_message,
            'topK': 50,
            'metadataFilters': []
        },
    )  # 3s timeout
except Exception:
    records = []  # fall back to answering without memory

片段 1:为当前轮次检索长期记录(代表性示例。完整源代码见仓库)。

组装函数添加额外的自定义逻辑。我们希望显式偏好排在推断事实之前,每个类别内的顺序稳定,并且在注入前对结果进行上限限制:

def assemble(records, cap=50):
    explicit = [r for r in records if r.type == 'USER_PREFERENCE']
    inferred = [r for r in records if r.type != 'USER_PREFERENCE']
    # explicit beats inferred; stable order within each class
    ordered = explicit + inferred
    return ordered[:cap]

片段 2:组装步骤将显式偏好排在推断事实之前。

元数据:在命名空间内对记忆进行子分组

命名空间回答了记录属于谁的记忆,而元数据回答了它是关于什么的。在sprout/{chat_id}/long_term中,对“我的矮牵牛花正在枯萎”进行语义搜索,会返回所有含义相近的内容。对园丁来说,这意味着三月份的肥料偏好和一篇无花果树修剪笔记,会与真正重要的记录排在一起。而结构化元数据帮助我们在记忆进入提示词之前缩小其范围。

这里有一条规则决定了每一个决策。只有当某个元数据键被声明为索引键时,它才能在服务端被过滤。你可以在使用 Amazon Bedrock AgentCore Memory 中的元数据进行结构化记忆过滤中了解更多。在本例中,sprout 使用了三个索引键:

IndexedKeys:  # on the AWS::BedrockAgentCore::Memory resource
  - Key: type  # seperate the kinds of records
    Type: STRING
  - Key: section  # which bed or area it describes
    Type: STRING
  - Key: plants  # what is growing there
    Type: STRINGLIST

每个条目指定一个键(该键必须与某个索引键匹配才能被过滤),并将extractionType设置为STRICTLY_CONSISTENT(从事件中透传)或LLM_INFERRED(从对话中提取)。对于推断出的键,提取配置可以将值限制在一个固定列表中。Sprout 正是这样做的,因此两条写入路径会创建相同的词汇表,无论记录由哪一部分创建,过滤的含义都相同。

持久化该轮对话并闭环

模型响应后,server.py会同时用用户轮次和助手轮次调用CreateEvent。这个新事件会馈入提取策略,从而为下一次丰富长期存储。

memory.create_event(
    memoryId=MEMORY_ID,
    actorId=chat_id,
    sessionId=session_id,
    payload=[
        {'role': 'user', 'content': user_message},
        {'role': 'assistant', 'content': reply},
    ],
)  # feeds USER_PREFERENCE / SEMANTIC / SUMMARIZATION extraction; errors are logged, never fatal

代码片段 3:持久化该轮对话,以便提取策略能够异步丰富长期记忆。

提取是异步的,因此本次会话中提到的一个事实通常要到之后的某次会话中才能被检索到。要针对这种延迟进行设计:短期会话事件覆盖当前对话,长期记录覆盖此前的一切。

综合起来:个性化的浇水计划

这里就是整条流水线端到端运作的地方。在几次对话中,你用平实的语言逐一记录整个花园,一次一株植物。每一次提及都会成为一个事件。提取策略将关于植物、其位置和日照情况的信息提取到sprout/{chat_id}/long_term中。今天早上用户问了一个问题:“你还记得我花园里的其他植物吗?”检索会把这些记录取回,组装会对它们排序,然后它们随系统提示词一起进入。助手会回答出用户的位置、日照情况、花坛构造、土壤表现和植物清单,而这些信息都没有出现在消息本身中。

Telegram chat where Sprout recalls the user’s full garden inventory, location, and sun exposure in response to a question

图 2:Sprout 通过回忆已存储的植物清单和生长条件,回答了一个关于花园的问题

在 Amazon EventBridge → Cron 路径上使用调度器技能,Sprout 还可以把该计划转化为主动提醒(“跳过香草,土壤昨天雨后还是湿的”),并在降雨或热浪来临时,根据天气技能进行调整。

记忆和视觉也会相互叠加。当用户发送一张枯萎植物的照片时,图像会传给 Claude Sonnet 4.5,而系统提示词仍然携带记忆层所知道的一切。助手会将照片与用户已保存清单中的墨西哥矮牵牛匹配起来,并在上下文中诊断出枯萎胁迫,而不是冷启动地分析一张匿名的植物照片。

Telegram chat where Sprout diagnoses a wilting plant from a photo using the user’s stored Mexican petunia inventory

图 3:视觉与记忆协同工作。照片传给视觉模型,而系统提示词携带用户已存储的花园上下文

视觉模型并非万无一失。在之前一次没有库存上下文的交流中,同一株植物被自信地识别为牵牛花,一种有着相似喇叭形紫色花朵的物种。用用户自己存储的库存来为视觉模型提供依据,正是这一点将听起来合理的猜测变成了正确的、个性化的诊断,这也很好地说明了为什么记忆能提高准确性,而不仅仅是改善语气。

用提示缓存保持推理成本低廉

在每一轮对话中注入记忆会使系统提示变得很大,而一个朴素的实现会在每次请求时都为这些 token 付费。Amazon Bedrock 上的提示缓存解决了这个问题。助手会组织其提示,使稳定的前缀(人设和组装好的记忆块)排在最前面,而易变的用户消息排在最后。Bedrock 会在多次请求之间缓存已处理的前缀,因此对话中重复的轮次会跳过对未变化部分的重新计算。对于受支持的模型,提示缓存最多可将成本降低 90%,将延迟降低 85%。

排序规则比任何单项设置都更重要:把稳定内容放在前面,易变内容放在后面,并保持记忆块内部排序的确定性(前面的组装函数有助于实现这一点),这样前缀在多次请求之间才能真正匹配。

基于 AgentCore 和 OpenClaw 构建的设计准则

Sprout 只是一个助手,但其背后的决策具有普遍性。如果你要在这个技术栈上构建自己的助手,以下准则是我们会带到任何领域的准则。

  • 包装,而非分叉。用一个轻量的 HTTP 包装器让你的智能体框架适配 AgentCore 容器契约,而不是修改框架。该契约很小,端口 8080,带有 /ping 和 /invocations,而包装器能让你保持在框架的升级路径上。
  • 在存储任何内容之前先设计命名空间。记忆命名空间是你的隔离边界。让用户 ID 成为唯一可变的片段,并从你已经信任的渠道原生 ID(例如聊天 ID)中选择它。多租户设计最终会面临审计和删除请求。一个清晰的命名空间方案能让这两者都变得轻而易举。
  • 把记忆视为增强,而非依赖。每个记忆操作都应被允许优雅地失败。检索失败应产生一个无记忆的回答,而不阻塞回复。用户对健忘的一轮对话的宽容度远高于对失败的一轮对话。
  • 按任务路由模型。对高并发的文本使用快速、高性价比的模型,把更强的多模态模型留给需要它的轮次。将模型 ID 放在环境变量中,这样路由变更就是配置,而不是代码。
  • 为缓存安排提示顺序。稳定的人设和记忆在前,易变的用户输入在后,全程保持确定性排序。这一个结构性习惯就是大部分推理节省的来源。
  • 为提取延迟做好规划。长期记忆是异步提取的,所以不要承诺在同一会话中就能回忆起新事实。让短期会话事件覆盖当前对话,让长期记录覆盖先前的对话。
  • 从第一天起就给它设预算。基于用量的智能体在出现重试循环或话多的用户之前都很便宜。在月度上限的 80% 和 100% 处设置 AWS Budgets 告警不花什么钱,还能及早发现意外。
  • 保持技能小巧且单一用途。一个技能应该只做用户能用一句话说清的一件事,比如查天气或设置提醒。小巧的技能可以独立测试、独立替换,也更容易让模型正确选择。一个什么都做的技能会迫使模型去猜你指的是它的哪种行为。

自己动手培育

两种种植方式,同一个花园:

  • 单步 Launch Stack:CloudFormation 模板指向一个公开的 Amazon Elastic Container Registry(Amazon ECR)镜像,因此除了一个 Telegram bot token 之外无需部署任何东西。
  • 自行构建:scripts/deploy.sh 脚本会验证模板,构建你自己的 ARM64 镜像并推送到你的私有 Amazon ECR 仓库,部署堆栈,并注册 Telegram webhook,从而实现完全可定制的构建。

截至 2026 年 7 月,轻度个人使用每月约花费 $5–9(大约 $2 基础设施、$1–3 Haiku 文本、$2 Sonnet 视觉),并内置 AWS Budget,在你设定的上限达到 80% 和 100% 时发出提醒。

完整源代码可在 sample-agentcore-memory-openclaw GitHub 仓库 中获取。

清理

实验完成后,请拆除所有资源以避免持续产生费用。由于整个系统就是一个 CloudFormation 堆栈,清理基本上只需一次删除:

  1. 删除 CloudFormation 堆栈。这会移除 AgentCore 运行时 agent、API Gateway、Lambda 函数、Amazon EventBridge 计划以及相关的 AWS Identity and Access Management(IAM)角色。
  2. 删除 AgentCore 记忆存储(及其命名空间),以确保不保留任何用户记录。
  3. 删除你推送到私有 ECR 仓库的任何镜像,如果该仓库不再需要,也一并删除。
  4. 如果在堆栈之外创建了 AWS Budget 提醒,请将其移除。
  5. 撤销 Telegram 的 webhook(或通过 BotFather 删除该 bot),如果不再需要,撤销 Bedrock 模型访问权限。

结论

该解决方案的可复用核心是 Amazon Bedrock AgentCore 上的无服务器 agent,具备技能系统和托管记忆。AgentCore 记忆免去了构建自定义向量存储和提取管道的需要,同时让你完全掌控 agent 记住和遗忘的内容;基于用量的计算加上提示缓存,使真正个性化的助手每月只需几美元;而 OpenClaw 技能清单让整个模式可跨领域移植。个性化还会产生复利效应:用户交互越多,助手就越有用。

要进一步深入,可以从单一领域入手,例如浇水提醒,并逐步扩展记忆范围;探索情景记忆,让 agent 能够引用具体的过往对话(“上次我们讨论无花果树时,你决定暂缓施肥”);或者 fork 仓库,换上你自己的角色设定和技能,培育你需要的任何助手。

要了解更多,请参阅 AgentCore 文档。以下相关文章更深入地介绍了这些构建模块:


关于作者

Thiago Verney

Thiago Verney

Thiago 是 Amazon One MHS 团队的前端工程师,专注于使用 React、TypeScript 和现代联邦微前端架构构建 AI 驱动的界面。他为 FC 的运营负责人构建以用户为中心的界面,此前曾在 AWS 的 Amazon Q Developer(现为 Kiro)团队工作。他热衷于创新,并致力于打造务实的解决方案来解决真实的用户问题。业余时间,他喜欢在德克萨斯州奥斯汀与妻子一起园艺、旅行和尝试各种爱好。

Sathya Balakrishnan

Sathya Balakrishnan

Sathya 是 Amazon Web Services(AWS)专业服务团队的首席云架构师,专注于数据和机器学习(ML)解决方案。他与美国联邦金融客户合作。他热衷于构建务实的解决方案来解决客户的业务问题。业余时间,他喜欢看电影并与家人一起徒步。

Akarsha Sehwag

Akarsha Sehwag

Akarsha 是 Amazon Bedrock AgentCore GTM 团队的高级生成式 AI 数据科学家。她在 AI/ML 领域拥有超过 7 年的专业经验,在生成式 AI、深度学习和计算机视觉领域为不同客户群体构建了生产级企业解决方案。工作之余,她喜欢徒步、骑行和打羽毛球。

来源:AWS Machine Learning Blog · aws.amazon.com