Agent 真正跑起来,靠的不是工具,而是 loop | WhatAICanDo Skip to content

Agent 真正跑起来,靠的不是工具,而是 loop

Devin
Published date:
2 min read

agent 有些人很快就会联想到 MCPskillplugin。这些东西当然重要,但如果你真想知道 agent 到底是怎么跑起来的,最该盯着看的其实不是它接了多少能力,而是它有没有一条像样的 loop

因为 agent 和普通聊天模型最大的区别,不是“工具更多”,也不是“回答更长”。真正的区别是,聊天模型通常是一问一答,答完这一轮,事情就结束了。agent 不是。对它来说,一轮输出只是过程,不是结尾。事情没做完,它就继续往下走。

这就是 loop。

如果换个角度看,大概就是:先看目标,再看现在知道什么,让 LLM 判断下一步,必要时调工具,拿回结果,更新状态,然后看要不要继续下一轮。

听上去不复杂,但 agent 真正有意思的地方 —— 也就是它的核心,基本就是 loop。

loop 到底是什么

第一次听到 loop,容易把它理解成“循环调用大模型”。这个理解抓住了形式,但还没触及核心。

真正有用的 loop,不是让模型多说几轮,而是让整个系统前后接得上:

要不然就不是 loop,只是重复刷新对话。

把它压到最简单,一个能工作的 agent loop,通常总会有这些东西:

换句话说,模型只是里面的一个节点,不是全部。

伪代码写出来,大概是这样:

while (!done) {
  context = buildContext(goal, state, memory, availableTools)
  decision = llm(context)
  action = parse(decision)

  if (action.type === "ask_user") {
    waitForUser()
  } else if (action.type === "call_tool") {
    result = executor(action)
    state = updateState(state, result)
    memory = updateMemory(memory, result)
  } else if (action.type === "respond") {
    output(action)
    if (taskFinished(action, state)) done = true
  } else if (action.type === "replan") {
    state = rewritePlan(state)
  }

  if (tooManySteps || highRisk || repeatedFailure) {
    escalateOrStop()
  }
}

代码不重要,重要的是从这里能看出来一件事:agent 不是大模型自己在外面飞,而是大模型被放进了一套运行着的系统里。

LLM 在 loop 里到底干嘛

“loop 控制 LLM”这种说法太肤浅。更贴近实际的理解是:运行时会先把这一轮的边界画出来,然后让模型在这个边界里做判断。

先决定这一轮让它干什么

比如这一轮,你到底是让它:

系统得先说清楚。不是每一轮都让模型直接输出“最终答案”。很多时候,一轮只负责一个局部动作,这样才稳。

再决定这一轮让它看什么

而且系统还得决定,这一轮到底让它看什么。一般不会把所有历史、所有文档、所有工具说明一股脑塞进去,而是只给当前目标、当前阶段、最近几步、相关记忆、允许使用的工具,再加上这一轮的输出格式要求。很多人会把这一步叫 context building,说白了,就是先把这一轮该看的牌发给它。

再决定它怎么说

再往下,是输出怎么接。成熟一点的 agent,通常不会让 LLM 随便吐一大段自然语言,再由程序去猜它是不是想调工具。更常见的是让它结构化输出。比如它明确说自己想搜文档,关键词是什么;或者它承认现在缺信息,想先问用户一个问题。这样系统就知道它这轮是在选动作、追问、输出,还是要求重规划。

最后决定采不采纳

但这里还有一个很关键、也很容易被漏掉的动作:即使模型说“我想调这个工具”,系统也不一定照做。运行时通常还会再检查一遍。工具是不是可用,参数合不合法,当前阶段适不适合调,预算和权限够不够,是不是高风险动作,要不要先让人确认。过了这些检查,才真的执行。

所以从头到尾,LLM 在 loop 里更像一个负责判断的节点。它不是整个 agent,也不是它想干嘛就干嘛。

能力是怎么被调起来的

顺着这条线再往下走,能力调度这件事其实也没有想象中那么花哨。无非就是三件事:

  1. 现在该不该调能力
  2. 该调哪一个
  3. 调完以后结果怎么接回下一轮

