大家好,刚刚参加完 re:Invent 2025,趁着记忆还鲜活,我准备开始写一系列关于最新更新的分享文章!

Amazon Bedrock AgentCore 最近推出了一项全新的长期记忆策略 —— Episodic Memory(情节记忆)

今天就来聊聊这个令人期待的更新内容。

https://aws.amazon.com/cn/blogs/aws/amazon-bedrock-agentcore-adds-quality-evaluations-and-policy-controls-for-deploying-trusted-ai-agents/https://aws.amazon.com/cn/blogs/aws/amazon-bedrock-agentcore-adds-quality-evaluations-and-policy-controls-for-deploying-trusted-ai-agents/

通过这个功能,AI Agent 能够从过去的经验中学习,并将这些“经验教训”应用到未来的交互中。不过,你也许会好奇:它和以往的长期记忆策略究竟有什么不同?

我们可以参考 AWS 官方博客中提到的“旅行预订 Agent”例子来理解这一点。

随着时间推移,Agent 会逐渐学习用户的预订习惯。例如,它可能会发现:“用户在出差时,经常因为客户会议而把返程航班改到更晚的时间。”当下次再次进行出差行程预订时,Agent 就能基于这种学习到的模式,主动提前推荐更灵活的返程选项。

可以把它理解为:AI Agent 能够从过去的经验中提炼出有价值的洞察,并在将来的任务中有效加以运用。

那么接下来,我们就实际动手试试看这个功能吧!

关于这次的更新

过去的长期记忆策略

在本次更新之前,AgentCore Memory 内置了以下 三种长期记忆策略

1. Semantic Memory(语义记忆)

  • 用于提取并保存事实性信息或知识。

2. User Preference(用户偏好)

  • 用于提取并记录用户的喜好与习惯。

3. Summary(摘要记忆)

  • 对对话内容进行要约并持续保存。

这次更新则是在这些基础上,新增了一种全新的内置长期记忆策略。

Episodic Memory(情节记忆)

本次加入的 Episodic Memory 与之前的长期记忆策略有一些显著的不同。

它会将用户与 Agent 的交互按“情节(episode)”的形式进行结构化存储,并在此基础上分析多个情节,进而自动生成“反思(reflection)”。
也就是说,它不仅记录发生了什么,还会从多个事件中提炼出更高层次的洞察与经验。

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/episodic-memory-strategy.htmlhttps://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/episodic-memory-strategy.html接下来,我们再更具体地看看它的工作机制。

Episodic Memory 的工作机制

Episodic Memory 策略由三个步骤自动执行,并将结果提取为长期记忆。
下面引用官方文档中的流程图来说明其工作方式。

1. Extraction(抽取)

系统会分析当前的交互内容,并判断一个“情节(episode)”是否已经完成。
与其他记忆策略不同的是,Episodic Memory 只有在检测到情节结束时才会生成记录

2. Consolidation(整合)

当情节结束后,相关事件会被整合成一个结构化的情节记录(episode record)。
每个情节包含以下信息:

  • Situation:情节发生的背景与上下文

  • Intent:用户或 Agent 的意图

  • Assessment:结果的评估

  • Justification:判断或决策的依据

  • Episode-level Reflection:该情节层级的反思内容

3. Reflection(反思)

系统会对多个情节进行横向分析,从中抽取更高层次、更广泛的洞察。

Reflection 可能提取的示例包括:

  • 针对特定任务,一贯成功的工具组合

  • 失败的处理方式及解决方法的模式

  • 来自多个相似情境中的成功案例所总结的最佳实践

这里正是 Episodic Memory 的独特之处。
以往的长期记忆策略大多在“抽取 → 结构化”之后就结束了,而 Episodic Memory 进一步加入了“反思(Reflection)”步骤。
这使得它不仅能记录发生过的事情,还能从过往经验中总结规律,实现更接近人类学习方式的记忆机制。

在哪些场景下特别有效?

我认为 Episodic Memory 在以下类型的场景中会特别发挥效果。
具体示例参考了 AWS 官方文档中的案例

deal use cases include customer support conversations, agent driven workflows, code assistants that rely on session history, personal productivity tools, troubleshooting or diagnostic flows, and applications that need context grounded in real prior events rather than static profiles.

使用场景 说明
客户支持 从过去的处理方式中学习更有效的解决方案
Agent 驱动的工作流 将以往任务执行的经验应用到下一次任务中
代码助手 基于会话历史提升上下文理解能力
故障排查(Troubleshooting) 参考过去的问题解决模式
个人效率工具 学习用户的工作习惯与模式

给我的印象是,这种策略特别适合需要让 Agent 记住过往经验并据此进行回答的场景。同时,它也非常适用于那些希望通过“回顾与反思”来不断提升任务熟练度的操作流程。

与其他策略的区分与使用场景

重新回顾各类长期记忆策略后,大致可以总结为下面的角色定位:

Semantic Memory(语义记忆)
→ 记录“知道了什么”(事实与知识)

User Preference(用户偏好)
→ 记录“用户喜欢什么”(偏好与习惯)

Summary(摘要记忆)
→ 记录“本次会话讨论了什么”(对话要约)

Episodic Memory(情节记忆)
→ 记录“发生了什么,以及为何成功/失败”
→ 从经验中提取能够提升成功率的知识

使用 Strands Agents 创建 Agent

那么接下来,我们就实际动手,创建一个使用 Episodic Memory 的 Agent。

