文章

Context Engineering 生产实战:把 Agent 上下文窗口当成资源调度

上下文工程不是把资料塞满窗口,而是围绕任务目标动态选择指令、记忆、工具结果和检索片段,让 Agent 在长任务中保持可靠、可控和低成本。

背景问题: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。它负责做五件事:

  1. 根据任务类型选择系统指令
  2. 根据当前状态选择消息历史
  3. 根据权限和任务选择工具
  4. 根据问题选择证据和记忆
  5. 根据 token 预算做压缩和降级

一个简单的上下文预算可以这样分配:

上下文部分建议用途风险
System / Developer 指令行为边界、角色、输出规则过长会变成难维护的隐式代码
用户请求当前目标和约束多轮对话中可能被旧目标污染
短期历史最近决策和对话连续性原样保留会快速膨胀
检索证据外部知识和项目资料Top-K 噪声会干扰判断
工具结果外部执行反馈原始日志通常 token 密度低
长期记忆偏好、稳定事实、项目规则过期记忆会导致错误个性化

2. 工具不是越多越好

工具描述本身也占上下文。更重要的是,工具之间如果功能重叠,模型会在选择工具时出现不稳定行为。

更可靠的做法是:

  • 每次只暴露当前任务需要的工具
  • 工具名称使用动词加对象,例如 search_project_docscreate_gmail_draft
  • 工具描述写清楚使用边界和失败条件
  • 工具输出返回结构化摘要,不返回大段原始日志
  • 对高风险工具增加审批或策略检查

这与 12-Factor Agents 中”own your context window”和”tools are just structured outputs”的思路一致:Agent 不是一个无限自由循环,而是由普通软件控制流包裹的一组模型决策点。

3. 长任务需要压缩、笔记和子任务隔离

长任务最容易出现上下文腐化:前面几轮的工具输出、错误重试和中间讨论持续累积,模型后来会抓错重点。

常用的三种处理方式:

  • Compaction:当消息历史接近阈值时,把历史压缩成高保真摘要,保留目标、约束、已完成动作、未解决问题和关键证据。
  • Structured Notes:让 Agent 把长期有效的信息写入结构化笔记,例如 plan.mddecisions.mdopen_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压缩或中断恢复后的任务成功率

参考资料

  1. Anthropic Engineering, “Effective context engineering for AI agents”, 2025-09-29: https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
  2. LangChain Docs, “Context engineering in agents”: https://docs.langchain.com/oss/python/langchain/context-engineering
  3. OpenAI Agents SDK, “Sessions”: https://openai.github.io/openai-agents-python/sessions/
  4. OpenAI Agents SDK, “Context management”: https://openai.github.io/openai-agents-python/context/
  5. HumanLayer, “12-Factor Agents”: https://github.com/humanlayer/12-factor-agents
  6. Seyedmoein Mohsenimofidi et al., “Context Engineering for AI Agents in Open-Source Software”, arXiv 2025: https://arxiv.org/abs/2510.21413
  7. Shihao Weng et al., “ARGUS: Defending LLM Agents Against Context-Aware Prompt Injection”, arXiv 2026: https://arxiv.org/abs/2605.03378
  8. Shijie Xia et al., “Diagnosing and Mitigating Context Rot in Long-horizon Search”, arXiv 2026: https://arxiv.org/abs/2606.29718

常见问题

Context Engineering 和 Prompt Engineering 有什么区别?
Prompt Engineering 更关注如何写好指令;Context Engineering 关注每次模型调用时到底放入哪些信息,包括系统提示、消息历史、工具列表、检索内容、记忆和运行状态。
上下文窗口越大,Agent 就越可靠吗?
不一定。更大的窗口能容纳更多信息,但也会带来注意力稀释、噪声累积、成本上升和调试困难。生产系统仍需要筛选、压缩、隔离和监控上下文。
什么时候应该使用长期记忆,而不是把历史消息全部塞进上下文?
当信息跨会话复用、频繁影响决策、且可以被结构化描述时,适合进入长期记忆;临时工具输出、重复日志和过期中间过程则应压缩或丢弃。