1918 字
约 6 分钟
11
S21-J09 · 上下文工程:静态前缀、轨迹与压缩

适用读者:做过"加提示词没效果"的调优、要把长会话 Agent 做稳、要压 token 成本的人。
前置:S21-J08(Agent 定义)、J06(编排);S20-J02(token 预算)。
覆盖旧文:A-4568(上下文工程,第 2 章,62,503 字符)→ 43 小节 / 约 6.3 万字符。
扩展点:E-S21-029(上下文三要素:代码/流程/环境)、E-S21-030(静态前缀 + 轨迹:为什么"前面不能动")、E-S21-031(压缩前必须保留的四类内容)。
上一篇:S21-J08 · 现代 Agent 的定义:LLM + 上下文 + 工具
下一篇:S21-J10 · 用户记忆与知识库。


1. 一句话结论

Agent 的请求结构永远是"静态前缀 + 动态轨迹"。 静态前缀(system prompt + 工具定义)在多轮间不变,轨迹(用户消息、模型回复、工具结果)不断增长。这一条结构决定了:前缀可以缓存,轨迹必须压缩——也就是"前面不能动、后面可以压"。

出处:《AI Agent 深入理解》第 2 章(A-4568)。

messages = [system] + tools_schema + [user, assistant(tool_calls), tool, …, status]
                                 └────── 轨迹(每轮增长)──────┘

2. 为什么"上下文质量"比"模型大小"更常是瓶颈(E-S21-029)

新工程师能力再强,不了解产品架构、业务规则、技术债,也发挥不出来。Agent 是永远的新员工。以一个 Coding Agent 为例,最低信息需求有三类:

类 内容 缺了会怎样
代码信息 目录结构、模块职责、数据结构、代码规范 语法对、风格错,甚至架构冲突
流程规范 分支策略、提交规范、Review 流程、CI 要求 直接往主分支提未测代码
环境信息 配置、测试库地址、部署方式、密钥管理 本地过、测试环境崩

判据:"给足背景它能干得很好,什么都不告诉它再聪明也白搭"。 而且这首先是组织问题——知识若只存在人的记忆和私聊里,Agent 无从获取。

对远程友好 = 对 Agent 友好:Linux 内核三十年的公开邮件列表、决策全记录,天然构成"信息可检索、结构化"的环境。

形式化定义(ReAct 原文):

策略 π(a_t | c_t),其中 c_t = (o_1, a_1, …, o_{t-1}, a_{t-1}, o_t)

要点:下一步动作依赖截至当前的完整交互上下文,不是眼前这一条输入。


3. 上下文在 API 层的构成(E-S21-030)

四类角色,缺一不可:

role 谁产生 作用
system 开发者 静态前缀:身份、规则、输出约束
user 用户/上游 任务输入
assistant 模型 文本或 tool_calls
tool 框架 按 tool_call_id 回填执行结果
第 1 次调用前: [system, user]
模型返回工具调用后: + assistant(tool_calls)
框架执行完:         + tool(call_abc), tool(call_def)
第 2 次调用后:      + assistant(最终回复) → 循环结束

这条轨迹的观察:Agent 框架的工作就是往列表里"按时追加"——追加错了(顺序、id、配对)模型就会出现"工具结果对不上调用"的幻觉。

3.1 为什么"前面不能动"

位置 变化频率 能否缓存
system prompt 一次会话内不变 可缓存
工具定义 会话内不变(除非动态工具) 可缓存
轨迹前半 已定稿 可缓存(只要不改写)
轨迹后半 每轮追加 不能缓存

判据:任何"改写历史"的操作都会让缓存前缀失效。 压缩要尽量从"轨迹尾部往前"做,且压缩后保持前缀稳定(J22 的 KV 命中同理)。


4. 每轮请求前,其实只做一次"上下文构造决策"(E-S21-031)

stable_prefix = system_message
stable_tools  = core_tool_schemas
trajectory    = load_message_history(session)
status        = make_status_message(derive_current_state(trajectory))

if estimated_tokens(stable_prefix, trajectory, status) > budget:
    trajectory = compress_old_evidence(
        trajectory,
        preserve=[decisions, constraints, failures, citations],
    )

request.messages = [stable_prefix] + trajectory + [status]

压缩时必须保留的四类:

保留 为什么
决策(已定的方案) 否则模型会反复推翻自己
约束(规则、边界) 否则越界操作
失败(试过且失败的路) 否则重复踩坑,烧 token
引用(文件路径、行号、来源) 否则无法复查

可以丢的:重复的原始输出、已被结论替代的中间读数、寒暄。

判据:压缩的目标不是"变短",是"保住可继续工作的最小状态"。 把"失败记录"压掉,是最常见的自伤。


5. 预算与触发时机

策略 触发 风险
固定阈值(如 70% 预算) 简单 阈值太高 → 贴近上限抖动
每轮增量预算 平滑 实现复杂
按任务阶段压缩 阶段边界清晰 阶段识别错 → 压早了
预算 = 上下文窗口 − 预留输出 token − 安全余量

判据:先扣掉"输出预留"再谈压缩。把窗口塞满,模型没有空间生成,会截断或报错。


6. 反例与排障

现象 根因 处理
长会话后"忘记约定" 约束被压掉 约束进静态前缀或状态消息
反复试同一条死路 失败记录被删 preserve 加 failures
成本忽高忽低 前缀被改写 → 缓存失效 固定前缀,压缩只动尾部
工具结果错位 tool_call_id 配对错 严格按 id 回填
输出被截断 没留输出预算 预算公式先扣预留

7. 常见误区

误区 纠正
"上下文就是提示词工程" 它是信息供给系统(含工具结果、状态、历史)
"塞更多信息总没坏处" 噪声会挤掉关键约束,且烧钱
"压缩就是摘要" 摘要会丢"失败/引用",要按四类保留
"历史可以随便改" 改历史 = 缓存全失效
"团队文档与 Agent 无关" 文档化是 Agent 的前置条件

8. 自测

  1. 上下文在 API 层的两个部分是什么?哪部分可缓存?
  2. 压缩时必须保留哪四类内容?举例说明丢"失败"的后果。
  3. 为什么把窗口塞满会出问题?
  4. ReAct 的 c_t 包含什么?为什么强调"完整交互上下文"?
答案
  1. 静态前缀(system + 工具定义,可缓存)与动态轨迹(不可缓存)。
  2. 决策、约束、失败、引用;丢失败 → 重复踩坑、烧 token。
  3. 没给输出留 token,模型无法生成完整答案。
  4. (o_1,a_1,…,o_t);因为下一步动作依赖全部历史观察与行动,而非单条输入。

9. 下一篇

S21-J10 · 用户记忆与知识库 —— 记忆的层次结构、四种存储格式、可执行代码作为知识表示,以及压缩与整理机制(待写)。


本篇属于系列《S21 · Agent 工程与 MCP》。旧文来源:A-4568(《AI Agent 深入理解》第 2 章);扩展点 E-S21-029/030/031。ReAct 定义引自原文引用的论文。

S21-J09 · 上下文工程:静态前缀、轨迹与压缩
https://www.clxhxhhr.top/posts/5493/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。