环境准备

# 创建项目目录
mkdir agentcore-episodic-demo
cd agentcore-episodic-demo

# 创建并启用虚拟环境
python -m venv .venv
source .venv/bin/activate  # Windows 请使用: .venv\Scripts\activate

# 安装依赖项
pip install bedrock-agentcore strands-agents strands-agents-tools bedrock-agentcore-starter-toolkit

创建 Episodic Memory 资源

Episodic Memory 需要在控制台中进行创建。本次示例中我们将使用以下设置:

Memory name(记忆名称)

Sample_episode_memory

Built-in strategy(内置策略)

勾选 Episodes

Strategy name(策略名称)

episodeStrategy

Namespace for extracted memories(抽取记忆的命名空间)

/strategies/{memoryStrategyId}/actors/{actorId}/sessions/{sessionId}
→ 以 Session ID 维度进行聚合

Namespace for reflection(反思记忆的命名空间)

/strategies/{memoryStrategyId}/actors/{actorId}
→ 以 Actor ID 维度进行聚合

创建完成后,请从以下字段中记录下 Memory ID

另外,后续也会需要 Strategy ID,请从下方信息中将其一并记录下来。

到这里为止,准备工作就已经完成了。接下来我们开始进入 Agent 的实现部分。

实现 Strands Agent

创建一个名为 agent.py 的文件。这里我们先实现一个非常简单的“计算型 Agent”。
我们会让这个 Agent 输出计算题目,然后故意给出错误回答,再让系统对这些回答进行分析,用以测试 Episodic Memory 的效果。

"""
使用 AgentCore Memory - Episodic Memory 的 Strands Agent 示例

使用 Strands 的 Session Manager,将短期记忆与 Episodic Memory(长期记忆)进行自动整合。

使用方法:
    python agent.py --actor-id user123 --session-id session456
    python agent.py -a user123 -s session456
"""

import argparse
import logging
import os

os.environ["BYPASS_TOOL_CONSENT"] = "true"

def parse_args():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(
        description="AgentCore Episodic Memory 演示 - 计算助手"
    )
    parser.add_argument(
        "-a",
        "--actor-id",
        type=str,
        default="demo_user",
        help="用户(Actor)ID(默认: demo_user)",
    )
    parser.add_argument(
        "-s",
        "--session-id",
        type=str,
        default="calculation_session_001",
        help="会话 ID(默认: calculation_session_001)",
    )
    parser.add_argument(
        "-m",
        "--memory-id",
        type=str,
        default=None,
        help="Memory ID(默认: 使用环境变量 MEMORY_ID)",
    )
    parser.add_argument("-v", "--verbose", action="store_true", help="启用详细日志")
    parser.add_argument(
        "--strategy-id",
        type=str,
        default=None,
        help="Memory Strategy ID(默认: 使用环境变量 MEMORY_STRATEGY_ID)",
    )
    return parser.parse_args()

# 解析参数
args = parse_args()

# 日志设定
log_level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(
    format="%(levelname)s | %(name)s | %(message)s",
    level=log_level,
    handlers=[logging.StreamHandler()],
)

# 启用 AgentCore Memory 相关日志
logging.getLogger("bedrock_agentcore").setLevel(
    logging.DEBUG if args.verbose else logging.INFO
)
# Strands 的日志仅输出重要信息
logging.getLogger("strands").setLevel(logging.WARNING)

from bedrock_agentcore.memory.integrations.strands.config import (
    AgentCoreMemoryConfig,
    RetrievalConfig,
)
from bedrock_agentcore.memory.integrations.strands.session_manager import (
    AgentCoreMemorySessionManager,
)
from strands import Agent
from strands_tools import calculator

# 从参数或环境变量中获取 Memory ID & Strategy ID
MEMORY_ID = args.memory_id or os.getenv("MEMORY_ID")
MEMORY_STRATEGY_ID = args.strategy_id or os.getenv("MEMORY_STRATEGY_ID")
ACTOR_ID = args.actor_id
session_ID = args.session_id

if not MEMORY_ID:
    print("⚠️ 未设置 MEMORY_ID")
    print("请先执行 setup_memory.py")
    exit(1)

if not MEMORY_STRATEGY_ID:
    print("⚠️ 未设置 MEMORY_STRATEGY_ID")
    print("请通过环境变量 MEMORY_STRATEGY_ID 或 --strategy-id 指定")
    exit(1)

print(f"✅ Memory ID: {MEMORY_ID}")
print(f"✅ Memory Strategy ID: {MEMORY_STRATEGY_ID}")
print(f"✅ Actor ID: {ACTOR_ID}")
print(f"✅ Session ID: {session_ID}")

# 配置 AgentCore Memory(包含 Episodic Memory)
config = AgentCoreMemoryConfig(
    memory_id=MEMORY_ID,
    session_id=session_ID,
    actor_id=ACTOR_ID,
    retrieval_config={
        # 取得“情节”(按 session 聚合的经验)
        f"/strategies/{MEMORY_STRATEGY_ID}/actors/{{actorId}}/sessions/{{sessionId}}": RetrievalConfig(
            top_k=5
        ),
        # 取得“反思”(按 actor 聚合的洞察)
        f"/strategies/{MEMORY_STRATEGY_ID}/actors/{{actorId}}": RetrievalConfig(
            top_k=3
        ),
    },
)

