智能体记忆管理与上下文压缩详解

前言

如果你用过AI编程助手,一定遇到过这样的场景:Agent吭哧吭哧改了半小时代码,修了好几个Bug,结果聊到后面它突然问:"话说,你一开始到底让我干什么来着?“更气人的是,因为Context太长、Token开销爆炸,之前处理的信息被无情丢弃,Agent瞬间"失忆”。

这不是某个模型的问题,而是所有依赖LLM(大语言模型)的AI Agent系统必须面对的上下文天花板。与Agent的每一次互动——无论是用户的新指令,还是它调用工具得到的结果,都会塞进同一个上下文中,导致其无限膨胀。

因此,Context Engineering(上下文工程)应运而生。如果说Prompt Engineering解决的是"怎么跟模型说话",那Context Engineering解决的则是"给模型看什么、怎么看"。

一、AI Agent的"记忆负担"从何而来?

1.1 上下文膨胀公式

为了更精确地理解这个问题,我们不妨先看一个简单的数学表示。

假设 xtx_txt 是第 ttt 轮的用户输入(或外部工具返回的信息),yty_tyt 是语言模型在第 ttt 轮产生的输出,而 CtC_tCt 代表到第 ttt 轮时累积的上下文历史。那么在第 t+1t+1t+1 轮,最直接的做法是:

Ct+1=Ct∪{xt+1}∪{yt}C_{t+1} = C_t \cup \{x_{t+1}\} \cup \{y_t\}Ct+1=Ct{xt+1}{yt}

也就是说,每一轮交互都意味着把新输入和模型输出追加到已有上下文中。在初始阶段,C0=∅C_0 = \emptysetC0=。随着 ttt 不断增大,CtC_tCt 的大小理论上会无限增长。当Token数量攀升到数万甚至数十万时,每次推理都要让模型"通读"全部历史——这不仅是计算资源的灾难,也是模型性能的灾难。

1.2 为什么不能放任不管?

把过长的上下文直接塞给模型,会产生至少三个层面的问题:

问题 描述
成本失控 Token就是钱。按API定价计算,一个十万Token的上下文每次交互都要重新处理全部历史,费用会随对话轮次指数级攀升。
性能衰减 LLM在超长上下文中的注意力会逐渐分散。研究表明,当上下文超过一定长度后,模型对中间位置信息的回忆准确率显著下降。
效率下降 更长的上下文意味着更长的首Token延迟,用户体验从"实时响应"变成"等待加载"。

因此,我们需要一套系统化的方法——Context Engineering的核心行为可以用一个函数 fff 来概括:

Ct+1=f(Ct,xt+1,yt)C_{t+1} = f(C_t, x_{t+1}, y_t)Ct+1=f(Ct,xt+1,yt)

这个 fff 不是简单地"全盘追加",而是一系列加工手段的集合:可能包括裁剪、摘要、替换、外部存储等策略。

二、记忆管理架构:短期 vs 长期

2.1 记忆类型三分法

LangChain的记忆实现参考了COALA论文的记忆分类学,将智能体记忆分为三大类:

记忆类型 描述 用途 实现方式
短期记忆(Short-term) 会话历史,仅在单次对话中有效 跟踪当前任务进度、对话上下文 内存中的状态、会话历史
长期记忆(Long-term) 跨会话持久化的知识 存储用户偏好、累积知识、研究进展 文件系统、数据库
程序性记忆(Procedural) 规则、技能、指令 指导Agent如何执行任务 Skills文件、策略文件

2.2 Deep Agents的四层记忆模型

Deep Agents是LangChain 2026年推出的下一代智能体框架,它的记忆管理非常有特点:

  1. 线程级记忆(Thread-scoped):默认情况下,记忆只在同一个线程内有效,切换线程后记忆会丢失。
  2. Agent级记忆:跨用户共享,让Agent逐步建立自己的身份、知识和偏好。
  3. 用户级记忆:每个用户隔离的记忆空间。
  4. 组织级记忆:整个组织共享的只读记忆(策略、最佳实践等)。

2.3 实现:文件系统抽象

Deep Agents的一个核心设计是"把记忆当文件"——所有的记忆都通过文件系统来管理。这有几个重要的好处:

  • 简单性:LLM天生就懂文件系统操作,不需要学习新的工具。
  • 可移植性:可以轻松切换底层存储(本地文件系统、Postgres、S3等)。
  • 透明度:人可以直接阅读和编辑记忆文件。