第一步:先有一份能力清单

第一步通常是先有一份能力清单。系统得知道自己手里有什么:工具名、用途、参数长什么样、权限等级、成本、限流、适合什么场景。MCP、原生工具、内部 API、插件,到了这里一般都会先被抽象成“可调用能力”。所以从 loop 的角度看,MCP 更像是一种接入方式,而不是 loop 本身。

第二步:再做动作选择

第二步是动作选择。这里通常是 LLM 参与最深的地方。运行时把目标、状态和工具清单给模型,模型提一个下一步建议,比如“先搜一下资料”或者“先调用日历”。然后系统再做一层校验。真正靠谱的 agent,往往都不是“模型一个人说了算”,而是“模型提议,系统把关”。

第三步:真正调用时还有执行器

第三步才是真正调用。工具被选中以后,通常还要经过一个执行器。这个名字听起来有点工程,但东西很实在:它负责参数转换、发起 API 调用、处理超时、做重试、做限流、捕获错误、统一结果格式。外部世界从来不是整齐的,模型会推理,不代表外部系统就会自动配合。

第四步:结果要回到回路里

最后一步,是把结果送回回路。工具结果回来以后,事情还没完。系统一般会更新任务状态、更新工作记忆、记录日志,再把真正重要的部分送回下一轮 LLM。没有这一步,前一轮和后一轮就接不上,回路也就断了。

任务为什么老是越跑越散

聊到这里,另一个经常把 agent 拖垮的地方也就顺带冒出来了:任务设计。

很多 agent 给人的感觉是,一开始还挺像那么回事,转几轮以后就开始飘。常见原因其实不是模型突然变笨了,而是任务从一开始就没立住。目标很大,但没有阶段;做到哪里了,没有状态;什么叫完成,没有定义;失败了怎么办,也没有约定。这样一来,loop 每一轮都像重新开局,当然容易发散。

一个能落地的任务,通常至少要把四件事说清楚。

任务对象

先是“这到底是哪件事”。你不一定非要写出一套很正式的数据结构,但至少要让系统知道:目标是什么,有什么约束,现在是什么状态,优先级怎样,有没有预算或截止时间。

中间状态

然后是中间状态。复杂任务最好别只有“未完成”和“已完成”两档。中间阶段越清楚,loop 越不容易迷路。比如搜集信息、规划、执行、等工具结果、等用户输入、验证、完成、失败,这些状态听起来朴素,但真有用。它让下一轮不用重新猜“我现在做到哪了”。

成功条件

还有一个特别重要、但经常被省掉的东西:成功条件。没有它,loop 很容易出现两种情况。要么事情其实已经差不多了,还在继续空转;要么明明没做完,却提前宣布结束。系统总得知道,什么东西交出来才算完成,哪些检查通过了才算可以收工,哪些情况必须停下来交给人。

失败条件

失败条件也一样重要。连续几次工具调用失败怎么办,缺关键输入但一直拿不到怎么办,超出预算怎么办,检查反复不过怎么办。不是非得把系统设计得很悲观,而是总得知道什么时候该停。

记忆怎么设计

说到这里,记忆这件事也会自然冒出来。很多人一提 agent 记忆,第一反应就是向量数据库。向量检索当然有用,但如果只把记忆理解成“往库里塞东西”,其实还是离日常运行有点远。

对一个 loop 来说,记忆最重要的不是“存得多”,而是“下一轮能拿到刚刚好的信息”。

通常至少会有三层。

工作记忆

第一层是工作记忆,离当前任务最近。这里放的是当前目标、当前阶段、最近几步动作、本轮关键结果、待办子任务、用户刚补充的限制条件。它不追求全,只追求近,追求这一轮能马上用上。

情节记忆

第二层可以叫情节记忆,也就是“这件事之前发生过什么”。比如之前走过哪条路线,哪个工具失败过,用户否决过什么方案,上一次停在什么地方。它的价值不是积累知识,而是避免系统一遍遍踩同一个坑。

长期记忆

