SubAgent 如何设计的节省上下文?Agent 工程实战与想法!

0 阅读3分钟

最近的工作

最近,我自己编写了一个给自己用的 CLI 工具(项目还在优化,暂不公布开源地址)

设计这个 CLI 的时候大范围借鉴了 kimi-cli

而关于 CLI 的设计上来说,业界也会有诸多的人如我一般,都会思考两件事

  1. 上下文如何节省
  2. 注意力如何不分散

于是我们今天就来聊一聊,我对这两件事的不同看法和实践

我们首先必须得知道的一个前提是上下文很昂贵

这个昂贵有两层含义,一个是经济上的,一个是对于 Agent 来说的

前者不必提,后者是当上下文接近 80% 的时候 AI 就会被记忆给拖累以至于无法产出代码

基于这个前提,我们自然会有许多手段来防止上下文溢出,这里先介绍一下三个业界内比较普遍的手段。

1. 上下文压缩

让 LLM 自己把整个上下文压缩,去掉冗余信息 kimi-cli 在这点上做的非常顶,它们的 COMPACT.md 非常棒。

2. 动态裁剪

上次跟朋友讨论这个的时候,朋友分享了一个 OpenCode 的插件

就是把一些不必要的 ToolCallToolResult 让 LLM 自己压缩起来

这种方案缺点是会导致模型提供商围绕请求做的缓存失效。

3. 子代理 (SubAgent)

当前的 SubAgent 的方案其实就是多花 Token 外包某项任务给其它 Agent,而后 Main Agent 就可以通过 SubAgent 的汇报来保证自己注意力不分散、上下文精湛且任务能成功完成。

这种方案缺点就是烧钱,你毕竟启动了一个新的 SubAgent,那么其实就是砸钱保证 Main Agent 的冰清玉洁。

4. 我个人的方案 (Fork)

我个人的方案是操作系统那个异常经典且令人拍案叫绝的 fork() 函数

其核心思想是:SubAgent 继承 MainAgent 在分叉时刻的完整上下文。

为什么是这个方案?

  1. 模型提供商的缓存大多数基于前缀匹配

DeepSeek, Anthropic or MoonShot 等提供商对缓存的判断其实是前缀是否相同。

前缀? 不知道有没有学习算法的小伙伴,有没有想到数据结构里的Trie前缀树。等等,你说到了是吧?为什么我们不能让 SubAgent 像树一样被生成出来呢?所以就有了这篇文章。

对当前 SubAgent 方案上下文的建模

Main Agent:Thinking RoundSubAgent:Thinking Round\begin{array}{c} \text{Main Agent:} \quad \underbrace{\rule{4cm}{0.4pt}}_{\text{Thinking Round}} \quad \blacktriangleright \\ \text{SubAgent:} \quad \underbrace{\rule{4cm}{0.4pt}}_{\text{Thinking Round}} \quad \blacktriangleright \end{array}

如果是 Fork 的上下文的建模如下

MainAgentRound 1Sub1MainSub2Round 2Round 2Round 2(并行)(并行)(并行)\begin{array}{ccccc} & & \stackrel{\text{Round 1}}{\text{MainAgent}} & & \\ & \swarrow & \downarrow & \searrow & \\ & \text{Sub1} & \text{Main} & \text{Sub2} & \\ & \downarrow & \downarrow & \downarrow & \\ & \text{Round 2} & \text{Round 2} & \text{Round 2} & \\ & \text{(并行)} & \text{(并行)} & \text{(并行)} & \end{array}

如果我们计入 缓存命中 的话,那么 fork 的方案就会有很明显的优势。

  1. 缓存复用率很高,缓存命中之后成本节省接近 90%
  2. 完整的项目记忆,对项目的记忆无损的转发到 SubAgent 上,只要这个 SubAgent 承担是有关项目的工作,那么就不必再去自己探索或依赖其它有信息损耗的设计方案(譬如 AGENTS.md)

其它

我个人最近在找工作,有任何工作机会欢迎联系我 Email: smallorangeqwq@gmail.com