做 Agent 落地做久了,我越发觉得一个团队最终能走多远,往往不取决于模型的“智力”,而取决于它有没有一套靠谱的“记性”。模型每个新对话都像失忆患者:昨天刚调好的工作流、刚踩过的坑、刚总结出来的套路,只要会话一关,全部归零。所以这篇系列第 3 篇,我把 Agent 记忆、上下文、Skills 与 Harness 这四件事放到一起聊。它们表面上是四个概念,本质上只回答一个问题:Agent 的经验到底怎么被保存、怎么被调用、又怎么被更新。
这四件事的从业者受众其实很广:无论你是在做客服 Agent、代码 Agent,还是内部知识库助手,最终都会撞到同一堵墙——模型上下文窗口有限,而业务经验无限。我读过一些相关的论文,也在工业界做过几个完整项目,这篇就把那些在论文里被包装成花哨名词的东西,还有在产线上实际趟出来的经验,一次性说清楚。你会看到一个完整的“经验存取系统”应该长什么样。
1. Agent 记忆的分层设计:别再把所有东西都往上下文里塞
1.1 工作记忆与长期记忆:为什么模型“记不住”才是常态
先把一个最基础的概念捋清楚:大模型本身几乎没有任何持久记忆。你给它一段文本,它根据这段文本生成回复,窗口一关,所有 token 就像黑板上的粉笔字一样被擦掉了。我们平时说的 Agent 记忆,实际上是靠外部系统“借”给模型的。所以设计记忆系统的第一步,就是分清楚哪些“记忆”放在哪里。
在认知科学里,人类记忆分工作记忆和长期记忆。你把这句话搬进 Agent 系统里,几乎是字面意义的通用:工作记忆就是模型每次调用时能看到的那些 token,也就是上下文窗口;长期记忆则是存在模型外部、需要时再检索回来的数据。两者的核心矛盾在于:工作记忆空间小、读取快、直接影响模型本次推理质量,但它是易失的;长期记忆容量大、可持久保存,但每次读取都要走一遍检索流程,有延迟、有噪声。
我在项目里最常看到的错误,就是新手把长期记忆和上下文画等号:既然模型有 128k 上下文,为什么不用外挂数据库,直接把所有历史记录全部丢进去?答案很简单,塞满上下文之后,模型并不会因此变聪明,反而会进入“lost in the middle”状态——长文本中间的信息召回率显著下降,你塞进去的旧经验不仅帮不上忙,还会把真正相关的新信息稀释掉。上下文窗口本质上是一张工作台,不是仓库;你把整个仓库搬上工作台,连工具都放不下。
1.2 情景记忆、语义记忆与程序性记忆:Agent 的三类经验
为了让长期记忆能被高效组织,工业界一般参考人类记忆再拆成三类:情景记忆(episodic)、语义记忆(semantic)和程序性记忆(procedural)。我在设计 Agent 记忆 Schema 的时候,就是按这三个维度建的集合:
- 情景记忆:存“某时某刻发生了什么”,比如“2025-06-03 用户 A 在订单退款时反复强调要优先处理物流异常”。这类记录有明确的时间线,用于回答“之前那次是怎么处理的”。
- 语义记忆:存“世界是怎么运作的”,比如公司退货政策、产品功能列表、领域知识。它是去情境化的,和某个特定时间点无关。
- 程序性记忆:存“怎么做”,比如“遇到退款纠纷时应该先查物流日志再发赔偿工单”。程序性记忆不应该是自然语言描述,而是可执行的步骤序列,这就是后面要讲的 Skills。
另一个值得借鉴的架构是双网络记忆模型。在认知科学里,海马体负责快速写入短期经验,大脑皮层负责缓慢巩固长期知识;Agent 系统里对应的设计是:短期区(比如 Redis 里存最近几轮对话)负责快速读写、低延迟,长期区(向量库+关系库)负责高容量、可检索。每次任务结束后,后台例行任务把短期区的重要记录做清洗、去重、格式规范化,然后“巩固”到长期区。这套“快慢分离”设计的好处是,高频读写不会拖垮数据库,长期积累也不会导致检索变慢。
1.3 记忆数据的生命周期:写入、读取、遗忘
记忆系统还有一条很少有人聊的命脉:遗忘。人类记性不好是有进化意义的,Agent 也一样。如果所有历史对话、所有失败记录都永久保留,你的向量库里会堆积大量过期且互相矛盾的记录,召回时相似度高却语义冲突的 chunk 会把模型搞到精神分裂。所以我在生产环境里会给每条记忆打上生命周期字段:
- created_at:这条记忆什么时候生成的;
- last_access_at:最后一次被检索到是什么时候;
- confidence_score:这条记录被模型调用后,成功解决任务的次数占比;
- expiry_policy:这条记忆多久后需要被 review,或者自动降权。
后台每隔一段时间跑一次“记忆整理”任务:置信度太低且长期无人访问的记忆会被归档,互相矛盾的两条记忆会保留置信度更高的一条,关联度高的短记忆会融合成一条长记忆摘要。这个过程业界一般叫 memory consolidation,但说白了和整理书桌差不多:常用的放桌面,不常用的进抽屉,废纸扔掉。没有遗忘机制的记忆系统跑半年后一定会变成垃圾场,我亲眼见过因为记忆库召回噪声太大,Agent 把老客户当成新客户,还差点按旧政策给了错误的折扣。
2. 上下文工程:经验如何被塞进有限窗口
2.1 上下文窗口是“工作台”不是“仓库”:1m 上下文到底改变了什么
这两年大模型厂商把上下文窗口越做越大,从 32k 到 128k,再到 1m。很多产品经理看到“1m 上下文”这个概念就兴奋,觉得 Agent 不需要记忆系统了,把所有资料全塞进去就行。这个理解是错误的。1m token 大概能装下 700 页书,确实可以容纳很大体量的资料,但你得想清楚两个问题。
第一个问题是成本。上下文是按输入 token 计费的,1m 的输入成本是 128k 的近 8 倍,你在实际业务里不可能每次都把 1m 塞满。第二个问题是注意力退化,前面提过的 lost in the middle 在超长上下文中会更明显:模型对长文本开头、结尾的内容感知很强,对中间内容感知很弱。上下文越长,中间部分的信息密度就得越高,否则模型只能记住开头和结尾的“废话”。
所以我的判断是:1m 上下文真正改变的是“资料载入”场景,比如把整本操作手册一次性喂给模型做问答,而不是改变“记忆系统”的设计逻辑。Agent 记忆该做还得做——上下文窗口是工作台,显存再大也不能替代数据库。当你的系统提示词、少量示例、工具定义、检索结果、中间推理过程加在一起超过窗口限制时,唯一正确的做法是让记忆系统介入,而不是简单粗暴地升级到更大窗口。
2.2 截断、压缩、检索:三种主流上下文管理方案对比
从业界实践看,上下文管理有三条路线:截断、压缩、检索。它们可以组合使用,但各自的适用面完全不同。
截断是最原始的做法,按滑动窗口丢掉早期的内容,只保留最近 N 轮对话。优点是实现简单、零额外开销,缺点是会丢失早期关键信息。比如一个客服 Agent 聊了 20 轮,用户在第 3 轮说了自己的会员等级,截断后模型又把它当普通用户对待。所以我在做系统设计时,会把“必须长期保留的关键字段”从对话流里抽出来放到状态变量里,对话本身再截断就不怕丢关键上下文了。
压缩是把早期对话做成摘要。你可以让模型把前 20 轮的对话总结成 200 字,下一次调用时用摘要代替原始记录。这个方案能有效利用窗口,但有信息损耗:摘要只会保留压缩者认为重要的信息,而关键细节经常被丢掉。我在实践里的做法是分级摘要:按业务维度分别做“用户诉求摘要”“已执行动作摘要”“待办事项摘要”,而不是做一段通篇的整体摘要。
检索是最符合“记忆”这个词的方案,也就是 RAG:把历史记录切块后放进向量库,每次根据当前问题检索 top-k 相关片段。缺点是检索本身有延迟,而且召回质量受 embedding 模型、切块大小、rerank 策略影响很大。生产环境里我一般用“检索 + 压缩摘要”的组合,检索出来的片段如果没有直接命中答案,再让模型对命中结果做一次压缩,输出最相关的 300 字放进上下文。
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 截断 | 实现简单、无延迟 | 丢信息、无跨会话记忆 | 短任务、一次性对话 |
| 压缩摘要 | 保留全局脉络、窗口利用率高 | 摘要环节有损耗、需额外 token | 长会话、客服对话 |
| 向量检索 | 高容量、可跨会话 | 有延迟、召回质量依赖检索链路 | 知识库、长期记忆召回 |
| 混合(检索+摘要) | 精度与容量兼顾 | 架构复杂、需要调参 | 生产环境主流方案 |
2.3 上下文塞爆之后的降级策略:优先级队列和逃生通道
无论你用什么方案,总会有一次调用因为用户输入超长、工具返回结果太大而把上下文塞爆。处理这种突发状况,必须有预案,不能到时报错让用户自己承担。我的做法是在 Agent 运行时维护一个“上下文优先级队列”。
我们可以把上下文里的内容分成几个等级:系统提示词和用户核心诉求是第一优先级,绝对不可丢弃;当前正在执行的任务上下文、最近一轮对话是第二优先级;历史对话摘要、检索结果片段、工具返回的大段 JSON 是第三优先级;示例和长文本参考资料是第四优先级。当窗口快满时,Harness 按从低到高的顺序压缩或丢弃低优先级内容,每次都留出至少 3k~5k token 给模型输出。
这里需要特别提醒一个细节:工具返回的 JSON 往往是上下文杀手。一个订单详情接口可能返回 8000 字的字段,但模型真正需要的只是其中 30 个字。所以在工具调用链路上,我强烈建议做一次“结果裁剪”。
只有 Canvas 文本、完整列表这类必须原样保留的结果才整段进入上下文,其他结构化结果用一段精简的摘要代替。我自己踩过的坑是:一个 SQL 查询工具返回了整表数据,直接把后续推理逼疯,模型开始幻觉编造不存在的字段。裁剪之后,这个问题就再没出现过。
另一个逃生通道是给 Agent 加一个“上下文溢出自检”步骤。每次组装 prompt 之前,让运行时统计 token 数,超过阈值时自动触发一次上文压缩再继续。这个操作可以在 Harness 层用代码实现,而不是把希望寄托在模型自身的判断上。后面第四章会再说 Harness 在整个链路里应该承担哪些脏活。
3. Skills:把经验固化成可复用的技能
3.1 Skills 与 Tools 的区别:工具是无状态的,技能是有流程的
我在做 Agent 时经常被问到:Skills 和 Tools 到底有什么区别?功能上确实有重叠,但架构理念很不一样。Tools 是无状态的原子操作,比如“查询订单号对应的订单状态”,输入一个 ID,返回一段 JSON,它自己不会判断什么时候该被调用。Skills 则是一个完整的“经验包”,它通常包含一段自然语言说明书、一批脚本、以及模型可以参考的调用流程;它回答的是“在什么场景下、按什么顺序、做哪些事才能解决一类问题”。
打个比方,Tools 是一把螺丝刀,Skills 是一本带图纸和检查单的装配手册。螺丝刀能拧螺丝,但你不知道什么时候用哪种型号、拧到什么扭矩、拧完怎么验证;装配手册会告诉你完整的流程。在 Agent 场景里,Skills 的价值在于把“经验”从人脑转移到系统里:前端开发的团队可以沉淀一个“前端开发 skills”,里面包含项目结构规范、代码风格检查命令、测试流程、常见报错的修复步骤;客服团队可以沉淀一个“售后处理 skills”,里面包含查单、判责、赔付模板等一系列操作流程。
为什么要强调有流程?因为大模型单独调用工具的准确率现在不算低,但它不会自动组织成一套多步骤流程。比如处理退货,模型可能会先查订单再问用户要凭证,但如果 Skill 里明确写了“先鉴权再查单再判责再生成回复模板”这个顺序,模型的成功率会显著提升。这本质上是在用工程手段弥补模型在长程规划上的不足。
3.2 一个 Skill 的标准结构:像写说明书一样写技能
以目前越来越多的 Agent 框架采用的格式为例,一个 Skill 通常长这样:
my-skill/ ├── SKILL.md ├── scripts/ │ ├── check_env.py │ └── run_debug.py └── assets/ └── templates/
SKILL.md 是这个技能的核心入口,我一般会保证它包含四块内容:功能描述(这个技能解决什么问题)、触发条件(什么情况下模型应该调用它)、操作步骤(1、2、3 可执行步骤,明确每一步的输入输出)、风险提示(哪些操作不能做,做了会有什么后果)。
--- name: frontend_debug description: 定位并修复前端页面样式与交互问题 when_to_use: 用户反馈页面错位、点击无响应、控制台报错时 version: 1.2.0 --- # 前端调试技能 ## 操作步骤 1. 在项目根目录执行 `yarn dev` 启动本地环境 2. 打开浏览器 DevTools,检查 Console 报错并截图关键堆栈 3. 修改源码后执行 `yarn lint && yarn test` 验证 4. 提交修改并附上修复说明 ## 风险提示 - 禁止直接修改 `node_modules` 下的文件 - 禁止在没有测试覆盖的情况下提交大规模重构这段元信息特别关键:模型看到when_to_use就能自行判断是否加载这个 Skill,而不是把几百个 Skill 全部塞进上下文。这就是“按需加载”的思路——Skill 本身存在磁盘或仓库里,平时不占 token,只有模型判断命中触发条件时才被注入。
3.3 Skills 的发现、测试与版本更新:技能也需要生命周期管理
Skill 的编写只是开始,真正的工程挑战在它的生命周期管理上。我见过太多团队花一星期写了十几个 Skill,结果一个月后全部失效,因为底层接口变了、依赖库升级了、或者业务流程调整了。这里分享三个我踩过坑后沉淀下来的做法:
第一,Skill 测试必须是自动化的。我在 CI 里会为每个 Skill 准备一组“测试用例”,每条用例是一个模拟用户请求,记录 Skill 执行前后的系统状态变化。Skill 改动后自动跑一遍用例集,核心指标是任务完成率(而不是模型回复的文本相似度)。一个 Skill 如果改了之后完成率下降 5%,就该拦下来看看是不是回归了。
第二个坑是 Skill 之间互相冲突。两个技能可能都对同一个问题给出不同流程,最后模型随机选了一个,结果不符合业务规范。解决方案是给 Skill 加上明确的conflict_policy和优先级字段,并在触发匹配阶段就做好路由决策,而不是把决策权完全交给模型自己。
第三是关于版本更新。Skill 的更新要遵循语义化版本:大版本号变化意味着行为不兼容(比如流程重构),小版本号变化意味着向后兼容的改进。旧版本不能立刻删除,我一般保留最近两个版本,因为线上 Agent 可能正在按旧 Skill 执行任务到一半,突然切换新版本会导致上下文撕裂。Skill 仓库里有新旧版本的同时,Harness 需要在会话开始时就锁定技能版本,会话中途不切换。
4. Harness:包住 Agent 的工程外壳
4.1 Harness 与 Agent 的区别:模型只负责思考,Harness 负责一切
Harness 这个词经常被误读成“另一个 Agent 框架”,其实它的含义比框架更具体。Agent 指的是“模型 + 工具调用 + 记忆 + 推理的决策核心”,而 Harness 是包在决策核心外面的整套工程运行时——安全边界、工具执行环境、状态管理、审计日志、错误恢复、生命周期控制,都属于 Harness 的职责范围。
我的同事常打一个比方:模型是发动机,Agent 是发动机带的一套动力系统,Harness 是整车。你不会只造发动机就上路,你得考虑刹车、油箱、仪表盘、外壳防撞。在 Agent 生产环境里,Harness 就是要解决这些问题:模型调一个工具,这个工具代码跑在哪里?它能不能访问文件系统?它执行失败怎么办?它超时了怎么终止?它每一步的结果能不能被完整审计?
比如前几年很火的基于 Rust 语言做 AI Agent,很多人冲着性能去,但真正用下来发现 Rust 的价值不是快,而是它天然适合写 Harness:类型系统能定义严格的工具协议,所有权机制能控制资源生命周期,编译行为能尽早暴露错误。我在实验项目里用过 Rust 搭过一个轻量 Harness,一个 main loop 管状态机,一个 trait 定义工具接口,还有一个后台线程管任务队列,整体内存占用很小,部署到低配机器上跑也比 Python 方案稳很多。不过 Rust 的生态相比 Python 还浅一些,日常业务我依然推荐 Python 生态的成熟方案,Rust 适合做对资源敏感的核心 Harness。
4.2 Harness 的关键模块:沙箱、权限、审计、恢复
一个合格的 Harness,至少要具备四块能力。第一块是沙箱隔离:所有工具调用都应该跑在受限环境里,容器级别的隔离是最低要求。这里的原因不需要多解释,模型有可能被提示注入,也可能自己走偏去执行危险命令;沙箱不是限制模型,而是保护你的生产环境。
第二块是权限控制。我给 Agent 设计了一套“最小权限 + 逐次确认”的机制:每个工具都有独立的权限定义(读哪些目录、写哪些接口、能不能发邮件、能不能删数据),默认全是拒绝。需要用到高权限工具时,Harness 抛出审批请求,由人工确认后才放行。这里要特别注意:权限控制必须在 Harness 层实现,不能让它变成模型上下文里的“系统提示词约定”,因为提示词只是建议,代码才是约束。
第三块是审计。我会让 Harness 记录每一次工具调用的完整轨迹:输入、输出、耗时、token 消耗、决策依据,统一输出成结构化日志。这些审计数据既用来排查问题,也用来评估记忆系统和 Skill 的长期质量。第四块是恢复。任务执行到一半挂了,Harness 需要能记录 checkpoint,让 Agent 从断点恢复到比较干净的状态重新执行,而不是从头开始。这三块缺一不可,缺了任何一个,你的 Agent 就只配叫“demo”。
4.3 私有化部署 Harness 的实战经验:离线环境也能跑起来
不少团队因为数据合规原因必须在内网部署整套 Agent 系统,这就涉及 Harness 的私有化落地。我踩过的坑不少,挑三个最典型的说一下。第一个是模型底座的问题:内网部署意味着不能调用公有云 API,只能跑本地模型,一般用 Ollama 或者 vLLM 拉起本地推理服务,再让 Harness 通过 OpenAI 兼容接口对接。这一步相对顺利,真正的坑在模型质量:小参数模型在复杂工具调用上经常偏离 schema,Harness 需要增加一层“结构化输出校验与重试”机制,否则模型输出不合法 JSON 时整个任务直接断掉。
第二个坑是组件镜像和依赖的离线安装。内网环境访问不了公共仓库,所有依赖必须在有网环境先打包好。我的建议是建立一套离线制品仓库:pypi 包、npm 包、Docker 镜像、模型权重文件统一管理,用 artifactory 或 nexus 做本地镜像源。这个过程很脏很累,但绕不开。
第三个是向量库和 embedding 模型也要内网化。线上用开源向量库问题不大,真正头疼的是 embedding 模型:如果从有网环境导出的向量和离线环境的 embedding 模型不一致,旧记忆的向量就全部失效。所以离线环境部署时,除了 agent 本身的 harness,还要把 embedding 服务一并部署在同一个 environment 里,并且训练记忆之前就要先统一 embedding 模型版本。这里建议在 Harness 里加一个启动自检:加载记忆库时核对 embedding 模型指纹,不一致直接拒绝启动,别等检索出错再来查。
5. 记忆、上下文、Skills 如何协同:一次完整的“调用-更新”闭环
5.1 一次任务里的经验流水线:从输入到经验沉淀需要几步
现在把前三章的内容串成一条完整的流水线。一次典型的任务处理流程大概是这样:
- 用户请求进入 Harness,Harness 先做意图识别和上下文组装;
- 运行时根据请求内容触发 Skills 匹配,把可能相关的 1~2 个 Skill 的 SKILL.md 注入工作记忆;
- 同时从长期记忆里检索相关的历史记录(情景记忆优先、语义记忆兜底),检索结果经过 rerank 后只保留 top-5 进上下文;
- Agent 开始推理,按 Skill 的操作步骤依次调用 Tools,每一步工具返回结果先经过裁剪再写回上下文;
- 任务结束后,Harness 把这次交互的关键信息写入短期记忆区;
- 后台巩固任务对短期记忆做清洗和去重,把有价值的经验“写入”长期记忆,把失败的教训标记为负样本;
- 如果本次任务暴露了现有 Skill 的缺陷,系统生成一条“Skill 改进建议”,供开发者 review 后更新 Skill 版本。
这套流水线的核心设计思路是:每一步都在做“相关性过滤”。不是所有数据都需要进入上下文,也不是所有交互都需要进入长期记忆。你把这条流水线画成数据流图,会发现它的瓶颈永远是第 3 步的检索质量;检索做得好,后续步骤顺理成章;检索噪声大,再强的 Harness 也是白搭。
5.2 记忆污染与“创伤记忆”:怎么防止坏经验被固化
记忆系统有一个在真实项目里非常致命、但论文里很少展开的问题:坏经验被固化。人类心理学里有一种说法叫创伤记忆,指极度负面的经历会被牢牢记住,甚至影响后续所有决策。Agent 也有类似现象——一次明显的失败如果被不加甄别地写入长期记忆,模型之后每次碰到相似场景都会调用这段失败经验,做出保守甚至错误的决策。
我在一个客服 Agent 项目里真实遇见过:有一次因为第三方支付接口临时故障,Agent 在退款流程中反复失败,失败记录被写入记忆库里。恢复之后半个月,Agent 只要遇到退款请求,就会先输出“可能无法处理退款”的预警话术,把正常用户也吓到了。根本原因就是记忆写入环节没有做“成功/失败标注”。
解决办法是:记忆不是一块白板,谁都能随便写字。写入长期记忆之前,Harness 必须判断这条经验的“可信度”。我的做法是引入一个评价层:任务成功完成的记录,标记为 positive 经验并提高置信度;任务失败或被用户纠正的记录,标记为 negative 样本,不在主检索链路里直接返回,只作为调试材料;需要被保留但置信度不高的记录,降为“候补经验”,只有没有 high-confidence 记忆命中时才会被调用。这有点类似给记忆加权重,而不是给它盖章定论。
还有一个常见的污染来源是提示注入:外部数据里夹带的恶意指令如果被模型当成了经验写入记忆,之后每次任务都会被它干扰。所以我的底线是:任何来自工具返回内容、网页抓取内容的外部信息,都不得直接进入长期记忆,必须先经过 Harness 的字段校验和过滤,再决定要不要写入。这条规则宁可严格,也不能放宽。
5.3 跨环境迁移 Agent 经验的实操方案:换账号、换机器怎么搬记忆
搜索结果里好几个人问:WorkBuddy 换账号之后,怎么把原来的记忆带过去?还有问一台电脑上的记忆配置怎么迁移到另一台电脑。这其实是所有把记忆存在本地的 Agent 应用都会遇到的问题,而且解决方案是通用的:记忆本质上是文件,迁移记忆就是迁移文件和保证环境一致。
首先,找到记忆存储位置。大多数本地 Agent 应用会把记忆文件放在用户目录下的隐藏文件夹里,一般包含三类内容:一是文本类记忆文件(JSON、Markdown,存用户偏好、任务经验等结构化记录),二是向量索引文件(把文本切片向量化之后保存的本地索引),三是配置文件(记录 embedding 模型、召回参数、Skill 启停状态等)。
迁移的时候,第一步是完整复制这三个部分到新机器/新账号的对应目录,注意路径结构不能变。第二步是确认 embedding 模型一致。这一步最容易翻车:如果你原来用的是 A 模型的向量,新环境换成了 B 模型,那么向量索引根本没法用,因为两个模型的向量空间不兼容。遇到这种情况就只能重新生成向量索引,把原始文本文件重新切块、重新 embedding。第三步是导入后做一次自检:随意问一个旧记忆里明确记录过的偏好,看 Agent 能否正确召回。召回失败优先检查向量库版本和 embedding 模型,而不是怀疑记忆文件没拷全。
如果是换账号,还要注意账号体系里可能包含权限相关配置,比如某些 Skill 只对特定账号开放;跨环境迁移后权限可能丢失,需要在 Harness 管理界面重新授权。我建议在迁移时先把记忆库导出成一个“迁移包”(记忆文件 + 版本指纹 + 权限清单),到新环境再整体导入,替代零散拷贝。这样漏东西的概率小很多,也方便审计。
6. 常见问题与排查技巧实录
6.1 上下文超长、性能劣化、上下文挤爆怎么办
症状通常是调用延迟莫名升高,或者 Agent 回复质量突然变差,甚至直接报错超出 token 限制。排查第一步不是改代码,而是把最近一次调用的 token 明细拉出来看:哪些内容占了最多 token。八成情况是工具返回结果没裁剪,或者某个批次把整批历史对话塞了进去。
我分享一个通用处理流程:先在 Harness 里加 prompt 组装日志,输出每个模块的 token 占用;超过窗口 70% 时自动触发“紧急压缩”;压缩动作优先级是:先丢低优先级示例、再压缩工具返回结果、再摘要历史对话、最后才截断用户原始输入。如果压缩之后仍然超限,应该拒绝执行任务并明确告诉用户原因,不要让模型硬跑导致幻觉。
另外很多人会忽略“输出 token 预留”。上下文窗口是输入输出共用的,我一般给输出预留至少 20% 的空间,否则模型会中途截断。如果你用的是流式输出,预留不够还会出现回复到一半就停的问题。
6.2 Skill 加载失败、测试不过、调用错误
Skill 加载失败最常见的原因是路径错误或格式不规范。SKILL.md 的 frontmatter 里字段名写错了、when_to_use写的触发条件太宽泛,都会导致模型在错误的时候加载它,或者在正确的时候不加载它。排查技巧是:在 Harness 里加一个“Skill 路由日志”,打印每次请求后匹配到的 Skill 列表和置信度分数,一眼就能看出是不是触发条件定义出了问题。
测试方面常见的问题是断言写得太死,比如直接对比模型输出文本是否包含某个关键词。正确做法是断言“任务完成后系统状态是否达到预期”,比如测试一个订单查询 Skill,应该断言“是否成功调用了订单接口 + 返回数据是否被正确传递”,而不是“回复里有没有出现订单号这几个字”。
还有一个容易踩的坑是 Skill 内部脚本的依赖缺失。脚本是在 Harness 的沙箱环境里跑的,沙箱环境不一定有全局的 node_modules 或 Python 包。我建议每个 Skill 自带依赖清单,Harness 在做沙箱镜像时统一预装好,并在 Skill 加载时做一次环境自检。
6.3 Harness 部署与运行时的坑:镜像、网络、权限
内网部署 Harness 时,除了前面提过的模型和依赖离线化问题,还有几个值得注意的点。第一是代理和网络策略:Agent 运行时要访问内网多个服务,网络策略要提前梳理清楚,尤其是工具回调地址和向量库地址,别在部署阶段才发现防火墙挡了关键端口。
第二是沙箱镜像的构建时机。沙箱镜像应该在开发阶段就按生产环境标准构建,而不是等部署时再现场装依赖。现场装依赖在无外网环境就是死路一条。我现在的做法是:开发环境用 Docker Compose 起整套 Harness,所有容器镜像统一 push 到内网镜像仓库,生产环境只做 docker pull。
第三是内存和 GPU 资源的分配。本地模型推理非常吃资源,Harness 自身也有开销,如果和模型推理挤在同一台机器上,容易出现 OOM。我的建议是 Harness 和模型服务分容器部署,资源配额分开设置,Harness 本身一般来说 2~4GB 内存就够,模型服务按模型参数量单独规划。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 回复质量突然下降 | 记忆库噪声过大 / 上下文超长 | 查看 token 明细,检查召回 top-k 质量 |
| 上下文超限 | 工具返回未裁剪 / 历史全量注入 | 抽查 prompt 组装日志,定位大头模块 |
| Skill 不触发 | 触发条件过窄 / frontmatter 格式错了 | 查看 Skill 路由日志与置信度分数 |
| Skill 触发但报错 | 沙箱缺依赖 / 权限未授权 | 在沙箱内跑一遍环境自检脚本 |
| 记忆召回失败 | embedding 模型版本不一致 | 核对向量库版本指纹,重新生成索引 |
| Agent 突然变得“胆小” | 负样本被当成正向记忆检索 | 检查记忆写入标注,区分 positive/negative |
| 内网镜像拉取失败 | 镜像未同步到内网仓库 | 统一走内网镜像源,禁止现场 build |
多说一句关于观测和复盘的事:很多团队把 Agent 上线就当终点,其实上线才是记忆系统和 Skill 系统开始“进化”的起点。你在生产环境里跑出来的问题、用户纠正过的话、模型反复出错的场景,这些才是记忆系统最宝贵的素材。我的个人习惯是每周固定抽 20 条记忆库新增记录,人工看一眼:哪些是在帮 Agent 变强,哪些在制造垃圾。这套“人工 review 记忆”的环节看着土,但它是我信心的最大来源。自动化的检索和召回再强,也替代不了人来判断经验本身的对错。做 Agent 越久,我越觉得记忆系统才是一个 Agent 真正的灵魂,Skills 和 Harness 只是让这个灵魂能安全地跑起来。今天分享的这些方案不一定适合所有团队,但围绕“保存、调用、更新”这三个动作来设计你的记忆体系,方向永远不会错。