把 Claude 用于长周期 Agent 任务,有一类问题几乎是必然出现的:任务跑到中途,Claude 开始”忘事”。它忘了第一步约定的格式规范,忘了某个已经确认过的业务规则,忘了三轮前你特别强调的约束条件。任务的方向越来越模糊,输出质量开始下滑,到最后你甚至不确定它还记不记得这个任务的核心目标。
上下文丢失不是 Claude 的能力问题,而是大语言模型在超长上下文中的固有特性——随着内容累积,早期信息的权重自然衰减。但这个问题可以通过架构和提示词设计大幅缓解。
本文由 Claude Ai中文官网 整理,提供 6 个在真实 Agent 项目中验证过的实用技巧,每个技巧都附上可直接复用的代码或提示词模板。
本文面向通过 Anthropic API 构建 Agent 的开发者,以及通过 Claude Code 执行长任务的用户。部分技巧同样适用于在 claude.ai 中进行长对话的场景。
一、先理解:上下文是怎么丢失的
有针对性地解决问题之前,先搞清楚上下文丢失的三种模式,因为不同模式需要不同的应对策略。
模式 A:早期信息权重衰减。这是最常见的模式。你在任务开始时定义的规则和约束,随着对话轮次增加被越来越多的中间内容”稀释”,Claude 对它们的关注度自然降低。表现为:任务运行到中后期,输出开始偏离最初定义的规范。
模式 B:工具调用结果噪音积累。Agent 每次调用工具(搜索、数据库、API),返回结果都会进入上下文。随着调用次数增加,大量已经处理过的结果堆积在上下文里,形成”噪音”,稀释了真正重要的信息密度。表现为:Claude 在后续步骤中引用了本该已经忽略的旧信息。
模式 C:多步推理中的误差传播。某个中间步骤的轻微偏差被后续步骤当作事实接受,误差逐步放大。表现为:任务方向逐渐漂移,每一步看起来都合理,但整体已经偏离了目标。
以下 6 个技巧分别针对这三种模式设计。
二、技巧 1:把核心约束放进永久性系统提示词
解决的问题:模式 A(早期信息权重衰减)
最简单也最有效的技巧:把任务中不会改变的核心约束,从对话历史里抽出来,放进系统提示词(system prompt),并通过 Prompt Caching 让它在每次调用中权重最高。
系统提示词在模型处理时享有天然的”前置优先级”,不会被对话历史的增长所稀释。只要任务继续,这些约束就永远在最高权重的位置。
import anthropic
client = anthropic.Anthropic()
# 把核心约束单独抽出来,放进系统提示词并缓存
CORE_CONSTRAINTS = """
【任务核心约束——始终遵守,不受对话内容影响】
1. 输出格式:所有代码块必须有语言标注,所有列表使用 Markdown 格式
2. 数据来源:只引用用户提供的文件,不使用外部推断
3. 不可做的事:不生成任何个人身份信息,不猜测缺失的数据
4. 错误处理:遇到不确定的情况,先说明"我不确定",再给出建议
5. 任务边界:只处理与当前任务直接相关的内容,不做范围外的延伸
在每次响应之前,先检查你的计划是否违反以上任何一条约束。
"""
def call_agent_with_stable_constraints(
task_context: str,
conversation_history: list[dict],
current_user_message: str
) -> str:
"""
每次调用都携带不变的核心约束作为系统提示词(缓存),
同时携带动态的对话历史和当前消息。
"""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
system=[
{
"type": "text",
"text": CORE_CONSTRAINTS,
"cache_control": {"type": "ephemeral"} # 缓存核心约束
},
{
"type": "text",
"text": f"当前任务背景:\n{task_context}"
# 任务背景如果不变,也可以加缓存
}
],
messages=conversation_history + [
{"role": "user", "content": current_user_message}
]
)
return response.content[0].text
什么内容适合放进系统提示词:
- 格式规范(输出格式、命名约定、结构要求)
- 绝对禁止项(不能做的事)
- 任务边界(超出范围的请求如何处理)
- 错误处理规则(不确定时怎么办)
什么不适合放进系统提示词:会随任务进展变化的状态(已完成的步骤、中间结果、当前进度)——这些应该用下面的技巧处理。
三、技巧 2:定期压缩对话历史,而不是无限追加
解决的问题:模式 A + 模式 B
对话历史无限增长是上下文丢失最直接的原因。每隔固定的轮次,对已经完成的对话部分做一次压缩摘要,用摘要替换原始内容。这样上下文长度保持在可控范围内,同时关键信息得以保留。
def compress_conversation_history(
history: list[dict],
keep_recent_n: int = 6,
compress_threshold: int = 20
) -> list[dict]:
"""
当对话历史超过阈值时,压缩早期部分为摘要。
始终保留最近 N 轮对话的完整内容。
"""
if len(history) <= compress_threshold:
return history # 未达到压缩阈值,原样返回
# 分割:需要压缩的旧内容 + 保留的近期内容
to_compress = history[:-keep_recent_n]
recent = history[-keep_recent_n:]
# 将旧内容格式化为可压缩的文本
history_text = "\n\n".join([
f"[{msg['role'].upper()}]: {msg['content'][:500]}..."
if len(msg['content']) > 500
else f"[{msg['role'].upper()}]: {msg['content']}"
for msg in to_compress
])
# 调用 Claude 生成摘要(用轻量模型节省成本)
summary_response = client.messages.create(
model="claude-haiku-4-5", # 用轻量模型做摘要
max_tokens=600,
messages=[{
"role": "user",
"content": f"""请将以下对话历史压缩为简洁摘要。
保留:
- 已完成的关键操作和决策
- 重要的中间结论
- 后续步骤需要参考的信息
- 约定的规则或格式变更
去除:
- 过程细节和中间推理步骤
- 已经不再相关的工具调用结果
- 重复的确认和回应
摘要控制在 300 字以内。
对话历史:
{history_text}"""
}]
)
summary = summary_response.content[0].text
# 用摘要替换旧内容,作为对话历史的第一条消息
compressed_history = [
{
"role": "user",
"content": f"[对话历史摘要(已压缩)]\n{summary}"
},
{
"role": "assistant",
"content": "明白,我已了解之前的进展,继续执行当前任务。"
}
] + recent
return compressed_history
压缩时机的建议:
- 每 15–20 轮对话压缩一次(根据每轮消息的平均长度调整)
- 在开始一个新的任务阶段之前主动压缩,把旧阶段的内容归档
- 当你感知到 Claude 开始”遗忘”早期约定时,立即手动触发压缩
四、技巧 3:把任务状态外化到结构化存储
解决的问题:模式 B + 模式 C
不要让 Claude 的上下文承担”任务状态数据库”的职责。把任务的完成进度、中间结果、待处理项,存到外部结构化存储(文件、数据库、Redis),每次调用 Claude 时只传入当前步骤真正需要的状态子集。
import json
from pathlib import Path
from datetime import datetime
class AgentStateStore:
"""
Agent 任务的外部状态存储。
Claude 的上下文只看到精选的状态快照,不是全部历史。
"""
def __init__(self, task_id: str, store_path: str = "./agent_states"):
self.task_id = task_id
self.path = Path(store_path) / f"{task_id}.json"
self.state = self._load()
def _load(self) -> dict:
if self.path.exists():
with open(self.path) as f:
return json.load(f)
return {
"task_id": self.task_id,
"objective": "",
"completed_steps": [],
"pending_steps": [],
"key_findings": [], # 重要发现,后续步骤需要参考
"decisions_made": [], # 已做的关键决策
"current_step": None,
"artifacts": {}, # 中间产物(文件路径等)
"created_at": datetime.now().isoformat()
}
def save(self):
self.path.parent.mkdir(parents=True, exist_ok=True)
with open(self.path, 'w') as f:
json.dump(self.state, f, ensure_ascii=False, indent=2)
def complete_step(self, step: str, result_summary: str):
"""标记步骤完成,只保存结果摘要而非全文"""
self.state["completed_steps"].append({
"step": step,
"summary": result_summary, # 摘要,不是全文
"completed_at": datetime.now().isoformat()
})
if step in self.state["pending_steps"]:
self.state["pending_steps"].remove(step)
self.save()
def add_key_finding(self, finding: str, relevant_to: list[str] = None):
"""记录重要发现,标注与哪些后续步骤相关"""
self.state["key_findings"].append({
"finding": finding,
"relevant_to": relevant_to or [],
"added_at": datetime.now().isoformat()
})
self.save()
def get_context_for_step(self, current_step: str) -> str:
"""
为当前步骤生成精选的上下文摘要。
只包含与当前步骤真正相关的信息,不是全量历史。
"""
# 找出与当前步骤相关的 key findings
relevant_findings = [
f["finding"] for f in self.state["key_findings"]
if not f["relevant_to"] or current_step in f["relevant_to"]
]
# 只展示最近 5 个已完成步骤的摘要
recent_completed = self.state["completed_steps"][-5:]
context = f"""【任务目标】
{self.state['objective']}
【已完成步骤(最近 5 个)】
{chr(10).join(f"✓ {s['step']}:{s['summary']}" for s in recent_completed) or "(无)"}
【关键发现(与当前步骤相关)】
{chr(10).join(f"• {f}" for f in relevant_findings) or "(无特别相关的发现)"}
【已做的关键决策】
{chr(10).join(f"• {d}" for d in self.state['decisions_made'][-3:]) or "(无)"}
【当前步骤】
{current_step}
"""
return context
使用这个状态存储的关键原则:进入 Claude 上下文的不是原始数据,而是经过筛选的相关摘要。 一个完整的工具调用返回结果可能有 5000 字,但进入后续步骤上下文的只需要 2–3 行关键发现。
五、技巧 4:工具调用结果的即时精炼
解决的问题:模式 B(工具调用结果噪音积累)
每次工具调用返回结果后,不要直接把原始结果放进下一次调用的上下文——先做一次精炼,只保留对后续步骤有价值的部分。
def refine_tool_result(
tool_name: str,
raw_result: str,
current_objective: str,
max_output_tokens: int = 200
) -> str:
"""
对工具调用的原始结果做即时精炼。
只保留对当前目标有价值的信息。
"""
if len(raw_result) < 500:
return raw_result # 结果足够短,直接使用
response = client.messages.create(
model="claude-haiku-4-5", # 轻量模型快速精炼
max_tokens=max_output_tokens,
messages=[{
"role": "user",
"content": f"""从以下 {tool_name} 的返回结果中,
提取与以下目标最相关的关键信息:
目标:{current_objective}
工具返回结果:
{raw_result[:3000]} # 截取前 3000 字避免精炼本身也超长
要求:
- 只保留与目标直接相关的信息
- 去除冗余的格式信息和不相关内容
- 用简洁的要点格式呈现
- 控制在 {max_output_tokens // 4} 字以内"""
}]
)
return response.content[0].text
# 在 Agent 循环中使用
def agent_step_with_refined_tools(
current_objective: str,
tool_call_result: dict
) -> str:
tool_name = tool_call_result["tool"]
raw_result = tool_call_result["result"]
# 精炼工具结果
refined = refine_tool_result(
tool_name=tool_name,
raw_result=raw_result,
current_objective=current_objective
)
# 进入上下文的是精炼后的结果,不是原始结果
return f"[{tool_name} 结果摘要]\n{refined}"
哪些工具调用结果最需要精炼:
- 搜索引擎返回:通常包含大量不相关的页面摘要
- 数据库查询返回:原始数据往往远多于实际需要的字段
- 网页内容抓取:HTML 解析后的文本通常包含大量导航栏、广告等噪音
- 大文件读取:只需要文件的相关部分,不需要全文
六、技巧 5:显式的阶段切换和状态重置
解决的问题:模式 A + 模式 C
长周期任务通常有自然的阶段划分(调研阶段 → 分析阶段 → 实现阶段 → 验证阶段)。在阶段切换时,不要无缝继续,而是做一次显式的”状态重置”:用一条消息总结上一阶段的关键产出,明确声明进入新阶段,并在新阶段的第一条系统消息中重申核心约束。
def transition_to_new_phase(
state_store: AgentStateStore,
completed_phase: str,
next_phase: str,
phase_deliverables: dict
) -> list[dict]:
"""
显式地切换任务阶段,重置上下文焦点。
返回新阶段的初始对话历史(干净的起点)。
"""
# 保存阶段产出到外部存储
state_store.state["artifacts"][completed_phase] = phase_deliverables
state_store.state["completed_steps"].append({
"step": f"完成阶段:{completed_phase}",
"summary": f"产出:{', '.join(phase_deliverables.keys())}",
"completed_at": datetime.now().isoformat()
})
state_store.save()
# 生成阶段交接摘要
handoff_summary = f"""
【阶段交接摘要】
已完成阶段:{completed_phase}
主要产出:
{chr(10).join(f"- {k}:{str(v)[:100]}..." for k, v in phase_deliverables.items())}
关键决策和发现:
{chr(10).join(f"- {d}" for d in state_store.state['decisions_made'][-5:])}
即将进入阶段:{next_phase}
"""
# 新阶段以干净的对话历史开始,只包含交接摘要
# 不携带上一阶段的完整对话历史
new_phase_history = [
{
"role": "user",
"content": handoff_summary + f"\n\n请确认你已了解上一阶段的产出,并准备开始 {next_phase} 阶段。"
},
{
"role": "assistant",
"content": f"已了解。{completed_phase} 阶段的关键产出已记录。现在开始 {next_phase} 阶段,将基于以上产出继续推进。"
}
]
return new_phase_history
为什么这很重要:不做显式切换,对话历史会把两个阶段的内容混合在一起,Claude 在新阶段的工作中可能受到旧阶段噪音的干扰。显式切换相当于给 Claude 一个”清空黑板,重新开始”的信号,但关键成果通过交接摘要传递,不会丢失。
七、技巧 6:在关键节点插入”上下文确认”
解决的问题:所有三种模式的主动预防
在执行关键操作之前,主动让 Claude 复述它对任务的理解——不是为了让它”再想一想”,而是作为一个早期预警机制:如果它复述出来的和你预期的不一样,说明上下文已经出现了漂移,现在修正比发现输出错误后再修正成本低得多。
CONTEXT_CHECK_PROMPT = """在执行下一步之前,请先确认你对以下内容的理解:
1. 当前任务的核心目标是什么?(一句话)
2. 你即将执行的操作是什么?
3. 这个操作完成后,下一步是什么?
4. 有没有任何约束条件你需要在这个操作中特别注意?
确认完成后再执行。"""
def run_with_context_check(
agent_fn,
check_every_n_steps: int = 8,
current_step_number: int = 0,
**kwargs
) -> str:
"""
每隔 N 步插入一次上下文确认检查。
"""
if current_step_number > 0 and current_step_number % check_every_n_steps == 0:
# 插入确认检查
check_response = agent_fn(
user_message=CONTEXT_CHECK_PROMPT,
**kwargs
)
print(f"\n[步骤 {current_step_number} - 上下文确认]\n{check_response}\n")
# 在实际系统中,这里可以加一个人工确认的机会
# 或者用另一个 Claude 调用来验证复述是否正确
return agent_fn(**kwargs)
在 claude.ai 交互场景中的用法:如果你是通过界面手动进行长对话,可以每 10 条左右发一次这样的消息:
在继续之前,请用 3 句话告诉我: 1. 你对这个任务的当前理解 2. 你认为下一步应该做什么 3. 有没有任何你不确定的地方 不需要长篇大论,简洁准确地告诉我就好。
如果 Claude 的复述出现了任何偏差,立即在这一步修正,比等到 10 步后发现方向跑偏再回头要省很多时间。
八、组合使用:一个完整的长周期 Agent 架构
以上 6 个技巧不是独立的选项,它们设计来协同工作。把它们组合起来,是一套完整的长周期 Agent 稳定性架构:
class StableLongCycleAgent:
"""
集成了上下文稳定性技巧的长周期 Agent。
适用于预计运行超过 2 小时、包含多个阶段的复杂任务。
"""
def __init__(
self,
task_id: str,
core_constraints: str,
task_objective: str
):
self.task_id = task_id
self.core_constraints = core_constraints
self.state_store = AgentStateStore(task_id)
self.state_store.state["objective"] = task_objective
self.state_store.save()
self.conversation_history = []
self.step_counter = 0
def execute_step(
self,
step_description: str,
tool_results: Optional[list[dict]] = None
) -> str:
self.step_counter += 1
# 技巧 1:每次调用都携带核心约束(缓存)
# 技巧 3:从外部状态存储获取精选上下文
step_context = self.state_store.get_context_for_step(step_description)
# 技巧 4:精炼工具调用结果
refined_tool_content = ""
if tool_results:
refined_parts = [
refine_tool_result(
tr["tool"], tr["result"],
step_description
)
for tr in tool_results
]
refined_tool_content = "\n\n".join(refined_parts)
# 技巧 6:每 8 步插入上下文确认
if self.step_counter % 8 == 0:
check_message = step_context + "\n\n" + CONTEXT_CHECK_PROMPT
else:
check_message = step_context
if refined_tool_content:
check_message += f"\n\n【工具返回(已精炼)】\n{refined_tool_content}"
check_message += f"\n\n请执行当前步骤:{step_description}"
self.conversation_history.append({
"role": "user",
"content": check_message
})
# 技巧 2:超过阈值时压缩对话历史
self.conversation_history = compress_conversation_history(
self.conversation_history,
keep_recent_n=6,
compress_threshold=20
)
# 调用 Claude(技巧 1:核心约束在系统提示词里)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
system=[
{
"type": "text",
"text": self.core_constraints,
"cache_control": {"type": "ephemeral"}
}
],
messages=self.conversation_history
)
result = response.content[0].text
self.conversation_history.append({
"role": "assistant",
"content": result
})
return result
def complete_step(self, step: str, result_summary: str):
"""记录步骤完成,更新外部状态"""
self.state_store.complete_step(step, result_summary)
def start_new_phase(
self,
completed_phase: str,
next_phase: str,
deliverables: dict
):
"""技巧 5:显式阶段切换,重置上下文"""
self.conversation_history = transition_to_new_phase(
self.state_store,
completed_phase,
next_phase,
deliverables
)
self.step_counter = 0 # 重置步骤计数器
九、针对 claude.ai 网页端用户的简化版技巧
如果你不是通过 API 构建 Agent,而是在 claude.ai 的对话框里做长任务,以上技巧的简化版同样适用:
对应技巧 1(固定核心约束):在对话最开始发一条”任务说明”消息,把所有规则和约束列清楚。当对话变长后,如果发现 Claude 开始忘记规则,把这条消息的内容复制粘贴到新消息里,说”请重新确认以下规则仍然适用”。
对应技巧 2(压缩历史):当对话超过 20 轮,发一条消息:”请总结我们到目前为止完成的工作和关键结论,控制在 300 字以内。”然后把这个摘要复制保存,开启新对话时把它粘贴进去作为起点。
对应技巧 5(阶段切换):在切换任务阶段时,主动发一条消息:”好的,第一阶段完成。关键产出是:[列出产出]。现在进入第二阶段,目标是:[说明目标]。请确认理解后开始。”
对应技巧 6(上下文确认):每隔 10 条消息左右,发一次上面提到的确认提问,让 Claude 复述它的当前理解。
总结:6 个技巧的适用时机
| 技巧 | 主要解决的问题 | 实现成本 | 最适合的场景 |
|---|---|---|---|
| 核心约束进系统提示词 | 早期规则被遗忘 | 低 | 所有长任务,第一个该做的 |
| 定期压缩对话历史 | 上下文无限膨胀 | 中 | 超过 20 轮的多轮对话任务 |
| 状态外化到结构化存储 | 中间结果噪音积累 | 高 | 多步骤、有多种类型中间结果的任务 |
| 工具结果即时精炼 | 工具返回噪音积累 | 中 | 频繁调用外部工具的 Agent |
| 显式阶段切换 | 跨阶段内容互相干扰 | 中 | 有明确阶段划分的长任务 |
| 上下文确认检查 | 所有模式的主动预防 | 低 | 关键操作前,或每隔 N 步 |
如果只能选一个:把核心约束放进系统提示词并缓存——这是成本最低、效果最直接的单一改进,能解决大多数长任务中”规则被遗忘”的问题。
如果要构建生产级的长周期 Agent:六个技巧组合使用,按照文中的架构示例实现。
更多关于 Claude Agent 开发的最佳实践和最新 API 功能说明,欢迎访问 Claude Ai中文官网 查阅持续更新的中文开发者文档。
上下文管理是 Agent 工程中被低估最多的问题。它不是”优化”,而是让长任务能够可靠完成的基础设施。把这 6 个技巧当作 Agent 设计的标配,而不是出了问题才想起来的补救措施。