Agent技能化与记忆工程:打造具备长期记忆的智能体实践指南
2026年第41周的 GitHub 趋势周报我连续刷了两天感受最强烈的一点是Agent 类项目终于不再以“聊天框 工具调用”为卖点了。这一周挤进趋势榜前列的仓库方向高度一致——把 Agent 的能力拆成可插拔的“技能”同时给 Agent 装上能真正长期沉淀的“记忆系统”。换句话说Agent 开发已经正式进入技能化与记忆工程阶段。这些项目解决的是同一个痛点Agent 怎么在一个持续运行的环境里稳定地做完具体任务并且在下一次需要的时候还能记起上次的结论。如果你正在做 Agent 类应用或者想从零自建一个长期陪你跑项目的个人助手这篇文章把技能化和记忆工程的底层逻辑拆开讲顺便附上一套能直接跑起来的最小实现。1. 周报里的集体转向技能化和记忆工程成了主线1.1 为什么这一周集中爆发前两年大家还在拼“提示词写得多好”“接了多少个 API”但 2026 年这批项目的共性问题是纯对话式 Agent 的天花板太低了。大模型本身的理解能力已经很稳真正把体验拉开差距的是 Agent 能不能在“多轮、长期、跨任务”的现实环境里持续工作。于是这一周的趋势榜上出现了一类新东西不是又一个“全能助手”而是“技能模块”“记忆存储层”“记忆清理策略”这类小而专的工程模块。背后是社区把过去通用型 Agent 踩过的坑沉淀成了可复用的方案工具一多就乱选、上下文一长就失忆、用户偏好压根记不住。与其继续堆功能不如先把“能力组织”和“信息留存”这两件事做好。还有一个外部原因模型接口的调用成本已经降到可以接受跑长任务的水平大家对“一个 Agent 跑几天”这件事不再心疼。既然长期运行成为可能“记忆会丢”就成了最刺眼的短板。于是这一周大量项目开始围绕记忆做文章完全符合阶段演进的逻辑。1.2 技能化与记忆工程的边界先说技能化。它不是一个新词但今年被重新定义了。以前的“技能”是一段 prompt现在的“技能”是一个带元数据、参数约束、触发条件、依赖列表、权限标记的独立模块。Agent 的“技能”不是模型天生会的而是我们像给系统装插件一样装进去的。技能化解决的是“Agent 能不能稳定地做某件事”。记忆工程则解决另一个问题“Agent 做完一件事之后能不能在下一次继续用上这件事的上下文”。它包括信息的抽取、压缩、存储、检索、更新和遗忘本质上是给 Agent 设计一个信息生命周期管理系统。用一个类比技能是岗位能力记忆是工作笔记。能力强但没有笔记的员工每次开会都像第一次参会有笔记但没有能力的员工笔记写得再好也不知道下一步该干什么。技能决定 Agent 的上限记忆决定 Agent 的可持续性两者缺一不可。2. Agent 技能化把能力拆成可插拔的技能槽2.1 技能注册表能力目录技能化落地的一个重要载体是技能注册表Skill Registry。它本质上是一张“能力目录”记录 Agent 现在能做什么、每个能力怎么调用、调用之前需要满足什么条件。我在本周一个仓库里看到的设计比较清晰一个技能条目包含下面这些字段{ name: create_memory, description: 当用户明确要求记住某条信息时使用例如“记住项目下周评审”“别忘了存一下会议结论”, params: { content: string要保存的信息, tags: array可选标签 }, entry: skills/memory/create.py, permission: user_approved, dependencies: [memory_store] }这里最值得学习的地方是把 description 写得极其具体。它不仅仅是给人看的更是给模型看的。模型做技能路由时靠的就是这段描述来判断“该叫哪个技能”。所以描述里不仅要写“什么时候用”还要写“什么时候不要用”。比如 create_memory 的技能描述最好加上一句“只记录用户明确要求保存的内容不要主动提取对话中的隐含信息。”这一点很多人会漏掉导致 Agent 自作主张存了一堆垃圾。技能注册表带来的另一个好处是权限可控。每个技能可以单独设置 permission敏感操作要求“user_approved”只读操作可以直接执行。生产环境下这个字段非常重要它能避免 Agent 在无人监督时执行危险动作。2.2 技能的三种形态看这周的项目技能基本可以归纳成三种形态。第一种是提示词技能。没有代码执行环节只靠一段精心设计的提示词完成特定任务比如“把这段内容总结成三点”“把技术文档翻译成中文”。它适合纯文本处理场景优点是轻量、容易调试缺点是能力边界有限。第二种是工具技能。绑定一个外部 API 或函数比如查数据库、发邮件、操作日历。这种技能是现在生产环境的主力。输入参数经过严格 schema 校验后再传给工具工具返回结果再交回给模型。技能化的意义在这里就体现出来了每个工具技能可以独立测试、独立升级不会因为改了 A 工具影响 B 技能。第三种是组合技能。它由多个子技能按流程编排而成比如“写周报”技能内部依次调用“查笔记”“汇总要点”“生成报告”三个子技能。组合技能是本周项目里增长最快的一类因为它解决的是 Agent 在复杂任务里的“合成”问题。单一技能能完成原子动作但真实场景往往需要一串动作。我的建议是设计技能时粒度宁可小一点。一个技能只做一件事比一个“万能技能”更容易维护也让模型的路由判断更精准。2.3 技能编排与动态加载当 Agent 拥有几十个技能后问题就从“实现技能”变成了“怎么选技能、怎么组合技能”。这一周的项目里我看到两种值得借鉴的思路。第一种是意图路由先由模型判断用户意图再从技能注册表里选出匹配的技能。这种方案适合技能描述写得好、彼此边界清晰的情况。第二种是工作流编排把固定流程写成 DAG技能之间用条件和并行组合起来。比如“处理报销单”技能先识别票据类型再调用 OCR 技能校验后写入财务表最后通知用户。每一步都可以单独替换流程本身则沉淀为配置文件。动态加载也是个被反复提到的关键词。Agent 启动时不加载全部技能而是按需加载路由判定命中某个技能后再把这个技能的依赖模块加载到内存。这样做有两个明显收益一是启动速度更快二是减少了冗余技能间的互相干扰。我看到某个项目的设计里技能模块之间有明确的依赖声明加载器会自动处理依赖顺序这一步直接省掉了不少人工排障的精力。3. 记忆工程让 Agent 记住真正值得记住的信息3.1 记忆分层短期、长期、语义与程序记忆记忆工程不是简单地“存对话记录”本周主流项目基本都在做记忆分层。我也跟着把这一套实践了一遍分层确实很有必要。记忆类型生命周期存储位置典型用途工作记忆单次任务内上下文窗口当前对话信息情景记忆数小时到数天结构化会话记录昨天聊过的内容语义记忆长期向量库/数据库用户偏好、事实结论程序记忆长期技能调用记录熟练动作、常用操作流程工作记忆就是上下文窗口模型实时能看到的。它的特点是快但容量小而且每次对话结束基本就清了。情景记忆是对单次会话做压缩后的摘要比如“今天上午和 A 同学讨论了数据中台的迁移方案结论是分两期走”。语义记忆是提炼出来的稳定事实比如“用户偏好用中文术语写接口文档”。程序记忆记录的是 Agent 自己的熟练操作路径比如“用户每次要求整理月报时都需要先拉取财务数据再汇总”。分层的好处是各归各管。临时消息不用挤占长期空间长期事实不会被频繁的会话冲掉检索时也能按类型精准定位。3.2 记忆写入与检索管线记忆工程的核心是一条完整的写入和检索管线。写入端大致是原始对话 - 过滤 - 抽取 - 压缩 - 向量化 - 落库。检索端是用户问题 - 向量化 - 召回 - 重排 - 注入上下文。这条管线的每一步都能展开成独立优化点。我自己从这周的项目里学到比较深的一点是过滤环节最重要。很多人把“全部对话记录”直接扔进向量库结果检索时什么都能命中反而把真正有用的信息淹没在噪声里。好的做法是设置一个“写入门槛”默认只保存用户明确要求记住的内容或者经过摘要合并后的结论。存储层方面我看到的最小可用方案是“SQLite 简单向量检索”先用 SQL 做结构化过滤再用向量做语义召回。这个方案的好处是不需要额外部署服务个人项目跑起来很顺手。数据量大了以后再迁移到专用向量库也不难因为抽象出来的读写接口是通用的。3.3 遗忘机制与记忆合并记忆工程的进阶题是“忘掉哪些信息”这周有几个项目专门做这个事情我觉得很有意思。如果不做遗忘记忆库在连续运行几周后就变成了一团乱麻旧的用户偏好可能已经变了过期的时间安排还在被反复召回重复的信息占满了存储空间。我实践下来比较有效的一套是给每条记忆加上 created_at、updated_at、source、access_count 字段。定期跑一个合并任务把同一主题的旧记忆合并成新版本超过一定时间没有被访问的内容降级为“待清理”用户明确否认过的事实直接从库里删除。合并的典型逻辑是同主题下新记忆的 updated_at 超过旧记忆时生成一条新的合并摘要同时把旧条目标记为归档。这样既能保留历史轨迹又不会干扰检索结果。如果你打算做长期运行的 Agent我强烈建议一开始就把遗忘机制设计进去后面补的话迁移成本比较高。4. 实操用 Python 搭一个带技能记忆的最小 Agent4.1 设计目标与基础架子说了这么多趋势还是直接上一套能跑的最小实现更有说服力。目标是做一个带“技能注册表 长期记忆”的极简 Agent能完成两个动作记住用户明确要求保存的信息并在用户问起时把相关信息找回来。架子分三块技能注册表负责描述和路由MemoryStore 负责存储Agent 主循环负责把输入接到技能上。我不引入任何第三方框架只依赖 Python 标准库里的 sqlite3 和 math方便直接复现。模型调用部分留一个接口注释你可以替换成自己实际使用的任何模型服务。4.2 核心代码实现下面是我整理后的完整骨架代码可以直接存成agent_minimal.py运行。import json import math import sqlite3 from datetime import datetime # ---------- 1. 技能注册表 ---------- SKILLS [ { name: remember, description: 用户明确要求记住信息时使用。触发词记住、别忘了、存一下。不要主动保存用户没要求的内容。, params: [content] }, { name: recall, description: 用户询问历史信息、偏好、过去说过的话时使用。触发词我之前、我上次、还记得吗。, params: [query] }, { name: echo, description: 上述技能都不匹配时的兜底回复直接根据对话上下文回答。, params: [question] } ] # ---------- 2. 记忆存储 ---------- class MemoryStore: def __init__(self, pathmemory.db): self.conn sqlite3.connect(path) self.conn.execute( CREATE TABLE IF NOT EXISTS memory( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT, created_at TEXT) ) def add(self, content): self.conn.execute( INSERT INTO memory(content, created_at) VALUES (?, ?), (content, datetime.now().isoformat()), ) self.conn.commit() def all_items(self): cur self.conn.execute(SELECT content FROM memory) return [row[0] for row in cur.fetchall()] # ---------- 3. 简易向量检索 ---------- def ngram_vector(text, n2): text text.lower() vec {} for i in range(max(0, len(text) - n 1)): gram text[i:in] vec[gram] vec.get(gram, 0) 1 return vec def cosine_similarity(a, b): common set(a.keys()) set(b.keys()) dot sum(a[g] * b[g] for g in common) norm_a math.sqrt(sum(v * v for v in a.values())) norm_b math.sqrt(sum(v * v for v in b.values())) return dot / (norm_a * norm_b 1e-9) def recall(query, store, top_k3, min_score0.05): q_vec ngram_vector(query) scored [] for item in store.all_items(): score cosine_similarity(q_vec, ngram_vector(item)) if score min_score: scored.append((score, item)) scored.sort(reverseTrue) return [item for _, item in scored[:top_k]] # ---------- 4. 技能路由 ---------- def route_skill(user_input): for skill in SKILLS: if skill[name] remember and any( k in user_input for k in [记住, 别忘了, 存一下] ): return skill if skill[name] recall and any( k in user_input for k in [我之前, 我上次, 还记得] ): return skill return SKILLS[2] # echo # ---------- 5. Agent 主循环 ---------- def llm_chat(prompt): # 这里替换成你实际使用的模型服务接口 # 例如return your_model_client.chat(prompt) raise NotImplementedError(请接入实际模型服务) def run_agent(user_input, store): skill route_skill(user_input) if skill[name] remember: content user_input for k in [记住, 别忘了, 存一下]: content content.replace(k, ) store.add(content.strip()) return 已存入长期记忆 if skill[name] recall: query user_input for k in [我之前, 我上次, 还记得]: query query.replace(k, ) hits recall(query.strip(), store) if hits: return 找到相关记忆\n \n.join(hits) return 记忆库中没有找到相关内容 # echo 技能交给模型直接回答 return llm_chat(user_input) if __name__ __main__: store MemoryStore() while True: user_input input(你: ) if user_input in (quit, exit): break print(Agent:, run_agent(user_input, store))4.3 运行效果与调参说明把代码跑起来后效果类似下面的交互你: 记住项目代号 Alpha 下周评审 Agent: 已存入长期记忆 你: 我上次说的项目代号是什么 Agent: 找到相关记忆 项目代号 Alpha 下周评审这个骨架虽然简单但已经具备技能化和记忆工程的最小要素技能注册SKILLS 列表、技能路由route_skill、记忆写入MemoryStore.add、记忆检索recall。要接入真实模型只需要把llm_chat里的NotImplementedError换成你实际用的模型接口即可。调参时重点看三个地方。一是 ngram 的 n对中文短文本用 2 效果可以英文可以试 3。二是 min_score 阈值设太低会召回大量无关内容设太高又会一无所获建议先从 0.05 起步根据测试结果微调。三是 top_k个人项目 3 到 5 通常够用。生产环境建议把 ngram 向量换成专用 embedding 接口同时把 SQLite 换成独立检索服务接口不需要改替换实现即可。5. 常见问题与排错技巧实录5.1 记忆污染写入门槛怎么定我在最初几轮测试里犯过一个典型错误把所有对话都写进记忆库。结果 Agent 在回答“今天天气怎么样”时也能把“用户中午吃了面条”作为相关记忆列出来。这就是记忆污染。排查思路是看写入管线的门槛是否过低。长期记忆只应该保存两类内容一类是用户明确要求记住的另一类是从多次会话中稳定提炼出来的结论。临时消息和寒暄内容要挡在写入环节之外。实际操作中我给自己定的规则是默认不写入除非用户表达了明确指令或者一条信息在三次以上会话中被反复提及才考虑合并后写入长期记忆。5.2 技能选择漂移技能多了以后最烦的问题是路由漂移。比如用户说“提醒我下午三点开会”Agent 却跑去调用了“搜索网络”技能。原因通常不是模型不行而是技能描述之间出现了语义重叠。解决办法有两个层次。第一在技能描述里加入“使用时”和“不要使用”的判别性语句比如搜索技能的描述里明确写“当用户需要使用实时外部信息时使用日程提醒类请求不要使用本技能”。第二在注册表里加一个优先级字段有重叠可能时按业务重要性排序。我见过一个做得比较细的项目路由模块在模型返回结果后还会做一次规则校验如果模型选了权限级别较高的技能但没有满足前置条件就打回重新选择。这个思路很值得借鉴。5.3 上下文越来越长的瓶颈长期运行后即使技能路由正确、记忆写入干净也会遇到一个硬性瓶颈每次把全部历史记忆灌进上下文提示词会越来越长响应速度和准确率都会下降。我的做法是三级处理工作记忆只放当前任务的必要信息情景记忆放最近几轮会话的压缩摘要语义记忆只有在检索命中时才注入提示词。每轮对话结束后把超过设定长度的旧消息折叠成摘要而不是继续堆原始文本。实测下来上下文长度能从几万 token 压到几千 token而且关键信息的召回率没有明显下降。5.4 排查与恢复速查表问题现象可能原因快速定位方法建议动作Agent 回复夹带无关历史记忆写入门槛过低垃圾信息进了长期库直接查看记忆表中最近 20 条记录提高写入门槛删除问题记录“记住”请求没生效路由时触发词没覆盖到用户表达方式打印技能路由命中的技能名扩充触发词或改用模型路由检索总是返回空结果阈值过高或存储内容过少手工执行向量相似度打印分值降低 min_score检查存储条数技能总选错技能描述语义重叠把技能描述对比着看增加判别语句调整优先级上下文越来越长历史消息未做压缩统计每次注入的 token 数增加摘要折叠机制排查时要记住一个原则先查数据再查代码最后怀疑模型。大多数问题都不是模型变笨了而是它前面拿到的数据就不对。6. 我的一点实操体会这几天集中看这批项目又自己动手跑了一遍最小实现最大的体会是技能化加记忆工程这条路本质上是在给 Agent 立规矩。技能是能力边界记忆是信息边界两者都做清楚了Agent 的行为才有可预测性。我现在的习惯是新建任何 Agent 项目都先写技能注册表再设计记忆分层最后才考虑对话体验。顺序反了的话后面基本都要返工。最后再分享一个小技巧给所有记忆都加上 created_at 和 source 字段看似简单但排查记忆污染时这两个字段能帮你快速定位来源救过我好几次。