AI Agent上下文管理:让Agent记住重要的事

📘 AI教程 💬 🔥 Trending 发布者: leakey
AI Agent上下文管理:让Agent记住重要的事

🩺 摘要

AI Agent的上下文窗口是有限的。聊久了前面的信息就丢了。怎么管理?

📝 详情

上下文管理实战:让AI Agent记住该记住的

为什么上下文管理是关键瓶颈?

大模型上下文窗口从4K扩展到128K甚至1M,但Token越多,成本越高、响应越慢、幻觉越严重。实测数据:

上下文长度 GPT-4o延迟 单次成本 准确率
4K tokens 0.8s $0.01 96%
32K tokens 2.5s $0.08 89%
128K tokens 8s $0.32 72%

策略一:滑动窗口

class SlidingWindowMemory:
    """只保留最近N轮对话"""
    def __init__(self, max_rounds=10, max_tokens=4000):
        self.max_rounds = max_rounds
        self.max_tokens = max_tokens
        self.history = []

    def add(self, role, content):
        self.history.append({"role": role, "content": content})
        # 裁剪:优先保证轮数限制
        if len(self.history) > self.max_rounds * 2:
            self.history = self.history[-(self.max_rounds * 2):]
        # 其次保证Token限制
        while self.count_tokens() > self.max_tokens:
            self.history.pop(0)

    def get_context(self):
        return self.history

    def count_tokens(self):
        return sum(len(m["content"]) * 1.3 for m in self.history)  # 中文约1.3token/字

# 适用场景:简单对话、客服聊天
# 优点:实现简单、性能好
# 缺点:可能丢失早期重要信息

策略二:摘要压缩

class SummaryCompressionMemory:
    """定期把历史对话压缩为摘要"""
    def __init__(self, llm_client, compress_every=5):
        self.llm = llm_client
        self.compress_every = compress_every
        self.summary = "对话开始"
        self.recent_history = []

    def add(self, role, content):
        self.recent_history.append({"role": role, "content": content})
        if len(self.recent_history) >= self.compress_every:
            self._compress()

    def _compress(self):
        recent_text = "\n".join([f"{m['role']}: {m['content']}" for m in self.recent_history])
        prompt = f"请将以下对话压缩为1-2句话摘要:\n{recent_text}"
        new_summary = self.llm.chat(prompt)
        self.summary = f"{self.summary} -> {new_summary}"
        self.recent_history = []

    def get_context(self):
        return [
            {"role": "system", "content": f"对话历史摘要:{self.summary}"},
            *self.recent_history[-3:]  # 保留最近3条原始消息
        ]

# 压缩效果对比
# 原始:100轮对话约5000 tokens -> 摘要后:200 tokens
# 成本降低:96%,信息保留率:约85%

策略三:关键信息提取

class KeyInfoMemory:
    """只保留用户的关键信息字段"""
    def __init__(self, key_fields=None):
        self.key_fields = key_fields or ["user_name", "role", "preferences", "project"]
        self.info_store = {}
        self.recent_messages = []

    def update_info(self, message):
        """用LLM从消息中提取关键字段值"""
        prompt = f"从以下对话中提取信息:{message}\n需要提取的字段:{', '.join(self.key_fields)}\n格式:JSON"
        extracted = json.loads(self.llm.extract(prompt))
        for k, v in extracted.items():
            if v:  # 只保存非空值
                self.info_store[k] = v

    def get_context(self):
        return {
            "user_info": self.info_store,  # 0 tokens(固定结构)
            "recent_history": self.recent_messages[-5:]  # 最近5轮
        }

# 效果:100轮对话 -> user_info(固定大小~200 tokens) + 最近5轮(~500 tokens) = 700 tokens
# 对比原始100轮(~5000 tokens):节省86% tokens,关键信息保留率95%+

推荐组合策略

场景 推荐策略 预期token节省
简单对话(<10轮) 不需要管理 0%
长对话(50-200轮) 滑动窗口 + 摘要压缩 80%
知识问答(有明确事实) 关键信息提取 86%
代码生成(需要完整上下文) 滑动窗口 60%
企业级对话(混合场景) 三层组合 85%+

最佳实践

  1. 不要把历史对话一股脑塞进去,按策略裁剪
  2. 定期做摘要压缩,一般在5-10轮对话后做一次
  3. 关键信息与对话历史分开存储,结构化的部分不占Token
  4. 监控Token消耗,超过预算时主动降级策略