# 创建 Session Manager
session_manager = AgentCoreMemorySessionManager(
    agentcore_memory_config=config, region_name="us-west-2"
)

# 创建 Strands Agent(整合 Session Manager)
agent = Agent(
    model="us.anthropic.claude-haiku-4-5-20251001-v1:0",
    tools=[calculator],
    system_prompt="""你是一位亲切的计算助手。
请使用 calculator 工具为用户提供准确的计算结果。
你可以参考过去的情节与反思内容,为用户提供分析与建议。""",
    session_manager=session_manager,
)

print("✅ Strands Agent(Episodic Memory 版本)初始化完成")

def main():
    """主函数 - 对话循环"""
    print("=" * 60)
    print("AgentCore Episodic Memory 演示 - 计算助手")
    print("=" * 60)
    print("\n请输入要计算的内容。")
    print("输入 'quit' 退出。\n")

    while True:
        try:
            user_input = input("\n输入> ").strip()

            if not user_input:
                continue

            if user_input.lower() == "quit":
                print("\n结束。")
                break

            print(f"\n👤 用户: {user_input}")
            response = agent(user_input)

            print(f"\n🤖 助手: {response.message}")

        except KeyboardInterrupt:
            print("\n\n结束。")
            break

if __name__ == "__main__":
    main()

我们通过 AgentCoreMemorySessionManager 来管理记忆。
有了它,就不需要进行复杂的实现:短期记忆会自动保存,长期记忆也会在需要时被自动引用,用起来非常方便。

测试

将之前在控制台记录下来的 MEMORY_IDMEMORY_STRATEGY_ID 设置到环境变量或命令行参数中。
完成设置后即可运行。

# 设置环境变量
export MEMORY_ID=mem_xxxxxxxxxxxxxxx
export MEMORY_STRATEGY_ID=xxx

# 运行 Agent
python agent.py -a demo_user -s demo_session

我们先让 Agent 输出一些计算题目,并借此提供可供分析的交互数据。
Actor ID 和 Session ID 通过命令行参数进行指定。

在这个测试中,我们会故意让 Agent 给出错误的回答
交互内容与日志会摘录一部分展示

python agent.py -a demo_user -s demo_session
✅ Memory ID: sample_episode_memory-XXXXXXXXXXXX
✅ Memory Strategy ID: episodeStratedgy-XXXXXXXXXXXX
✅ Actor ID: demo_user
✅ Session ID: demo_session
INFO | botocore.credentials | Found credentials in environment variables.
INFO | bedrock_agentcore.memory.client | Initialized MemoryClient for control plane: us-west-2, data plane: us-west-2
INFO | botocore.credentials | Found credentials in environment variables.
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | botocore.credentials | Found credentials in environment variables.
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | bedrock_agentcore.memory.client | Retrieved total of 0 events

✅ Strands Agent with Episodic Memory 初始化完成
============================================================

AgentCore Episodic Memory 演示 - 计算助手
============================================================

请输入计算请求。
输入 'quit' 退出。

输入> 请给我出一些不带答案的计算题。

👤 用户: 请给我出一些不带答案的计算题。
INFO | bedrock_agentcore.memory.client | Created event: 0000001764751005760#85588878
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | bedrock_agentcore.memory.integrations.strands.session_manager | Created agent: default in session: demo_session with event 0000001764751006760#b25a885d
INFO | bedrock_agentcore.memory.client | Retrieved 0 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session
INFO | bedrock_agentcore.memory.client | Retrieved 0 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user

# 我将给你出 3 道计算题!

**问题1:**
请计算 $\frac{3}{4} + \frac{5}{8} - \frac{1}{2}$。

**问题2:**
请找出满足 $x^2 + 5x + 6 = 0$ 的 x 的值。

**问题3:**
请计算函数 $f(x) = 2x^3 - 3x^2 + 1$ 在 $x = 2$ 时的导数。

---

想一想,解出来后告诉我!如果不会,我可以给提示,也可以一起解。

输入> 1 题答案 21,2 题答案 4331,3 题答案 312。

👤 用户: 1 题答案 21,2 题答案 4331,3 题答案 312。
INFO | bedrock_agentcore.memory.client | Created event: 0000001764751022116#f1d18ddd
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | bedrock_agentcore.memory.integrations.strands.session_manager | Created agent: default in session: demo_session with event 0000001764751023116#f41cc292
INFO | bedrock_agentcore.memory.client | Retrieved 0 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session
INFO | bedrock_agentcore.memory.client | Retrieved 0 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user

那我们来检查一下你的答案!

Tool #1: calculator  
Tool #2: calculator  
Tool #3: calculator  

...

## 评分结果

| 问题      | 你的答案     | 正确答案    | 判定 |
| --------- | ------------ | ----------- | ---- |
| **问题1** | 1.21         | **0.875**   | ❌    |
| **问题2** | 4331         | **-3, -2**  | ❌    |
| **问题3** | 312          | **12**      | ❌    |

很遗憾,这三题都不正确 😅

**讲解:**

- **问题1:** 分数通分后计算,结果是 0.875  
- **问题2:** 方程因式分解为 (x+3)(x+2)=0,解为 -3 和 -2  
- **问题3:** 导数 f'(x)=6x²-6x,代入 x=2 得到 12  

如果还有想挑战的题目,我们也可以一起看看解法!

---

输入> 再给我出一道题

👤 用户: 再给我出一道题

