Back to Blog
Tech Tutorials2026-05-2812 min read

Context Management in Practice: When AI Loses Memory in Million-Token Conversations

Deep dive into LLM Agent context management challenges, from compression strategies and disaster recovery to async summarization.

大模型 Agent 对话上下文管理实战:当 AI 在百万 Token 长对话中"失忆",我们该怎么办?


专栏信息

《从零到一构建跨平台 AI 助手:WeClaw 实战指南》专栏

专栏定位:面向开发者和技术决策者的实战专栏,用真实案例和完整代码带你理解如何构建生产级 AI 应用

本系列共 29 篇,分为九大模块

  • 模块一【通讯架构设计】(3 篇):混合通讯、设备绑定、请求路由
  • 模块二【核心技术实现】(4 篇):WebSocket 路由、心跳重连、离线队列
  • 模块三【安全与治理】(3 篇):密钥管理、Token 吊销、速率限制
  • 模块四【调试与监控】(2 篇):全链路追踪、日志分析
  • 模块五【问题诊断实战】(3 篇):典型问题排查与修复
  • 模块六【性能优化】(1 篇):启动速度、内存优化
  • 模块七【架构演进史】(1 篇):从 0 到 1 的完整历程
  • 模块八【上下文管理工程】(12 篇):压缩策略、容灾机制、Tool 配对、异步摘要、安全脱敏

本文是模块八第 1 篇,将带您深入理解大模型 Agent 上下文管理的问题本质与解决思路。


作者与项目

作者简介:翁勇刚 WENG YONGGANG 新概念龙虾-WeClaw 开发团队负责人,一群专注于跨平台 AI 应用的实践者 理念:"再复杂的技术,也能用代码讲清楚"


摘要

本文结构概览: 本文首先从一个"AI 失忆"的真实场景切入,揭示上下文管理的三重核心困境(窗口有限、信息有价、配对有规),然后横向对比三种主流开源方案(一体化压缩流、向量长期记忆、渐进截断),分析各自的优劣势,最后引出 WeClaw 的渐进式优化路线。全文遵循"问题驱动->原理讲解->方案对比->决策推导"的闭环逻辑。

背景:大语言模型(LLM)的上下文窗口从 4K 增长到 2M tokens,看似"无限空间",但 Agent 在 ReAct 推理循环中每轮产生的 tool_call + tool_result 消息快速膨胀,一个复杂任务可能产生数万 tokens 的对话历史。当窗口被填满时,模型要么遗忘早期上下文,要么报错崩溃。

核心问题:如何在有限的上下文窗口中,保留最有价值的信息,同时维持消息结构的完整性?

解决方案:通过对比三种开源方案的设计哲学,提炼出"渐进式上下文工程"方法论——分档阈值、三级容灾、token-budget 尾部保护、结构化摘要等 12 项核心能力。

关键成果

  • 梳理了上下文管理的三重困境与解决框架
  • 横向对比了 Hermes-Agent、CoPaw、WeClaw 三种方案的架构差异
  • 明确了"窗口大小-成本-延迟"三角权衡的决策方法
  • 为后续 11 篇专题文章奠定了技术全景

适合读者:有 Python 基础,对 LLM Agent 架构、上下文工程、对话管理感兴趣的开发者

阅读时长:约 12 分钟

关键词上下文管理LLM AgentReAct 循环对话压缩Tool 配对消息截断渐进式优化


一、场景重现 —— 当 AI 助手"失忆"

1.1 一个令人崩溃的对话

想象这个场景:

用户:帮我分析 A 股半导体板块的近期走势,重点关注中芯国际和北方华创
AI:(调用 stock_query 工具,查询行情,输出详细分析...)
用户:很好,再帮我看下港股的腾讯和美团
AI:(调用工具,输出分析...)
用户:结合 A 股和港股的情况,给我一个综合投资建议

[... 中间穿插了 20 轮关于量化策略的讨论 ...]

用户:回到之前的话题,你觉得中芯国际和腾讯哪个更值得长期持有?
AI:请问您指的是哪两只股票?我没有找到相关讨论记录。

