【学习笔记】Harness | 须弥纳芥子,Context Compact for Endurance —— -Claude-Code实战(7/13)
到现在,Agent已经学会了:调工具、做Todo、任务分给子Agent,按需加载Skill。
它会的东西越来越多,上下文也会膨胀越来越快。
如果没有压缩机制,很快就会出现这些问题👇
这节课我们要学的就是:
在不丢掉主线连续性的前提下,给活跃上下文腾空间
先理解几个概念。什么是上下文窗口、活跃上下文、压缩👇
1. 把大的工具结果写进磁盘存起来
2. 把旧的工具结果进行压缩,保留最新的
3. 整体过长时,做一次完整的关键信息总结
直接看图👇
💡注意:压缩不是删历史,而是把细节拿掉,好让系统继续工作。
我们看一下 agents/s06_context_compact.py 中的核心逻辑:
核心逻辑是:通过持久化大型输出(写进磁盘)、微压缩旧记录(替换占位)、全局摘要重组(总结关键信息)来实现压缩。
配置与状态定义。设置上下文阈值、持久化路径,定义结构化对象来追踪压缩状态和最近操作的文件。# 定义阈值与路径CONTEXT_LIMIT = 50000 # 上下文触发压缩的上限PERSIST_THRESHOLD = 30000 # 单次工具输出持久化的阈值TRANSCRIPT_DIR = ... # 历史副本存储目录@dataclassclass CompactState: has_compacted: bool = False # 标记是否发生过压缩 last_summary: str = "" # 存储最近一次生成的对话摘要 recent_files: list[str] = field(default_factory=list) # 记录最近操作的 5 个文件
将大的输出写进磁盘。当输出内容过大时,将其写入磁盘文件,仅返回带文件路径的简短预览。def persist_large_output(tool_use_id: str, output: str) -> str: if len(output) <= PERSIST_THRESHOLD: return output # ... 将完整 output 写入 .task_outputs 目录 return f"<persisted-output>Full saved to: {path}\nPreview: {output[:2000]}</persisted-output>"
微压缩策略。仅保留最近 3 次工具调用的完整结果,将更早的工具返回内容替换为简短占位符。def micro_compact(messages: list) -> list: tool_results = collect_tool_result_blocks(messages) if len(tool_results) <= KEEP_RECENT_TOOL_RESULTS: return messages # 对倒数第 4 个及更早的结果进行清理 for _, _, block in tool_results[:-KEEP_RECENT_TOOL_RESULTS]: block["content"] = "[Earlier tool result compacted...]" return messages
对话总结。调用 LLM 将漫长的历史记录总结为关键点,并以此摘要作为新的对话起点。def summarize_history(messages: list) -> str: # 引导 LLM 提取:目标、发现、已改文件、剩余工作 prompt = "Summarize this coding-agent conversation..." # ... 调用 API 获取摘要 return response.content[0].text.strip()def compact_history(messages: list, state: CompactState, focus: str | None = None) -> list: write_transcript(messages) # 压缩前先备份完整 JSONL 历史 summary = summarize_history(messages) # ... 组装 summary + 最近文件列表 return [{"role": "user", "content": f"This conversation was compacted...\n{summary}"}]
增强版工具执行。执行 Bash 或读写操作,并在过程中自动触发输出持久化和文件追踪。def execute_tool(block, state: CompactState) -> str: # 包含 bash, read_file, write_file, edit_file 等 # 其中 read_file 会调用 track_recent_file 记录操作痕迹 # 所有的输出都会经过 persist_large_output 检查 if block.name == "compact": return "Compacting..." ...
Agent 主循环。在每一轮对话前检查并执行压缩逻辑,支持调用compact 工具。def agent_loop(messages: list, state: CompactState) -> None: while True: messages[:] = micro_compact(messages) # 1. 执行微压缩 if estimate_context_size(messages) > CONTEXT_LIMIT: messages[:] = compact_history(messages, state) # 2. 超限时自动触发全局压缩 response = client.messages.create(...) # 3. AI 思考 messages.append(...) if response.stop_reason != "tool_use": return # 4. 执行工具并检查 AI 是否主动要求 compact manual_compact = any(b.name == "compact" for b in response.content) # ... 执行工具逻辑 ... if manual_compact: messages[:] = compact_history(messages, state) # 5. 手动压缩
进入 learn-claude-code 项目目录并启动代码
cd learn-claude-codepython agents/s06_context_compact.py
测试一下,让它【把agents/目录下的所有python文件读一遍】(中间信息过长省略)
可以看到将所有python文件读完了并进行了总结。
在这个过程中其实是进行了压缩过程的,只是没有显示地表现出来。
我们新测试一下,让它【把agents/目录下的所有python文件读一遍,直到自动触发压缩】
(中间信息过长省略)
这里就很明显了。
这一节课学习了如何对上下文信息进行压缩,来保证任务持续正常进行下去。
其实到现在,我们已经一步步构建起了具备工具调用、任务规划、子 Agent 委派、动态技能加载以及上下文压缩的Agent👇。
我们的 Agent 已经能够读、写、执行、规划、委派,并且可以一直干活而不会耗尽上下文。
下一步,我们将在这个基础上,进一步夯实基础,为系统添加权限控制、钩子系统、持久化记忆、错误恢复等功能。
后续所有功能都将围绕我们目前实现的 Agent 来构建。