# 再给你出一道题!

**问题4:**  
请计算不定积分:$\int (3x^2 + 2x - 1) dx$

---

输入> 答案是 21 + C!

👤 用户: 答案是 21 + C!

那我们来确认一下!

...

## 评分结果

| 问题      | 你的答案     | 正确答案                 | 判定 |
| --------- | ------------ | ------------------------ | ---- |
| **问题4** | 21 + C       | **$x^3 + x^2 - x + C$**  | ❌    |

很遗憾,答案不正确 😅

**讲解:**

不定积分按项积分:

- 3x² → x³  
- 2x → x²  
- -1 → -x  

所以最终答案是 **x³ + x² - x + C**

要继续挑战下一题吗?

---

输入> 今天就到这里结束吧!!

👤 用户: 今天就到这里结束吧!!

好的!辛苦啦!🎉  

今天的计算题挑战到这里结束,感谢你的参与!

**今天的总结:**

- 问题1~3:分数计算、方程求解、微分  
- 问题4:积分  

如果下次还需要计算题或数学讲解,随时来找我,我们一起继续加油!💪  

明天见!👋

过了一段时间后,我在 Memory 的 CloudWatch Logs 中找到了已执行的抽取(Extraction)相关日志。

{
    "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:XXXXXXXXXXXX:memory/sample_episode_memory-XXXXXXXXXXXX",
    "event_timestamp": 1764752065253,
    "memory_strategy_id": "episodeStratedgy-XXXXXXXXXXXX",
    "namespace": "/strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session",
    "session_id": "demo_session",
    "body": {
        "log": "Starting episodic memory generation for requestId: XXXXXXXXXXXX-sample_episode_memory-XXXXXXXXXXXX-demo_user-demo_session-episodeStratedgy-XXXXXXXXXXXX-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, memoryId: sample_episode_memory-XXXXXXXXXXXX, episodeId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
        "requestId": "XXXXXXXXXXXX-sample_episode_memory-XXXXXXXXXXXX-demo_user-demo_session-episodeStratedgy-XXXXXXXXXXXX-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "isError": false
    },
    "resource": {
        "attributes": {
            "service.name": "sample_episode_memory-XXXXXXXXXXXX",
            "cloud.resource_id": "arn:aws:bedrock-agentcore:us-west-2:XXXXXXXXXXXX:memory/sample_episode_memory-XXXXXXXXXXXX",
            "cloud.platform": "aws_bedrock_agentcore"
        }
    },
    "attributes": {
        "aws.resource.type": "AWS::BedrockAgentCore::Memory",
        "aws.agentcore.memory.namespace": "/strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session",
        "session.id": "demo_session"
    },
    "timeUnixNano": 1764752065253129800,
    "severityNumber": 9,
    "severityText": "INFO"
}
・・・
{
    "resource_arn": "arn:aws:bedrock-agentcore:us-west-2:XXXXXXXXXXXX:memory/sample_episode_memory-XXXXXXXXXXXX",
    "event_timestamp": 1764752072150,
    "memory_strategy_id": "episodeStratedgy-XXXXXXXXXXXX",
    "namespace": "/strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session",
    "session_id": "demo_session",
    "body": {
        "log": "Starting reflection generation with episodic record for requestId: XXXXXXXXXXXX-sample_episode_memory-XXXXXXXXXXXX-demo_user-demo_session-episodeStratedgy-XXXXXXXXXXXX-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, memoryId: sample_episode_memory-XXXXXXXXXXXX, episodeId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
        "requestId": "XXXXXXXXXXXX-sample_episode_memory-XXXXXXXXXXXX-demo_user-demo_session-episodeStratedgy-XXXXXXXXXXXX-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "isError": false
    },
    "resource": {
        "attributes": {
            "service.name": "sample_episode_memory-XXXXXXXXXXXX",
            "cloud.resource_id": "arn:aws:bedrock-agentcore:us-west-2:XXXXXXXXXXXX:memory/sample_episode_memory-XXXXXXXXXXXX",
            "cloud.platform": "aws_bedrock_agentcore"
        }
    },
    "attributes": {
        "aws.resource.type": "AWS::BedrockAgentCore::Memory",
        "aws.agentcore.memory.namespace": "/strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session",
        "session.id": "demo_session"
    },
    "timeUnixNano": 1764752072150010986,
    "severityNumber": 9,
    "severityText": "INFO"
}

从日志来看,Consolidation(整合)Reflection(反思) 两个阶段似乎都已经执行了。
接下来,我再次询问 Agent,请它对之前的计算结果进行分析,看看它是否能够利用这些长期记忆。

输入> 请根据我过去的计算结果分析一下我的倾向并给出一些建议。

👤 用户: 请根据我过去的计算结果分析一下我的倾向并给出一些建议。
INFO | bedrock_agentcore.memory.client | Created event: 0000001764752293989#28d670d8
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | bedrock_agentcore.memory.integrations.strands.session_manager | Created agent: default in session: demo_session with event 0000001764752294989#b56c8c04
INFO | bedrock_agentcore.memory.client | Retrieved 3 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user
INFO | bedrock_agentcore.memory.client | Retrieved 2 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session
INFO | bedrock_agentcore.memory.integrations.strands.session_manager | Retrieved 5 customer context items

# 📊 你的计算结果趋势分析

我对你今天的 4 道题的作答情况做了一下分析:

---

## 📈 趋势分析