from deepagents import create_deep_agent
from deepagents.backends.filesystem import FilesystemBackend

agent = create_deep_agent(
    memory=["~/.deepagents/AGENTS.md"],  # 记忆文件
    skills=["/skills/user/"],           # 技能文件
    backend=FilesystemBackend(root_dir="/", virtual_mode=True),
)

三、上下文压缩策略详解

Context Engineering有四大策略:Write(持久化)、Select(检索)、Compress(压缩)、Isolate(隔离)。我们重点来看压缩策略。

3.1 策略一:LLM摘要(Summary)

核心做法:当上下文超出预设阈值时,调用语言模型对历史对话进行摘要,用结构化的总结替换掉冗长的原始消息记录。

优点

  • 信息密度高:模型能提炼出对话中的关键意图、已完成的任务、下一步计划等核心要素。
  • 语义压缩而非机械截断:相比简单地从头部删除旧消息,摘要保留了语义连贯性。

缺点

  • 额外开销:摘要本身也需要一次LLM调用,消耗额外的Token。
  • 信息丢失风险:摘要过程中无法避免细节的损失。如果模型把某句关键的参数配置"归纳"掉了,后续任务就可能出错。

Deep Agents的实现

当上下文超过模型窗口的85%时,Deep Agents会:

  1. 调用LLM生成结构化的摘要(包含会话意图、已创建的产物、下一步计划)
  2. 用摘要替换工作内存中的完整对话历史
  3. 同时把原始完整消息写入文件系统作为记录
# 摘要提示词示例(简化版)
system_prompt = """请生成这段对话的摘要,包含以下信息:
1. 当前会话的目标和意图
2. 已完成的工作和创建的文件
3. 下一步计划
4. 重要的约束条件和决定

用简洁、结构化的方式表达。"""

3.2 策略二:观察屏蔽(Observation Masking)

核心做法:将工具调用返回的大量输出内容(如读取的文件全文、Shell命令结果、API响应等)替换成一个简短的占位标记,例如 [这里曾经有工具输出,如需查看请检索]。

在具体实现中,Observation Masking通常遵循一个简单的逻辑:将完整输出存入外部存储,分配唯一ID,然后在上下文中替换为 [Obs:{ref_id} elided] 这样的模板。

为什么这招管用?

因为在Agent的轨迹中,工具输出往往是最"膨胀"的部分——实测数据显示,工具输出通常占上下文的70%以上,而真正需要在后续步骤中参考的往往只是其中很小的一部分。

Deep Agents的两种卸载策略

卸载类型 触发时机 内容 阈值
大工具结果卸载 每次工具调用后 大工具响应内容 >20,000 tokens
大工具输入卸载 上下文超阈值时 旧的写入/编辑参数 上下文85%阈值

示例:

原始:
├─ User: 读取 /src/config.py
├─ Assistant: [调用 read_file]
└─ Tool: [3000行代码内容]

卸载后:
├─ User: 读取 /src/config.py
├─ Assistant: [调用 read_file]
└─ Tool: [文件已保存至 /memory/obs_123.txt,前10行预览: ...]

3.3 策略三:记忆淘汰(Memory Eviction)

核心问题:当上下文窗口满了,你决定删除什么、保留什么?

一个简单的策略是:递归摘要。将旧对话压缩成摘要,保留核心信息,丢弃细节。

但这里有个问题:压缩多少才合适?压缩太多,关键信息会丢失;压缩太少,空间仍然紧张。

实践建议:保留70%的信息密度是一个不错的平衡点——既能保持上下文的连续性,又能显著节省空间。

另一种策略:基于时间/重要性的淘汰

不是所有记忆都同等重要。可以给不同类型的记忆设置不同的TTL(生存时间):

记忆类型 TTL建议 原因
用户偏好 永久 需要长期记住用户习惯
任务状态 会话结束后删除 只在当前任务中有用
操作日志 30天 可能需要调试历史问题

3.4 策略四:上下文隔离(Isolation)

核心思想:使用子Agent来隔离不同类型的工作,只有结果返回给主Agent。

例如:

  • 主Agent需要分析一个大代码库
  • 它不应该把整个代码库都加载到自己的上下文中
  • 而是创建一个子Agent,让子Agent专门处理代码分析
  • 子Agent可以有自己的上下文管理策略
  • 最后只把分析结果返回给主Agent

