AI Context Management 实战:用 MCP 管理 Agent 上下文窗口
深入探讨如何利用 Model Context Protocol 有效管理 AI Agent 的上下文窗口,避免信息丢失和上下文溢出问题。
上下文窗口是 LLM 最宝贵的资源。每个 Token 都有成本,每次对话都有上限。当 AI Agent 需要处理大量外部信息时,如何高效管理上下文窗口成为关键挑战。MCP 的设计为这个问题提供了优雅的解决方案。
上下文窗口的挑战
LLM 的上下文窗口虽然在不断扩大(Claude 支持 200K Token),但在实际 Agent 场景中仍然经常遇到限制:
信息膨胀——当 Agent 调用多个工具时,每个工具返回的结果都会占用上下文空间。一次数据库查询可能返回数千行数据,一个文件读取可能返回数万字内容。
噪音干扰——过多的上下文不仅浪费 Token,还会降低 LLM 的推理质量。研究表明,当上下文过长时,LLM 对中间信息的关注度会显著下降(“迷失在中间”问题)。
成本累积——在 API 调用中,输入 Token 的费用与数量成正比。不必要的上下文直接增加运营成本。
MCP 的上下文友好设计
MCP 的架构天然有利于上下文管理:
按需获取
MCP 的工具调用是按需进行的——LLM 只在需要时才调用工具获取信息,而不是预先加载所有数据。这避免了不必要的上下文占用。
传统方式:预加载所有数据 → 上下文爆炸
MCP 方式:按需调用工具 → 精准获取所需信息
结构化返回
MCP 工具返回结构化的内容,Client 可以对返回结果进行后处理——截断、摘要或过滤——再注入到上下文中。
Resource 缓存
MCP 的 Resource 支持订阅和缓存机制。当 Resource 内容变化时,Server 会通知 Client,Client 可以只保留最新的版本。
上下文管理策略
策略一:结果截断
对工具返回的结果进行长度限制:
server.tool('search', '搜索文档', {
query: z.string(),
maxResults: z.number().default(5),
}, async ({ query, maxResults }) => {
const results = await doSearch(query);
const limited = results.slice(0, maxResults);
return {
content: [{
type: 'text',
text: limited.map(r => `${r.title}: ${r.summary}`).join('\n'),
}],
};
});
策略二:渐进式获取
先返回摘要,LLM 需要时再获取详情:
// 第一步:返回摘要列表
server.tool('list_documents', '列出文档摘要', {
directory: z.string(),
}, async ({ directory }) => {
const docs = await listDocs(directory);
return {
content: [{
type: 'text',
text: docs.map(d => `[${d.id}] ${d.title} - ${d.preview}`).join('\n'),
}],
};
});
// 第二步:按需获取详情
server.tool('read_document', '读取指定文档的完整内容', {
docId: z.string(),
}, async ({ docId }) => {
const doc = await getDoc(docId);
return {
content: [{ type: 'text', text: doc.content }],
};
});
策略三:上下文压缩
在 Client 端实现上下文压缩:
class ContextManager {
private maxTokens: number;
private messages: Message[] = [];
constructor(maxTokens: number = 100000) {
this.maxTokens = maxTokens;
}
addMessage(message: Message) {
this.messages.push(message);
this.trim();
}
private trim() {
let totalTokens = this.estimateTokens();
while (totalTokens > this.maxTokens && this.messages.length > 2) {
// 移除最早的工具调用结果
const idx = this.messages.findIndex(
m => m.role === 'tool'
);
if (idx >= 0) {
this.messages.splice(idx, 1);
} else {
break;
}
totalTokens = this.estimateTokens();
}
}
private estimateTokens(): number {
return this.messages.reduce(
(sum, m) => sum + (m.content?.length || 0) / 4,
0
);
}
}
策略四:智能摘要
当上下文接近限制时,用 LLM 对历史对话进行摘要:
async function summarizeContext(messages: Message[]): Promise<Message[]> {
const claude = new Anthropic();
const response = await claude.messages.create({
model: 'claude-haiku-4-20250414', // 使用小模型降低成本
max_tokens: 1000,
messages: [{
role: 'user',
content: `请将以下对话历史压缩为简明摘要,保留关键信息:\n\n${JSON.stringify(messages)}`
}],
});
return [{
role: 'user',
content: `对话摘要:${response.content[0].text}`
}];
}
MCP 工具设计中的上下文考量
返回精简数据
工具应该返回 LLM 真正需要的信息,而不是原始数据的全部:
// 差:返回所有字段
server.tool('get_user', {}, async ({ id }) => {
const user = await db.query('SELECT * FROM users WHERE id = ?', [id]);
return { content: [{ type: 'text', text: JSON.stringify(user) }] };
});
// 好:只返回相关字段
server.tool('get_user', {}, async ({ id }) => {
const user = await db.query(
'SELECT name, email, role FROM users WHERE id = ?', [id]
);
return { content: [{ type: 'text', text: JSON.stringify(user) }] };
});
支持分页
对于可能返回大量数据的工具,实现分页机制:
server.tool('list_issues', '列出项目 Issues', {
projectId: z.string(),
page: z.number().default(1),
pageSize: z.number().default(10),
}, async ({ projectId, page, pageSize }) => {
const issues = await getIssues(projectId, page, pageSize);
const total = await getIssueCount(projectId);
return {
content: [{
type: 'text',
text: JSON.stringify({
issues,
pagination: {
page,
pageSize,
total,
hasMore: page * pageSize < total,
},
}),
}],
};
});
常见问题(FAQ)
上下文窗口大小对 MCP 有影响吗?
有。上下文窗口越大,MCP 工具可以返回的数据越多。但在实际使用中,仍然建议控制返回数据量,因为过多信息会降低 LLM 推理质量。
如何监控上下文使用量?
在 Client 端统计每次请求的 Token 数量。Claude API 的响应中包含 usage 字段,显示输入和输出的 Token 数。
Resource 和 Tool 在上下文管理上有什么区别?
Resource 的内容可以被 Client 缓存和管理,适合静态或低频变化的数据。Tool 的结果是临时的,每次调用都会占用新的上下文空间。
总结
上下文管理是 MCP Agent 开发中的关键技能。通过按需获取、结果截断、渐进式加载和智能摘要等策略,你可以在有限的上下文窗口中最大化 Agent 的能力。
MCP 的架构设计为此提供了良好的基础——工具的按需调用、结构化返回和 Resource 缓存机制,都是为高效的上下文管理而生的。