【免费下载链接】mini-coding-agent
Minimal and readable coding agent harness implementation in Python to explain the core components of coding agents.
mini-coding-agent 是一个用 Python 编写的极简 coding agent(编码智能体),这篇文章带你解析它的上下文压缩四板斧:工具输出截断、Transcript 分层压缩、read_file 去重和重复调用拦截,看看截断与去重如何防止 Prompt 爆炸。
作为 mini_coding_agent.py 六大核心组件中的第 4 个,「Context Reduction And Output Management」(上下文缩减与输出管理)解决的是 coding agent 最现实的痛点:历史只增不减,而上下文窗口有限。前文讲过,agent 每一轮都会把「稳定前缀 + 记忆 + 完整对话记录 + 当前请求」重新拼成一份完整 Prompt 发给模型。如果没有压缩,读几个文件、跑几次测试,Prompt 就会迅速膨胀,轻则挤掉关键指令,重则直接超出模型上下文窗口。
四板斧速览:上下文压缩的四个拦截点
mini-coding-agent 用四个机制层层设卡,全部集中在 mini_coding_agent.py 中:
| 板斧 | 拦截点 | 关键实现 | 上限 |
|---|---|---|---|
| 一:出口截断 | 工具结果写回历史前 | clip() | 单条 4000 字符 |
| 二:分层压缩 | 重建 Transcript 时 | history_text()的 recent 窗口 | 近 900 / 旧 180~220 |
| 三:读操作去重 | 重建 Transcript 时 | seen_reads集合 | 同路径只留一条 |
| 四:总量兜底 + 循环拦截 | Transcript 末尾 / 工具调用前 | MAX_HISTORY、repeated_tool_call() | 全文 12000 字符 |
两个全局常量定义在文件头部,一眼就能看懂设计意图:
MAX_TOOL_OUTPUT = 4000 MAX_HISTORY = 12000(见 mini_coding_agent.py)
板斧一:工具出口统一截断——每条结果最多 4000 字符
第一道关卡是模块级函数clip():
def clip(text, limit=MAX_TOOL_OUTPUT): text = str(text) if len(text) <= limit: return text return text[:limit] + f"\n...[truncated {len(text) - limit} chars]"(见 mini_coding_agent.py)
它的设计有两个亮点:
- 单点收口:所有工具(
read_file、search、run_shell……)的结果都经过run_tool()这一个出口,出口处统一调用clip(tool"run")(见 mini_coding_agent.py),不管模型跑了什么命令,结果都进不了 4000 字符以上的「巨无霸」。 - 保留截断通知:截断时不是静默丢弃,而是追加
...[truncated N chars]。模型因此知道内容不完整,会改用read_file的start/end分段读、或缩小搜索范围,而不是基于残缺信息瞎猜。
顺带一提,同样的手法还用在静态信息上:项目文档截断到 1200 字符(mini_coding_agent.py)、git status 截断到 1500(mini_coding_agent.py)、记忆笔记压缩到 220(mini_coding_agent.py)、任务描述 300 字符(mini_coding_agent.py)。截断不是打在某一处,而是打在每一个「进入 Prompt 的入口」上。
板斧二:Transcript 分层压缩——最近 6 条保真,旧记录瘦身
历史不截断到固定条数,而是按「新旧」区别对待。history_text()在每次构建 Prompt 时把 history 重新渲染成文本,核心逻辑:
recent_start = max(0, len(history) - 6) ... if item["role"] == "tool": limit = 900 if recent else 180 else: limit = 900 if recent else 220(见 mini_coding_agent.py)
效果是:最近 6 条记录保留 900 字符的完整细节,更早的记录压缩到 180~220 字符,约 1/5 的体量。模型对「刚发生了什么」看得很清楚,对「很久以前做了什么」只保留骨架。
为什么是 6?因为默认--max-steps就是 6(mini_coding_agent.py),一次用户请求最多产生 6 步工具调用——recent 窗口恰好覆盖「当前这一轮请求」的全部上下文,再往前的内容都归入压缩区。
板斧三:read_file 去重——外加一个写操作失效机制
coding agent 最常见的上下文浪费是:同一个文件被反复读,同样的文件内容在 Transcript 里出现 N 遍。mini-coding-agent 用一个seen_reads集合解决:
seen_reads = set() ... if item["role"] == "tool" and item["name"] in ("write_file", "patch_file"): seen_reads.discard(path) if item["role"] == "tool" and item["name"] == "read_file" and not recent: if path in seen_reads: continue seen_reads.add(path)(见 mini_coding_agent.py)
两个关键细节值得品味:
- 跳过的是整条记录(
continue),既删文件内容,也删对应的调用行,重复读取在 Prompt 中彻底消失。 - 写操作会清空去重标记:一旦对某路径执行了
write_file或patch_file,就discard(path),之后对该文件的读取必须重新完整展示——否则模型会基于旧版本文件内容做判断,这是去重策略最容易埋的雷。
项目为这两个行为都写了专门的回归测试:test_history_text_deduplicates_unchanged_repeated_reads(无写入时重复读只保留一条,见 tests/test_mini_coding_agent.py)和test_history_text_deduplicates_reads_but_not_after_write(写后第二次读取不得跳过,见 tests/test_mini_coding_agent.py)。从测试代码能看出作者对这块逻辑的严谨程度。
板斧四:总量兜底与重复调用拦截
最后两道保险,一个防「总量」,一个防「内卷」:
1. Transcript 总量封顶。history_text()的最后一行对整体再做一次截断:
return clip("\n".join(lines), MAX_HISTORY)(见 mini_coding_agent.py)
无论历史堆了多少条、去重后还剩多少,进入 Prompt 的 Transcript 永远不会超过 12000 字符。即使前几板斧全部失效,也不会失控。
2. 源头拦截重复调用。与其等同样内容进历史再压缩,不如直接不让它进来。repeated_tool_call()检查最近两条工具事件是否「同名且参数完全相同」,若是,run_tool()直接返回错误:
if self.repeated_tool_call(name, args): return f"error: repeated identical tool call for {name}; choose a different tool or return a final answer"(见 mini_coding_agent.py)
这个错误信息本身就是提示词工程——它不只是拒绝,还告诉模型「换一个工具或给出最终答案」。对应测试见 tests/test_mini_coding_agent.py。
四板斧如何协同:一次 ask 的 Prompt 数据流
把四板斧放回prompt()的组装过程,整条链路就清晰了:
- 落盘时全量保存:
record()把工具结果完整写入 session JSON(mini_coding_agent.py),只做了 4000 字符的出口截断——所以会话可以无损续接; - 构建 Prompt 时按需压缩:
history_text()现场渲染,依次应用分层压缩(板斧二)和读去重(板斧三); - 总量兜底:渲染结果再过一次 12000 字符上限(板斧四);
- 源头防循环:重复调用在进入历史之前就被拒绝(板斧四)。
💡 这里最妙的一点是:压缩只发生在「读」的路径上,而不是「写」的路径上。磁盘上的 Transcript 永远是完整的,压缩是构建 Prompt 时的一个只读视图。既不损失可恢复性,又保证了每次发给模型的 Prompt 体积可控。
小结:可以直接抄走的上下文管理清单
mini-coding-agent 用不到 100 行相关代码(clip 与 history_text)就覆盖了上下文压缩的通用套路,四个要点可以直接借鉴到自己的 agent 项目里:
- ✂️工具出口统一截断,且保留「被截断」通知,引导模型分段读取;
- 🕘Transcript 分层:recent 窗口保真、旧记录瘦身,窗口大小对齐单轮步数预算;
- 🧹重复读取去重,但写操作必须让去重标记失效,防止模型看到陈旧内容;
- 🛡️总量封顶 + 重复调用拦截,一个兜底、一个在源头掐断循环。
理解了这四板斧,你就掌握了「如何防止 Prompt 爆炸」的最小可行方案——复杂项目里的摘要式压缩(summarization)无非是这套思路的升级版。
更多组件解析:项目背景与运行方式见 README.md,完整交互示例见 EXAMPLE.md。
【免费下载链接】mini-coding-agent
Minimal and readable coding agent harness implementation in Python to explain the core components of coding agents.
相关推荐
Agent Zero 上下文截断机制解析:从 `fw.msg_truncated.md` 模板到源码级实现
Agent Zero 上下文截断机制解析:从 fw.msg_truncated.md 模板到源码级实现 导读 在 Agent Zero 这类长会话 AI 框架中
人工智能大模型AI AgentAgent 框架自主智能体多智能体工具调用MCP 服务浏览器控制Pixelfed 代码去重重构指南:四大 Boilerplate 模板的收敛与源码级解析
Pixelfed 代码去重重构指南:四大 Boilerplate 模板的收敛与源码级解析 导读 notes/DeduplicationChanges.md 记录
后端前端长对话上下文爆炸怎么办?capsule-react上下文压缩机制与上下文引擎协同指南
长对话上下文爆炸怎么办?capsule react上下文压缩机制与上下文引擎协同指南 capsule react 是 Astrid OS(Unicity AOS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考