这种方式可以有效防止主上下文被非必要的细节污染。

四、Deep Agents实战:代码示例

4.1 基础记忆配置

from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from langgraph.store.postgres import PostgresStore
from langgraph.checkpoint.postgres import PostgresSaver

DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"

with (
    PostgresStore.from_conn_string(DB_URI) as store,
    PostgresSaver.from_conn_string(DB_URI) as checkpointer,
):
    store.setup()
    checkpointer.setup()

    agent = create_deep_agent(
        backend=lambda rt: StoreBackend(rt),
        store=store,
        checkpointer=checkpointer,
        skills=["/skills/user/"],
        memory=["/memory/AGENTS.md"],
    )

    # 第一个对话
    config = {
        "configurable": {"thread_id": "thread-1"},
        "metadata": {"assistant_id": "my-assistant"},
    }
    agent.invoke(
        {"messages": [{"role": "user", "content": "记住:我喜欢简洁的回答。"}]},
        config,
    )

    # 切换到新线程,但记忆依然存在
    config2 = {
        "configurable": {"thread_id": "thread-2"},
        "metadata": {"assistant_id": "my-assistant"},
    }
    result = agent.invoke(
        {"messages": [{"role": "user", "content": "你还记得我的偏好吗?"}]},
        config2,
    )
    print(result)  # 会记得用户喜欢简洁回答

4.2 自定义上下文压缩

如果Deep Agents的默认压缩策略不满足需求,你可以自定义:

from langchain_core.messages import BaseMessage, SystemMessage
from typing import List

def custom_compression_strategy(
    messages: List[BaseMessage],
    max_tokens: int
) -> List[BaseMessage]:
    """自定义压缩策略示例"""
    
    # 1. 保留最新的10条消息
    recent_messages = messages[-10:]
    
    # 2. 对更早期的消息进行摘要
    if len(messages) > 10:
        # 这里可以调用LLM生成摘要
        summary_text = generate_summary(messages[:-10])
        summary_message = SystemMessage(content=f"对话摘要:{summary_text}")
        return [summary_message] + recent_messages
    
    return recent_messages

# 在创建Agent时使用
agent = create_deep_agent(
    # ...
    compression_strategy=custom_compression_strategy,
)

五、常见问题与最佳实践

5.1 什么时候用什么策略?

场景 推荐策略
工具输出特别大 Observation Masking(卸载)
对话历史很长,但需要保持连贯性 LLM Summary(摘要)
有些记忆明显不再需要 Memory Eviction(淘汰)
不同任务的上下文容易混淆 Context Isolation(隔离)

5.2 如何决定保留多少上下文?

一个经验法则是:

  1. 永远保留系统提示词:这是Agent的核心指令。
  2. 保留最近的N轮对话:通常5-20轮比较合适。
  3. 保留关键决策点:比如用户明确的需求变更、重要的工具调用结果。
  4. 可以摘要的尽早摘要:不要等上下文满了才想起来压缩。

5.3 如何调试记忆问题?

如果Agent出现"失忆"或"混淆",可以检查:

  1. 压缩是不是太激进了:检查摘要是否丢失了关键信息。
  2. 记忆文件是否正确保存:确认持久化层工作正常。
  3. 上下文窗口设置是否合理:是不是给模型塞了太多内容。
  4. 使用LangSmith追踪:查看完整的上下文变化轨迹。

六、总结

Context Engineering和记忆管理是构建生产级Agent系统的关键。核心思想是:

  1. 不要把所有东西都塞给模型:每一个Token都应该有它存在的理由。
  2. 分层管理记忆:短期、长期、程序性记忆各司其职。
  3. 让Agent自己管理记忆:给Agent读写记忆文件的能力,而不是硬编码规则。
  4. 监控和调试:使用LangSmith等工具观察上下文的变化。

随着Agent任务变得越来越复杂,这些技术只会变得更加重要。希望这篇文章能帮助你构建出更"聪明"、更"持久"的AI Agent系统!

参考资料

  • LangChain Deep Agents文档:https://docs.langchain.com/oss/python/deepagents/
  • Context Management for Deep Agents:https://www.langchain.com/blog/context-management-for-deepagents
  • Context Engineering深度拆解:https://m.toutiao.com/group/7642192312428167716/
  • Active Context Compression论文:https://www.arxiv.org/pdf/2601.07190
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