
做Agent的人迟早会撞上一堵墙你明明把Memory、Context、Skills和Harness这些词背得很熟一落到生产环境却发现上下文窗口动不动就爆换个会话Agent就失忆昨天刚调好的经验今天又要从头教。这些问题归根结底是同一件事——经验到底怎么被保存、调用和更新这一篇作为Agent系列总结的第三篇我不打算只罗列论文概念而是把工程侧真正踩过的坑、用过的方案和背后的取舍一起聊一聊。无论你是在搭个人助理、企业级工作流Agent还是研究多Agent系统下面这些内容都会涉及如何把一次性对话沉淀成可复用经验怎么把有限上下文窗口当成资源经营以及Skills和Harness在整个系统里到底承担什么角色。1. 为什么所有经验都塞进上下文是走不通的1.1 上下文窗口是工作台不是仓库很多刚接触Agent的开发者会有一个直觉既然模型能看多长的上下文那我就把历史对话、知识文档、用户偏好全塞进去Agent不就什么都知道了吗我用两个字回答会炸。上下文窗口本质上是模型在生成下一句话时能够抬头看到的有限范围。你可以把它想象成一张桌子模型只能在这张桌子上摊开材料工作。桌上能放的东西确实越来越多——从几千token到几十万甚至出现了宣称1M上下文的模型——但桌子不等于仓库。真正的仓库应该是可检索、可持久化、可跨会话共享的记忆系统。为什么不能把一切都放在上下文里至少有四个现实问题成本问题按token计费的API上下文越长每次调用越贵而且长上下文的费用是超线性增加的。延迟问题模型处理长输入的时间会明显上升交互式Agent会变得“像慢动作重播”。注意力稀释问题相关关键词淹没在海量历史文本里模型抓重点的能力反而下降这在长文档问答中尤其明显。状态丢失问题会话一结束或者临时会话切换上下文直接归零经验无法跨越会话形成积累。所以工程上的第一课就是上下文窗口永远是临时工作台我们需要单独的组件来承担长期存储的职责。1.2 记忆的分层工作记忆、长期记忆与程序性记忆要设计好Agent的记忆可以先借用认知科学里的一套分层思路这不是掉书袋而是因为分层直接对应了不同的存储介质和读写频率。工作记忆短期记忆指Agent在当前任务执行过程中临时保存的信息比如用户刚才说要导出PDF格式、中间结果里第3条记录是重复的。它的特点是生命周期短、更新频繁、不需要长期保留。工程上通常就放在上下文中或放在一次任务执行的变量池里。长期陈述性记忆指跨会话保留的事实、偏好和事件比如用户之前明确拒绝过邮件自动发送、上周二部署时发现端口冲突。工程上可以存在JSON文件、SQLite里或者重向量化成嵌入存进向量数据库。程序性记忆指怎么做一件事的步骤和套路比如先备份再升级数据库、代码提交前必须跑lint。这类经验不应该以自然语言散落在对话记录里而应该固化成可调用的技能Skills。很多团队一开始只做了短期记忆长期记忆的存储却忘了程序性记忆。结果就是Agent能记住事实但不会总结操作流程。后面我会专门讲Skills就是为了补上这一层。1.3 双网络记忆模型给Agent设计带来的工程启发论文界经常提双网络记忆模型大概是说新皮层负责快速学习具体实例海马体负责缓慢巩固并整合成稳定知识。这个机制放在Agent工程里非常有用。我的理解是Agent的短期记忆应该追求快速写入、快速失效类似新皮层记录刚发生的事实而长期记忆则要有异步整合的过程类似海马体的离线巩固——不是每一个细节都直接进长期库而是在任务结束后做摘要、去重、关联再写入。我记得有个项目就是把所有Agent执行日志直接倒进向量库结果向量库变成垃圾场重复内容、过期信息、互相矛盾的记忆混在一起检索出来的结果甚至会把Agent带偏。后来改成双通道临时记录先进一个短期待整合区跑完一批任务后统一清洗再合并到长期记忆库准确率立刻好看了很多。这里我多说一句创伤记忆。这里的创伤不是心理创伤而是指高价值的失败教训。它非常值得被单独记录下来什么时候出的问题、当时的完整上下文、错误日志是什么、如何规避。这类经验对Agent的成长价值远高于一百条顺风顺水的成功日志所以应该在记忆系统里专门打标签、提高权重。1.4 一个很现实的场景换账号、换环境后记忆去哪了我见过太多个人AI应用比如聊天助手、效率工具用户用久了积累了一堆偏好和习惯。结果用户换台电脑、换个账号登录发现Agent对他的了解全部清零。这比对话记录丢失更致命因为那些记忆是用户在一次次操作中积累出来的数字人格切片。问题出在我们把记忆存错了地方。有些实现把记忆直接写进了会话记录文件或者存在浏览器的LocalStorage里账号一换自然读不到。工业界的落地做法应该是记忆独立于会话、独立于模型、独立于设备作为一种可导出的数据资产。你可以简单类比成游戏存档进度不能只存在内存里要落到硬盘换了电脑登录只要云端存档还在进度就能续上。我在自己的工具里就定义了一套记忆导出格式至少包含用户偏好、历史决策、避免事项、关键节点然后支持外部文件或服务端同步。这样用户从WorkBuddy这类工具换到自建Agent也能把记忆带过来继续用。2. 上下文管理实战窗口有限但经验可以分层存放2.1 1M上下文只是更大的一层缓存不是真正的记忆现在有些模型主推1M上下文窗口听起来能塞下厚厚一本书很多人就开始兴奋说以后再也不用RAG了。我劝你先冷静一下。1M上下文确实能解决一类特定问题单篇超长文档的理解比如一份完整的年度财务报告、一整本开源技术手册。让模型在足够长上下文里做全局推理比零散切片的效果好很多。这是真实技术价值不能否定。但它解决不了经验积累的问题。理由很简单上下文永远和某个具体任务绑定。哪怕窗口有一百万token任务做完了这个窗口就关了下次新任务又要重新铺一轮。它只是把工作台换成了更大的桌子但货物还是不能搬到办公室之外。而且长窗口是有隐性代价的。我实测过一个近似1M的超长上下文场景输入阶段耗时明显飙升token费用也让人肉疼。更麻烦的是当关键信息被埋在几十万token深处模型经常过目就忘检索性错误反而变多。所以我的原则是长上下文用来处理需要全局视野的单一文档而跨任务积累的通用经验依然要落到外部记忆。2.2 上下文溢出时的四套处理手法无论窗口多大总有装不下的时候。真正该掌握的是上下文溢出后的处理手法这里直接给四套经过验证的方案。滑动窗口只保留最近N轮对话更早的内容直接丢弃或做摘要。适合闲聊型Agent因为它需要的是对当下语境的反应。摘要压缩把一段长历史先让模型总结成结构化摘要再将摘要放回上下文顶端。注意摘要要不断迭代更新不是一次性做完就完事。分段裁剪任务导向重组如果输入是超长文档先做段落切分再根据当前需要解决的问题只提取和问题相关的几个区块。外部挂载指针替换把详细内容存到记忆库或文件系统上下文只保留一行引用提示例如详见记忆条目#42等模型真正需要时再通过工具读取。我自己的经验是这四套手法不是单选而是组合拳。通常我会先用滑动窗口确定活着的上下文范围再对移出窗口的对话做一次摘要同时把关键实体单独写入长期记忆库形成双保险。2.3 长上下文与RAG的分工边界很多人把长上下文和RAG当对立面其实它们是分工关系。长上下文适合的场景是一次性把完整的源数据给模型看信息无损但成本高、延迟高。RAG适合的场景是数据量巨大企业知识库、产品文档、代码仓库无法全部塞进窗口先通过检索挑出最相关的内容再把经过裁剪的内容交给模型。有个经验性的判断标准如果源数据在10万token以内且是单次任务的固定上下文可以优先考虑长窗口如果数据可能持续增长、来源多样并且需要做跨会话更新那一定要上RAG或外部记忆库。我在处理一个客户文档问答Agent时就是这么干的常见问题答复存在向量库里用RAG检索当遇到需要通读整份合同条款的任务时才把合同全文挂进长上下文。这样兼顾了成本和效果也避免了一遇到长文档就把上下文撑爆。2.4 开源模型上下文不够用的补救措施5万token档位不是每个团队都能用上百万级上下文的商业模型。很多开源模型比如Qwen系列里27B的规格标称上下文只有5万token左右实际推理时可能2万就开始质量下降。面对这种情况纯靠上下文管理是不够的需要动结构。我实践下来最有效的补救是外部状态化把本应挤在上下文里的系统状态转移到显式存储里。举个例子做一个多Agent协作任务原来我要把每个子Agent的中间输出全放到主Agent的context里结果没几轮就爆了。后来改成每一个子Agent完成后只写一条执行摘要结果ID到共享存储主Agent上下文里只保留几个ID和摘要需要细节时再按ID去读取。上下文占用直接下降了80%。如果你用的是低代码平台比如Dify这类工作流最常见的坑是中间变量一直在上下文里传递导致节点一多就超长。解决办法是及时清理变量或者把大块中间结果写入外部数据集再在后续节点通过查询拿回。别让每个节点都背着一整条工作流的全部数据。2.5 别忽视上下文污染过期信息比没有信息更危险上下文再大如果里面混着过期信息模型会被带偏。我在一个运维Agent里遇到过系统里有一条几个月前的旧配置项在上下文里Agent每次都会把它当作当前配置来用结果给出的操作建议全是错的。为什么因为上下文不会自动标注这条信息已失效。解决这个问题需要给上下文里的每个片段附加元信息尤其是时间戳和来源。在组装上下文时加入一道信息新鲜度过滤超过一定时效的信息降权或者直接交给记忆库的校验模块判断是否过时。只要你开始做上下文审计就会发现信息太多不是问题信息太旧才是。3. Skills把做过一次成功的事编译成可复用技能3.1 提示词、技能、工具函数三者到底差在哪同一个任务你可以用三种方式实现写一段提示词让模型现场发挥、写一个Skill文件让Agent按固定套路执行、写一个工具函数让外部代码直接完成。提示词是最灵活但也最不可控的模型每次都会重新思考流程容易飘。工具函数是最可控的但只能处理完全确定的任务没法应对开放式需求。Skills正好在中间它把一些最有效的执行流程沉淀成结构化知识让Agent在合适的时机遵循这部分经验同时保留模型面向开放输入的灵活性。用厨艺做类比提示词像是口头告诉厨师差不多这么做吧工具函数像是给他一台自动炒菜机而Skill更像是一本你本人经验写成的菜谱它还包括了火候判断、避坑点、用料替换方案厨师可以按菜谱执行也能根据现场食材灵活调整。3.2 Skill文件的标准长相从Claude Skills到Codex Skills我看过不少Skills定义目前比较欣赏的思路是Claude Skills这种SKILL.md 渐进式披露的形态。它把技能拆成一个Markdown文件开头是结构化的元信息正文是分层次的说明。一个SKILL.md的大致长相--- name: deploy_service description: 部署容器化服务到生产环境适用于Docker Compose项目。 when_to_use: 当用户要求上线、更新或回滚一个已有服务时。 version: 2.1.0 tags: - devops - deployment --- # 部署流程总览 部署分三步环境检查、发布镜像、健康检查。 ## 详细步骤 ### 1. 环境检查 - 确认服务器剩余磁盘空间 - 确认当前运行版本 ### 2. 发布镜像 ... ## 注意事项 - 生产环境禁止直接 docker compose down会导致流量中断 ...关键在渐进式披露顶层只放总览和快速判断让Agent在读文件开头就知道何时该用、大致流程是怎样的细节放在后面Agent在真正执行时再往下读。这样既不会让技能描述占满上下文也能保证关键时刻有足够细节。Codex Skills也类似本质上是把标准化操作流程专业经验封装成可读取的文档。社区里有人整理了非常多的开箱Skills比如前端开发SKills会包含项目脚手架、代码规范检查、浏览器调试步骤、组件测试套路等等。用起来是真的能减少模型自由发挥带来的随机性。3.3 Skill的注册、检索、调用与更新一个生命周期实例Skill不是把文件放进仓库就完事它要能参与Agent的决策循环。我把Skill的生命周期分成四步注册把所有Skill的元信息名字、描述、适用条件、版本登记到Agent的技能目录里。目录可以是一份JSON索引文件也可以是向量库里的技能描述嵌入。检索当用户输入一个新任务时Agent第一步不是直接写答案而是先做意图解析然后根据技能目录里的描述找出最匹配的1到3个候选Skill。调用Agent读取候选Skill的顶层内容根据when_to_use和当前任务做最终确认然后加载详细步骤开始执行。更新每次技能被使用后应该记录运行结果如果发现步骤有问题就修改Skill文件并更新版本号。这里最重要的实践是注册信息写得越具体命中率越高。如果技能描述写处理部署模型根本分不清是前端部署还是后端部署写成部署容器化服务到生产环境适用于Docker Compose项目命中率会大幅提升。3.4 怎么从零搭一个内部Skills库附测试方法我在团队里落地Skills库时规定了一套简单可复用的流程。首先每个技能只能解决一个明确的场景。不要造一个全能工作流技能那注定又臭又长。比如前端开发Skills应该拆成初始化项目、代码规范修复、浏览器调试三个独立文件。其次统一技能文件放在独立目录并赋予版本后缀。目录结构类似这样skills/ deploy_service/ v2.1.0.md v2.0.0.md index.json frontend_init/ v1.0.0.md第三给每个技能建一套测试用例。用固定的10到20个任务描述去触发该技能统计两个指标召回率该用技能时模型有没有选到和误用率不该用时有没有乱用。如果误用率高多半是when_to_use描述写得宽泛了直接改描述。我在实际调整中经常发现技能库超过30个之后光靠文本描述匹配就开始失灵。这时可以考虑给每个技能加标签并在注册目录里加上负面提示——明确写如果用户只是想查看状态不要调用本技能。这招很土但极其有效。4. HarnessAgent的驾驶舱与控制台4.1 Harness和Agent的区别先搞清楚缰绳和马的职责我一直觉得Harness这个词被译成框架有点委屈了。它本意是马的挽具/缰绳强调的是控制和引导。所以Harness和Agent的关系不是同一个东西而是马和缰绳的关系。Agent是那个做判断和执行的智能体它负责理解目标、规划步骤、调用工具。Harness是承载Agent运行的外部系统它负责提供环境、限制权限、管理记忆、加载技能、记录日志、处理异常。也就是说Harness决定了Agent在哪块场地上跑、哪些工具能碰、关键时刻人能不能拉得住。为什么工业界一定要有Harness因为纯放养Agent太不可控。没有HarnessAgent可以任意访问文件系统、执行危险命令、遗忘关键上下文、无法被观测。而Harness像一道安全围栏把Agent的能力限制在可管理的范围内。4.2 Harness的核心模块拆解模型路由、记忆、技能、工具与沙箱一个合格的Agent Harness通常至少要包含这些模块模块职责常见实现方式模型路由根据任务类型选择不同模型轻量对话/重型推理路由规则、成本预算策略上下文组装从记忆库检索内容与当前对话拼装成模型输入RAG、模板、缓存管理记忆服务读写短期和长期记忆提供检索与更新接口SQLite、Redis、向量库技能调度加载技能目录匹配任务并注入相关技能文档Skills Registry、嵌入检索工具执行器调用外部工具如Shell、HTTP、浏览器、文件操作沙箱、命令白名单、超时控制安全与审计记录所有操作日志支持回放与拦截日志系统、人工审批钩子状态管理保存任务执行中间状态支持恢复与重试状态机、持久化队列我见过不少Agent项目夭折在生产环境不是模型不够聪明而是缺了Harness里的安全与审计。没有日志出问题根本没法复盘没有沙箱一个错误命令可能让数据库备份文件被清空。4.3 从DeepSeek Harness这类开源工程里能学到什么近期社区里讨论比较多的DeepSeek Harness本质上是提供了一个把大模型放进受控执行环境里的工程架子。它比较强调LLM在终端/Shell类任务中的可控执行这给我几点启发。第一环境隔离是Harness的底线。所有Agent能跑的命令都应该在容器或沙箱里执行至少也要做系统调用白名单。我在自己的项目里干脆规定不允许Agent直接执行裸rm命令只能用封装过的safe_remove工具这个工具会先列出删除清单再确认一次。第二内网部署要考虑模型服务与Harness的解耦。很多团队需要把Harness部署到内网服务器模型也要私有化。这时Harness应该设计成只依赖标准化的模型推理接口比如OpenAI兼容接口这样换了模型服务后其余模块不用动。第三语言选型上如果对并发和资源控制要求高可以选择Rust这类系统语言来实现Harness的底层部分如果更看重迭代速度那用Python写原型是合理的。我个人的筛选标准是个人工具和快速验证用Python商业级多租户服务从第一天就考虑更硬核的实现因为Harness往往要做资源隔离Rust这类语言在权限控制和内存安全上有不可替代的优势。4.4 一个最小的Harness工作流设计可直接照抄的循环最后分享一个我在自己项目里使用的极简Harness循环代码量很少但足够跑通记忆-技能-工具的闭环1. 接收用户任务 2. 从长期记忆库检索相关偏好和历史结论 3. 从技能目录匹配候选Skill根据描述做相似度匹配 4. 组装上下文任务描述 检索到的记忆 技能内容 工具列表 5. 让模型生成执行计划Harness审核是否包含危险操作 6. 逐步骤交给工具执行器运行每个步骤记录结果和日志 7. 如果中途失败把错误信息回传给模型进行修正 8. 整个任务完成后生成任务摘要写入短期待整合记忆区 9. 异步任务负责清洗摘要、合并去重再写入长期记忆库 10. 输出最终结果这个循环最重要的不是智能而是每一步都可以被观察和中断。只要任何一步日志出现异常人工可以立刻介入而不是等到Agent跑完全部流程才做检查。Harness存在的意义不是放大Agent的能力而是给能力套上一套可管控的缰绳。5. 经验如何被真正调用和更新写入、读取、冲突与闭环5.1 写入路径不是所有对话都要进记忆记忆系统的第一步是判断该记什么。很多人的默认做法是全量保存这是错的。全量保存会导致信息熵太高检索出来的全是废话重要经验被淹没。我在实际项目里给记忆写入设置了几个过滤器信息价值过滤这条信息会不会影响后续任务比如用户今天心情不错这种临时状态除非要长期调整语气否则不写。重复过滤同样的事实已经存在就不再追加改为更新原记录的时间戳和置信度。结论优先能写成结论的不要写过程。与其记住用户昨天试了三次导出前两次都失败不如记住用户倾向先预览再导出导出失败多是格式不兼容。失败优先凡是执行失败、被用户纠正、引发过事故的经验一定要单独打上高权重标签。这一类记录是Agent成长最快的养料。5.2 读取路径检索、精排、组装上下文记忆写进去不算完关键是读的时候能不能读到正确的知识。读取路径我总结为三步检索、精排、组装。检索阶段根据当前任务的关键词和语义从记忆库拉出候选记录。精排阶段用重排序模型或规则对候选记录进行打分依据是相关性、时效性、来源权威性和是否带失败教训标签。组装阶段只把精排后的TopK放进上下文并且每条记录标注时间和来源方便模型判断可信度。有一个小细节很值得注意读取时要把记忆和上下文分开。记忆是经过整理和验证的可以信任上下文里的内容是当前任务的原料可能存在噪声。组装时给模型一个角色指令让它优先引用记忆库中的结论再用当前上下文做补充这样能明显减少模型被上下文里的临时信息带偏的问题。5.3 记忆更新产生冲突了怎么办只要记忆系统用久了一定会出现冲突昨天记录用户喜欢言简意赅的回复今天用户却说这次给我详细一点。这种冲突怎么处理我的做法是给记忆记录附加三个字段时间戳、置信度、覆盖策略。当新旧记忆冲突时先看置信度——带失败教训的记忆置信度高再看时间衰减——离现在越近记录权重越大最后看冲突类型——如果是偏好类的变化新记录覆盖旧记录如果是事实类的矛盾则保留两条并在读取时都提供给模型。另一个容易忽略的点是版本回退。每次记忆更新前至少把被覆盖的内容存在历史表里。有一次我们的Agent在长期记忆里改错了参数后续任务全被带偏排查了半天才发现是几天前一次自动更新写脏了数据。从那以后我就强制要求任何批量写入记忆的脚本都必须先生成变更日志且支持一键回滚。5.4 一次完整闭环从事故到技能再到Harness策略我想用一个真实的闭环来收尾这一章。之前我们有Agent负责自动处理线上部署有一次它因为环境变量未设置直接把测试环境配置文件推到了生产环境虽然没有造成数据损失但触发了告警。事故发生后我们做了一次完整的复盘并按四层结构把经验沉淀进了系统第一层写入创伤记忆把这次事故的时间、触发条件、错误命令、恢复步骤全部存进长期记忆库并打上最高权重标签。第二层固化成Skill新建了一个生产部署前检查技能把校验环境变量、备份当前配置、先演练发布三个步骤写成SKILL.md并且明确在注意事项里写出未通过检查禁止发布。第三层升级Harness策略在工具执行器里增加一条强制规则如果Agent发起对生产环境的写入必须先经过人工确认钩子。第四层更新检索权重在读取路径里给失败教训类记忆加了更高的精排权重保证下次部署任务启动时模型优先看到这条教训。整个过程大概花了一下午但效果立竿见影。后面Agent再跑部署流程基本不需要人盯。这个案例也解释了为什么我说记忆、Skills和Harness不是三个孤立组件而是一个互相强化的闭环记忆提供素材Skills把素材变成行动规范Harness用工程手段保证规范被执行执行后的新经验又回流到记忆。我自己的习惯是构建Agent系统时先抓住这个闭环让经验从任务中来经过提炼进入记忆库沉淀成技能最后在Harness层面形成规则。一套系统如果这四个环节都跑通了它才真正称得上有成长能力而不是一个每次都靠临场发挥的玩具。如果你正在做Agent相关项目不妨从今天开始试着记录一次失败经验把它写成一条带标签的记忆再花半小时包装成一个Skill你会发现下次运行时的稳定性会比想象中提升一大截。