# 决定 AI Agent 能力上限的第二层：三种失控，各需一个独立上限

> 掘金 5913 分那篇把 Agent 的能力上限落在上下文工程，论证很扎实——但它写到的路由、预算、熔断都停在单步之内。任务级的三个数字不在：最多跑多少步、最多花多少钱、允不允许派子 agent。步数上限从 10 提到 20，最坏账单的输入那一半约翻四倍——三种失控各需一个独立上限，外加三个能设上限的前提。

- Published: 2026年8月30日
- Author: Leo Kaka, Engineering
- Tags: agents, reliability, cost
- Canonical: https://pirouter.ai/zh/blog/agent-ceiling-routing-layer

---
Agent 的能力上限不是一个数，是两层串起来的：**上下文层决定它每一步看到什么、
判断得准不准；调用层决定这个循环能不能跑完、跑多久、花多少钱。** 两层是串联，
不是并联——上下文优化到满分的 Agent，跑在一条没有花费上限的 `while True` 里，
上限依然是零。

本周掘金那篇 5913 分的帖子讲的是第一层，讲得很扎实。这篇讲第二层，
它有三个名字：**步数、花费、扇出**。

## 热帖把上限落在上下文工程，这个判断在它的论域里是对的

掘金那篇[《走进 AI Agent 第二篇：决定 AI Agent 能力上限的关键技术》](https://juejin.cn/post/7677562804154531890)
（本刊选题雷达 2026-08-30 采集时 5913 分、13 条评论，均为移动读数）给出的答案是一句话：

> 模型的能力是天花板，上下文的质量才是真正决定 Agent 能跳多高的地板。

这句话我完全同意，论证密度也高。举三个它讲到的地方：

- **KV Cache 约束**。它给了三条硬规则：系统提示词与工具定义一旦确定就不要改、
  动态信息永远追加到末尾、用标准 API 格式不要自行拼接消息。这三条是缓存命中率的
  物理前提，不是风格建议。
- **上下文腐化与压缩**。它引了 Lost in the Middle 那一类长上下文检索退化现象，
  并给出作者自己的复现读数：用 Kimi K3 把上下文预算压到 128K 触发压缩，
  一次把 147,877 字符压到 1,963 字符仍保住了关键信息——**这是它自己跑的，
  不是我们的实测。**
- **状态栏**。这一条它引的是第三方基准（ContextDistill-Bench），弱模型准确率涨
  40 到 54 个百分点，强模型思考 token 砍掉八九成以上。

有意思的是，**这篇文章并非没碰调用层的概念，而是它碰到的每一个都停在单步之内**：
它写了「路由」——指的是靠 `description` 字段选中哪个 Skill；写了「预算」——指的是
单个工具输出占多少上下文；甚至写了「熔断器」——指的是压缩连续失败后停手。
三个词都在，指向的都是**这一步内部怎么安排**。

任务级的那三个数字不在：整个任务最多跑多少步、最多花多少钱、允不允许派子 agent 派几个。
「重试」这个词全文没有出现过。

这不是漏，是论域——讲上下文工程的文章没义务讲任务级的界。
但**搜「AI Agent 能力上限」的人不是在做文献分类**，他是 Agent 跑不稳，
想知道自己卡在哪儿。这两层的症状长得很不一样。

## Harness 这一层里，还有一半没人画：调用怎么发出去

同一位作者的[《图解 AI Agent ①：大模型接上 API，为什么还不算 Agent？》](https://juejin.cn/post/7677170455305879562)
给了一个好用的坐标系：

> AI Agent ≈ 大模型（大脑）+ Harness（控制系统）

大脑负责想，Harness 负责让它接触真实环境、拿到反馈、再想下一步。

**下面这一步是我们加的**：Harness 这半边还能再切两半。

一半是**它给模型看什么**——上下文怎么组织、缓存前缀怎么稳住、长了怎么压、
什么时候派子 agent 隔离掉大块中间数据。热帖和图解系列讲的都是这半边。

另一半是**它替模型把调用发出去**——整个任务最多跑多少步、最多花多少钱、
允不允许派子 agent 派几个。
这半边通常没人画，因为**单步跑通时它完全不可见**：让 Agent 读个文件改行代码，
这一层是零也正常，只在循环跑长了之后才显形。

不是个别遗漏。刚引的那篇讲工具权限，同系列
[《模型到底是怎么读取文件的？》](https://juejin.cn/post/7677762452274085914)讲文件读取，
同日采到 702 与 648 分——热度都在前半边。

## 三种失控，每种都要一个自己的上限：步数、花费、扇出

multigrid.ai 那篇 [The unbounded agent](https://multigrid.ai/learn/unbounded-agent)
把这件事拆得很干净，第一句话就指出了问题：

> Every agent framework's quickstart is an unbounded agent. It has a loop, a tool list and
> a while-true.

每个框架的快速上手都是一个无界 agent：一个循环、一张工具表、一个 while-true——
而你的生产代码大概率就是从那个 quickstart 长出来的。

### 步数：模型说完成了，不等于它真的能停

第一种失控最直观。原文的描述是 agent「retries the same failing tool, or oscillates
between two states」——反复重试同一个失败的工具，或者在两个状态之间来回摆。

多数人的处理方式是让模型自己判断该停了。这个做法的问题，原文一句话说透：

> The model deciding is a heuristic; a bound is a guarantee.

模型来判断是启发式，设一个界才是保证。**而启发式失灵的时候，正好是你最需要它生效的时候**——
循环卡死往往就是因为模型对当前状态的判断出了问题，这时候再问它「你完成了吗」，
是在读一块坏掉的仪表。

### 花费：步数上限翻倍，输入侧的账单翻四倍

第二种没那么直觉。原文是「Steps are bounded but each step grows」——步数有界，
但每一步在变长：transcript 一直累积，第二十步把第一到十九步整个重发一遍。

由此得到的推论最该被记住：

> If turns add roughly constant length, total input tokens across an `n`-step run grow with
> `n` squared rather than `n`. Doubling the step limit from ten to twenty does not double the
> worst-case bill; it roughly quadruples the input half of it.

如果每轮长度大致恒定，一次 n 步运行的总输入 token 是随 n 的平方增长，不是随 n。
**把步数上限从 10 提到 20，最坏情况账单的输入那一半不是翻倍，是大约翻四倍**——
注意限定语是「输入那一半」，输出侧不按这个规律走，所以整张账单的涨幅取决于你的
输入输出比。这个数字有直接的操作意义：调 `max_steps` 的人脑子里默认的是线性。

同一个机制在账单侧有另一套叙述。MachineLearningMastery 的
[Identifying Token Costs Hiding in Your Agentic Loop](https://machinelearningmastery.com/identifying-token-costs-hiding-in-your-agentic-loop/)
把它列为第一个成本陷阱：

> Passing the full conversation history to every model call means you pay for the same
> historical tokens repeatedly.

**这里是两篇文章咬合的地方**：上下文膨胀有两个后果。热帖治的是**质量后果**——
上下文长了模型读不好，所以要压缩要隔离；这一层治的是**成本与终止性后果**——
上下文长了钱变多，而且是平方地变多，所以要设界。同一个膨胀，两拨人看到两件事。

MLM 的第二个陷阱和这条相乘：无界重试会「drag the full bloated context of the failure
along for every retry」——每次重试都拖着那份已膨胀的失败上下文。**失败重试是在最贵的
上下文长度上重复付费**。重试预算本身怎么设（按近期成功调用的比例，而非每请求固定几次），
本刊 [Retry storms: 9K to 100K RPS](/blog/retry-storms) 写过，这里不重复。

### 扇出：子 agent 各带一份预算，乘起来才是你的账单

第三种最容易漏。原文：

> The agent spawns sub-agents or parallel tool calls, each of which has its own step budget.

Agent 派出子 agent 或并行工具调用，**每一个都带着自己那份步数预算**。

这一条和前一条是两件事，别合并着算。前一条讲的是**一个循环内部**步数怎么把账单撑起来；
这一条讲的是**循环有几个**。一个五步的主循环派出三个各二十步的子 agent，总步数不是 5，
也不是你给主循环设的那个 20——每个子 agent 都带着自己的一份额度出门。原文的说法是
`Bounds that are per-agent rather than per-task multiply`：**按 agent 设的界会翻倍，
按任务设的界才不会。** 至于每个子 agent 内部的增长曲线长什么样，取决于它继承了多少
上下文，这个我们没有可引的数据，不猜。

这里有个不太舒服的呼应。热帖推荐用子 Agent 隔离来控上下文——「用隔离代替压缩」，
让大体积中间数据不进主上下文。隔离确实解决了上下文膨胀，但它同时把预算问题从一份
变成了 N 份。**两个都正确的做法，在不同维度上互为代价**——不是谁写错了，
是这一层没被摆上台面时必然会发生的事。

![三行清单卡「三种失控，三个独立的界」：步数——反复重试同一个失败工具或在两个状态间摆动；花费——步数有界但每步在长，输入侧随步数平方增长；扇出——子 agent 各带一份预算，按 agent 设的界会翻倍](/blog/images/agent-ceiling-routing-layer-fig.png "三种失控互相看不见对方：任何一个界都拦不住另外两个。")

三种放在一起：

| 失控类型 | 症状长什么样 | 该设的界 | 能靠模型自觉吗 |
|---|---|---|---|
| ✗ 步数 | 反复重试同一个失败工具、两个状态之间摆动、任务永远差最后一步 | 单次任务最大步数 | ✗ 判断力本身就是坏掉的那个零件 |
| ✗ 花费 | 账单与步数不成比例、后半程每步都比前半程贵 | 单次任务花费上限 | ✗ 模型看不到累计账单 |
| ✗ 扇出 | 主循环看着很短，账单对不上 | 子 agent 并发数与深度上限 | ✗ 每个子 agent 只知道自己那份 |

这三种失控还有个照镜子的版本——你自己手动切模型的时候。本刊
[《手动在四个模型之间切换？这套规则有三个失效点》](/zh/blog/you-are-already-routing)
写的是**人脑里那套规则的三个失效点**：前提数字会过期、额度耗尽后没写降级路径、失效是无声的。
对照着看：**人的失效是「忘了」，循环的失控是「不会停」**——人会累会分心，
所以规则失效；循环不累不分心，所以它一直转。处方正好相反：人要提醒，循环要界。

## 能设上限的三个前提：完成条件、外部进展、可回滚的工具

界不是随便设的。同一篇文章给了三个前提，缺一条你就设不下去——或者设下去了不敢用。

**一、可判定的完成条件。** 原文：「Not 'the model says it is finished' but a predicate
you can evaluate.」不是「模型说它完成了」，而是一个你能求值的谓词。
落到代码里就是一句话：**你写得出一个能跑的判定函数吗。**

**二、外部可见的进展。** 原文：「a step that changes nothing is detectable」——
如果每一步本该改变 transcript 之外的某样东西，那么什么都没改的那一步就是可检出的。
这是空转检测的全部依据：不看模型说什么，看世界变了没有。

**三、幂等可回滚的工具。** 原文要求每个工具「leave the world in a state you can resume
from or roll back」——留下一个你能续跑或能回滚的世界状态。这条决定了前两条敢不敢用：
**工具不可回滚，你就不敢在中途停**，于是所有上限都成了摆设——触发上限的后果
是留下一个半完成的烂摊子。

三条里最难的是第一条。**多数 Agent 任务根本写不出可判定的完成条件**——
「把这个 bug 修好」「整理一下这批数据」，这些任务的完成态是模糊的。
写不出来，默认就退回去问模型，而这正是三种失控的共同起点。

我的判断是：**写不出判定函数的任务，就该老老实实用步数上限硬兜，不要假装它有个终点。**
硬兜的代价是偶尔在一个本来能做完的任务上中断，可见、可调、一次几毛钱；
不兜的代价是某一次它不停了，而你在睡觉。

MLM 那篇还列了两条不涉及架构改动、翻一遍代码就能拿到的：**工具返回未过滤**（原始 API
响应直接塞进上下文，元数据和空字段一个都用不上）与**系统提示词重复注入**（每次调用都送一份
定义了 20 个工具的系统提示词，哪怕这步只用一个）。

## 先把这一层画出来，再决定自建还是买

回到标题。上限是两层的串联：上下文层满分、调用层是零，Agent 的表现会是
「有时候很惊艳，跑长了就翻车」——这个症状最误导人的地方在于，它看起来像模型不够强。

有一件成本为零的事现在就能做：**去你的 agent 循环里找这三个数字——最大步数、
单次任务花费上限、子 agent 并发与深度上限。找不到就是没设**——不是设得不好，
是这一层在你的代码里还不存在。

再往外看一步。单个循环之外，这一层的问题会跑到进程外面去：多个 agent 共享同一个上游配额、
一个供应商静默降级同时影响所有循环、账单账户本身的层级变动。故障域比 API 端点大得多——
本刊 [Tier 3 to Tier 1 mid-flight](/blog/billing-failure-domain) 写的就是账单层与目录层
怎么在状态页全绿时让服务停下来。到了那个尺度，无论自建还是买，要问的是同一批问题：
上限是配置项还是硬编码，触发之后的默认动作是什么，多个循环共享配额时谁先被限。

热帖那句「上下文的质量才是地板」是对的。这篇想补的只有一句：**地板之上还得有个天花板，
而这个天花板没人替你钉。**

---

## Sources

### juejin.cn

- [《走进 AI Agent 第二篇：决定 AI Agent 能力上限的关键技术》](https://juejin.cn/post/7677562804154531890)
- [《图解 AI Agent ①：大模型接上 API，为什么还不算 Agent？》](https://juejin.cn/post/7677170455305879562)
- [《模型到底是怎么读取文件的？》](https://juejin.cn/post/7677762452274085914)

### multigrid.ai

- [The unbounded agent](https://multigrid.ai/learn/unbounded-agent)

### machinelearningmastery.com

- [Identifying Token Costs Hiding in Your Agentic Loop](https://machinelearningmastery.com/identifying-token-costs-hiding-in-your-agentic-loop/)
