Agent 自主学习记忆:让 AI 从经验中成长的闭环系统
当一个人反复解决同类问题后,会自然形成"直觉"------不需要每次都从头推理,而是调用过往经验快速决策。Agent 的自主记忆系统,正是在模拟这种从"新手"到"专家"的成长过程。
一、为什么 Agent 需要记忆?
1.1 无状态 Agent 的困境
传统的 LLM Agent 是无状态的------每次对话结束后,它在本次交互中积累的工具调用经验、问题解决模式都会烟消云散。下一次面对相同类型的问题时,Agent 只能从零开始推理,重复完整的"摸索 → 试错 → 成功"过程。
这带来了两个显著的问题:
- 效率浪费:同类问题每次都要经历完整的推理链路,消耗大量 Token 和时间
- 能力无法沉淀:Agent 永远停留在"新手"水平,无法从过往的成功经验中学习和进化
用人类的类比来理解:一个没有记忆的 Agent,就像一个每天早上醒来都会忘记昨天所有事情的工程师------他可能很聪明,但永远无法积累专业技能。
1.2 认知科学的启示:程序性记忆
在认知科学中,人类的记忆系统分为多个层次:
| 记忆类型 | 人类认知 | Agent 对应 |
|---|---|---|
| 感觉记忆 | 瞬间的感官输入 | 当前轮次的用户输入 |
| 短期记忆 | 工作记忆,容量有限 | 会话上下文窗口 |
| 长期记忆 - 陈述性 | 事实和概念知识 | 知识库 / RAG |
| 长期记忆 - 程序性 | "怎么做"的技能记忆 | ⬅ 技能提炼系统 |
其中,程序性记忆(Procedural Memory)是最关键的一种------它记录的不是"知道什么",而是"怎么做"。一个熟练的骑自行车的人不需要回忆平衡力学的公式,他的身体会"自动"完成所有动作。同样,一个拥有程序性记忆的 Agent,在面对"查询应用日志"这类已经成功处理过的任务时,不需要重新推理应该用什么工具、怎么构造参数------它可以直接调用已沉淀的"技能"。
Agent 的自主记忆系统,本质上就是在构建这种程序性记忆。
1.3 Hermes Agent 的启发
Hermes Agent(由 Nous Research 开发)率先提出了一个优雅的解法:让 Agent 拥有自主学习的能力。其核心理念是------
"The only agent with a built-in learning loop --- it creates skills from experience, improves them during use, and builds a deepening model across sessions."
这个"闭环学习回路"(Closed Learning Loop)的思想深深启发了我们。然而 Hermes Agent 的架构复杂度远超一般的嵌入式场景所需:
- 五层记忆体系:事实记忆 / 会话数据库 / 压缩机制 / 程序性记忆 / 用户建模
- 重基础设施依赖:SQLite + FTS5 全文检索、Honcho 框架用户画像建模、额外的 LLM 语义匹配调用
- 独立部署形态:被设计为独立运行的 Agent 服务,支持 Docker、SSH 等多种部署方式
- 高触发门槛:需要 5+ 步骤的复杂任务才会触发 Skill 提炼
对于想给现有 Spring Boot 应用"加点 Agent 智能"的场景来说,我们需要的是取其精髓,做一个"刚刚好"的简版------保留核心闭环,砍掉重依赖。
二、整体架构:三层记忆体系
我们将 Agent 的记忆能力拆分为三个层次,各司其职:
┌─────────────────────────────────────────────────┐
│ Agent Engine │
│ (AgentEngine / AgentStreamEngine) │
├─────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ MemoryManager│ │ SkillStore │ │
│ │ (短期记忆) │ │ (长期记忆) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ │ ┌────────────┴──────────┐ │
│ │ │ SkillExtractor │ │
│ │ │ (记忆提炼器) │ │
│ │ └────────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 会话历史 │ │ 磁盘持久化 │ │
│ │ (内存) │ │ (JSON 文件) │ │
│ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────┘
| 层次 | 组件 | 职责 | 存储方式 |
|---|---|---|---|
| 短期记忆 | MemoryManager |
管理单次会话的对话历史,支持自动压缩 | 内存(ConcurrentHashMap) |
| 长期记忆 | SkillStore |
存储和检索从历史执行中提炼的可复用技能 | 磁盘持久化(JSON 文件) |
| 记忆提炼 | SkillExtractor |
通过 LLM 从成功的执行链路中自动提炼技能 | 异步处理 |
这三层形成了一个完整的学习闭环:执行 → 追踪 → 提炼 → 存储 → 检索 → 注入 → 更好地执行。
三、长期记忆:技能的提炼与复用
长期记忆是整个系统最核心的部分------它让 Agent 能够跨会话地积累和复用经验。
3.1 执行追踪:SkillExecutionTrace ------ 记忆的原材料
一切记忆的起点是忠实记录。就像运动员通过回看比赛录像来改进技术,Agent 也需要完整的"执行录像"来提炼技能。
每当 Agent 处理一个用户请求时,引擎会创建一个 SkillExecutionTrace 对象,完整记录本次执行的全过程。在 Agent 循环中,每一次工具调用的入参、出参、成功与否都会被记录:
java
executionTrace.addToolCallRecord(
SkillExecutionTrace.ToolCallRecord.builder()
.order(traceOrder) // 执行顺序
.toolName(toolName) // 工具名称
.arguments(arguments) // 调用参数
.result(result) // 执行结果
.success(true) // 是否成功
.build()
);
SkillExecutionTrace 的数据模型设计简洁而完整:
| 字段 | 类型 | 说明 |
|---|---|---|
userQuery |
String | 用户的原始问题 |
toolCallRecords |
List | 工具调用记录链(按执行顺序) |
finalResponse |
String | Agent 最终的回复内容 |
success |
boolean | 整体执行是否成功 |
startTime / endTime |
long | 执行时间窗口 |
其中最关键的设计是 isWorthExtracting() 方法------不是所有的执行都值得提炼:
java
public boolean isWorthExtracting() {
return success && toolCallRecords != null && toolCallRecords.size() >= 2;
}
这个判断的设计哲学是:只有成功的、涉及多步骤工具调用的执行才值得沉淀为技能。单步的简单操作(如直接查询一次数据库)不需要提炼,因为 LLM 本身就能处理得很好。只有当任务涉及多个工具的组合调用时------这些"组合套路"才是真正有价值的经验。
3.2 技能提炼:SkillExtractor ------ 从具体到抽象的升华
这是记忆系统中最有创意的部分。当一次执行被判定为"值得提炼"后,SkillExtractor 会用 LLM 来分析执行轨迹,自动提炼出可复用的技能。
异步不阻塞
技能提炼是一个相对耗时的过程(需要额外调用一次 LLM),因此采用异步执行,不阻塞用户的主请求流程:
java
public void extractAsync(SkillExecutionTrace trace) {
if (!trace.isWorthExtracting()) {
log.debug("[SkillExtractor] 执行记录不满足提炼条件,跳过");
return;
}
agentExecutorService.submit(() -> {
try {
extract(trace);
} catch (Exception e) {
log.error("[SkillExtractor] 异步提炼技能失败", e);
}
});
}
这里使用共享的 Agent 线程池(agentExecutorService),而不是为提炼单独创建线程池,减少资源开销的同时也保证提炼任务不会因为并发过多而互相干扰。
提炼的核心:Prompt 工程
提炼的关键在于抽象 ------不是记住"这次查了 equidae 应用的日志",而是提炼出"如何根据用户指定的应用名查询日志"。SkillExtractor 通过精心设计的 Prompt 引导 LLM 完成这个从"具体执行"到"通用模式"的升华:
你是一个技能提炼助手。根据下面的执行记录,提炼出一个可复用的技能描述。
要求:
1. 从执行记录中抽象出通用的执行模式,而不是记录具体的参数值
2. 技能名称应简洁,描述应说明何时使用该技能
3. 步骤的参数模板应描述参数规则,而非具体值
4. 标签应包含关键词,方便后续检索
这段 Prompt 的设计有三个精妙之处:
- 强调"抽象"而非"记录":要求提炼通用模式,防止 LLM 简单地复制粘贴具体参数------这是从"陈述性记忆"到"程序性记忆"转化的关键
- 要求结构化输出 :以 JSON 格式返回,包含
name、description、steps、tags,便于程序化处理和存储 - 关注"可检索性":要求生成标签,为后续的技能匹配做准备------提炼时就考虑到了未来的使用场景
执行轨迹的文本化
在发送给 LLM 之前,执行追踪会被转化为结构化的文本描述:
java
private String buildTraceDescription(SkillExecutionTrace trace) {
StringBuilder description = new StringBuilder();
description.append("## 执行记录\n\n");
description.append("**用户问题**:").append(trace.getUserQuery()).append("\n\n");
description.append("**执行步骤**:\n");
for (SkillExecutionTrace.ToolCallRecord record : trace.getToolCallRecords()) {
description.append(record.getOrder()).append(". 调用工具 [")
.append(record.getToolName()).append("]\n");
description.append(" 参数:").append(truncate(record.getArguments(), 500)).append("\n");
if (record.isSuccess()) {
description.append(" 结果:").append(truncate(record.getResult(), 300)).append("\n");
} else {
description.append(" 失败:").append(record.getErrorMessage()).append("\n");
}
}
description.append("\n**最终回复**:").append(truncate(trace.getFinalResponse(), 500));
description.append("\n**执行结果**:").append(trace.isSuccess() ? "成功" : "失败").append("\n");
return description.toString();
}
注意这里对参数和结果做了截断处理 (truncate),避免过长的内容消耗过多 Token。这是一个务实的工程决策------对于提炼"如何做"的技能来说,过于详细的工具返回值反而是噪音。
3.3 技能模型:SkillRecord ------ 结构化的"经验卡片"
LLM 提炼出的技能被封装为 SkillRecord 对象,它是整个记忆系统的核心数据结构。可以把它理解为一张结构化的"经验卡片":
java
public class SkillRecord {
private String id; // 唯一标识
private String name; // 技能名称(如:"查询应用日志")
private String description; // 适用场景描述
private List<SkillStep> steps; // 执行步骤列表
private List<String> tags; // 检索标签
private int successCount; // 成功使用次数
private int totalCount; // 总使用次数
private long createdAt; // 创建时间
private long updatedAt; // 最后更新时间
}
每个执行步骤 SkillStep 记录的是模板化的参数规则,而非具体的参数值------这正是"程序性记忆"的核心特征:
java
public static class SkillStep {
private int order; // 步骤序号
private String toolName; // 使用的工具名称
private String argumentsTemplate; // 参数模板描述(自然语言)
private String expectedResult; // 预期结果描述
}
SkillRecord 还内置了一个关键方法 toPromptText(),用于将技能格式化为可直接注入 System Prompt 的文本:
java
public String toPromptText() {
StringBuilder promptText = new StringBuilder();
promptText.append("【技能:").append(name).append("】\n");
promptText.append("适用场景:").append(description).append("\n");
promptText.append("执行步骤:\n");
for (SkillStep step : steps) {
promptText.append(" ").append(step.getOrder())
.append(". 调用工具 [").append(step.getToolName()).append("]");
if (step.getArgumentsTemplate() != null && !step.getArgumentsTemplate().isEmpty()) {
promptText.append(",参数规则:").append(step.getArgumentsTemplate());
}
if (step.getExpectedResult() != null && !step.getExpectedResult().isEmpty()) {
promptText.append(",预期结果:").append(step.getExpectedResult());
}
promptText.append("\n");
}
promptText.append("历史成功率:")
.append(successCount).append("/").append(totalCount).append("\n");
return promptText.toString();
}
注意最后一行------成功率信息也被包含在 Prompt 中,让 LLM 在决策时能参考这个技能的历史可靠性。一个成功率 5/6 的技能和一个成功率 1/6 的技能,对 LLM 的引导力度是不同的。
3.4 技能存储与检索:SkillStore
SkillStore 是技能的持久化仓库,负责技能的存储、加载和检索。
持久化策略:索引 + 独立文件
技能以 JSON 文件的形式持久化到磁盘,存储结构为:
{workspace}/skills/
├── skill-index.json # 索引文件(技能 ID 列表)
├── a1b2c3d4e5f6g7h8.json # 技能1的完整数据
├── i9j0k1l2m3n4o5p6.json # 技能2的完整数据
└── ...
这种"索引 + 独立文件"的设计有两个好处:
- 启动快速:先加载索引,再按需加载技能文件,避免一次性读取所有数据
- 更新安全:单个技能的更新不会影响其他技能文件,降低数据损坏风险
同名技能合并
当新提炼的技能与已有技能同名时,SkillStore 会合并统计数据而非简单覆盖:
java
SkillRecord existing = findByName(skill.getName());
if (existing != null && !existing.getId().equals(skill.getId())) {
skill.setSuccessCount(existing.getSuccessCount() + skill.getSuccessCount());
skill.setTotalCount(existing.getTotalCount() + skill.getTotalCount());
skill.setCreatedAt(existing.getCreatedAt());
// 移除旧记录
skillIndex.remove(existing.getId());
deleteSkillFile(existing.getId());
}
这意味着同一类型的技能会被不断强化------每一次成功执行都会累加到技能的统计数据中,而技能的步骤描述会更新为最新提炼的版本。这类似于人类反复练习某项技能后,执行方式会逐渐优化。
基于关键词的加权检索
当用户发起新的请求时,SkillStore 会通过分词匹配的方式检索相关技能:
java
public List<SkillRecord> searchSkills(String userQuery, int maxResults) {
String queryLower = userQuery.toLowerCase();
String[] queryTokens = queryLower.split("[\\s,,、;;。.!!??]+");
return skillIndex.values().stream()
.map(skill -> new AbstractMap.SimpleEntry<>(skill, calculateMatchScore(skill, queryTokens)))
.filter(entry -> entry.getValue() > 0)
.sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
.limit(maxResults)
.map(AbstractMap.SimpleEntry::getKey)
.collect(Collectors.toList());
}
匹配分数的计算采用加权评分机制:
| 匹配位置 | 权重 | 设计理由 |
|---|---|---|
| 技能名称 | 3.0 | 名称是最核心的标识,高权重确保精确匹配 |
| 标签精确匹配 | 2.0 | 标签是 LLM 提炼时专门生成的检索关键词 |
| 技能描述 | 1.0 | 描述包含场景信息,但匹配精度较低 |
| 标签模糊匹配 | 1.0 | 部分匹配作为补充 |
此外,还引入了成功率加权------历史成功率高的技能会获得更高的优先级:
java
if (skill.getTotalCount() > 0) {
double successRate = (double) skill.getSuccessCount() / skill.getTotalCount();
score *= (0.5 + 0.5 * successRate);
}
这个公式的含义是:成功率从 0% 到 100%,总系数从 0.5 到 1.0 。一个成功率 100% 的技能,匹配分数不会被折损;而一个成功率为 0% 的技能,分数会被减半。这形成了一种自然的优胜劣汰机制------可靠的技能被优先推荐,不可靠的技能逐渐边缘化。
3.5 技能注入:闭环的最后一环
检索到的技能最终通过 System Prompt 注入 的方式,影响 Agent 的下一次决策。这发生在 AgentEngine / AgentStreamEngine 的 buildEnhancedSystemPrompt 方法中:
java
private String buildEnhancedSystemPrompt(String userQuery) {
List<SkillRecord> matchedSkills = skillStore.searchSkills(userQuery, MAX_SKILL_INJECTION);
if (matchedSkills.isEmpty()) {
return SYSTEM_PROMPT;
}
StringBuilder enhanced = new StringBuilder(SYSTEM_PROMPT);
enhanced.append("\n\n## 历史经验技能\n");
enhanced.append("以下是从历史成功执行中沉淀的技能,当用户问题匹配时可参考使用:\n\n");
for (SkillRecord skill : matchedSkills) {
enhanced.append(skill.toPromptText());
enhanced.append("\n");
}
enhanced.append("请根据用户问题判断是否可以参考上述技能来执行任务。");
return enhanced.toString();
}
设计上限制了最多注入 3 个技能 (MAX_SKILL_INJECTION = 3),这个约束有两层考虑:
- 避免 Prompt 过长:过多的技能描述会挤占 LLM 的上下文窗口,影响对用户实际问题的理解
- 避免决策混乱:注入太多可能冲突的技能反而会让 LLM "选择困难"
注入后的 System Prompt 看起来会像这样:
你是一个智能助理,专门帮助用户查询和分析业务数据。
...(原始 System Prompt)...
## 历史经验技能
以下是从历史成功执行中沉淀的技能,当用户问题匹配时可参考使用:
【技能:查询应用日志】
适用场景:当用户需要查看某个应用最近的运行日志时
执行步骤:
1. 调用工具 [sls_query],参数规则:根据用户指定的应用名和时间范围构造查询
2. 调用工具 [sls_query],参数规则:如果结果过多,添加过滤条件缩小范围
历史成功率:5/6
请根据用户问题判断是否可以参考上述技能来执行任务。
注入方式选择 System Prompt 而非 Few-shot 示例,是因为 System Prompt 中的内容会被 LLM 视为行为指导 而非需要模仿的模式,Agent 可以根据实际情况灵活参考而非生硬照搬。
四、短期记忆:会话历史的智能压缩
除了长期的技能记忆,MemoryManager 负责管理单次会话内的短期记忆。LLM 的上下文窗口是有限的,当一次会话中的对话消息过多时,需要进行智能压缩。
4.1 压缩触发条件
当非系统消息数量超过阈值(默认 20 条)时,自动触发压缩。
4.2 压缩策略
压缩算法遵循"保新弃旧、摘要兜底"的原则:
- 保留所有系统消息:System Prompt 包含 Agent 的核心指令和注入的技能描述,绝不能丢弃
- 保留最近的 N 条消息(默认 10 条):最近的对话上下文对当前交互最为重要
- 将更早的消息压缩为摘要:以一条新的系统消息注入,确保 Agent 不会完全丧失对历史对话的感知
java
AgentMessage summaryMessage = AgentMessage.builder()
.role("system")
.content("历史对话摘要:" + summary)
.timestamp(System.currentTimeMillis())
.build();
4.3 摘要生成
摘要中包含三类信息:
- 统计概览:用户提了几个问题、助手回复了几次、调用了几次工具
- 最近内容:最后 3 条消息的简要内容(截断至 100 字符)
- 角色标注:每条内容都标注了来源角色(user / assistant)
这种设计是一种有损压缩------它牺牲了早期对话的细节,但保留了统计特征和最近上下文,让 Agent 能"大致记住"之前聊了什么,而不是完全失忆。
五、完整的学习闭环
让我们用一个完整的时序来回顾整个自主记忆系统的工作流程:
用户提问:"查一下 equidae 应用最近一小时的错误日志"
│
▼
┌─ Agent Engine ─────────────────────────────────────────┐
│ │
│ 1. 检索匹配技能 │
│ SkillStore.searchSkills("查 equidae 错误日志") │
│ → 找到【技能:查询应用日志】(成功率 5/6) │
│ │
│ 2. 构建增强 System Prompt │
│ 原始 Prompt + 匹配到的技能描述 │
│ │
│ 3. 创建执行追踪 │
│ SkillExecutionTrace 开始记录 │
│ │
│ 4. Agent 循环执行(参考注入的技能) │
│ Step 1: 调用 sls_query → 获取日志 │
│ Step 2: 调用 sls_query → 过滤出 ERROR 级别 │
│ 每步都记录到 ExecutionTrace │
│ │
│ 5. 返回最终结果给用户 │
│ │
│ 6. 异步提炼(不阻塞用户) │
│ SkillExtractor.extractAsync(trace) │
│ → LLM 分析执行轨迹 │
│ → 提炼出新技能或更新已有技能的统计数据 │
│ → SkillStore.saveSkill(skill) 持久化 │
│ │
└─────────────────────────────────────────────────────────┘
│
▼
下一次类似问题 → Agent 直接参考已有技能,更快更准地解决
这个闭环的每一个环节都不可或缺:
| 环节 | 组件 | 类比 |
|---|---|---|
| 追踪 | SkillExecutionTrace |
运动员的比赛录像 |
| 提炼 | SkillExtractor |
教练分析录像后总结出的训练要点 |
| 存储 | SkillRecord + SkillStore |
写入训练手册并归档 |
| 检索 | SkillStore.searchSkills() |
面对新比赛时翻阅训练手册 |
| 注入 | buildEnhancedSystemPrompt() |
赛前复习相关战术 |
| 反馈 | 成功率统计 | 根据比赛结果更新训练手册的有效性评价 |
六、与 Hermes Agent 的对比:大而全 vs 小而美
| 维度 | Hermes Agent | AliOO Agent Starter |
|---|---|---|
| 定位 | 独立的全能型 Agent 服务 | 嵌入式 Spring Boot Starter |
| 语言/生态 | Python / 独立运行 | Java / Spring Boot 生态 |
| 记忆层次 | 五层(事实 / 会话 / 压缩 / 程序性 / 用户建模) | 三层(短期会话 / 技能存储 / 技能提炼) |
| Memory 存储 | SQLite + FTS5 全文检索 | ConcurrentHashMap(短期)+ JSON 文件(长期) |
| Skill 提炼触发 | 复杂任务(5+ 步骤) | 成功执行且 ≥ 2 次工具调用(更低门槛) |
| Skill 检索 | LLM 语义检索 + FTS5 | 分词关键词匹配 + 加权评分(零额外 LLM 开销) |
| Skill 注入方式 | System Prompt 注入 | System Prompt 注入(一致) |
| Skill 改进 | 运行时自动修补(额外 LLM 调用) | 成功率追踪 + 同名技能合并(轻量统计) |
| 用户建模 | Honcho 框架辩证建模 | 不涉及(聚焦技能沉淀) |
| 外部依赖 | SQLite、FTS5、Honcho 等 | 无额外依赖,纯 Java 实现 |
| 部署方式 | 独立服务(Docker / SSH 等) | pom.xml 加一行依赖 |
| 接入成本 | 需要独立部署和运维 | 零运维,随应用启停 |
我们做了哪些减法?
- 砍掉用户建模层:企业内部工具场景中,用户群体相对固定,深度用户画像的 ROI 不高
- 砍掉 Skill 自修复:用更简单的"成功率统计 + 同名覆盖"替代------不可靠的技能自然会被权重压低
- 砍掉 Memory Nudge:将周期性的"记忆推动"简化为"每次成功执行后立即异步提炼",更加直接
- 砍掉 FTS5 全文检索 :用 Java 原生的分词 + 加权评分替代,零外部依赖
我们保留了什么核心?
- 闭环学习回路:执行 → 追踪 → 提炼 → 持久化 → 检索 → 注入,一个环节都没有少
- LLM 驱动的技能提炼 :不是简单地记录执行日志,而是用 LLM 做抽象和泛化
- System Prompt 注入:让 LLM 在推理时自然参考历史经验
- 统计反馈机制:成功率影响检索排序,形成自然的优胜劣汰
核心理念一致,工程实现做减法------这就是设计哲学。
七、设计思考与未来演进
7.1 当前设计的取舍
关键词检索 vs 语义检索
当前使用分词 + 加权匹配进行技能检索,实现简单但语义理解能力有限。例如,用户问"看看系统最近有没有报错"时,分词后的 token 可能无法精确匹配到名为"查询应用日志"的技能。Hermes Agent 使用 FTS5 + LLM 语义检索,效果更好但成本更高。考虑到 Starter 的轻量化定位,当前方案是合理的折中。
统计摘要 vs LLM 摘要
短期记忆的压缩采用了简单的统计摘要(消息数量 + 最近内容截断),而非调用 LLM 生成语义摘要。这是出于成本和延迟的考虑------压缩发生在每次请求的关键路径上,额外的 LLM 调用会直接影响用户体验。
JSON 文件 vs 数据库
技能持久化选择 JSON 文件而非 SQLite 等数据库,牺牲了查询能力但换来了零外部依赖。对于技能数量在数百量级以内的场景(这是大多数企业内部 Agent 的常态),这个选择完全够用。
7.2 可能的演进方向
- 引入向量检索:复用项目已有的 Embedding 能力(知识库模块),对技能描述做向量化,提升语义匹配的准确度
- 技能版本管理:记录技能的演化历史,支持回滚到历史版本
- 技能自动退化:当技能的成功率持续下降时,自动触发重新提炼或标记为过期
- 跨实例共享:将技能存储迁移到共享存储(如 Redis / OSS),实现多实例间的经验共享
- LLM 驱动的压缩:在短期记忆压缩中引入 LLM 生成更高质量的语义摘要
八、总结
Agent 的自主记忆功能,本质上实现了一个 "执行 → 记录 → 提炼 → 存储 → 检索 → 注入"的闭环学习系统。它借鉴了认知科学中"程序性记忆"的概念和 Hermes Agent "让 Agent 从经验中学习"的核心理念:
SkillExecutionTrace是"眼睛"------忠实记录每一次执行的完整轨迹SkillExtractor是"大脑"------通过 LLM 从具体经验中抽象出通用模式SkillRecord是"笔记"------结构化地存储可复用的技能卡片SkillStore是"书架"------提供技能的持久化存储和智能检索MemoryManager是"短期记忆"------管理会话内的上下文,在需要时自动压缩
这套系统让 Agent 不再是一个"每次都从零开始的新手",而是一个越用越聪明的智能助手------每一次成功的执行都会成为它未来更好表现的基石。
"An agent that forgets everything is forever a beginner. An agent that remembers and learns becomes an expert."