
上下文工程深度解析:从 KV Cache 到 Agent Skills 的技术原理与工程实践
本文基于开源技术书《深入理解 AI Agent》第二章,系统解析上下文工程的技术体系。该章是全书最关键的一章,从 API 消息结构出发,深入 KV Cache 底层原理,再依次展开提示工程、Agent Skills、Agent 状态栏和上下文压缩等核心技术。上下文工程是 Harness 中"上下文与工具"层面的核心实现,决定了 Agent 在每个决策点能看到什么信息、以什么结构看到这些信息。

上下文为什么是决定性因素
该章开篇即指出:大语言模型在标准测试中成绩亮眼,但到了实际业务场景中却常常让人失望。原因是模型执行具体任务时需要的背景信息(产品架构、业务规则、内部约定)根本不在通用模型的训练数据中。
一个中等能力的模型配上精心组织的上下文,往往能胜过一个顶级模型在信息匮乏下的盲目摸索。上下文工程因此成为利用现有模型开发高效 Agent 的关键所在。OpenAI 研究员翁家翌的观点被引用:“人和模型一样,最重要的是 Context。”
API 消息结构:上下文的工程骨架
理解上下文工程的基础是理解大模型 API 的消息结构。以 OpenAI Chat Completions API 为例,核心是一个消息列表,每条消息有一个角色标识:
- system:系统提示词,定义 Agent 身份和行为规则
- user:用户输入
- assistant:模型之前的回复(包括文本和工具调用)
- tool:工具执行结果,通过 tool_call_id 关联到对应的工具调用
此外,工具定义(tools)作为请求的独立字段,告诉模型有哪些工具可用。这意味着"四种消息角色 + tools 字段"恰好覆盖了第一章所说的五个上下文组成部分。
Agent 核心循环的实现
Agent 框架的核心工作就是管理这个 messages 列表:在合适的时机往里追加消息,然后把整个列表送给模型。核心逻辑只有一个 while 循环:模型返回了 tool_calls 就执行工具并继续循环,没有就输出结果并退出。

上下文由两部分组成:上半部分(System Prompt + Tool Definitions)在整个对话过程中保持不变,是静态前缀;下半部分(对话历史,即轨迹)随交互不断增长。这个"静态前缀 + 轨迹"的结构,是后续讨论 KV Cache 优化、上下文压缩等技术的基础。
KV Cache:前缀稳定性背后的底层原理
KV Cache 是该章技术密度最高的部分,其核心直觉是:模型每生成一个 token,都要回头看一遍前文所有 token 的中间计算结果。KV Cache 把前文的中间计算结果缓存下来,下一轮只需要计算新增 token 的部分。前提是要复用的上下文 token 前缀保持不变。
注意力机制与 QKV
理解 KV Cache 需要先理解注意力机制。每个新词生成自己的 Query(查询向量),与所有已有词的 Key(键向量)做点积计算匹配度,再用所有词的 Value(值向量)加权求和。如果每次都从头计算所有 K 和 V,计算量会随上下文长度不断增长。KV Cache 把已算过的 K 和 V 缓存起来,让新词直接复用。