发生了什么?

在中间 20 轮对话中,早期的半导体分析上下文已经被挤出窗口。AI 不是"忘了",而是字面意义上的"看不到了"——那些消息已经从发给模型的 messages 数组中被截断了。

1.2 问题的本质

这不是 AI 的"记忆力差",而是上下文窗口的物理限制

┌─────────────────────────────────────────────┐
│         上下文窗口 (Context Window)           │
│                                             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │ System   │  │ 历史消息  │  │ 当前输入  │  │
│  │ Prompt   │  │ History  │  │ Input    │  │
│  │ (固定)   │  │ (动态)   │  │ (实时)   │  │
│  │ ~20K tok │  │ 变化中   │  │ 最新     │  │
│  └──────────┘  └──────────┘  └──────────┘  │
│  ↑                                          │
│  当历史消息超过窗口剩余空间时,必须截断        │
└─────────────────────────────────────────────┘

System Prompt 占据固定空间(身份定义、工具描述、行为指引),当前输入必须保留,留给历史消息的空间是动态变化的。当历史消息膨胀到超出可用空间时,就需要"上下文管理"来取舍。


二、三重困境 —— 为什么上下文管理这么难?

[图片: "上下文管理三重困境"概念图 | 生成方式: 文生图 PROMPT: "A triangular diagram showing three competing forces: Limited Context Window, Information Value Preservation, and Message Pairing Integrity, with an AI robot in the center trying to balance all three, tech illustration style, dark blue background"]

2.1 困境一:窗口有限

即使模型支持 128K 甚至 1M tokens,窗口也不是无限的:

模型原始窗口有效窗口(输出预留后)实际可用(安全余量)
GPT-4o128K~120K~100K
Claude 3.5200K~190K~160K
Gemini 1.5 Pro2M~1.9M~1.5M
通义千问-Max32K~28K~24K

关键点:有效窗口 = 原始窗口 - 输出预留 - 安全余量。一个 128K 的模型,实际可用于历史消息的空间可能只有 80-100K tokens。

2.2 困境二:信息有价

不是所有消息的价值相同:

消息价值金字塔:

                    ┌─────────────┐
                    │  用户最新请求  │  ← 最高优先级
                    │  (活跃任务)   │
                   ┌┴─────────────┴┐
                   │  未完成的工具   │
                   │  调用配对       │
                  ┌┴───────────────┴┐
                  │  最近的对话轮次   │
                  │  (含上下文)      │
                 ┌┴─────────────────┴┐
                 │  早期的分析结论    │  ← 需要摘要保留
                 │  (可压缩)         │
                ┌┴───────────────────┴┐
                │  冗余的工具输出      │  ← 可以裁剪
                │  (重复/过期)        │
                └─────────────────────┘

一条"请分析中芯国际"的 tool_result 可能包含 50KB 的行情数据,而一条"好的"回复只有 50 字符。固定轮次保护无法区分它们的价值差异。

2.3 困境三:配对有规

ReAct Agent 的消息结构有严格的配对约束:

# 正确的消息序列
[
    {"role": "assistant", "tool_calls": [{"id": "call_001", "function": {"name": "search", ...}}]},
    {"role": "tool", "tool_call_id": "call_001", "content": "...结果..."},  # 必须配对
    {"role": "assistant", "content": "根据搜索结果..."},
]

# 错误的消息序列("孤儿"消息)
[
    {"role": "assistant", "tool_calls": [{"id": "call_001", ...}]},  # tool_call 存在
    # tool_result 被截断删除了!
    {"role": "assistant", "content": "..."},  # 模型不知道 call_001 的结果
]

孤儿消息的后果

  • 模型 API 报错:"Every tool_call must have a corresponding tool result"
  • 模型困惑:尝试"重新调用"已有结果的工具
  • 日志污染:每个 ReAct 步骤都报告"缺失结果"

这三重困境互相矛盾:窗口有限要求截断,信息有价要求保留,配对有规要求结构化处理。没有任何一种方案能同时完美解决这三个问题。


三、三种开源方案横评 —— 各自的设计哲学

