AI Agent上下文工程:从提示词优化到上下文压缩的全链路实践
引言:Agent真正的瓶颈,正在从“模型能力”转向“上下文能力”
过去两年,AI Agent工程实践中有一个非常明显的变化:开发者最初把主要精力放在模型选择、Prompt编写和Tool Calling上,而进入生产环境之后,真正让系统变得复杂的往往不是这些环节,而是上下文管理。
一个简单的聊天机器人,只需要把用户问题发送给大模型即可:
用户问题
↓
Prompt
↓
LLM
↓
回答
但一个真正的企业级Agent通常需要同时处理:
当前用户请求;
多轮对话历史;
用户长期偏好;
当前任务状态;
历史任务结果;
工具调用记录;
数据库查询结果;
RAG检索结果;
外部网页或API数据;
系统规则;
安全策略;
Agent自身产生的中间状态;
其他Agent返回的信息。
最终发送给模型的已经不再是一个简单Prompt,而是一套动态构建出来的Context Package(上下文包)。
可以把Agent的一次模型调用抽象为:
[
C_t = S + I_t + H_t + M_t + R_t + T_t + O_t
]
其中:
(S):System Instruction,系统指令;
(I_t):当前用户输入;
(H_t):短期对话历史;
(M_t):长期记忆;
(R_t):检索结果;
(T_t):工具及其执行状态;
(O_t):Agent运行过程中的其他状态。
因此,Agent的核心问题已经从:
“怎么写一个更好的Prompt?”
逐渐变成:
“在有限Token预算下,如何让模型在当前任务中获得最有价值、最可靠、最及时的上下文?”
这就是上下文工程(Context Engineering)真正解决的问题。
长上下文模型并不意味着可以无限制地把所有历史数据塞进去。研究已经发现,即使模型具备很长的上下文窗口,关键信息位于长上下文中间位置时,模型的利用能力仍可能明显下降,这就是著名的“Lost in the Middle”现象。([arXiv][1])
所以,上下文工程不是简单地“扩大Context Window”,而是围绕上下文生命周期进行系统设计。
一、什么是AI Agent上下文工程
1.1 Prompt Engineering与Context Engineering的区别
Prompt Engineering主要关注:
如何设计一段更好的提示词,让模型完成特定任务。
例如:
你是一名专业的软件架构师。
请分析下面的系统需求,并输出:
1. 系统架构
2. 技术选型
3. 数据库设计
4. 风险分析
这属于典型的Prompt Engineering。
而Context Engineering关注的是:
模型在某一次推理时,到底应该看到什么信息、以什么顺序看到、哪些信息应该被压缩、哪些信息应该实时检索、哪些信息应该永久保存。
例如用户连续进行了50轮对话:
System Prompt
+
用户画像
+
最近10轮对话
+
任务摘要
+
历史决策
+
当前数据库状态
+
RAG结果
+
工具调用结果
+
当前问题
这里真正困难的已经不是Prompt本身,而是:
哪些信息应该进入Context?
这也是为什么一个Agent即使使用同一个模型,不同上下文架构可能产生完全不同的效果。
二、Agent上下文的完整生命周期
一个生产级Agent可以采用下面的上下文生命周期:
┌─────────────────┐
│ User Request │
└────────┬────────┘
↓
┌─────────────────┐
│ Context Builder │
└────────┬────────┘
↓
┌─────────────────┼──────────────────┐
↓ ↓ ↓
Short Memory Long Memory Retrieval
↓ ↓ ↓
└─────────────────┼──────────────────┘
↓
Context Ranking
↓
Context Compression
↓
Token Budget
↓
Prompt Assembly
↓
LLM
↓
┌───────────┴───────────┐
↓ ↓
Tool Calling Final Answer
↓
State Update
↓
Memory Extraction
↓
Context Persistence
因此可以把上下文工程拆成七个核心环节:
上下文构建;
上下文分层;
上下文检索;
上下文排序;
上下文压缩;
上下文装配;
上下文更新。
这七个环节构成Agent Context Pipeline。
三、第一层:上下文分层设计
最常见的错误,是把所有信息都放进一个messages数组。
例如:
{
"messages": [
{
"role": "system",
"content": "..."
},
{
"role": "user",
"content": "..."
},
{
"role": "assistant",
"content": "..."
}
]
}
在Agent运行时间较短时没有问题,但随着任务复杂度增加,这种设计会逐渐失控。
更合理的方式是把Context拆成不同层级。
3.1 Immutable Context
这部分内容在一个Agent生命周期内基本不变化。
例如:
Agent身份
系统规则
输出格式
安全策略
工具定义
业务规则
可以称为:
Static Context
这部分应该尽可能稳定。
原因很简单:很多模型平台支持Prompt Cache。如果每次请求前面的内容发生变化,会降低缓存命中率。
例如OpenAI API已经提供Prompt Cache相关能力,并通过prompt_cache_key等机制帮助优化相似请求的缓存命中。([OpenAI 平台][2])
因此生产系统中应该尽量做到:
稳定System Prompt
↓
稳定Tool Definition
↓
稳定业务规则
↓
动态Context
↓
用户问题
而不是:
用户问题
随机信息
Tool结果
System Prompt
用户画像
历史消息
频繁改变Prompt前缀会破坏缓存收益。
四、第二层:短期记忆与长期记忆
Agent记忆不能简单理解为“聊天记录”。
更合理的方式是分成:
Short-Term Memory
+
Working Memory
+
Long-Term Memory
4.1 Short-Term Memory
保存当前任务最近发生的事件。
例如:
用户:帮我设计一个订单系统
Agent:需要支持哪些支付方式?
用户:微信和支付宝
Agent:是否需要分销?
用户:需要三级分销
当前任务中这些信息具有较高价值。
因此最近若干轮应该保留。
4.2 Working Memory
Working Memory比聊天历史更重要。
它不是“用户说了什么”,而是:
Agent现在知道什么,以及任务进行到了哪一步。
例如:
{
"goal": "设计订单系统",
"payment": [
"wechat",
"alipay"
],
"distribution": {
"enabled": true,
"level": 3
},
"database": "MySQL",
"backend": "Go",
"status": "architecture_design"
}
这类结构化状态比几十轮自然语言对话更加稳定。
因此一个成熟Agent应该逐渐从:
Conversation as State
升级到:
State + Conversation
也就是说:
不要让聊天记录承担数据库的职责。
五、第三层:长期记忆不是“把所有历史保存下来”
长期记忆最容易出现两个极端。
第一种:
什么都保存。
第二种:
什么都不保存。
正确的方法是建立Memory Policy。
例如:
用户明确偏好
↓
长期记忆
临时问题
↓
不保存
任务结果
↓
根据价值决定
重要业务决策
↓
长期保存
一次性的闲聊
↓
丢弃
可以定义一个Memory Score:
[
Score = Importance \times Recency \times Relevance
]
例如:
Importance = 0.9
Recency = 0.8
Relevance = 0.95
Score = 0.9 × 0.8 × 0.95
= 0.684
当Score低于阈值时,不需要进入模型Context。
六、上下文检索:不是“搜索越多越好”
RAG系统经常存在一个误区:
找到越多文档,模型获得的信息越充分。
实际上恰恰相反。
如果一次检索返回:
20个文档
每个文档1500 Token
那么:
20 × 1500 = 30000 Token
即使模型能够接受30K上下文,也不代表30K信息都应该输入。
因为真正需要解决的问题是:
Information Retrieval → Context Selection
而不是:
Information Retrieval → Context Dump
七、Context Ranking:给上下文排序
可以为每个候选Context计算综合评分:
[
Score_i =
\alpha R_i +
\beta S_i +
\gamma T_i +
\delta Q_i
]
其中:
(R_i):与当前Query相关性;
(S_i):信息可信度;
(T_i):时效性;
(Q_i):信息质量。
例如:
type ContextItem struct {
ID string
Content string
Relevance float64
Trust float64
Freshness float64
Quality float64
TokenCount int
}
排序:
func Score(c ContextItem) float64 {
return 0.50*c.Relevance +
0.20*c.Trust +
0.15*c.Freshness +
0.15*c.Quality
}
然后只选择Top-N。
这一步非常重要,因为:
Context Window应该被看作有限预算,而不是无限仓库。
八、上下文压缩:Agent进入生产环境的关键能力
上下文压缩通常分为四类:
1. 截断
2. 摘要
3. 结构化压缩
4. 语义压缩
九、第一种压缩:简单截断
最简单的策略:
保留System Prompt
+
保留最近N轮
+
删除最早消息
例如:
messages = messages[-20:]
优点:
简单;
快;
不增加额外LLM调用。
缺点也非常明显:
早期重要决策
↓
直接丢失
例如用户在第2轮说:
数据库必须使用PostgreSQL。
第40轮继续讨论系统设计时,如果第2轮已经被截掉,Agent可能重新推荐MySQL。
这就是典型的上下文丢失。
十、第二种压缩:摘要
更成熟的方法是Summary。
例如原始对话:
用户:我要开发一个电商系统。
用户:后端使用Go。
用户:数据库使用MySQL。
用户:Redis用于缓存。
用户:支付使用微信和支付宝。
用户:需要三级分销。
...
压缩为:
【项目摘要】
项目类型:电商系统
技术栈:
- Go
- MySQL
- Redis
支付:
- 微信
- 支付宝
业务:
- 三级分销
当前阶段:
订单系统架构设计
这样可以从几千Token压缩到几百Token。
但摘要也存在一个严重问题:
摘要模型可能把“看起来不重要”的信息错误删除。
因此不能简单让模型:
请总结以上对话。
而应该指定Summary Schema。
例如:
{
"goal": "",
"constraints": [],
"decisions": [],
"open_questions": [],
"facts": [],
"tool_results": [],
"next_action": ""
}
这种结构化摘要比自由文本摘要更适合Agent。
十一、第三种压缩:状态化压缩
这是企业Agent中非常值得采用的方法。
与其:
保留100轮对话
不如:
对话
↓
提取事实
↓
提取决策
↓
提取任务状态
↓
形成State
例如:
{
"task": {
"name": "订单系统",
"status": "payment_design"
},
"decisions": [
"Backend=Go",
"Database=MySQL",
"Cache=Redis"
],
"constraints": [
"支持微信支付",
"支持支付宝",
"三级分销"
],
"pending": [
"支付回调设计",
"订单状态机设计"
]
}
这类State可以直接存储到Redis或数据库。
最终Agent上下文只需要:
当前State
+
最近对话
+
相关历史
而不是整个Conversation。
十二、第四种压缩:工具结果压缩
Agent最容易爆Token的地方之一,其实不是用户聊天,而是Tool Calling。
例如Agent调用数据库:
SELECT * FROM orders;
返回:
10000 rows
然后直接塞给LLM。
这基本等于主动制造Context灾难。
正确方式应该是:
Tool
↓
Raw Result
↓
Result Processor
↓
Structured Result
↓
Context
例如:
{
"total": 10000,
"status_distribution": {
"paid": 7820,
"pending": 1210,
"cancelled": 970
},
"recent_orders": [
{
"id": 10001,
"amount": 299
}
]
}
模型通常只需要知道:
数据意味着什么。
而不是:
数据库返回了什么。
十三、Tool Result应该具有Token Budget
可以给每一个工具设置最大Context预算:
tools:
order_query:
max_context_tokens: 1500
search:
max_context_tokens: 3000
database:
max_context_tokens: 2000
web_search:
max_context_tokens: 4000
超过预算:
Raw Result
↓
Filter
↓
Rank
↓
Summarize
↓
Context
这样可以防止一个异常Tool调用直接吞掉整个Context Window。
十四、上下文装配:Context Builder才是Agent的核心组件
生产级Agent应该拥有一个独立的Context Builder。
架构可以设计成:
┌───────────────┐
│ User Request │
└───────┬───────┘
↓
┌─────────────────┐
│ Context Builder │
└────────┬────────┘
│
┌──────────────────┼─────────────────┐
↓ ↓ ↓
User Memory Task State Retrieval
↓ ↓ ↓
└──────────────────┼─────────────────┘
↓
Context Ranking
↓
Context Compression
↓
Token Budget
↓
Prompt Assembly
↓
LLM
Go接口可以设计成:
type ContextBuilder interface {
Build(ctx context.Context, req BuildRequest) (*Context, error)
}
type BuildRequest struct {
UserID string
Conversation string
Query string
TokenBudget int
}
type Context struct {
System string
Memory []ContextItem
History []ContextItem
Retrieval []ContextItem
ToolResults []ContextItem
TaskState map[string]any
}
这样可以让Context成为独立基础设施,而不是散落在Agent代码中的大量字符串拼接。
十五、Token Budget:上下文工程的核心约束
假设模型Context Window为128K Token。
并不意味着:
128K全部给输入
还需要考虑:
System Prompt
+
Tools
+
Memory
+
History
+
Retrieval
+
Output
+
Reasoning
因此应该提前进行预算。
例如:
Context Window 128K
System 6K
Tools 12K
Memory 8K
History 20K
RAG 30K
Output Reserve 16K
-------------------------
Safety Margin 10K
最终:
实际Context Budget ≈ 26K
这比简单依赖模型的最大上下文限制安全得多。
OpenAI API文档也明确说明,当输入超过模型上下文限制时,可以采用截断策略;如果禁用截断,超过限制则会直接报错。([OpenAI 平台][2])
因此生产系统不应该把:
Context Limit
当成:
Application Budget
两者不是一回事。
十六、上下文压缩触发机制
不要每一轮都压缩。
可以采用阈值策略:
Token Usage < 60%
↓
正常运行
60% ~ 75%
↓
优先减少低价值Context
75% ~ 85%
↓
摘要历史 + 压缩Tool Result
> 85%
↓
强制Compaction
例如:
func NeedCompaction(used, limit int) bool {
return float64(used)/float64(limit) >= 0.80
}
更好的策略不是“达到100%再压缩”,而是提前留出安全区。
十七、Compaction:从截断升级为上下文重构
Compaction可以理解为:
把大量历史状态重新编码成更小、更高价值的上下文。
例如:
100轮Conversation
↓
事实提取
↓
任务状态
↓
关键决策
↓
未完成事项
↓
工具结果摘要
↓
20轮高价值Context
这比单纯删除旧消息可靠得多。
现代Agent平台也已经开始提供显式的Compaction能力。例如OpenAI Responses API中已经出现compaction相关对象,用于表示由上下文压缩产生的压缩项。([OpenAI 平台][2])
这意味着上下文压缩正在从“开发者自行拼Prompt的小技巧”,逐渐变成Agent Runtime的一等能力。
十八、Compaction必须保护关键事实
压缩过程中最重要的问题不是:
能压缩多少?
而是:
哪些信息绝对不能丢?
建议建立四级信息分类:
P0:不可丢失
P1:重要
P2:可压缩
P3:可删除
例如:
类型 | 等级 | 策略 |
|---|---|---|
用户明确业务约束 | P0 | 永久保存 |
已确认技术选型 | P0 | 结构化保存 |
当前任务状态 | P0 | 实时更新 |
重要工具结果 | P1 | 摘要 |
普通历史对话 | P2 | 压缩 |
寒暄 | P3 | 删除 |
重复信息 | P3 | 去重 |
这样Context Compaction就不再是“让模型总结”,而是一个有明确策略的状态转换过程。
十九、Context Update:上下文必须持续更新
很多Agent系统只关注:
Context → LLM
却忽略:
LLM → Context
实际上Agent每次运行之后都应该更新状态。
完整流程:
Request
↓
Build Context
↓
LLM
↓
Tool Calls
↓
Result
↓
State Update
↓
Memory Extraction
↓
Context Store
例如Agent完成一次任务:
{
"event": "payment_design_completed",
"decision": {
"provider": "wechat",
"callback": "async",
"idempotency": true
}
}
这个事件应该进入Task State。
而不是仅仅留在聊天记录里。
二十、Event Sourcing思路可以用于Agent状态管理
对于复杂Agent,可以把每一次重要变化记录为Event:
{
"event_id": "evt_10001",
"type": "decision_made",
"timestamp": "2026-08-13T09:20:00Z",
"payload": {
"database": "mysql"
}
}
连续事件:
TaskCreated
↓
DatabaseSelected
↓
PaymentSelected
↓
ArchitectureCompleted
↓
CodeGenerated
↓
TestCompleted
然后可以从Event重建Agent State。
这对于:
长任务;
多Agent协作;
Agent恢复;
故障重试;
审计;
Debug;
都非常有价值。
二十一、多Agent系统中的上下文工程
多Agent架构还有一个特殊问题:
Agent之间应该共享多少上下文?
最危险的设计是:
Agent A全部Context
↓
Agent B全部Context
↓
Agent C全部Context
这样不仅Token成本高,而且会产生严重的信息污染。
更好的方式是:
Agent A
↓
Task Result
↓
Structured Handoff
↓
Agent B
例如:
{
"task": "architecture_analysis",
"result": {
"backend": "Go",
"database": "MySQL",
"cache": "Redis"
},
"confidence": 0.92,
"open_questions": [
"是否需要消息队列"
]
}
Agent B不需要知道Agent A的全部思考过程,只需要获得:
结论
依据
约束
未解决问题
这就是Context Isolation。
二十二、不要把Chain-of-Thought当成Context数据库
一个非常重要的工程原则是:
模型推理过程和业务状态不是一回事。
Agent真正需要长期保存的应该是:
事实
决策
约束
任务状态
工具结果
最终结论
而不是:
模型所有中间推理文本
这样可以显著降低Context体积,同时提高状态稳定性。
对于复杂任务,更推荐保存:
{
"decision": "使用Redis作为缓存",
"reason": "降低高频读取数据库压力",
"source": "architecture_analysis",
"confidence": 0.91
}
而不是保存大量自然语言推理过程。
二十三、Prompt Cache与Context Engineering
上下文工程还有一个经常被忽略的经济因素:
相同Context是否可以被缓存?
如果一个Agent每次请求都发送:
10K System Prompt
+
20K Tools
+
30K Business Knowledge
+
2K User Query
其中前60K几乎完全不变,那么最合理的设计是让稳定前缀保持稳定。
可以组织为:
[Stable Prefix]
System
Tools
Business Rules
Static Knowledge
[Dynamic Context]
Memory
Task State
RAG
Tool Results
[User Query]
这样可以同时获得:
更好的Prompt Cache命中;
更低输入Token成本;
更低延迟;
更稳定的上下文结构。
OpenAI文档明确提供了缓存Token使用量等指标,API响应中可以看到cached_tokens等Usage信息,因此生产系统可以直接监控缓存命中效果。([OpenAI 平台][2])
二十四、上下文成本模型
可以把一次Agent调用成本抽象为:
[
Cost =
C_{input}
C_{cached}
C_{output}
C_{tool}
C_{retrieval}
]
如果每次请求都把100K历史上下文重新发送,那么即使模型性能没有问题,成本也可能迅速增长。
更值得关注的是:
[
TotalCost =
\sum_{t=1}^{N}
ContextTokens_t
\times
Price
]
所以优化Agent成本最直接的方法之一,不是简单更换便宜模型,而是:
减少无效Context Token。
二十五、上下文工程的缓存架构
推荐设计三级缓存:
┌──────────────┐
│ L1 Memory │
│ Local/Process│
└──────┬───────┘
↓
┌──────────────┐
│ L2 Redis │
│ Hot Context │
└──────┬───────┘
↓
┌──────────────┐
│ L3 Database │
│ Long Memory │
└──────────────┘
例如:
L1:
当前请求Context
L2:
最近任务State、短期Memory
L3:
用户长期记忆、历史任务、知识数据
检索顺序:
L1 → L2 → L3 → Vector Search
这样能够减少大量无意义查询。
二十六、Context Store数据库设计
可以建立:
CREATE TABLE agent_context (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
session_id VARCHAR(64) NOT NULL,
context_type VARCHAR(32) NOT NULL,
content TEXT NOT NULL,
importance FLOAT DEFAULT 0,
relevance FLOAT DEFAULT 0,
token_count INT DEFAULT 0,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
);
其中:
context_type
可以是:
system
memory
fact
decision
task_state
tool_result
summary
retrieval
这样后续可以针对不同类型采用不同策略。
二十七、推荐的Agent Context架构
综合前面的设计,一个比较完整的企业级架构可以是:
┌─────────────────────┐
│ User Input │
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Query Understanding │
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Context Builder │
└──────────┬──────────┘
│
┌───────────────────────┼───────────────────────┐
↓ ↓ ↓
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Short Memory │ │ Long Memory │ │ Retrieval │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└───────────────────────┼───────────────────────┘
↓
┌─────────────────────┐
│ Context Ranking │
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Token Budget Manager│
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Context Compaction │
└──────────┬──────────┘
↓
┌─────────────────────┐
│ Prompt Assembly │
└──────────┬──────────┘
↓
┌─────────────────────┐
│ LLM │
└──────────┬──────────┘
↓
┌─────────────┴─────────────┐
↓ ↓
Tool Calling Final Answer
↓
Result Processing
↓
State Update
↓
Memory Extraction
↓
Context Store
二十八、一个可落地的Context Builder实现
下面给出一个简化的Go实现:
type ContextManager struct {
MemoryStore MemoryStore
Retrieval Retriever
Compressor Compressor
Tokenizer Tokenizer
}
func (m *ContextManager) Build(
ctx context.Context,
req BuildRequest,
) (*Context, error) {
memory, err := m.MemoryStore.Search(
ctx,
req.UserID,
req.Query,
)
if err != nil {
return nil, err
}
docs, err := m.Retrieval.Search(
ctx,
req.Query,
10,
)
if err != nil {
return nil, err
}
context := &Context{
Memory: memory,
Retrieval: docs,
History: req.History,
TaskState: req.TaskState,
}
tokens := m.Tokenizer.Count(context)
if tokens > req.TokenBudget {
context, err = m.Compressor.Compress(
ctx,
context,
req.TokenBudget,
)
if err != nil {
return nil, err
}
}
return context, nil
}
关键点不是代码本身,而是:
Build
↓
Count
↓
Budget
↓
Compress
Context Manager应该拥有明确的Token预算控制能力。
二十九、Context Compression不要只看Token压缩率
一个压缩器如果:
原始:10000 Token
压缩:1000 Token
看起来非常优秀。
但如果压缩后丢失:
数据库选型
支付方式
关键业务约束
那么这个压缩器实际上是失败的。
因此应该定义:
[
Compression\ Efficiency =
\frac{Useful\ Information\ Retained}
{Context\ Tokens}
]
而不是:
[
Compression\ Ratio =
\frac{CompressedTokens}
{OriginalTokens}
]
真正优秀的Context压缩应该做到:
Token ↓
信息密度 ↑
任务成功率不下降
三十、建立Context Evaluation体系
生产环境中不能只测试:
回答是否正确?
还应该测试:
1. Context Recall
关键事实是否被保留?
2. Context Precision
加入的上下文是否真正有用?
3. Context Utilization
模型是否正确使用上下文?
4. Compression Loss
压缩前后任务成功率下降多少?
5. Token Efficiency
完成相同任务需要多少Token?
6. Cache Hit Rate
稳定Context的缓存命中率是多少?
三十一、Lost in the Middle应该成为测试项
长Context测试不能只把正确答案放在:
开头
或者:
结尾
而应该测试:
10%
30%
50%
70%
90%
不同位置。
因为研究显示,长上下文模型在关键证据位于中间位置时可能出现明显性能下降。([arXiv][1])
因此Agent评测数据集应该专门设计:
Long Context
+
Distractors
+
Position Shift
+
Multiple Relevant Facts
测试模型是否真的使用了Context,而不是只依赖最近几条消息。
三十二、一个生产级Context策略
对于绝大多数企业Agent,可以从下面这套策略开始:
System Prompt
↓
稳定不变
Tool Definition
↓
稳定不变
User Profile
↓
只保留长期有效信息
Task State
↓
结构化存储
Recent History
↓
保留最近5~20轮
Long History
↓
Summary
RAG
↓
Top-K + Rerank
Tool Result
↓
结构化 + 摘要
Context
↓
Token Budget
超过阈值
↓
Compaction
这比单纯使用:
messages = 全部历史消息
可靠得多。
三十三、常见错误与反模式
33.1 把所有聊天记录全部发送
这是最常见的问题。
结果:
Token成本 ↑
延迟 ↑
噪声 ↑
相关性 ↓
模型注意力分散
33.2 把RAG结果全部塞给模型
RAG应该解决:
不知道
而不是:
什么都给模型
检索系统必须承担过滤责任。
33.3 只使用Summary,不保存原始事实
Summary有损压缩。
因此重要事实应该独立保存:
Fact Store
+
Summary
而不是:
只有Summary
33.4 让Tool直接返回巨大文本
应该:
Tool
↓
Result Processor
↓
Structured Data
↓
LLM
33.5 Context没有Token Budget
如果Context没有Budget,它迟早会失控。
所有生产Agent都应该能够回答:
当前Context多少Token?
各模块占多少?
哪部分最占Token?
哪些Context被压缩?
哪些Context被丢弃?
三十四、Context Observability:必须知道模型到底看到了什么
Agent日志不能只记录:
request
response
至少应该记录:
{
"session_id": "sess_001",
"model": "xxx",
"input_tokens": 18240,
"cached_tokens": 12100,
"output_tokens": 1300,
"context": {
"system": 3200,
"memory": 900,
"history": 4200,
"retrieval": 6800,
"tools": 2400,
"task_state": 740
},
"compaction": {
"triggered": true,
"before": 31000,
"after": 14200
}
}
这样出现:
“Agent为什么忘记用户刚才说的话?”
时,工程师才能真正定位:
是没有检索?
还是排序错误?
还是Context被压缩?
还是Token Budget不足?
还是Tool结果覆盖?
还是模型没有正确利用Context?
三十五、推荐的Context工程目录结构
对于Go Agent项目,可以采用:
agent/
├── context/
│ ├── builder.go
│ ├── budget.go
│ ├── ranking.go
│ ├── compression.go
│ ├── summarizer.go
│ └── policy.go
│
├── memory/
│ ├── short_term.go
│ ├── long_term.go
│ ├── vector.go
│ └── store.go
│
├── retrieval/
│ ├── search.go
│ ├── reranker.go
│ └── filter.go
│
├── state/
│ ├── state.go
│ ├── event.go
│ └── reducer.go
│
├── tools/
│ ├── registry.go
│ ├── executor.go
│ └── result_processor.go
│
├── agent/
│ ├── runner.go
│ └── planner.go
│
└── observability/
├── tracing.go
├── metrics.go
└── context_log.go
这样的架构可以把Context从Agent业务逻辑中解耦出来。
三十六、从Prompt Engineering走向Context Engineering
Prompt Engineering解决的是:
怎么告诉模型做什么
Context Engineering解决的是:
模型现在应该知道什么
两者并不是替代关系,而是上下游关系:
Prompt Engineering
↓
Instruction
Context Engineering
↓
Information
Agent Runtime
↓
Execution
LLM
↓
Decision
未来Agent系统的竞争力,很大程度上不再取决于谁写了一段更漂亮的System Prompt,而取决于谁能构建更加可靠的Context Runtime。
三十七、企业级落地路线
如果从零开始建设Context Engineering体系,不建议一开始就做得非常复杂。
可以分四个阶段。
第一阶段:基础Context
实现:
System Prompt
+
Recent History
+
Token Counting
目标:
防止Context无限增长。
第二阶段:Memory + State
加入:
Short Memory
Long Memory
Task State
目标:
不再依赖完整聊天记录保存任务状态。
第三阶段:Retrieval + Compression
加入:
RAG
Rerank
Summary
Compaction
Tool Result Compression
目标:
在有限Token下提升信息密度。
第四阶段:Context Runtime
最终建设:
Context Builder
Context Policy
Context Budget
Context Ranking
Context Compression
Context Cache
Context Observability
Context Evaluation
这时候Context已经不再是Agent代码中的一个变量,而成为独立基础设施。
三十八、结语:Agent的核心不是记住一切,而是知道此刻需要什么
长上下文解决的是:
模型能够容纳多少信息。
上下文工程解决的是:
模型应该看到哪些信息。
这是两个完全不同的问题。
一个128K甚至更大的Context Window,并不能自动解决长对话中的“遗忘”、RAG噪声、Tool结果膨胀和Token成本问题。已有研究表明,长上下文模型依然可能受到信息位置和上下文长度的影响。([arXiv][1])
因此,一个真正成熟的Agent应该遵循这样的上下文原则:
不是保存所有信息
↓
而是保存重要信息
不是检索所有文档
↓
而是检索相关信息
不是发送所有工具结果
↓
而是发送有效结果
不是无限扩大Context
↓
而是管理Context Budget
不是简单删除历史
↓
而是进行结构化Compaction
不是让Conversation承担全部状态
↓
而是Conversation + State + Memory
不是只看模型输出
↓
而是观察整个Context Pipeline
最终可以把Agent上下文工程浓缩成一个公式:
[
Agent\ Intelligence
\approx
Model\ Capability
\times
Context\ Quality
\times
State\ Consistency
]
模型决定Agent的上限,而上下文决定模型在具体任务中能够发挥多少能力。
对于生产环境而言,真正值得投入的不是把Prompt再写长一点,而是建立一套完整的Context Runtime:能够检索、筛选、排序、压缩、缓存、更新和观测上下文,并且始终围绕当前任务的Token预算做信息取舍。
当Agent从“聊天机器人”升级到能够连续运行数小时、数天甚至数周的业务系统之后,上下文工程就不再是优化项,而会成为Agent架构中与模型、工具、记忆和工作流同等重要的基础设施。
参考资料
Nelson F. Liu, Kevin Lin, John Hewitt, Ashwin Paranjape, Michele Bevilacqua, Fabio Petroni, Percy Liang. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172, 2023. ([arXiv][1])
OpenAI API Documentation. Responses API / Streaming Events / Context Truncation / Compaction / Prompt Caching. OpenAI API官方文档
OpenAI. Data controls in the OpenAI platform. OpenAI Platform Documentation. OpenAI Platform官方文档
[1]: https://arxiv.org/abs/2307.03172?utm_source=chatgpt.com "Lost in the Middle: How Language Models Use Long Contexts"
[2]: https://platform.openai.com/docs/api-reference/responses-streaming/response/refusal/delta?lang=curl&utm_source=chatgpt.com "Streaming events | OpenAI API Reference"