一个关键发现是注意力储存池现象:序列第一个 token 往往吸收了异常高的注意力权重(有时超过 70%),因为 softmax 约束要求所有权重必须分配到某个地方,模型学会把剩余权重倾倒到固定位置。另一个重要模式是位置偏好:模型对上下文开头和结尾的信息分配更高注意力,中间部分更容易被忽视。
三条核心实践结论
该章提炼了三条即使跳过原理细节也必须记住的核心结论:
缓存失效的工程代价
一个真实案例说明了这些原则的工程意义:某团队客服 Agent 每天处理 10 万次对话,工程师在系统提示词里加了一行实时时间戳。第二天监控告警:所有对话的首 token 延迟从 0.5 秒涨到 3-5 秒,月度推理账单几乎翻倍。原因是那一行时间戳使每次请求的 token 序列从时间戳位置开始不同,该位置及之后的 KV 状态无法复用。
Chat Template 的作用
Chat Template 把 API 的结构化 JSON 消息转换为模型能理解的线性 token 流。用特殊标记(如 <|im_start|>system)划分每条消息的边界和角色。理解它的存在有两个实用价值:
第一,解释了为什么必须使用标准 API 格式——自行拼接消息会破坏模型训练时建立的优先级体系,导致思维链保留机制失效。
第二,解释了 KV Cache 为什么对前缀敏感——Chat Template 将 system 消息和工具定义转换为固定 token 序列放在最前面,这些 token 的 KV 被缓存后可跨请求复用,但前缀中任何位置的变化都会导致后续缓存失效。
缓存作为架构约束
在生产级 Agent 系统中,缓存不仅是性能优化手段,更是一个架构约束。Claude Code 的实践揭示了几个体现这种约束的设计决策:
- 提示词结构由缓存边界决定,动态元素必须放到边界之后
- 子 Agent 必须与父 Agent 字节级对齐以命中 Prompt Cache
- 工具结果的替换字符串在首次出现时就被冻结
核心启示是:在设计 Agent 架构时,缓存经济性不是事后优化,而是前置约束。
提示工程:系统提示词的设计方法
提示工程的核心对象是系统提示词——Agent 的"员工手册"。该章从多个维度讨论其优化方法。
结构化与流程驱动
现代大语言模型对结构化输入展现出显著敏感性。XML 标签提供机器可解析的精确语义,Markdown 提供人机共读的组织逻辑。两者配合可以形成双层结构。
更关键的是流程驱动优于规则堆砌。流程驱动的提示词让模型在任何时刻都能清楚知道自己处于哪个阶段、当前步骤的目标是什么、完成后该进入哪个步骤。该章的消融实验证实:打乱信息组织结构、去除标题层次后,任务成功率下降超过 30%。
业务规则细化
该章强调,业务规则细化不是技术问题,而是产品设计问题。以一个帮用户打电话处理账单的 Agent 为例,计费系统设计涉及三种模式的精确区分。模糊的规则会导致 Agent 行为极不稳定——“帮我取消 Netflix 订阅"到底算"省钱"还是"取回本属于用户的钱”?
核心设计哲学是:大语言模型的优势在于遵循复杂指令和从长上下文中提取信息,但不应该在业务规则制定上被赋予过多自由裁量权。在优秀的 Agent 公司里,提示词一般由产品经理来设计。
工具定义设计
工具定义的质量直接决定 Agent 使用工具的准确性。从 Claude Code 的工具定义可以观察到,每个描述都精心设计了使用边界、具体示例、性能提示和工具间协作关系。该章还揭示了工具定义正在向渐进式披露演进的趋势:OpenAI Responses API 提供 tool_search 和 defer_loading 标记,Anthropic 提供 Tool Search 机制,Codex CLI 默认开启 BM25 检索的 tool_search——这些机制都遵循"名称和简述常驻、完整 schema 按需追加到末尾"的设计原则。
提示注入防御
提示注入是 Agent 安全的核心威胁之一:攻击者通过 Agent 处理的外部内容(网页、邮件、文档)将伪装成系统指令的文本混入上下文。在 Agent 系统中这比普通聊天机器人更危险,因为 Agent 拥有工具调用能力,被注入的指令可能导致不可逆操作。
上下文层防御的核心是帮模型分清"指令"与"数据":来源标记(用 XML 标签包裹并标注来源)、结构化角色(严格利用 Chat Template 的角色体系传递信息)和输入清洗。但该章清醒地指出,上下文层只能降低攻击成功率,无法做到万无一失。
Agent Skills:渐进式披露的工程实现
随着 Agent 覆盖的业务场景越来越多,把所有知识塞进一个系统提示词会带来两个问题:浪费 token 和注意力被稀释。Agent Skills 采用渐进式披露的设计哲学——先给 Agent 看一份目录摘要,需要时再加载完整内容。

三层结构
每个 Skill 包含三个层次:
- 第一层(元数据):SKILL.md 开头的 YAML frontmatter,包含 name 和 description。目录在完整正文加载前对 Agent 可见,使其能判断当前任务是否需要某项能力。
- 第二层(核心流程):当 Agent 判断需要某个 Skill 时,运行时才加载完整的 SKILL.md。
- 第三层(细则):通过文件引用深入到更详细的子文档。
description 字段是路由决策的关键,写法应像路由条件而非功能介绍——"何时该用我"比"我能做什么"重要得多。
Skills 与 KV Cache 的关系
Skills 机制对 KV Cache 极为友好。完整 Skill 正文在被选中后追加到上下文末尾,而不是插回前缀。因果注意力决定了每个 token 的 KV 只依赖它之前的 token,因此在末尾追加新内容不会改变任何已缓存 token 的 K/V。新增的工具 schema 只需在首次出现时计算一次,此后就并入不断增长的"前缀",在后续所有轮次持续命中。
该章揭示了一个重要的工程原则:选择 Agent 交互模式时,应与模型厂商的训练方法保持一致。基础模型公司推行的 Agent 用法,本质上是它们专门训练过的模式。
Agent 状态栏:元信息注入机制
Agent 状态栏解决的是另一个独立问题:如何让 Agent 随时看到任务进度、环境变化和工具调用计数等运行时状态。