[图片: 三方案对比雷达图 | 生成方式: Python matplotlib 脚本,五维雷达图(压缩质量/延迟/成本/可靠性/复杂度),三条线分别标注 Hermes/CoPaw/WeClaw]

3.1 方案 A:一体化压缩流水线(代表项目:Hermes-Agent)

核心思想:每次 API 调用后检查上下文长度,超标时触发压缩。

# 简化示意
async def run_agent_loop(self, user_message):
    # 1. 添加用户消息
    self.messages.append({"role": "user", "content": user_message})

    while not finished:
        # 2. 调用 LLM(核心推理)
        response = await self.call_llm(self.messages)

        # 3. 处理工具调用
        if response.tool_calls:
            for tc in response.tool_calls:
                result = await execute_tool(tc)
                self.messages.append(tool_result_msg)

        # 4. 关键:每轮结束后检查是否需要压缩
        if self.should_compress():
            summary = await self.generate_summary()
            self.messages = [summary_msg] + self.recent_messages

优势

  • 时机精准:在自然边界(API 调用后)触发压缩
  • 三级容灾:辅助模型 -> 主模型重试 -> 静态回退
  • Token-budget 尾部保护:按 token 预算而非轮次保护近期消息

劣势

  • 每次压缩都有 LLM 调用成本
  • 压缩质量依赖模型能力

3.2 方案 B:记忆分层架构(代表项目:CoPaw)

核心思想:将记忆分为工作记忆、情景记忆、语义记忆三层,通过向量检索召回相关记忆。

┌──────────────────────────────────┐
│         工作记忆 (Working)        │  ← 当前对话窗口,完整保留
│  最近 N 轮对话,无压缩           │
├──────────────────────────────────┤
│         情景记忆 (Episodic)       │  ← 历史对话的结构化摘要
│  时间索引 + 事件链               │
├──────────────────────────────────┤
│         语义记忆 (Semantic)       │  ← 长期知识,向量检索
│  ReMeLight 向量数据库            │
└──────────────────────────────────┘

优势

  • 理论上无限记忆容量
  • 支持跨会话的长期记忆召回
  • 语义检索能关联相关但非连续的信息

劣势

  • 向量检索可能召回不相关内容("假阳性")
  • 架构复杂度高,需要额外的向量数据库
  • 检索延迟增加(每次对话前需要搜索相关记忆)
  • 摘要写入向量库时可能丢失细节

3.3 方案 C:渐进截断(WeClaw 旧方案)

核心思想:简单的"先进先出"截断,超出窗口限制时删除最早的消息。

# WeClaw 旧方案的简化逻辑
def enforce_limit(self, messages, max_messages=200):
    if len(messages) <= max_messages:
        return messages
    # 直接删除最旧的消息
    return messages[-max_messages:]

优势

  • 实现极简,零额外成本
  • 延迟最低(无 LLM 调用)
  • 易于调试和理解

劣势

  • 早期上下文全部丢失,无摘要保留
  • 不考虑消息价值,按时间顺序粗暴截断
  • 可能切断 tool_call/tool_result 配对
  • 在 128K+ 窗口下,阈值设置不合理导致从不触发

四、为什么没有银弹?—— 三角权衡

三种方案各有侧重,本质上是在窗口大小、成本、延迟三个维度上做权衡:

                  高压缩质量
                      ↑
                      │
         Hermes ●─────┤
                      │
    低成本 ◄──────────┼──────────► 高成本
                      │
                      │     ● CoPaw
         WeClaw ●─────┤
                      │
                  低延迟
维度Hermes (压缩流水线)CoPaw (记忆分层)WeClaw 旧方案 (截断)
压缩质量高(LLM 生成摘要)中(向量检索)无(直接丢弃)
调用成本中(每轮可能调 LLM)高(向量库+检索)
延迟影响低(异步后台)中(检索耗时)
架构复杂度
信息保留好(结构化摘要)好(语义召回)差(全丢)
Tool 配对保护间接
跨会话记忆
适用窗口32K-2M任意<32K

关键洞察:没有"最佳方案",只有"最适合当前场景的方案"。


