你肯定遇到过这一幕
让 agent 花半小时摸清一个 codebase 的某个子系统,它读文件、grep、推理,每个细节都翻了个遍。
然后你切到下一个任务------让它去看另一块逻辑。
怪事来了:它的回答开始引用一些通用概念 ,而不是它自己半小时前发现的那些具体函数名、文件路径、设计模式。
不是 agent 变蠢了。是 context 在长 session 里被稀释了。
这篇讲的是怎么治。
先搞清楚到底发生了什么
模型对早期细节注意力下降了------这就是 attention dilution。
为什么?半小时的探索过程里,context 已经被塞满:文件内容、grep 输出、推理链条、来回的对话。早期那些精华细节虽然还"在"context 里,但已经被埋在一堆中间过程下面,模型的 attention 自然顾此失彼。
这是长 session 的典型病:context degradation。
很关键的一点:这个过程不可逆。给更精确的 prompt 救不回来------你甚至明确点名某个函数,模型也只能在饱和 context 里勉强响应。新任务又会往这个已经爆仓的 context 里塞更多东西,问题只会变本加厉。
三个直觉错招
碰到这个问题,大部分人的第一反应是下面这三种里的一种。它们都不对。
错招一:/clear 一把梭。 这是核武器级操作。它把半小时的探索成果全部丢掉 。听起来确实"重置"了,但代价是------如果新任务跟旧任务有任何关联(比如新看的 ORM 跟之前的 routing 有交互),你就得重新探索一遍。清空不等于干净,是把澡盆里的水连孩子一起倒掉。
错招二:硬撑,用更精确的 prompt。 上面说了,attention dilution 不可逆。在饱和 context 里继续工作,只会让 context 更饱和。
错招三:直接 spawn 一个 sub-agent 跑新任务,事后手动合并。 这个最具迷惑性,看起来挺聪明。但它有两个致命漏洞:sub-agent 启动时没拿到旧任务的上下文,可能漏掉两块逻辑之间的交互;而你的主 session 还是那个被污染的 context,问题一个都没解决。
正解:Summary + Sub-agent 两步走
正确的做法同时干掉两个问题------保住旧知识 + 给新任务一个干净的脑子。
第一步,把旧任务的关键发现 summarize 出来 ------凝练成结构化的 facts block:发现的函数、文件路径、设计模式、踩过的坑。这一步不能省,因为新任务可能随时需要旧上下文。
第二步,spawn 一个 sub-agent 跑新任务,把 summary 塞进它的初始 context 。Sub-agent 拿着 fresh context 启动,专心跑新任务,完全不被旧任务的探索历史污染。它跑完之后只把精华结果返回主 agent。
这个套路有个名字------scratchpad 模式 + sub-agent isolation 模式的组合 。Summary 是一个持久化的 facts block ,sub-agent 提供 isolated context。两者缺一不可。
理解一下本质:Sub-agent 隔离的不是知识,是注意力和 context 预算。知识通过 summary 显式打包过去------你决定哪些保留、哪些丢弃。Context 预算通过 fresh window 重置------sub-agent 不需要继承你那半小时的探索泥潭。
实操:Claude Code 怎么写
第一步:让主 session 把发现写到磁盘
不要让它"在 context 里 summarize"------直接写到文件。
vbnet
Before we move on, summarize what you've learned about <旧子系统>
into a structured doc covering: <关键实体> discovered, file locations,
design patterns, and any gotchas. Save it to ./tmp/<topic>-findings.md
为什么写到磁盘比放 context 里好?三个理由:持久化 (session 挂了文件还在)、可复用 (任意 sub-agent 都能读)、抗稀释(文件不会被 attention 衰减)。
第二步:Spawn sub-agent 跑新任务
最直接的就是 Task tool 内置的 subagent。在主 session 里说:
css
Spawn a subagent to investigate <新任务>. Have it first read
./tmp/<topic>-findings.md for background, then do the exploration.
Return a structured summary of findings.
Task tool 会启动一个 fresh context 的 sub-agent 。它跑完之后只把最终 summary 返回主 session------主 context 不会被新任务的探索过程污染。
如果你有自定义的 subagent 配置(比如 .claude/agents/<name>.md),prompt 可以更简洁:
xml
Use the <name> subagent for <新任务>. Pass it ./tmp/<topic>-findings.md
as background context.
实操:Agent SDK / API 怎么写
如果你是用代码自己编排的,逻辑等价:
ini
# 1. 主 agent 先把发现 summarize 出来
summary = await main_agent.query(
"Summarize findings as structured markdown"
)
# 2. Spawn 一个全新的 agent 实例(fresh context)跑新任务
new_result = await query(
prompt=f"Background context:\n{summary}\n\nNow investigate ...",
options=ClaudeAgentOptions(
# 注意:不传 resume / continue,是全新 session
allowed_tools=["Read", "Grep", "Glob"]
)
)
# 3. 主 agent 收到 sub-agent 的 result,决定下一步
关键点 :sub-agent 启动时不带主 session 的对话历史 ,只带你显式注入的 summary。这是它能保持干净的根本原因。
顺便辨析一个易错点:sub-agent 和 fork_session 不是一回事
很多人会混淆这两个概念,但它们解决的问题完全相反。
fork_session 是复制完整对话历史 到一个新的 session ID。两边都带着旧任务的污染 context 。它的用途是"我想从某个 checkpoint 分叉出两条不同的探索路线",不适合本场景 ------这里的目标恰恰是甩掉污染。
Sub-agent / 新 query 是 fresh context ,只带你主动打包好的 summary。这才是治长 session 退化的药。
记住这个对比:fork 是带着包袱起跑,sub-agent 是放下包袱起跑。
一句话口诀
把整个技巧压缩成一句话:
Summarize 写盘 → spawn sub-agent → sub-agent 读盘 + 跑新任务 → 返回精华 summary
90% 的"长 session 切新任务"场景就是这个三件套。
什么时候该用这一招
不是每次切任务都要这么搞。三个信号告诉你该上这套流程:
一是主 session 已经跑了 20+ 分钟 ,明显感觉到模型开始引用通用概念而不是具体细节。二是新任务跟旧任务有潜在交互 ,你不能直接 /clear 把旧知识扔了。三是新任务本身预计也要密集探索,会进一步往 context 里灌东西。
三个条件凑齐两个,就别犹豫,按这个套路走。
收尾
/clear 牺牲知识换干净,硬撑既不解决退化又制造更多污染,简单 spawn sub-agent 解决一半但留下半个烂摊子。
只有 summarize + sub-agent 两边都要。
写盘那一下花的几十秒,比你后面用 /clear 重新探索半小时划算得多。