云计算百科
云计算领域专业知识百科平台

Context Window 终极指南:为什么 Agent 聊得越久,反而越容易出错?

Context Window 终极指南:为什么 Agent 聊得越久,反而越容易出错?

做 Agent 时,我遇到过一个很反直觉的问题:

明明给模型的历史信息更多了,回答却不一定更好。

有一次我让 Agent 根据前面的需求继续生成一份项目方案。刚开始还能跟上,但聊到后面,它开始出现:

  • 把早期已经否定的方案重新拿出来;
  • 忘记用户刚刚确认过的格式;
  • 工具调用结果被后续内容淹没;
  • 同一个问题重复解释;
  • Token 消耗越来越高,响应越来越慢。

后来我才意识到,问题不只是“模型记性不好”,而是 Context Window(上下文窗口)管理得不好。

上下文窗口不是简单的“能放多少字”,而是直接影响 Agent 的理解、规划、工具调用和任务完成率。

一、Context Window 到底是什么?

可以把 Context Window 理解成:

模型一次能够看到并处理的全部上下文空间。

它通常包括:

System Prompt
+
用户当前问题
+
历史对话
+
工具调用记录
+
工具返回结果
+
检索到的知识

比如一次 Agent 请求可能是:

系统规则:2000 tokens
历史对话:6000 tokens
工具结果:5000 tokens
知识库内容:4000 tokens
当前问题:500 tokens

总共就是 17500 tokens。

这意味着,窗口越大,不代表一定越好。真正重要的是:

相关信息占比
+
信息顺序
+
噪声多少
+
成本与延迟

二、为什么上下文太长反而会出问题?

1. 关键信息被淹没

前面有 30 页聊天记录,真正有用的可能只有其中 3 段。

模型虽然“看到了”,但未必能准确抓住重点。

2. 旧信息与新信息冲突

用户前面说:

默认使用 Python

后面又说:

现在项目改用 Java

如果没有明确更新机制,模型可能把两条都当成有效信息。

3. 成本和延迟上升

每轮都把完整对话重新发送,Token 消耗会持续增加。

4. 工具结果占据大量空间

SQL 查询结果、网页内容、日志文件往往比用户问题长得多,如果全部塞进上下文,很容易挤掉真正重要的信息。

三、上下文管理的第一步:不要什么都放

我现在会把上下文拆成几类:

必须保留:
– 系统规则
– 当前任务目标
– 最近几轮对话
– 当前步骤的工具结果

可以压缩:
– 很早的历史对话
– 已完成的中间过程
– 重复说明

应该外置:
– 大型文档
– 长日志
– 全量数据库结果
– 不相关历史

原则很简单:

模型需要的是“当前决策所需的信息”,不是所有历史原文。

四、四种常见的上下文管理策略

1. 滑动窗口

只保留最近 N 轮对话:

messages = messages[–20:]

优点是简单、成本可控。

缺点是旧信息可能直接丢失。

2. 历史摘要

把很早的对话压缩成一段摘要:

用户是 Java 后端开发,正在准备秋招;
偏好中文、Markdown、详细解释;
当前项目是企业级多 Agent 工作台。

这比保留 100 条原始消息更有效。

3. RAG 检索

需要旧资料时,不把全文一直放在上下文里,而是临时检索最相关的几段。

当前问题
↓
检索相关文档
↓
只注入 Top-K 内容

4. Memory 外置

把稳定的用户信息、长期目标和任务状态放到独立存储中,需要时再取出来。

五、如何构造一个干净的 Agent Context?

我比较推荐把上下文分成四层:

context = {
"system_rules": system_prompt,
"task_state": current_task_state,
"recent_messages": recent_messages,
"retrieved_memory": relevant_memory
}

最终再按固定顺序组装:

1. 系统规则
2. 当前任务目标
3. 必要的历史摘要
4. 相关记忆
5. 当前问题
6. 当前步骤的工具结果

这个顺序很重要。

如果把大量工具日志放在最前面,模型可能会把日志当成主要任务;如果把当前目标埋在最后,也容易出现方向漂移。

六、一个简单的上下文压缩实现

def build_context(system_prompt, summary, recent_messages, tool_results, question):
context = [
{"role": "system", "content": system_prompt},
{
"role": "system",
"content": f"历史摘要:
{summary}"
}
]

context.extend(recent_messages)

if tool_results:
context.append({
"role": "system",
"content": f"当前工具结果:
{tool_results}"
})

context.append({
"role": "user",
"content": question
})

return context

如果历史太长,可以先摘要:

def summarize_history(messages):
text = "
".join(
f"{m['role']}: {m['content']}"
for m in messages
)

return llm_generate(
f"请提取任务目标、用户偏好、已完成步骤和未解决问题:
{text}"
)

注意摘要不要只总结“聊了什么”,还要保留:

已确认决策
待办事项
失败记录
用户偏好
关键约束

七、Context Window 和 Memory 的区别

这两个概念很容易混在一起。

Context Window:
模型这一轮能看到什么

Memory:
系统长期保存什么

举个例子:

Memory:
用户偏好 Markdown

Context:
本轮任务需要生成项目方案

Memory 是外部存储,Context 是当前送给模型的工作集。

所以真正的 Agent 通常是:

长期 Memory
↓
检索相关信息
↓
组装当前 Context
↓
交给 LLM

八、如何验证上下文管理是否有效?

建议至少比较三种方案:

方案 A:完整历史直接拼接
方案 B:滑动窗口 + 摘要
方案 C:滑动窗口 + 摘要 + RAG + Memory

重点测:

  • 任务完成率;
  • 关键约束保留率;
  • 工具调用正确率;
  • 平均 Token 消耗;
  • P95 响应时间;
  • 用户纠正次数。

例如:

完整历史:
完成率 62%,Token 2800,平均 12.3s

窗口 + 摘要:
完成率 74%,Token 2100,平均 10.8s

窗口 + 摘要 + RAG + Memory:
完成率 93%,Token 1600,平均 8.5s

这类对比更能说明上下文治理的价值。

九、最常见的坑

1. 把所有内容都塞给模型

上下文不是越多越好,重点是相关性。

2. 只压缩历史,不保存决策

如果摘要没有保留“用户已经确认的方案”,后面还是会重复讨论。

3. 工具结果不做裁剪

大型 JSON、日志和网页正文应该先过滤、截断、结构化。

4. 不区分不同任务

代码调试、文档写作、知识问答需要的上下文完全不同,不能用同一套模板硬套。

5. 没有成本监控

建议记录:

输入 Token
输出 Token
总 Token
单轮耗时
摘要耗时
检索耗时

最后

我现在越来越觉得,Context Window 不是大模型的一个参数,而是 Agent 的“工作记忆空间”。

如果管理得好:

Agent 更稳定
任务更连续
成本更可控
工具调用更准确

如果管理得不好:

信息越多,噪声越大
历史越长,错误越难定位
模型越强,系统越难控制

真正成熟的 Agent,不是把所有历史都交给模型,而是能够判断:

这一轮,哪些信息必须让模型看到?哪些信息应该摘要?哪些信息应该去知识库或 Memory 里临时取?

这才是上下文工程真正要解决的问题。

标签

#Agent #ContextWindow #上下文工程 #RAG #Memory #大模型应用 #后端开发

赞(0)
未经允许不得转载:网硕互联帮助中心 » Context Window 终极指南:为什么 Agent 聊得越久,反而越容易出错?
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!