五、WeClaw 的选择 —— 渐进式优化路线

5.1 为什么不选 CoPaw 的记忆分层?

WeClaw 是一个桌面端 AI 助手,核心场景是单用户长对话,而非多用户知识共享:

  1. 无需跨会话语义检索:用户通常在单一会话中完成一个任务
  2. 向量数据库过重:引入额外的基础设施依赖,增加部署复杂度
  3. 检索质量不稳定:向量相似度 ≠ 语义相关性,"假阳性"召回可能误导模型

5.2 为什么选择借鉴 Hermes 的流水线?

Hermes 的设计哲学与 WeClaw 的需求高度契合:

  1. 压缩时机精准:在 API 调用后的自然边界触发,不干扰推理循环
  2. 可靠性优先:三级容灾确保任何情况下都不会丢失上下文
  3. 成本控制:静态回退方案在极端情况下零成本保留关键信息

5.3 渐进式优化的 12 项能力

基于 Hermes 的启发,WeClaw 在两轮迭代中实现了 12 项核心能力:

序号能力解决的问题
1三级容灾辅助 LLM 不可用时的降级策略
2分档自适应阈值大窗口模型不触发压缩
3Token-budget 尾部保护固定轮次保护的粒度问题
4用户消息锚定最后一条 user 消息被摘要吞掉
510 字段结构化摘要摘要丢失活跃任务信息
6双语行为约束摘要中的提问被模型误执行
7密钥脱敏API Key 残留在摘要中
8截断通知模型不知道上下文被压缩过
9手动压缩命令用户无法主动触发压缩
10异步后台摘要压缩阻塞主对话循环
11跨会话状态隔离切换会话后压缩器状态残留
12统一孤儿处理Tool 配对断裂的一致性修复

后续 11 篇文章将逐一深入讲解每项能力的设计与实现。


六、总结与展望

6.1 核心要点回顾

  1. 上下文管理是 Agent 的"生死线":窗口有限、信息有价、配对有规,三重困境必须同时应对
  2. 没有银弹:压缩质量、成本、延迟三者不可兼得,需要根据场景权衡
  3. 渐进式优化是务实选择:借鉴成熟的压缩流水线设计,逐步补齐 12 项能力

6.2 一个核心公式

上下文管理 = 智能截断(阈值策略) + 可靠压缩(三级容灾) + 精准保护(尾部锚定) + 结构完整(配对维护)

6.3 下一步学习方向

前置知识

  • 了解 ReAct 推理循环的基本流程
  • 理解 LLM API 的 messages 数组结构
  • 熟悉 async/await 异步编程范式

后续主题

  • 下一篇:《架构选型——三个开源项目的上下文管理哲学》
  • 深入对比 Hermes、CoPaw、WeClaw 的代码级架构差异

下期预告:《架构选型:三个开源项目的上下文管理哲学》

  • Hermes 的"调用后触发" vs WeClaw 的"调用前检查"
  • CoPaw 的 ReMeLight 向量记忆系统
  • 为什么 WeClaw 最终选择了"借鉴而非照搬"
  • 架构决策的关键差异表与选型指南

敬请期待!


附录 A:术语表

术语含义
ReActReasoning + Acting,LLM Agent 的推理-行动循环模式
tool_callLLM 输出的工具调用请求,包含函数名和参数
tool_result工具执行结果,与 tool_call 通过 ID 配对
孤儿消息存在 tool_call 但缺少对应 tool_result 的消息
上下文窗口模型单次请求能处理的最大 token 数
压缩/摘要将多条历史消息合并为一条简短的摘要消息
尾部保护保留最近 N 条消息不被压缩截断的策略

附录 B:参考资料

  1. Hermes-Agent GitHub -- 上下文压缩流水线参考
  2. CoPaw GitHub -- 记忆分层架构参考
  3. ReAct: Synergizing Reasoning and Acting in LLMs -- ReAct 原始论文
  4. 下一篇:《架构选型:三个开源项目的上下文管理哲学》(本系列第 47 篇)

版权声明:本文为 CSDN 博主「翁勇刚」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。