跳转到内容

Context Engineering 怎么做:别把所有信息都塞给模型

Context Engineering 负责决定模型这一步该看到什么。 输入材料的选择会影响质量、成本和延迟。Prompt Engineering 关注“指令这句话怎么写”,Context Engineering 关注整个上下文里应该放什么、不放什么:材料太少,模型找不到依据;什么都塞进去,关键约束会被无关内容淹没,费用和延迟同步上升。

管理的办法是按职责分层:系统规则保持稳定,当前任务状态结构化保存,RAG 为当前问题取证,Memory 只留未来有价值的事实,工具结果先摘要再附引用,接近预算时做可审计的压缩。有两条边界要放在最前面:压缩摘要是有损视图,关键事实和终态必须能回到原始 trace 与结构化状态核对;权限永远由执行层强制检查,写进上下文不等于真的被约束。

假设 Agent 的任务是“生成并提交月度报告”。两种做法的差别:

  • 全量塞入:系统提示里堆全部业务文档,聊天记录原样保留,工具每次返回完整日志。第一轮尚可,到第十轮预算耗尽,“发布前必须人工确认”这类关键约束被淹没在日志里。
  • 按职责加载:每轮只组装当前决策需要的信息,完整数据按引用回查。

按职责加载时,这个任务的上下文大致是:

系统规则 → 职责边界、输出契约(稳定,可缓存)
任务状态 → 目标、约束、当前步骤(结构化 JSON)
最近对话 → 用户最新指令与澄清
检索结果 → 本月指标口径文档片段(带来源)
记忆 → 用户确认过的报表格式偏好
工具结果 → 指标查询摘要 + 完整数据引用
输出预留 → 生成报告草稿所需 token

其中任务状态是一个结构化对象,每轮只把当前决策需要的字段放进上下文,也更容易持久化和恢复:

{
"goal": "生成并提交月度报告",
"constraints": [
"只使用已批准数据源",
"发布前必须人工确认"
],
"completed": [
"collect_data"
],
"current_step": "validate_metrics",
"open_questions": [
"是否排除测试租户"
],
"artifacts": {
"raw_metrics": "artifact://metrics-123"
}
}

工具输出也采用“摘要 + 引用”。下面用测试日志说明结构,需要细节时再读完整记录:

{
"summary": "3 个测试失败,均与时区有关",
"items": [
{
"test": "scheduleAtMidnight",
"error": "expected UTC+8, got UTC"
}
],
"truncated": true,
"artifact_uri": "artifact://test-log-456"
}
层负责不应该负责
System Prompt稳定角色、边界、决策原则长篇业务知识、动态状态
Task State当前目标、约束、已完成步骤用户全部历史
Conversation当前交互所需的近因信息永久记忆
RAG从外部知识中即时检索证据保存用户长期偏好
Memory跨会话保存经过筛选的事实和经验原样堆积聊天记录
Tool Result支撑下一次决策的最新观察无限日志、完整二进制
层该做不该做
System Prompt写职责、允许/禁止动作、不可信内容处理、停止条件、输出契约;计算版本号并让评测对应版本塞全部 API 文档、客户资料、每轮都变的任务状态、数百条相互冲突的边缘规则
Task State结构化保存目标/约束/进度,便于持久化和恢复用聊天历史隐式承载任务状态
RAG查询改写 → 权限过滤 → 混合召回 → rerank → 去重和多样性 → 片段压缩 → 来源引用 → 证据不足时明确返回不足只用向量相似度(产品名、错误码、订单号等精确实体需要关键词或结构化查询);把检索结果当可信指令
Memory区分偏好、事实、情景、程序等类型;写入前做候选提取 → 类型判断 → 来源验证 → 敏感数据检查 → 租户绑定 → 去重合并 → 过期策略原样堆积聊天记录;让模型通过普通对话修改身份、权限等受保护状态
Tool Result结构化摘要 + 截断标记 + artifact 引用每轮附完整日志或二进制内容
Compaction压缩为已确认事实、已完成步骤、未解决问题、关键工具结果引用、用户最新约束、已否决方案及原因;摘要与原始 trace 分开保存把摘要当事实来源;让压缩把“不确定”变成“确定”或丢失否定词

三条容易被忽略的横切问题:

  • Just-in-time 加载:不要在任务开始时把所有可能相关的信息都放进来。让 Agent 通过受限工具按需获取——先看目录和摘要,再选相关对象,必要时继续深入。这和工程师先看 tree 再打开相关文件,而不是一次 cat 整个仓库是同一个道理。
  • 检索结果不可信:检索到的内容同样是外部数据,不能改变系统权限和目标。
  • 缓存:稳定系统前缀、Tool Schema、文档解析结果、Embedding、权限过滤后的检索候选、确定性工具结果都可以缓存。缓存键至少包含内容哈希、模型或解析版本、租户与权限范围、数据版本、过期时间;不要跨用户复用含私有信息的 Prompt cache。

一轮决策的完整顺序大致是:

下一步重新加载任务状态与最新输入按需取相关资料组装必要上下文模型判断工具执行保存结果与进度

每步先判断是否已完成、是否仍在权限和预算内,需要继续时才进入下一轮。接近上下文预算时压缩旧轨迹并保留引用。压缩发生之后,高风险事实(金额、权限、终态)应从结构化状态或原始 trace 重新读取,而不是依赖摘要。

不要等上下文溢出才临时裁剪。原则是先预留输出,再分配输入。下面是一个自定示例(不是任何厂商的推荐配方,比例应按任务的检索密度和对话长度调整):假设有效窗口 100k tokens——

用途占比token
输出预留10%10k
系统规则与工具定义15%15k
当前任务状态15%15k
最近对话20%20k
检索与记忆30%30k
工具结果10%10k

配套监控比比例本身更重要:每一类上下文占用、每轮增长速度、被裁剪的信息、检索命中后是否真的被引用、上下文长度与成功率/延迟/成本的关系。

失败模式实际后果
上下文越长越好成本上升,关键指令反而被忽略
把 RAG 当 Memory当前取证和跨会话复用互相污染
把摘要当事实有损视图被当成终态,审计无法回溯
所有工具永远可见工具过多增加选择错误;应按任务阶段只暴露必要工具
把权限写进 Prompt权限必须由执行层强制,Context Engineering 解决不了这个问题

落地时可以从最朴素的路径开始:给上下文分类并记录 token 占用,把任务状态改成结构化对象,给工具输出加摘要与引用,RAG 加权限过滤,记忆加来源与过期,超预算时生成可审计的压缩,再用 eval 比较不同策略的任务成功率。

延伸阅读: