全部课程
亲手写一个 Agent/ Loop · 一次调用不是 agent,循环才是/ 先把 agent 卡在半路 源码
Loop · 一次调用不是 agent,循环才是

先把 agent 卡在半路

别急着看"主循环"三个字。这一课不讲机制,先让你亲手把一个 agent 弄"死"——看它怎么在任务做到一半时停住、干等。你先撞上这个坑,下一课那个循环才有意义。

上一章你造好了 Session——一本记事的账本。这一章要让 agent 动起来:真的读文件、跑命令、一步步把事做完。

但动起来之前,先看它不会动的样子。这一课不讲任何机制,就干一件事:把一个 agent 弄卡住,让你亲眼看它死在半路。 你先撞上这个坑,下一课那根救命的循环才有分量。

卡在半路——桥只修了一半,阿澄站在断口伸出爪子,却够不到对岸;一次调用的 agent 就这样停在半空。


一个只会”说一句”的 agent

假设你刚学会调大模型,写了个最朴素的 agent:把用户的话发给模型,把模型的回答打印出来。就这样:

用户:帮我看看 login.ts 为什么报错
模型:这个我需要读一下 login.ts 的内容。
      (调用工具 read("login.ts"))

模型很配合——它说它要读文件,还老老实实发出了一个 read 的工具调用。

这就是”只调一次模型”的天花板:模型能开口要工具,但没人替它执行、再把结果递回去。 它像一个被按了暂停的人,话说到一半,永远停在那儿。


你来当那段”缺失的代码”

那段缺失的代码该干嘛?我们不写代码,你来当它。 我给你模型每一轮说的话,你决定下一步做什么。转几圈,你就会摸到那个规律。

第 1 轮,模型说:

我要读 login.ts。(调用 read("login.ts"))

于是第 2 轮,你把文件内容递回去、再问了一次。模型看了文件,说:

我看到了。顺手 grep 一下整个目录,看还有没有别处也这样。(调用 bash("grep ..."))

你照做:执行 grep、把结果递回、再问一次。第 3 轮,模型说:

找到了。login.ts 第 42 行少了 await,另外还有两处一样的问题。(这一轮它没有再要任何工具)


你刚才在手动转的那个东西

你刚才凭直觉转了三圈,每一圈都在做同一件事:

看模型这轮要不要工具 → 要,就执行、把结果递回、再问一次 → 不要,就停。

这个”一圈一圈转、转到模型不再要工具为止”的东西,就是 agent 的主循环(loop)。你朴素 agent 缺的,正是它。

  • 一次调用,只能拿到”我要读文件”这半句——然后死在半路(你一开始撞上的坑)。
  • 一个循环,能替模型把工具执行掉、结果递回、接着问,直到它把事真的做完(你后来手动转出来的)。

你已经用直觉把它转出来了。下一课,我们把你这三圈变成十行代码,并且回答一个你可能还没意识到的问题:

刚才是你在判断”该停了”。可代码怎么知道该停?——其实不是代码知道,是模型每一轮都在悄悄告诉它。

那个信号,下一课见。