状态栏的理论基础是一个深刻洞察:上下文学习更像检索而非推理。模型擅长从已有内容中查找信息,但不擅长主动归纳和总结。上下文窗口是一台"只有一半的检索引擎"——检索这一半非常强,但没有"提炼层"。关于"已经打了几次电话"的知识没有被自动提炼出来,而是以原始通话记录的形式分散在 KV Cache 中,模型每次都要从原始信息中现算一遍。
状态栏的本质是把分散在上下文各处的隐式状态提炼为可直接使用的显式知识。实验表明,为模型提供一条提前算好的状态栏后,较小开源模型的准确率可以接近前沿大模型,且思考效率大幅提升——不带状态栏时思考量随上下文变长持续增长,带上状态栏后变得基本恒定。
状态栏的位置与缓存代价
Agent 状态栏在 API 层面是作为一条 user 角色的消息插入到上下文末尾的——而不是修改开头的 system 消息。原因正是 KV Cache 约束:修改 system 消息会破坏整个前缀的缓存。
状态更新有两种实现方式:每轮替换(移除旧状态、追加新状态,会使上次注入后的短后缀缓存失效)和持久追加(旧状态永久保留,对缓存完全友好但会累积陈旧状态)。选择取决于状态大小、更新频率和轨迹长度的权衡。
上下文压缩策略
随着多轮交互深入,上下文不断膨胀。该章指出压缩有三个截然不同的动机:
上下文腐化:隐蔽的质量衰减
该章引入了一个重要概念——上下文腐化(Context Rot)。这与上下文溢出是不同的问题:溢出是"装不下了",腐化是"装得下但找不到了"。无关的内容一旦占到上下文的大头,Agent 的决策质量就会明显下滑,但表面上还在正常工作,只是决策质量悄然下降。
压缩的设计原则是:与其期望模型从冗长上下文中自动学习,不如主动地、显式地进行知识提炼。
压缩与 KV Cache 的关系
压缩和 KV Cache 看似矛盾——前者要求修改上下文,后者要求前缀不变。关键在于理解压缩发生的时机和位置:压缩不是在单次 API 调用中修改上下文,而是在两次 API 调用之间由 Agent 框架对消息列表进行预处理。System Prompt 和 Tool Definitions 永远不动,压缩对象是对话历史中的 tool results,替换位置之后的缓存会失效但之前的仍然有效。

该章的实验对比了六种压缩策略,从无压缩到自适应窗口化。上下文感知压缩将 token 使用量减少了 75% 以上,而自适应窗口化策略通过阈值触发和批量压缩,在初期保持完整原始信息的同时控制了上下文增长。
子 Agent 上下文隔离:隔离优于压缩
一个更釜底抽薪的思路是让大体积的中间信息根本不进入主上下文。主 Agent 把会产生海量中间内容的任务委派给子 Agent,子 Agent 在自己的上下文中完成探索,只把结论性摘要回传。这本质上是用隔离代替压缩:压缩是有损的事后补救,隔离让噪声从一开始就与主上下文绝缘,主 Agent 的 KV Cache 前缀完全不受影响。
小结
上下文工程的主线是显式管理信息:API 消息结构定义骨架,稳定前缀提高 KV Cache 命中率,Prompt、Skills 和状态栏分别承载规则、按需知识与当前状态,压缩则在保留决策、约束、失败和来源的前提下提高历史信息密度。这些技术共同回答了一个核心问题:怎样以更低成本向模型提供一个信息充分的上下文,让 Agent 的通用思考能力得以在具体任务中充分发挥。
本文内容整理自开源技术书《深入理解 AI Agent》(bojieli/ai-agent-book),采用 Apache 2.0 许可证
网硕互联帮助中心




评论前必须登录!
注册