短期记忆就是 LLM 的上下文窗口——它既是 Agent 「当下能看见什么」的全部,也是最容易爆掉的那个容器。ReAct 轨迹越积越长、用户对话越来越久、工具返回越来越大,全都压在这个有限的窗口里。怎么管好它,是 Agent 工程最日常也最关键的活。
短期记忆的本质,是一次 LLM 调用所能「看见」的全部文本。它有以下特征:
| 特征 | 含义 |
|---|---|
| 有限 | 受 Token 上限约束(几 K 到几百 K) |
| 易失 | 调用结束即消失,下次重新拼装 |
| 显式 | 所有内容必须显式拼进 Prompt |
| 昂贵 | Token 数与成本、延迟成正比 |
把短期记忆比作「工作台」最贴切:上面能摆的东西有限,摆太多会乱、会找不到重点,每干完一次活儿(一次调用)就要清空重摆。
💡 短期记忆不是免费的:每多放一个 Token,每次调用都要多付一次钱、多花一次推理时间。「拼 Prompt」是 Agent 最容易烧钱的地方——一个不优化的 Agent,可能把 80% 的 Token 预算花在重复搬运历史上。
LLM 的上下文窗口有硬上限。常见模型窗口:
| 模型类型 | 典型窗口 |
|---|---|
| 早期 LLM | 4K-8K |
| 主流 LLM(2024) | 32K-128K |
| 长上下文 LLM | 200K-1M+ |
窗口虽大,但**「能装」不等于「该装」**。原因有三:
| 不该装满的理由 | 后果 |
|---|---|
| 成本 | Token 多 = 钱多 |
| 延迟 | 长 Prompt 推理慢 |
| 注意力稀释 | 上下文越长,LLM 越抓不住重点 |
<svg viewBox="0 0 720 320" xmlns="http://www.w3.org/2000/svg"> <line x1="60" y1="280" x2="680" y2="280" stroke="#475569" stroke-width="2"/> <line x1="60" y1="40" x2="60" y2="280" stroke="#475569" stroke-width="2"/> <text x="680" y="300" font-size="12" fill="#475569" text-anchor="end">上下文长度 →</text> <!-- 成本(线性上升) --> <line x1="80" y1="260" x2="640" y2="80" stroke="#db2777" stroke-width="2"/> <text x="650" y="80" font-size="11" fill="#db2777">成本(线性)</text> <!-- 延迟(线性上升) --> <line x1="80" y1="270" x2="640" y2="120" stroke="#ca8a04" stroke-width="2"/> <text x="650" y="120" font-size="11" fill="#ca8a04">延迟(线性)</text> <!-- 注意力质量(倒 U) --> <path d="M 80 220 Q 200 80 360 80 T 640 240" stroke="#2563eb" stroke-width="2" fill="none"/> <text x="650" y="240" font-size="11" fill="#2563eb">注意力质量(倒 U)</text> <text x="360" y="30" font-size="13" fill="#475569" text-anchor="middle" font-weight="bold">上下文长度的三重代价</text> </svg>
注意力质量是倒 U 形——太短信息不足,太长注意力被稀释。最优长度不是「装满」,而是「刚好够」。
最简单的压缩——只保留最近 N 步,丢弃更早的。
全轨迹: [S1, S2, S3, S4, S5, S6, S7, S8, S9] 窗口=5: 实际送进 Prompt = [S5, S6, S7, S8, S9]
当前 Prompt: [System: 你是财务助手] ← Profile [User: 帮我分析 AAPL] ← 原始任务 (在 S1, 被丢了!) [Step 5-9 的轨迹] ← 最近 5 步 → Agent 忘了在分析 AAPL!
问题:简单滑动窗口会丢失任务目标——而目标通常在最早的第一步。
保留 = [Goal(开头)] + [最近 N 步(结尾)] 丢弃 = 中间的旧步骤 实际送进 Prompt: [System: 你是财务助手] [Goal: 帮我分析 AAPL] ← 保头 [Step 7, 8, 9] ← 保尾
| 变体 | 做法 |
|---|---|
| 简单窗口 | 最近 N 步 |
| 保头保尾 | Goal + 最近 N 步 |
| 加权窗口 | 最近步全保,旧步摘要保 |
⚠️ 滑动窗口的最大风险是丢目标。生产实践几乎都用「保头保尾」或更复杂的加权方案,绝不用简单窗口——简单窗口迟早让 Agent 忘了自己在干什么。
定期让 LLM 把旧轨迹压缩成一段摘要,替换原始轨迹。
| 粒度 | 做法 | 信息损失 |
|---|---|---|
| 完整摘要 | 把每步 Thought/Action/Observation 都概括 | 低 |
| 结论摘要 | 只保留每步的结论(数字、事实) | 中 |
| 任务级摘要 | 整段轨迹压成「已完成了什么」 | 高 |
[原始轨迹 Step 1-5] Thought 1: 查苹果营收 Action 1: search("Apple revenue 2024") Observation 1: $391B Thought 2: 查 2023 对比 Action 2: search("Apple revenue 2023") Observation 2: $383B Thought 3: 计算增长率 Action 3: calculate("...") Observation 3: 2.0% [摘要] "已查询: 苹果 2024 营收 $391B、2023 营收 $383B; 增长率 2.0%。"
原始约 200 Token,摘要约 30 Token,压缩比约 7:1。
💡 摘要的代价:摘要本身要花一次 LLM 调用。触发时机很关键——太频繁(每步摘要)成本高,太稀疏(最后才摘)窗口已爆。生产实践通常「每 K 步触发一次」(K 通常 3-5)。
| 失败 | 表现 | 对策 |
|---|---|---|
| 漏关键信息 | 摘要丢了关键数字 | 关键事实外存 |
| 摘要错误 | LLM 摘错了 | 摘要后做校验 |
| 递归失真 | 摘要的摘要越来越偏 | 保留原始 Goal 不参与摘要 |
摘要压缩是「语义级」压缩——靠 LLM 理解后重写。还有一类「Token 级」硬压缩——不改变语义,直接压缩 Token。
代表工作是 LLMLingua:用小模型评估每个 Token 的「重要性」,删除低重要性的 Token。
原始: "我想要查询苹果公司在 2024 年的财务年度的总营收数据" 压缩: "查询苹果 2024 财年总营收"
| 压缩方式 | 压缩比 | 语义损失 | 适用 |
|---|---|---|---|
| 语义压缩(摘要) | 5-10:1 | 中(需 LLM) | 长历史 |
| Token 级压缩(LLMLingua) | 2-5:1 | 低 | 紧 Prompt |
| 组合 | 10-20:1 | 中 | 大型 Agent |
⚠️ 硬压缩的局限:Token 级压缩对短而精的 Prompt 效果有限(本来就没多少冗余);对长而冗余的 Prompt(如重复历史、啰嗦描述)效果显著。生产中常与摘要组合使用。
把轨迹里的关键事实抽出来单独存(如存到 Memory 的「事实区」),轨迹本身只留指针。
[事实区] - 苹果 2024 营收: $391B (来自 Step 2) - 苹果 2023 营收: $383B (来自 Step 4) - 增长率: 2.0% (来自 Step 6) [轨迹区 - 精简] - Step 1-2: 查 2024 营收 (见事实区) - Step 3-4: 查 2023 营收 (见事实区) - Step 5-6: 计算增长率 (见事实区)
| 做法 | 内容 |
|---|---|
| 数值 | 所有数字、日期、金额 |
| 命名实体 | 人名、公司名、地名 |
| 决策 | 「选了 A 而非 B」 |
| 错误 | 失败的尝试与原因 |
生产实践通常组合多种策略:
| 层 | 作用 |
|---|---|
| Goal 抽出 | 保证不丢目标 |
| 关键事实外存 | 保证关键数据可查 |
| 旧轨迹摘要 | 压缩历史 |
| 滑动窗口 | 保留近期细节 |
这四层组合,能在绝大多数场景下平衡「保留关键信息」与「控制窗口长度」。
| 反模式 | 表现 | 后果 | 正确做法 |
|---|---|---|---|
| 全量历史 | 每轮拼全部轨迹 | 窗口爆炸+贵 | 分层压缩 |
| 简单窗口 | 只留最近 N 步 | 丢目标 | 保头保尾 |
| 每步摘要 | 摘太频繁 | 摘要本身烧钱 | 每 K 步触发 |
| Goal 也摘要 | Goal 被压缩失真 | Agent 失方向 | Goal 不参与摘要 |
| 不抽事实 | 关键数字随轨迹丢 | 重新查一遍 | 关键事实外存 |
| 过长 System Prompt | Profile 写太长 | 每次都付长 Prompt 钱 | Profile 精简 + 分层 |
💡 上下文管理是 Agent 工程的「隐性成本中心」。它不显眼,却决定了 Agent 的运行成本上限。一个不优化的 Agent,可能比优化过的贵 5-10 倍——多出来的钱几乎都花在重复搬运历史上。生产 Agent 上线前,必须做一次上下文预算审计:每轮平均多少 Token、瓶颈在哪、能压多少。
下一节《5.2 长期记忆与向量数据库》将讨论跨会话的持久化记忆——Embedding、向量库选型、写入策略。