| 项目           | 详情                                   |
| -------------- | -------------------------------------- |
| **正确率**     | 0/4 (0%)                               |
| **倾向**       | 对所有问题都给出了与正确答案差距很大的回答 |
| **模式**       | 类似随意数字组合一样的随机性           |

---

## 🔍 详细观察

### **各题目的特点:**

1. **问题1(分数计算)**
   - 你的答案: 1.21  
   - 正确答案: 0.875  
   - **误差:** 约 38% 的误差  

2. **问题2(二次方程)**
   - 你的答案: 4331  
   - 正确答案: -3, -2  
   - **误差:** 可能对解方程的方法理解不够  

3. **问题3(求导数的值)**
   - 你的答案: 312  
   - 正确答案: 12  
   - **误差:** 答案比正确值大了 26 倍  

4. **问题4(不定积分)**
   - 你的答案: 21 + C  
   - 正确答案: x³ + x² - x + C  
   - **误差:** 可能还没有掌握不定积分结果应该呈现的形式  

---

## 💡 改进建议

### **你的优势:**

✅ **积极练习的态度** —— 即使答错了也愿意继续挑战新题,这点非常棒!

### **需要改进的地方:**

1. **基础概念的理解**  
   - 可能需要复习一下分数通分、因式分解等基本技能  

2. **计算步骤的确认**  
   - 不要一下子写出答案,逐步仔细计算每一步会更重要  

3. **对题目形式的理解**  
   - 对于微分、积分来说,“答案的形式”很关键(例如 x³ + x² - x 这种按项展开的形式)  

4. **下次的解题方式建议**  
   - 遇到不会的问题,先说“请给我提示”也是完全没问题的  
   - 也可以一步一步一起把题解出来  

---

## 🎯 下次练习的建议

下次练习时可以考虑:

1. 建议**从相对简单的题目开始**  
2. 如果你能**把计算过程也展示出来**,就更容易定位是在哪一步出错  
3. 也可以考虑**针对某一个领域集中练习**,这样效果会更好  

加油!💪
INFO | bedrock_agentcore.memory.client | Created event: 0000001764752307293#ebacaabf
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | bedrock_agentcore.memory.integrations.strands.session_manager | Created agent: default in session: demo_session with event 0000001764752308293#4b8ffcd2
INFO | bedrock_agentcore.memory.client | Retrieved total of 1 events
INFO | bedrock_agentcore.memory.integrations.strands.session_manager | Created agent: default in session: demo_session with event 0000001764752309293#8462a34a

由于这里同时使用了短期记忆,因此很难断言哪些内容完全来自长期记忆。不过,从下面的日志来看,两种长期记忆(Episode 与 Reflection)似乎都已经成功被检索到了

INFO | bedrock_agentcore.memory.client | Retrieved 3 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user
INFO | bedrock_agentcore.memory.client | Retrieved 2 memories from namespace: /strategies/episodeStratedgy-XXXXXXXXXXXX/actors/demo_user/sessions/demo_session

接下来我们来具体看一下:这些数据究竟是以怎样的结构被保存下来的。
我准备了一个用于测试的脚本,通过执行它来获取并查看长期记忆的内容。

其中的 Memory ID 和 Strategy ID 是我在脚本中直接写死的,如果你要复用这段代码,请根据自己的环境进行相应修改。

"""
AgentCore Memory - 长期记忆查询脚本

直接检索并显示 Episodic(情节)与 Reflection(反思)记忆。
"""

import os
import sys

from bedrock_agentcore.memory import MemoryClient

MEMORY_ID = "sample_episode_memory-XXXXXXXXXXXX"
ACTOR_ID = "demo_user"
SESSION_ID = "demo_session"
STRATEGY_ID = "episodeStratedgy-XXXXXXXXXXXX"

if not MEMORY_ID:
    print("⚠️ 未设置 MEMORY_ID")
    print("请先执行: export MEMORY_ID=mem_xxxxxxxx")
    sys.exit(1)

# 初始化 Memory Client
memory_client = MemoryClient(region_name="us-west-2")

print("=" * 80)
print("🔍 AgentCore Memory - 长期记忆查询工具")
print("=" * 80)
print(f"Memory ID: {MEMORY_ID}")
print(f"Actor ID: {ACTOR_ID}")
print(f"Session ID: {SESSION_ID}")
print()

def query_episodes(search_query: str, top_k: int = 5):
    """查询 Episodic(按会话聚合的经验)"""
    print("\n" + "=" * 80)
    print(f"📖 情节记忆查询: '{search_query}'")
    print("=" * 80)

    namespace = f"/strategies/{STRATEGY_ID}/actors/{ACTOR_ID}/sessions/{SESSION_ID}"

    try:
        # 使用 retrieve_memories 方法(snake_case)
        records = memory_client.retrieve_memories(
            memory_id=MEMORY_ID,
            namespace=namespace,
            query=search_query,
            top_k=top_k,
        )

        if not records:
            print("✗ 未找到任何情节记忆(Episode)")
            return

        print(f"✓ 找到 {len(records)} 条情节记忆\n")

        for i, record in enumerate(records, 1):
            content = record.get("content", {}).get("text", "")
            record_id = record.get("id", "unknown")

            print(f"【情节 {i}】")
            print(f"ID: {record_id}")
            print(f"内容:\n{content}\n")
            print("-" * 80)

    except Exception as e:
        print(f"⚠️ 出错: {e}")

