0 背景
https://fairy-study.blog.csdn.net/article/details/159253372?spm=1001.2014.3001.5502
https://fairy-study.blog.csdn.net/article/details/159253478?spm=1001.2014.3001.5502
按需加载上下文:
https://fairy-study.blog.csdn.net/article/details/159253494?spm=1001.2014.3001.5502
一、核心问题:上下文「无限膨胀」导致Agent崩溃
第五季的「按需技能加载」解决了系统提示的代币浪费,但新的致命问题出现:
Agent在执行复杂任务时(比如读取30个Python文件、运行20次bash命令),所有工具调用的原始结果都会永久留在上下文列表中,导致:
- 代币超限:上下文窗口有固定上限(比如100K代币),大量原始文件内容/命令输出会快速占满窗口,API调用直接失败;
- 推理效率低:模型需要在海量冗余信息中找核心,响应变慢、易出错;
- 无法长会话:几轮交互后上下文就满了,Agent无法完成跨数十轮的复杂任务(比如重构整个代码库)。
简单说:第五季只解决了「输入侧(系统提示)」的代币浪费,没解决「输出侧(上下文积累)」的膨胀问题------S06的核心就是补这个缺口。
二、核心解决方案:三层上下文压缩策略(渐进式瘦身)
核心逻辑是「轻量→自动→手动 三层递进压缩」,在不丢失关键信息的前提下,把上下文「瘦身」到窗口限额内,支持无限长会话:
┌─────────────────────────────────────┐
│ 原始上下文(含大量工具原始结果) │
└─────────────────────────────────────┘
↓ 每轮必执行(Layer 1:微压缩)
┌─────────────────────────────────────┐
│ 替换旧工具结果为占位符 │
│ 例:[Previous: used read_file] │
│ 保留最近N轮工具结果,旧的只留标识 │
└─────────────────────────────────────┘
↓ 代币超阈值触发(Layer 2:自动压缩)
┌─────────────────────────────────────┐
│ 1. 完整对话保存到.transcripts/磁盘 │
│ 2. LLM摘要整个对话(保留核心信息) │
│ 3. 上下文替换为「摘要+确认消息」 │
│ 例:[Compressed] 已读取agents/下15个文件,均为Python脚本... │
└─────────────────────────────────────┘
↓ 模型手动调用(Layer 3:手动压缩)
┌─────────────────────────────────────┐
│ 模型主动调用compact工具,触发和Layer2相同的摘要逻辑 │
│ 用于代币未超限但模型想主动瘦身的场景 │
└─────────────────────────────────────┘
三、核心代码逻辑(三层压缩的落地)
1. Layer 1:Micro-Compact(微压缩,每轮必执行)
python
import json
from pathlib import Path
import time
from anthropic import Anthropic
# 配置:保留最近3轮工具结果,旧的替换为占位符
KEEP_RECENT = 3
client = Anthropic()
def micro_compact(messages: list) -> list:
# 第一步:找出所有tool_result类型的消息片段
tool_results = []
for msg_idx, msg in enumerate(messages):
# 只处理user角色的tool_result(工具执行结果都是user角色返回给模型的)
if msg["role"] == "user" and isinstance(msg.get("content"), list):
for part_idx, part in enumerate(msg["content"]):
# 定位tool_result类型的片段
if isinstance(part, dict) and part.get("type") == "tool_result":
# 提取工具名称(比如read_file/bash)
tool_name = part.get("content", "").split(":")[0] # 简化逻辑,实际会解析block.name
tool_results.append((msg_idx, part_idx, part, tool_name))
# 第二步:如果工具结果超过3轮,替换旧的为占位符
if len(tool_results) <= KEEP_RECENT:
return messages # 最近3轮内,不压缩
# 只保留最后KEEP_RECENT个,前面的旧结果替换
for msg_idx, part_idx, part, tool_name in tool_results[:-KEEP_RECENT]:
# 只压缩长内容(短内容没必要)
if len(part.get("content", "")) > 100:
# 核心:用简短占位符替换海量原始内容
messages[msg_idx]["content"][part_idx]["content"] = f"[Previous: used {tool_name}]"
return messages
核心作用:
- 「静默压缩」:用户/模型无感知,每轮调用模型前自动执行;
- 「最小侵入」:只替换旧的、长的工具结果,保留最近3轮的完整结果,不影响模型当前执行;
- 「低成本」:纯字符串替换,无需调用LLM,不额外消耗代币。
2. Layer 2:Auto-Compact(自动压缩,代币超限触发)
python
# 配置:代币阈值(比如50000)
TOKEN_THRESHOLD = 50000
TRANSCRIPT_DIR = Path(".transcripts")
TRANSCRIPT_DIR.mkdir(exist_ok=True)
# 辅助函数:估算上下文代币数(简化版,实际用Anthropic的token计算器)
def estimate_tokens(messages: list) -> int:
text = json.dumps(messages)
return len(text) // 4 # 粗略估算:1token≈4字符
def auto_compact(messages: list) -> list:
# 第一步:保存完整对话到磁盘(防止信息丢失)
timestamp = int(time.time())
transcript_path = TRANSCRIPT_DIR / f"transcript_{timestamp}.jsonl"
with open(transcript_path, "w", encoding="utf-8") as f:
for msg in messages:
# 每行一个JSON,方便后续恢复/查看
f.write(json.dumps(msg, ensure_ascii=False, default=str) + "\n")
# 第二步:调用LLM生成对话摘要(保留核心信息)
summary_prompt = f"""
Summarize this conversation for continuity, keep all key information:
1. What tasks is the agent working on?
2. Key results of tool calls (e.g., read 15 Python files in agents/)
3. Unfinished steps or decisions
Do NOT include full file contents or long command outputs.
Conversation:
{json.dumps(messages, ensure_ascii=False, default=str)[:80000]} # 避免超长输入
"""
response = client.messages.create(
model=os.environ["MODEL_ID"],
messages=[{"role": "user", "content": summary_prompt}],
max_tokens=2000, # 摘要长度限制
)
summary = response.content[0].text if hasattr(response.content[0], "text") else "(no summary)"
# 第三步:替换整个上下文为「压缩标记+摘要」
compressed_messages = [
{"role": "user", "content": f"[Compressed]\n\n{summary}"},
{"role": "assistant", "content": "Understood. Continuing."}
]
return compressed_messages
核心作用:
- 「兜底压缩」:当上下文代币超阈值时,强制瘦身到几千代币;
- 「信息保全」:完整对话保存到磁盘,摘要保留核心逻辑,不影响后续执行;
- 「彻底瘦身」:把数万行的上下文替换为几百字的摘要,释放90%以上的窗口空间。
3. Layer 3:Manual-Compact(手动压缩,模型主动触发)
python
# 工具映射中新增compact工具
TOOL_HANDLERS = {
# ... 基础工具(bash/read/write/load_skill)
"compact": lambda **kw: "Compressed conversation successfully."
}
# Agent循环整合三层压缩
def agent_loop(messages: list):
while True:
# Layer 1:每轮微压缩
messages = micro_compact(messages)
# Layer 2:代币超限则自动压缩
if estimate_tokens(messages) > TOKEN_THRESHOLD:
messages = auto_compact(messages)
# 调用模型
response = client.messages.create(
model=os.environ["MODEL_ID"],
messages=messages,
tools=TOOLS,
max_tokens=8000,
)
messages.append({"role": "assistant", "content": response.content})
# 执行工具调用(省略基础逻辑)
results = []
manual_compact = False
for block in response.content:
if block.type == "tool_use":
if block.name == "compact":
manual_compact = True # 模型调用了compact工具
# ... 执行其他工具 ...
# Layer 3:模型手动触发压缩
if manual_compact:
messages = auto_compact(messages)
# ... 后续逻辑 ...
核心作用:
- 「主动可控」:模型可在代币未超限但上下文杂乱时,主动调用
compact工具瘦身; - 「复用逻辑」:和自动压缩共用
auto_compact函数,保证摘要格式一致。
四、从第五季到第六季的核心变化(面试重点)
| 组成部分 | 第五季(按需技能加载) | 第六季(三层压缩) |
|---|---|---|
| 工具数量 | 5(基础+load_skill) | 5(新增compact工具,总数不变) |
| 上下文管理 | 无压缩,任由上下文膨胀 | 三层渐进式压缩(微/自动/手动) |
| 旧工具结果处理 | 永久保留在上下文 | 微压缩替换为占位符 |
| 代币控制 | 仅控制技能加载的代币 | 全链路控制(微压缩+阈值自动压缩) |
| 历史记录 | 仅存在内存,重启丢失 | 保存完整转录到.transcripts/磁盘 |
| 核心目标 | 减少「输入侧」代币浪费 | 解决「输出侧」上下文膨胀 |
五、执行流程示例(直观理解)
用户指令:「逐个读取agents/目录下的所有Python文件」
- 初始阶段 :模型调用
read_file读取第1-3个文件,上下文保留完整内容(微压缩只保留最近3轮); - 微压缩触发 :读取第4个文件时,第1个文件的
read_file结果被替换为[Previous: used read_file]; - 自动压缩触发 :读取第20个文件后,上下文代币超50000,触发
auto_compact:- 完整对话保存到
.transcripts/transcript_171xxx.jsonl; - LLM生成摘要:「已读取agents/下20个Python文件,均为Agent相关脚本,包含s01-s05的工具调用逻辑」;
- 上下文被替换为摘要+确认消息,代币从60000降到2000;
- 完整对话保存到
- 继续执行:模型基于摘要继续读取剩余文件,上下文始终保持在阈值内。
六、核心价值(面试答法)
第六季的三层压缩解决了Agent「长会话能力」的核心问题:
- 无限会话:通过渐进式压缩,上下文永远不会占满窗口,支持数十轮甚至上百轮的复杂任务;
- 信息不丢:微压缩保留最近结果,自动/手动压缩保存完整转录到磁盘,摘要保留核心逻辑;
- 成本可控:微压缩无额外代币消耗,自动/手动压缩的摘要消耗远低于保留原始内容;
- 无感知体验:压缩对用户/模型透明,不影响任务执行的连续性。
这也是工业级Agent的必备能力------面试时重点说清「三层压缩的递进逻辑」「微压缩的静默替换」「自动压缩的磁盘保全+摘要瘦身」,就能体现你对Agent内存/上下文管理的深度理解。
总结
第六季的核心是「上下文全生命周期管理」:
- 微压缩:「日常瘦身」,处理旧的长工具结果,低成本且无感知;
- 自动压缩:「应急兜底」,代币超限时彻底瘦身,保全核心信息;
- 手动压缩:「主动优化」,模型按需触发,适配复杂场景;
- 磁盘转录:「安全网」,所有历史不丢失,可追溯/可恢复。
对比第五季:第五季是「少拿」(按需加载技能),第六季是「少存」(压缩上下文),两者结合实现了代币和上下文的双重高效管理。