《深入理解 AI Agent》之学习笔记-DAY 3(上下文工程 — API 消息结构 + Agent 核心循环 + KV Cache)
Day 3:上下文工程 — API 消息结构 + Agent 核心循环 + KV Cache
目标
从 API 层面搞清楚:每次调用 LLM 时,上下文到底长什么样,以及为什么"前缀不能动、末尾可以追加"这条铁律如此重要。
核心知识点
1. 上下文 = 消息列表
从 API 视角看,每次调用 LLM 时的上下文就是一个消息列表(messages),列表中每条消息都有一个角色(role):
| 角色 | 谁产生的 | 做什么 |
|---|---|---|
system |
开发者写的 | Agent 的"岗位说明书"——身份、规则、约束。通常只有一条,放在最前面 |
user |
终端用户 | 用户的输入请求 |
assistant |
模型生成的 | 之前的回复,包括文本 + 工具调用请求。被放回消息列表让模型"记住"自己说过什么 |
tool |
Agent 框架 | 工具执行后的结果,通过 tool_call_id 关联对应的调用 |
此外,工具定义(tools) 作为请求的独立字段(不是消息),告诉模型有哪些工具可用。
关键事实:每次调用都是无状态的。 模型不会"记住"上一次的对话,Agent 框架必须每次都把完整历史送回去。
2. Agent 核心循环:一个 while 循环
书中给了一段最简的 Python 实现,核心逻辑只有一个循环 + 一个判断:
messages = [
{"role": "system", "content": "You are a helpful assistant..."},
{"role": "user", "content": "What's the current time and weather?"},
]
while True:
response = client.chat.completions.create(
model="...", messages=messages, tools=tools
)
assistant_message = response.choices[0].message
messages.append(assistant_message) # 追加模型回复
if not assistant_message.tool_calls:
print(assistant_message.content) # 无工具调用 = 任务完成
break
for tool_call in assistant_message.tool_calls:
result = execute_tool(tool_call.function.name, tool_call.function.arguments)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result,
})
# 回到循环顶部,带着更新后的 messages 再次调用模型
5 个步骤:
- 模型推理 → 2. 判断是否有工具调用 → 3. 执行工具 → 4. 结果追加到上下文 → 5. 无工具调用则退出
消息列表的增长过程:
初始: [system, user]
第1轮后: [system, user, assistant(tool_calls), tool, tool] ← 模型决定调2个工具
第2轮后: [system, user, assistant(tool_calls), tool, tool, assistant(content)] ← 最终回复
Agent 框架的核心工作就是管理这个 messages 列表——所有上下文工程技术,本质上都是在优化这个列表的内容和结构。
3. 上下文的构成:静态前缀 + 轨迹
把 API 结构和 Day 1 学的"五个组成部分"对应起来:
┌─────────────────────────────────────────┐
│ 静态前缀(不变,可缓存) │
│ ├─ system 消息(系统提示词) │
│ └─ tools 字段(工具定义) │
├─────────────────────────────────────────┤
│ 轨迹(动态增长,随交互累积) │
│ ├─ user 消息(用户输入 + RAG 检索的外部知识) │
│ ├─ assistant 消息(回复 + 思考 + 工具调用) │
│ └─ tool 消息(工具执行结果) │
└─────────────────────────────────────────┘
理解了这个结构,就能理解后面所有上下文工程技术的出发点:前面不能动(缓存),后面可以压缩(管理长度)。
4. KV Cache:为什么前缀不能动
这是今天技术密度最高的部分。作者专门提示:可以跳过原理推导,只需记住三条核心结论。
直觉:做菜的比喻
大模型在处理上下文时,会把前面已经处理过的内容缓存起来,下次只需要处理新增的部分。就像做菜——如果前几步完全一样(同样的食材、同样的刀工),你可以直接从上次切好的地方继续;但如果前面任何一步变了(换了一种食材),后面所有步骤都得重来。
没有缓存时的问题
Agent 在第 6 轮对话时,上下文累积了 2000 个 token。没有缓存的情况下,模型每生成一个新 token 都要重新计算这 2000 个 token 的中间结果——相当于第 6 轮要像第 1 轮那样从头算,而且前缀更长,代价比第 1 轮大得多。计算量随上下文长度平方级增长。
KV Cache 怎么解决
把已算过的 K(键)和 V(值)向量缓存起来,新 token 只需计算自身的 K/V,然后与缓存中的一起完成注意力计算。
为什么改一个字就全废了
大模型由几十到上百层 Transformer 堆叠。各层串联:第 1 层的输出喂给第 2 层,层层向下传递。如果修改了第 1 个 token(比如系统提示词改了一个字),第 1 层的输出就变了,第 2 层的输入随之改变——所有层的缓存都必须重算。
一个真实故事
某团队的客服 Agent 每天处理 10 万次对话。某天工程师为了让 Agent "知道"当前时间,在系统提示词里加了一行 Current time: {{now}}。第二天监控告警:所有对话的首 token 延迟从 0.5 秒涨到 3-5 秒,月度推理账单几乎翻了一倍。
原因:那一行时间戳让系统提示词每次都不同,KV Cache 在每次请求都完全失效。
三条核心结论(必记!)
| # | 结论 | 做什么 |
|---|---|---|
| 1 | 系统提示词和工具定义一旦确定就不要改 | 哪怕多一个空格,都会导致缓存全部失效,延迟成倍增加 |
| 2 | 动态信息永远追加到末尾 | 时间戳、用户状态等变化内容,作为新消息追加到对话末尾 |
| 3 | 使用标准 API 格式,不要自行拼接消息 | 结构化消息会被 Chat Template 翻译成模型训练时见过的固定 token 序列 |
常见错误模式
| 错误模式 | 问题 | 正确做法 |
|---|---|---|
| 动态系统提示词(嵌入时间戳) | 每次请求前缀都变,缓存全废 | 时间信息追加到末尾 |
| 动态用户配置(每次更新余额) | 破坏缓存 | 用专门的状态管理机制 |
| 工具定义动态排序 | 改变顺序导致缓存失效 | 保持固定顺序 |
| 滑动窗口历史 | 破坏前缀一致性 + 丢失关键工具结果 | 用压缩策略代替 |
| 文本格式化(USER:… ASSISTANT:…) | 偏离训练格式,削弱模型能力 | 用标准 role-content 格式 |
KV Cache vs Prompt Cache
两个层级的缓存,容易混淆:
| KV Cache | Prompt Cache | |
|---|---|---|
| 层级 | 模型内部(单次推理) | API 服务层(跨请求) |
| 作用 | 加速单次请求内 token 生成 | 减少跨请求的重复计算成本 |
| 原理 | 缓存已算的 K/V 向量 | 前缀相同则复用之前的 KV Cache |
| 经济影响 | 影响延迟 | 直接影响 API 计费 |
两者都要求前缀稳定,但 Prompt Cache 的经济影响更大——它直接影响你的 API 账单。
思考练习
-
画出你的 Agent 消息列表结构:假设你要做一个"帮用户查股票行情"的 Agent,写出:
- system 消息应该包含什么?
- 需要哪些工具?工具定义怎么写?
- 用户问"帮我查下 601567 的实时价格",前两轮的消息列表会长什么样?
-
判断对错:以下做法哪些会破坏 KV Cache?为什么?
- (a) 在系统提示词中写
当前时间: {datetime.now()} - (b) 每轮对话末尾追加一条工具调用计数消息
- © 根据用户输入动态选择 3 个工具放入 tools 字段
- (d) 把 tool 结果的 JSON 格式改为
USER: {result}纯文本
- (a) 在系统提示词中写
自测题
- API 消息有哪四种角色?各自由谁产生?
- Agent 核心循环的 5 个步骤是什么?什么时候循环结束?
- KV Cache 的三条核心结论是什么?
- 为什么修改对话历史中间的消息会导致性能下降?(从 Transformer 层级串联的角度解释)
- KV Cache 和 Prompt Cache 有什么区别?哪个对 API 计费影响更大?
- 滑动窗口对话历史有什么两个严重问题?
更多推荐



所有评论(0)