def query_reflections(search_query: str, top_k: int = 3):
    """查询 Reflection(按 Actor 聚合的洞察)"""
    print("\n" + "=" * 80)
    print(f"💡 反思记忆查询: '{search_query}'")
    print("=" * 80)

    namespace = f"/strategies/{STRATEGY_ID}/actors/{ACTOR_ID}"

    try:
        # 使用 retrieve_memories 方法(snake_case)
        records = memory_client.retrieve_memories(
            memory_id=MEMORY_ID,
            namespace=namespace,
            query=search_query,
            top_k=top_k,
        )

        if not records:
            print("✗ 未找到任何反思记忆(Reflection)")
            print("(当累积了多个情节后,会自动生成反思)")
            return

        print(f"✓ 找到 {len(records)} 条反思记忆\n")

        for i, record in enumerate(records, 1):
            content = record.get("content", {}).get("text", "")
            record_id = record.get("id", "unknown")

            print(f"【反思 {i}】")
            print(f"ID: {record_id}")
            print(f"内容:\n{content}\n")
            print("-" * 80)

    except Exception as e:
        print(f"⚠️ 出错: {e}")

def list_all_episodes(max_results: int = 10):
    """列出所有情节记忆(Episode)"""
    print("\n" + "=" * 80)
    print(f"📋 全部情节记忆列表(最多 {max_results} 条)")
    print("=" * 80)

    namespace = f"/strategies/episodeStratedgy-XXXXXXXXXXXX/actors/{ACTOR_ID}/sessions/{SESSION_ID}"

    try:
        # 通过空查询获取记录
        records = memory_client.retrieve_memories(
            memory_id=MEMORY_ID,
            namespace=namespace,
            query="",
            top_k=max_results,
        )

        if not records:
            print("✗ 未找到任何情节记忆(Episode)")
            return

        print(f"✓ 找到 {len(records)} 条情节记忆\n")

        for i, record in enumerate(records, 1):
            content = record.get("content", {}).get("text", "")
            record_id = record.get("id", "unknown")

            print(f"{i}. [{record_id}]")
            print(f"   {content[:100]}{'...' if len(content) > 100 else ''}\n")

    except Exception as e:
        print(f"⚠️ 出错: {e}")

def interactive_mode():
    """交互模式"""
    print("\n" + "=" * 80)
    print("🔍 交互模式")
    print("=" * 80)
    print("可用命令:")
    print("  e <搜索关键词>  - 查询情节记忆(Episode)")
    print("  r <搜索关键词>  - 查询反思记忆(Reflection)")
    print("  list           - 列出全部情节记忆")
    print("  quit           - 退出")
    print()

    while True:
        try:
            user_input = input("query> ").strip()

            if not user_input:
                continue

            if user_input.lower() == "quit":
                print("结束程序。")
                break

            if user_input.lower() == "list":
                list_all_episodes()
                continue

            parts = user_input.split(maxsplit=1)
            if len(parts) < 2:
                print("⚠️ 用法: e <搜索关键词> 或 r <搜索关键词>")
                continue

            command, query = parts

            if command.lower() == "e":
                query_episodes(query)
            elif command.lower() == "r":
                query_reflections(query)
            else:
                print(f"⚠️ 未知命令: {command}")

        except KeyboardInterrupt:
            print("\n结束程序。")
            break

def main():
    """主函数"""
    if len(sys.argv) > 1:
        # 从命令行参数直接执行查询
        query = " ".join(sys.argv[1:])
        print(f"\n搜索关键词: '{query}'\n")
        query_episodes(query)
        query_reflections(query)
    else:
        # 进入交互模式
        interactive_mode()

if __name__ == "__main__":
    main()

脚本已经创建完成,接下来我们来执行它。
为了在交互模式下查看有哪些情节记忆(Episode)被保存了下来,我尝试输入查询语句:
「请告诉我我计算失败的倾向」 来检索相关记忆。

================================================================================
🔍 AgentCore Memory - 长期记忆查询工具
================================================================================
Memory ID: sample_episode_memory-XXXXXXXXXXXX
Actor ID: demo_user
Session ID: demo_session

================================================================================
🔍 交互模式
================================================================================
命令:
  e <搜索关键词>  - 搜索情节(Episode)
  r <搜索关键词>  - 搜索反思(Reflection)
  list           - 列出所有情节
  quit           - 退出

query> e 私の計算の失敗傾向について教えて
      (查询:请告诉我我在计算中的失败倾向)

================================================================================
📖 情节搜索: '请告诉我我在计算中的失败倾向'
================================================================================
✓ 找到了 3 条情节记录

随后,就收到了如下结果返回。