第三层是长期记忆。用户的长期偏好、某个项目的历史资料、团队固定的术语表,或者一些业务规则,通常放在这里。它不是每轮都塞给 LLM,而是需要的时候再检索出来。

常见的坑

记忆这件事里,最常见的坑也挺直白:

所以比起“有没有记忆”,更重要的问题往往是:这条信息属于哪一层,要留多久,下一轮到底需要原文还是摘要,什么时候可以淘汰。

从系统角度看,它大概有哪些层

如果把这些东西稍微抽象一下,从系统角度看,一个 loop 里面大概总会有这些层:

这些层未必要在代码里摆得一模一样,但大多数能工作的 agent,思路都差不多。loop 能不能闭合,靠的就是这些地方能不能互相接住。

用写文章这件事,跑一遍 loop

拿一个接近日常的例子来说,假设目标是:写一篇面向普通读者的文章,解释 agent 的 loop 如何控制 LLM、调度能力、管理记忆和任务。

一个更像样的 agent,大概率不会一上来就开写正文。它通常会先建立任务状态,把目标、读者、限制条件这些最基本的东西写进去,再看还缺不缺关键输入。缺了,就先问。

然后它会先规划结构。这个阶段不急着出正文,而是先搞清楚应该回答哪些问题,顺序怎么排,哪些地方要举例,哪些地方要放伪代码。结构出来以后,系统还可以先过一遍,看看是不是覆盖了真正要回答的东西。

再往后,才是补上下文。如果发现“怎么控制 LLM”这一段讲得还不够,它会去检索资料、读本地文档、读代码说明,结果拿回来以后写进工作记忆。

接着才开始分段写作。一般也不是整篇一次吐完,而是一段一段写:先写 loop 是什么,再写 LLM 的角色,再写能力调度,再写任务设计,再写记忆设计。每一段写完,都可以顺手检查一下。

最后还有一轮验证。有没有偏题,控制关系是不是讲清楚了,任务、记忆、调度是不是讲透了,哪段是不是还在说空话。如果某个地方不过,就回到那一段修,而不是把整篇文章推翻重来。

看到这里,其实就差不多了。一直在转的不是“大模型自己”,而是这套运行时里的回路。LLM 只是其中负责判断的一段。

skillMCPplugin 放在什么位置

至于 skillMCPplugin,这篇不打算多讲。skill 更像一套做事方法,会影响 loop 的走法,但不等于 loop;MCP 更像标准化的能力接入方式,解决的是“怎么接进来”,不是“这件事怎么推进”;plugin 更像附加能力模块,给系统增加能做的动作,但不决定 loop 该怎么转。

所以如果一定要压成一句话,大概可以这么理解:loop 是回路,LLM 是做判断的节点,skill 是方法,MCP 是连接方式,plugin 是附加能力。

为什么有些 agent 还是像聊天机器人

聊到最后,其实判断一个东西到底像不像 agent,也没有那么玄。如果一个系统只是给模型一堆工具说明,让它自己挑一个,工具结果回来以后再往下说,那它当然已经比纯聊天强一点了,但很多时候还是更像“带工具的对话系统”。

一个更完整的 agent,通常还会多出这些东西:明确的任务状态,清楚的成功和失败条件,结构化动作协议,受控的能力调用,分层记忆,以及检查、重试、回滚、停机这套机制。最关键的是,它会多轮推进,而不是一次说完就算数。

说到底,看的还是同一件事:它有没有一套稳的 loop。

最后一句话

现在再回头看,loop 其实没有那么玄。说的无非就是系统怎样一轮一轮地读取目标、组织上下文、调用 LLM 做判断、把判断变成动作、拿回结果、更新状态,然后继续下一轮。

没有这条回路,大模型再强,也更像一个很能说的模型。有了这条回路,再加上任务、记忆、能力调度、执行器和检查机制,它才慢慢有了“做事”的味道。

所以以后再听到“大脑”“四肢”这种比喻,可以当作一种形象化的说法,但不必过度解读。真正决定 agent 能不能跑起来的,通常不是哪个部件最像什么,而是这条回路到底有没有搭起来,而且接得稳不稳。

Next
What Makes an Agent Work Is Not the Tools, but the Loop