背景问题:Agent 失败常常不是模型不够强,而是上下文失控
很多团队在做 LLM Agent 时,会先关注模型选择、工具调用和提示词模板。但进入真实业务后,最难的问题通常不是”模型会不会调用工具”,而是模型在每一步调用时到底看到了什么。
一个 Agent 的上下文通常不只包含用户输入,它还可能包含:
- 系统提示词和开发者指令
- 多轮消息历史
- 可用工具列表和工具描述
- 工具调用结果
- RAG 检索片段
- 用户偏好、项目规则、权限信息
- 运行时状态、计划、待办事项和错误日志
如果这些信息被粗暴地拼到一起,短期看能跑通 Demo,长期看会出现四类问题:上下文污染、注意力稀释、成本失控、行为不可解释。这也是为什么 Context Engineering 正在从”提示词优化技巧”变成 Agent 工程中的核心基础设施。
Anthropic 在 2025 年的工程文章中把上下文称为 Agent 的”critical but finite resource”,并将 Context Engineering 定义为在推理时选择和维护最优 token 集合的策略。LangChain 文档也把”没有把正确上下文传给 LLM”列为 Agent 不可靠的主要原因之一。本文不把 Context Engineering 当成概念口号,而是把它拆成一个可以落地的生产系统设计问题。
核心原理:上下文窗口是一种生产资源
1. 上下文不是越多越好
LLM 的上下文窗口看起来像一个容量限制,本质上更像一个注意力预算。当输入越来越长时,模型需要在更多 token 之间建立关联,噪声、重复内容和过期中间状态都会争夺注意力。
在生产 Agent 中,常见错误是:
- 把完整聊天历史永远保留
- 把每次工具调用结果原样追加
- 把检索结果按相似度 Top-K 直接塞入
- 把所有工具都暴露给模型
- 把长期记忆、短期状态和运行时依赖混在一起
这些做法会让模型”看起来知道很多”,但真正需要做决策时,关键信号反而被淹没。
2. Context Engineering 的目标是高信号密度
可以把每次 LLM 调用前的上下文构建看成一个函数:
type ContextInput = {
userRequest: string;
systemPolicy: string;
shortTermState: AgentState;
longTermMemory: MemoryStore;
retrievedDocs: RetrievedChunk[];
toolResults: ToolResult[];
runtimePermissions: PermissionScope;
};
type ModelContext = {
instructions: string;
messages: Message[];
tools: ToolSpec[];
evidence: EvidenceBlock[];
workingNotes: string;
outputContract: JsonSchema;
};
function buildModelContext(input: ContextInput): ModelContext {
const evidence = selectHighSignalEvidence(input.retrievedDocs);
const compactedHistory = compactConversation(input.shortTermState.messages);
const toolSummary = summarizeToolResults(input.toolResults);
const tools = selectAllowedTools(input.runtimePermissions, input.userRequest);
return {
instructions: renderInstructions(input.systemPolicy, input.runtimePermissions),
messages: compactedHistory,
tools,
evidence,
workingNotes: input.shortTermState.currentPlan,
outputContract: buildOutputSchema(input.userRequest),
};
}
这个函数的目标不是”尽量多放”,而是让模型在当前步骤看到最小但足够的信息集合。
3. 上下文至少分成三类
工程上建议把上下文拆成三层,而不是统一拼接成一个大 prompt:
- Model Context:模型本次调用能看到的内容,包括指令、消息、工具、输出格式和检索证据。
- Tool Context:工具执行时可以访问的本地对象、用户身份、权限、数据库连接、运行时依赖。OpenAI Agents SDK 文档特别强调,运行时 context 对象本身不会发送给 LLM,它是工具、生命周期钩子和本地代码使用的应用上下文。
- Lifecycle Context:模型调用和工具调用之间的处理逻辑,包括摘要、裁剪、审批、日志、重试、错误压缩和安全检查。
这三类上下文如果不分开,最容易出现两个问题:一是把不该给模型看的敏感信息塞进 prompt;二是把只属于本地执行的依赖误认为模型知识。
工程落地:从”拼 Prompt”到”上下文调度器”
1. 为每次模型调用建立 Context Builder
生产系统不要让业务代码到处手工拼 prompt,而应该建立统一的 Context Builder。它负责做五件事:
- 根据任务类型选择系统指令
- 根据当前状态选择消息历史
- 根据权限和任务选择工具
- 根据问题选择证据和记忆
- 根据 token 预算做压缩和降级
一个简单的上下文预算可以这样分配:
| 上下文部分 | 建议用途 | 风险 |
|---|---|---|
| System / Developer 指令 | 行为边界、角色、输出规则 | 过长会变成难维护的隐式代码 |
| 用户请求 | 当前目标和约束 | 多轮对话中可能被旧目标污染 |
| 短期历史 | 最近决策和对话连续性 | 原样保留会快速膨胀 |
| 检索证据 | 外部知识和项目资料 | Top-K 噪声会干扰判断 |
| 工具结果 | 外部执行反馈 | 原始日志通常 token 密度低 |
| 长期记忆 | 偏好、稳定事实、项目规则 | 过期记忆会导致错误个性化 |
2. 工具不是越多越好
工具描述本身也占上下文。更重要的是,工具之间如果功能重叠,模型会在选择工具时出现不稳定行为。
更可靠的做法是:
- 每次只暴露当前任务需要的工具
- 工具名称使用动词加对象,例如
search_project_docs、create_gmail_draft - 工具描述写清楚使用边界和失败条件
- 工具输出返回结构化摘要,不返回大段原始日志
- 对高风险工具增加审批或策略检查
这与 12-Factor Agents 中”own your context window”和”tools are just structured outputs”的思路一致:Agent 不是一个无限自由循环,而是由普通软件控制流包裹的一组模型决策点。
3. 长任务需要压缩、笔记和子任务隔离
长任务最容易出现上下文腐化:前面几轮的工具输出、错误重试和中间讨论持续累积,模型后来会抓错重点。
常用的三种处理方式:
- Compaction:当消息历史接近阈值时,把历史压缩成高保真摘要,保留目标、约束、已完成动作、未解决问题和关键证据。
- Structured Notes:让 Agent 把长期有效的信息写入结构化笔记,例如
plan.md、decisions.md、open_issues.md。 - Sub-agent Isolation:复杂研究或代码迁移任务可以让子 Agent 独立探索,再只返回压缩结果,避免主 Agent 的上下文被大量细节污染。
压缩不是简单摘要,它需要明确保留和丢弃的策略:
compaction_policy:
keep:
- user_goal
- hard_constraints
- accepted_decisions
- unresolved_errors
- source_links
- next_actions
discard:
- duplicate_tool_logs
- obsolete_intermediate_outputs
- failed_attempt_details_after_summary
- irrelevant_small_talk
4. RAG 要从”取 Top-K”升级为”证据调度”
在 Agent 场景里,RAG 不应该只是向量检索 Top-K。更好的做法是把证据分成不同类型:
- 事实证据:官方文档、论文、规范
- 项目证据:代码、配置、接口说明
- 用户证据:当前需求、偏好、历史决定
- 运行证据:日志、指标、工具返回值
每类证据都应该有来源、时间、可信度和适用范围。模型最终回答时不一定要看到所有证据原文,但 Context Builder 必须知道为什么选择这些证据。
适用场景
Context Engineering 特别适合以下场景:
- Coding Agent:需要理解项目结构、测试命令、接口约束和历史修改决定
- 企业知识库问答:需要同时处理权限、时效性、引用来源和输出格式
- 客服 Agent:需要融合用户资料、订单状态、历史工单和业务规则
- 数据分析 Agent:需要在大型表、查询结果和中间图表之间保持任务连续性
- 多 Agent 研究系统:需要隔离探索上下文,并把结果压缩给主 Agent
如果只是一次性分类、摘要或简单问答,完整的 Context Engineering 平台可能过重。但只要任务进入多轮、工具调用、长历史、权限控制和可追溯交付,就应该把上下文管理前置设计。
常见误区
误区一:把上下文窗口当数据库
上下文窗口不是数据库,它是模型当前决策的工作记忆。长期事实应该存储在数据库、文件、向量库或记忆系统中,再按需取回。
误区二:认为长上下文模型可以省掉检索和压缩
长上下文模型降低了工程复杂度,但不等于可以忽略上下文质量。窗口越大,越需要处理噪声、重复和过期信息。
误区三:把所有工具一次性暴露给模型
工具越多,选择空间越大,错误调用和提示注入风险越高。生产系统应按任务、权限和阶段选择工具。
误区四:摘要只追求短
摘要的目标不是短,而是可继续执行。一个好的压缩结果应该让 Agent 知道当前目标、已完成工作、关键证据、风险和下一步。
误区五:忽略上下文安全来源
Agent 读取网页、邮件、文档、代码注释和工具返回值时,会遇到不可信内容。2026 年关于 context-aware prompt injection 的研究也强调,攻击者可以利用动态上下文影响 Agent 决策。因此上下文系统需要记录来源和可信边界。
上线检查清单与监控指标
上线前至少检查以下八项:
- 上下文预算:每类上下文是否有 token 上限和降级策略?
- 证据选择:检索结果是否有来源、时间、可信度和去重?
- 工具裁剪:是否只暴露当前任务需要的工具?
- 权限隔离:本地运行 context 是否和 LLM 可见 context 分离?
- 压缩策略:长任务是否有 compaction、笔记和恢复机制?
- 可观测性:是否记录每次模型调用看到的上下文摘要、工具列表和 token 用量?
- 安全边界:是否标记不可信上下文并限制其影响高风险工具调用?
- 回归评估:是否有固定任务集评估上下文裁剪前后的成功率、成本和延迟?
建议监控的关键指标:
| 指标 | 含义 |
|---|---|
context_tokens_per_call | 每次模型调用的上下文 token 数 |
evidence_utilization_rate | 被引用或影响答案的证据占比 |
tool_result_compression_ratio | 工具结果压缩比例 |
stale_memory_hit_rate | 命中过期记忆的比例 |
context_rebuild_latency | 构建上下文的耗时 |
agent_recovery_success_rate | 压缩或中断恢复后的任务成功率 |
参考资料
- Anthropic Engineering, “Effective context engineering for AI agents”, 2025-09-29: https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
- LangChain Docs, “Context engineering in agents”: https://docs.langchain.com/oss/python/langchain/context-engineering
- OpenAI Agents SDK, “Sessions”: https://openai.github.io/openai-agents-python/sessions/
- OpenAI Agents SDK, “Context management”: https://openai.github.io/openai-agents-python/context/
- HumanLayer, “12-Factor Agents”: https://github.com/humanlayer/12-factor-agents
- Seyedmoein Mohsenimofidi et al., “Context Engineering for AI Agents in Open-Source Software”, arXiv 2025: https://arxiv.org/abs/2510.21413
- Shihao Weng et al., “ARGUS: Defending LLM Agents Against Context-Aware Prompt Injection”, arXiv 2026: https://arxiv.org/abs/2605.03378
- Shijie Xia et al., “Diagnosing and Mitigating Context Rot in Long-horizon Search”, arXiv 2026: https://arxiv.org/abs/2606.29718