我先描述一个场景,做 AI Agent 的人大概率都遇见过:对话刚到第 8 轮,Agent 开始重复问你早就答过的需求;到第 15 轮,它把你开场定的目标忘干净;第 30 轮,上下文窗口顶满,你不得不截断历史,或者花大把 token 让它把前面的内容重新压缩成摘要。我管这个叫“上下文自残”:不是模型笨,是架构把数据库该干的活,硬塞给了上下文。解决思路其实很直接——上下文只放当前这一轮需要的东西,其他的全部落进数据库,等要用的时候再按需查回来。下面直接把我从 SQLite 到向量检索摸出来的那套记忆层方案摊开讲,适合正在做 AI Agent、RAG 应用,或者被长对话搞到头大的开发者和产品负责人。
1. 健忘症的病根:上下文窗口从来就不是“记忆”
1.1 模型是无状态计算器,不是有记忆的大脑
很多人在 Agent 健忘时第一反应是“换个上下文更长的模型”,或者“再调一调 prompt”。但我建议先认清一个底层事实:大模型本身是没有状态的。每次 API 调用都是一次全新的独立计算,所谓“对话连续”,其实是 Agent 框架把历史消息原封不动地塞进新的请求里,让模型自己“看到”之前说过什么。
也就是说,模型不是忘了,是每次请求都被迫重新读一遍历史。这里的“历史”一旦超过模型的上下文窗口,框架只能做三件事:截断、压缩、或者直接报错。很多 Agent 框架里提到的“执行上下文”,本质就是当前请求中模型可见的文本快照,不是一个可以随取随用的长期空间。快照注定会过期,放在快照里的“记忆”自然也保不住。
如果你做过稍微复杂的 Agent,应该已经发现:长对话跑得越久,模型越容易把早期信息搞丢。那不是幻觉,那是上下文被截断之后的必然结果。我甚至见过一个项目,用户第一轮明确说了“最终交付物要用 PostgreSQL”,结果 20 轮之后 Agent 用 MySQL 写了一整套建表 SQL。用户以为模型“疯了”,其实是前面那行约束早被挤出窗口了。
1.2 上下文自残的三种常见姿势
在真实项目里,上下文被“自残”大致有三种姿势。
第一种是硬截断。框架按 token 上限,把最早的历史消息直接丢掉。这种方式实现最简单,但代价也最直接:最早的消息往往是用户目标、项目约束、决策记录这些锚点信息,丢掉之后 Agent 就会开始自由发挥。
第二种是摘要压缩。把多轮对话交给模型总结成几句话,然后只保留摘要。这看起来聪明,但摘要本身就是有损压缩,里面的细节、数字、边界条件很容易丢。更麻烦的是,如果每次满了都压缩一次,压缩出来的摘要又会在下一次被继续压缩,错误和遗漏会逐层累积。
第三种是无限重放。也就是不压缩也不截断,每次把全部历史都塞进 prompt,直到窗口爆炸。这种方式在小 demo 里能跑,但一旦对话轮次变多,token 成本会涨到让人肉疼,请求延迟也会明显上升。
这三种姿势的共同问题在于:我们让上下文同时承担了“工作台”和“仓库”两个角色。工作台需要快速操作,仓库需要海量存储,硬把仓库里的所有东西都堆到工作台上,自然放不下。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 把提示词当存储,等于用便签纸记全家账
2.1 为什么 token 成本会失控
先算一笔账。假设上一轮对话历史有 8000 token,下一轮模型生成回复时,需要把 8000 token 的历史全部重新读一遍。这还不是最可怕的,最可怕的是每多一轮,历史就越长,模型每生成一个字都要面对越来越长的上下文。
第 3 轮可能是 24000 token 的重复阅读,到第 10 轮累计就是接近 100000 token 的重复阅读。这个成本不是线性增长,而是接近 O(n²) 的累积。再加上 Agent 场景里的函数调用、工具返回结果、检索结果注入,上下文用量会比你想象中更快触顶。
所以你会看到很多“上下文用量满了怎么办”的问题。不管是用 Cursor 的压缩上下文命令,还是在 Claude Desktop 里调整上下文压缩设置,甚至用 workbuddy 问上下文用量满了怎么处理,本质上都是在同一个困境里打转:我们用上下文承载了太