ID: unknown
内容:
{"situation":"Based on the limited information provided, it appears the user has submitted their math calculation results to the AI assistant, requesting analysis of these results and seeking feedback on their mathematical performance in Japanese. The user likely has a history of solving mathematical problems and wanted expert evaluation of their work.","intent":"The user's primary goal was to receive a comprehensive analysis of their math calculation results, understand patterns in their performance, identify their strengths and weaknesses, and obtain specific recommendations for improving their mathematical skills.","assessment":"Yes","justification":"The assistant provided a thorough analysis of the user's math performance, including specific numerical data showing 0% accuracy, detailed error analysis for each problem type, identified performance patterns, and offered targeted advice for improvement. The comprehensive structure of the response addressing all aspects of the user's request indicates successful fulfillment of the user's goal.","reflection":"The assistant effectively structured their analysis into multiple clearly defined sections (trend analysis, problem-specific observations, improvement advice, and next steps), which created a comprehensive and organized response. This methodical approach allowed the assistant to thoroughly address different aspects of mathematical performance evaluation. The assistant demonstrated strong analytical capabilities by providing specific numerical assessments (0% accuracy rate) and detailed error analysis for each of four different math problems, suggesting they effectively processed and interpreted the user's prior work. The response balanced identifying weaknesses with constructive suggestions, maintaining a supportive tone that encouraged continued effort. The assistant did not need to use external tools for this analysis, relying instead on careful organization of information presumably available from previous interactions. For similar situations involving performance analysis, this approach of segmenting feedback into clear categories (trends, specific observations, strengths/weaknesses, and actionable next steps) represents an effective pattern that could be applied to various educational assessment contexts.","turns":[{"situation":"The user has requested analysis of their past calculation results, asking for trend analysis and advice in Japanese. The user appears to be seeking feedback on their math performance.","intent":"The assistant aims to analyze the user's math calculation results, identify patterns in their performance, and provide constructive feedback and recommendations for improvement.","action":"The assistant provided a comprehensive analysis without using external tools, organizing the response with detailed sections including trend analysis, observations per problem, improvement advice highlighting strengths and weaknesses, and suggestions for next steps.","thought":"The assistant chose to structure the analysis with multiple sections because the task required evaluation of mathematical work across different problem types. The response includes specific numerical data about the user's accuracy (0% correct), detailed error analysis for each problem, and targeted advice, suggesting the assistant inferred this information from previous interactions not shown in this conversation sample.","assessmentAssistant":"Yes, the assistant successfully achieved its goal by providing a detailed analysis of the user's math performance with specific feedback on four different math problems, identifying trends in errors, and offering constructive advice for improvement with a supportive tone.","assessmentUser":"Yes, this turn represents the END OF THE CONVERSATION EPISODE as there is no next turn showing the user's response or follow-up questions, and the assistant's comprehensive analysis and recommendations provide a natural conclusion to the inquiry about past calculation results."}]}
--------------------------------------------------------------------------------
ID: unknown
内容:
{"situation":"The conversation appears to be ending after a math practice session where the user and AI assistant worked through various mathematical problems. The user has explicitly indicated in Japanese (\"今日はこれで終わりにしましょう!!\") that they want to conclude the session for the day.","intent":"The user's intent was to formally end the current math practice session and receive appropriate closure from the assistant.","assessment":"Yes","justification":"Based on the summary provided, the assistant successfully recognized the user's request to end the session, acknowledged it appropriately, provided a summary of the topics covered during their practice (fractions, equations, differentiation, and integration), and closed with an encouraging tone that welcomed future interactions.","reflection":"The assistant demonstrated effective communication by properly recognizing the multilingual cue from the user (Japanese text indicating session end) and responding appropriately to this social signal rather than continuing with more math content. The assistant successfully employed a closure pattern that included acknowledgment, summary of accomplishments, and forward-looking encouragement. This pattern helps provide a sense of completion and progress to the user while maintaining engagement for future sessions. For educational interactions like this math tutoring session, such structured closures are particularly valuable as they reinforce learning by recapping covered material. The assistant avoided the common mistake of ignoring closure requests or responding with unnecessary additional educational content when the user has clearly signaled they are finished for the day.","turns":[{"situation":"The user has indicated they want to end the math practice session for today with the message \"今日はこれで終わりにしましょう!!\" (Let's finish for today!). After multiple math problems and feedback sessions, the user is ready to conclude the conversation.","intent":"To acknowledge the user's request to end the session, provide a friendly closure, and summarize what was covered during the math practice session.","action":"The assistant provided a polite closing message acknowledging the end of the session, summarizing the types of math problems covered (fractions, equations, differentiation, and integration), and encouraging the user to return for future practice.","thought":"The assistant recognized the user's desire to conclude the session and responded with an appropriate closing message. The summary of covered topics helps reinforce the learning experience, while the encouraging tone aims to maintain engagement for future interactions.","assessmentAssistant":"Yes, the assistant successfully acknowledged the user's request to end the session and provided a friendly closing message that appropriately summarized the math practice session and left the door open for future interactions.","assessmentUser":"Yes, this is clearly the end of the conversation episode as the user explicitly stated they wanted to finish for today, and there are no further messages indicating continuation of the conversation."}]}
--------------------------------------------------------------------------------
【情节 3】

ID: unknown
内容:
・・・

可以看到,系统确实是按照前面提到的那 5 个维度 认真做了分析。
不过,每条 Episodic 记录本身的信息量都相当大,所以如何做好筛选——比如按相关度排序、只取前几条结果——就显得非常重要了。

接下来,我也来试着获取一下 Reflection(反思记忆) 的内容。

query> r 请告诉我我在计算中的失败倾向

================================================================================
💡 反思记录搜索: '请告诉我我在计算中的失败倾向'
================================================================================
✓ 找到了 3 条反思记录

情节记忆(Episode Memory)与反思记忆(Reflection Memory)的区别

从实际抽取出的数据来看,情节记忆反思记忆 在结构与内容上都有明显不同。

情节记忆(Episode Memory)的特点

情节记忆是某一次对话或操作流程的具体、详细记录,它关注的是:

“当时发生了什么?”

从数据结构可以看到,它包含我们之前介绍的多个分析视角:

  • situation(情境)

  • intent(意图)

  • assessment(评估)

  • justification(理由)

  • reflection(单次情节内的反思)

  • turns(每个回合的详细记录)

其中 turns 的内容尤其细致,不仅记录了助手采取了什么动作,还包括:

  • 为什么会选择该动作

  • 当时的推理逻辑

  • 使用了哪些工具

  • 工具的执行流程

也就是说,Episode Memory 是一种 “逐回合、逐动作的事件日志 + 行为理由”


示例:误答问题时生成的情节记忆内容

以你输入“1 21 2 4331 3 312”时的那段对话为例,Episode Memory 中保留了非常具体的信息,例如:

  • 用户输入了 "1 21 2 4331 3 312"

  • 助手调用了 calculator 工具 3 次

  • 正确答案应该是:

    • 问题 1:0.875

    • 问题 2:[-3, -2]

    • 问题 3:12

  • 用户的所有回答都不正确

 {"situation":"The user has responded with what appears to be their answers to the three math problems: \"1 21 2 4331 3 312\". The user seems to be participating in the math problem exercise initiated in the previous turn.","intent":"To check the user's answers to the three math problems by using calculation tools to determine the correct solutions.","action":"The assistant used the calculator tool three times: (1) to evaluate 3/4 + 5/8 - 1/2, (2) to solve the quadratic equation x^2 + 5x + 6 = 0, and (3) to find the derivative of 2x^3 - 3x^2 + 1 with respect to x.","thought":"The assistant recognized that the user provided answers and decided to verify them using calculation tools to provide accurate feedback. For each problem, the assistant selected the appropriate calculator function (evaluate, solve, derive) with the exact expressions from the original problems.","assessmentAssistant":"Yes, the assistant successfully initiated the verification process by using the calculator tool with the appropriate functions and expressions for each problem. This allows the assistant to determine the correct answers to compare with the user's responses.","assessmentUser":"No, the next turn shows that the user is providing tool results for the calculations and there is additional calculation needed for problem 3, indicating the user is still engaged with solving the math problems."},{"situation":"The user's message・・・}}

反思记忆(Reflection Memory)的特点

与详细记录每次对话过程的 情节记忆(Episode Memory) 不同,
反思记忆(Reflection Memory) 专注于从多个情节中抽取「经验」与「可复用的策略」。

换句话说:

Episode Memory:记录“发生了什么”
Reflection Memory:记录“从中学到了什么”

它是跨多个 Episode 进行分析后生成的、更加抽象与通用化的知识。


反思记忆包含两种模式

① 类似“总结版 Episode”的结构

这一类 Reflection 会以类似 Episode 的格式出现,
包含 situation、intent、reflection 等字段,属于“跨情节总结”。

例如:

  • 多次分析数学计算结果 → 生成一个“如何给用户提供数学反馈”的总结

  • 多次教学对话 → 生成一个“如何有效结束教学会话”的模式

这种类型更像是把多个 Episode 进行「统合后的高级摘要」。


② 完全抽象化的模式(模式化反思)

第二类结构非常具有“策略知识库”的味道,
从数据结构上可以清楚看出它的用途:

字段 含义
title 这个反思对应的“策略名称”
use_cases 这个策略适用于哪些场景
hints 在后续回答中应该如何应用这个策略(动作指南)
confidence 模型对该策略有效性的信心分数

你得到的 Reflection 数据示例正是这种结构,例如:

{
  "title": "Strategic Use of Calculator Tool for Math Verification",
  "hints": "Match the calculator function to the specific mathematical operation: 
            use 'evaluate' for arithmetic expressions, 
            'solve' for equations, 
            'derive' for derivatives, 
            'integrate' for integrals...",
  "confidence": "0.9"
}

在数学验证方面,我了解到应该战略性地使用 calculator 工具。更具体地说,对于算术表达式要用 evaluate,解方程使用 solve,求导使用 derive,积分使用 integrate。这些提示并不是给人类看的,而是 AI Agent 在处理这些问题时自然积累出来的抽象化知识,非常有趣。而且如果有实际可应用的场景,这些经验就能真正发挥作用,让 Agent 更高效地运作。

两种记忆之间的关系

如果说 情节记忆(Episodic Memory) 是“具体经验的记录”,那么 反思记忆(Reflection Memory) 就是从多次经验中提取出来的“知识与洞察”。

我理解为:系统通过分析情节记忆,从中抽取出可泛化的模式或最佳实践,然后将这些内容作为反思记忆进行保存。

这样一来,AI Agent 不仅能够引用过去发生的具体事件,还能将从这些事件中学到的教训应用到未来的交互中。实际查看日志结构时,我也觉得相当有收获。

结语

这次尝试了 AgentCore Memory 新增加的长期记忆策略——Episodic Memory(情节记忆)

与其他长期记忆策略相比,尤其有趣的是它的 Reflection(反思)阶段。随着知识不断累积,我感觉 Agent 未来可能会给出更好的建议。不过,它是否能用于真正的生产环境,我个人也还在观察。

我认为这种机制可能适合“经验越多表现越好”的场景,但目前我也无法明确指出具体的最佳使用案例。如果之后找到了更贴近实际的例子,会再在博客中分享!

如果本文对你有哪怕一点点帮助,我就非常高兴了。感谢阅读到最后!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