一、为什么 Agent 需要上下文管理?
Context Engineering 是指管理和组织大模型每次推理所需要的上下文信息,让模型始终基于正确、完整、最新的信息进行回答。
由于大模型无法记住所有内容,而且上下文窗口有限,因此需要合理组织输入,例如聊天历史、RAG 检索结果、用户记忆(Memory)、系统提示词、工具返回结果等,并控制哪些信息需要保留、哪些需要丢弃,避免上下文过长或无关信息干扰模型。
Context Engineering 的核心不是写 Prompt,而是决定每一轮应该把哪些信息交给模型。
Agent 上下文管理就是在有限 Token 的情况下,对历史、知识、状态和记忆等进行管理,并动态构建最适合当前任务的上下文。
二、Agent 上下文包含哪些内容?
一个完整 Agent 的上下文并不是简单的聊天记录,而是由多种信息共同组成。不同类型的上下文承担不同职责,Agent 会根据当前任务动态选择需要的信息。
整体结构如下:
Agent Context
├── System Context(系统上下文)
├── User Input(用户输入)
├── Conversation Context(对话历史)
├── Memory Context(用户记忆)
├── Knowledge Context(知识上下文)
├── Tool Context(工具上下文)
└── Agent State(任务状态)
1. System Context(系统上下文)
System Context 用于定义 Agent 的角色、行为规则和约束条件。
你是一个企业知识库助手。
要求:
1. 优先根据知识库回答问题
2. 不确定的信息不要编造
3. 涉及敏感操作需要确认
优先级最高、通常固定、决定 Agent 的整体行为
2. User Input(用户输入)
User Input 是当前请求,也是 Agent 推理的起点。
用户:
帮我设计一个 Go 微服务架构
它代表用户当前想解决的问题。
User Input 和历史对话不同。
当前输入:
帮我设计一个Go微服务架构
历史消息:
之前讨论:
项目使用 Gin + MySQL + Redis
二者作用不同:
-
User Input 决定当前任务目标
-
History 提供任务背景信息
每次 Agent 调用 LLM 时,当前用户输入通常是必不可少的上下文。
3. Conversation Context(对话上下文)
Conversation Context 保存当前会话中的历史消息。
用户:
帮我设计订单系统
Agent:
订单系统包含订单、支付、库存模块
用户:
数据库怎么设计?
如果没有历史:
数据库怎么设计?
模型无法知道讨论的是哪个系统。
但是历史消息不能无限保存,如果持续追加会导致:
-
超出模型上下文限制
-
Token成本增加
-
无关信息影响模型推理
因此需要进行历史管理,常见方式:
(1)滑动窗口
只保留最近 N 轮消息。
优点:实现简单、成本低
缺点:早期重要信息可能丢失
(2)历史摘要
当历史过长时,将旧消息压缩成摘要。
原始:
用户讨论订单系统设计,
包括MySQL分库分表、
Redis缓存、
消息队列削峰。
摘要:
用户正在设计订单系统,
关注数据库和缓存方案。
(3)重要信息提取
不是所有聊天内容都值得长期保留。
低价值:
你好
谢谢
好的
高价值:
项目使用Go开发
数据库采用MySQL
部署使用Docker
可以提取成结构化信息:
{
"language":"Go",
"database":"MySQL",
"deploy":"Docker"
}
4. Memory Context(用户记忆)
Memory Context 用于保存用户长期有效的信息,它解决:
Agent 如何跨会话记住用户?
用户第一次:
我喜欢使用Go开发
保存:
{
"preference":"Go"
}
之后:
帮我设计后端架构
Agent 查询 Memory:
用户偏好:
Go技术栈
生成更符合用户习惯的方案。
Memory 通常分为两类:
Short-term Memory(短期记忆)
保存当前任务相关信息:
-
当前聊天记录
-
Agent执行状态
-
工具调用结果
通常存储:
-
Redis
-
内存
Long-term Memory(长期记忆)
保存长期信息:
-
用户技术偏好
-
历史项目
-
常用配置
通常存储:
-
MySQL
-
PostgreSQL
-
Vector Database
5. Knowledge Context(知识上下文)
Knowledge Context 主要来自外部知识库,例如 RAG。
流程:
用户问题
↓
Embedding
↓
向量数据库检索
↓
Top-K文档
↓
加入Context
↓
LLM回答
例如:
公司的退款规则是什么?
Agent 查询:
退款政策.md
订单规则.md
财务制度.md
然后将相关内容加入上下文,但是 RAG 返回内容也需要控制:
-
Chunk大小
-
Top-K数量
-
Rerank排序
-
Context压缩
6. Tool Context(工具上下文)
Agent 调用工具后,工具返回结果也是上下文。
例如调用天气 API:
{
"city":"北京",
"temperature":30
}
这个结果需要继续提供给 LLM 推理。
流程:
用户问题
↓
调用工具
↓
工具结果
↓
LLM继续推理
但是工具结果可能非常大,例如搜索返回几十篇文档。
因此通常需要截断、摘要、过滤、排序
7. Agent State(Agent状态)
Agent 与普通聊天最大的区别是他可以执行任务。
例如:
帮我部署一个服务
Agent执行:
分析任务
↓
制定计划
↓
调用工具
↓
检查结果
↓
继续执行
因此需要保存任务状态,例如:
type AgentState struct {
Goal string
CurrentStep string
Completed []string
Remaining []string
}
Agent State 可以支持:
-
长任务执行
-
中断恢复
-
失败重试
综上,一个完整 Agent 的 Context 不只是历史聊天,而是:
Context =
System规则
+
当前用户输入
+
历史对话
+
用户记忆
+
外部知识
+
工具结果
+
任务状态
Agent 会根据当前任务,从这些上下文中选择最有价值的信息,而不是简单地将所有数据全部发送给 LLM。
三、Agent 如何动态选择需要哪些上下文?
前面介绍了 Agent 可以使用哪些上下文,但是实际问题是:
每次请求是不需要都加载全部上下文
例如:
今天北京天气怎么样?
不需要历史聊天、用户记忆、知识库,只需要天气工具。
所以 Agent 需要根据用户问题动态选择上下文。
整体流程:
用户问题
↓
Context Router
↓
判断需要哪些Context
↓
加载对应信息
↓
Context Builder
↓
LLM
1. 基于规则选择
简单场景可以通过规则判断。
例如:
公司的退款规则是什么?
关键词:
规则
政策
制度
判断:
{
"need_rag":true,
"need_memory":false
}
2. 使用 LLM 作为 Context Router
更通用的方法是让一个模型先分析用户问题。
流程:
用户问题
↓
Router Agent
↓
判断需要哪些上下文
↓
加载Context
↓
回答Agent
例如:
帮我设计Go后端架构
Router输出:
{
"intent":"technical_design",
"contexts":[
"memory",
"history",
"knowledge"
]
}
表示需要:
Memory:
用户技术栈
项目背景
History:
之前讨论过的方案
Knowledge:
Go架构最佳实践
3. Agent 自主规划上下文
更高级的方式是让 Agent 自己决定缺少什么信息。
类似 Tool Calling,流程:
用户问题
↓
Agent Planner
↓
判断缺少的信息
↓
调用Context工具
↓
获取信息
↓
继续推理
例如:
帮我设计项目架构
Agent 判断:
需要用户项目背景
→ 查询Memory
需要之前讨论内容
→ 查询History
需要技术方案
→ 查询Knowledge
然后执行:
{
"actions":[
{
"tool":"search_memory",
"reason":"获取用户技术偏好"
},
{
"tool":"retrieve_docs",
"reason":"获取架构资料"
}
]
}
这实际上就是:
把 Context 获取能力封装成 Agent 可以调用的工具。
四、整体流程
用户输入
↓
Input Processor
(清洗、改写、补充上下文)
↓
Planner / Intent Detector
(理解任务)
↓
Context Router
(决定需要哪些Context)
↓
Context Retrieval
(Memory/History/RAG/Tool)
↓
Context Compression
(上下文太多了就压缩)
↓
Prompt Builder
↓
LLM
↓
Action执行
↓
Memory/State更新