AI 智能体的执行原理

很久没更新。这篇把「AI 智能体到底是怎么把一件事做完的」按执行过程写清楚。不讲某一家产品的界面,只讲运行时里反复发生的那几步。

先把对象说清楚

普通对话模型做的是一次生成:你给一段上下文,它回一段文字,然后停住。

智能体多出来的是一个会停下来再出发的循环。它面对的不是「回答这句话」,而是「把这个目标做完」。做完往往要经过好几轮:想下一步、调用一个工具、看工具返回了什么、再决定要不要继续。

所以智能体不是另一个更长的提示词。它是模型,加上一套负责循环、调用工具、记下观察的运行时。

一次执行里有四样东西

跑起来之前,运行时手里通常有这些:

  • 目标。用户这句话,以及系统提示里规定的完成标准。
  • 模型。负责决定下一步。它不直接碰文件、网络或数据库。
  • 工具。搜索、读文件、跑命令、发请求。每件工具有名字、参数和返回值。
  • 记忆。眼下这场对话的上下文,以及写在外面的笔记、文件或检索结果。

模型负责「下一步做什么」。运行时负责「真的去做,并把结果送回来」。两边分开,后面很多现象就好理解了。

主循环

把一次任务收成这个循环:

  1. 组装上下文。把目标、可用工具、已经发生的步骤,整理成模型这次能看见的输入。
  2. 让模型决定。模型要么给出最终答复,要么给出一次或多次工具调用。
  3. 执行工具。运行时检查参数、真正调用,拿到一份观察。
  4. 把观察写回去。观察成为下一轮上下文的一部分。
  5. 检查是否停止。完成、失败、步数或预算到顶、或者碰到需要人确认的动作,就退出。否则回到第 1 步。

用一段接近运行时的伪代码看:

state = { goal, tools, history: [] }

while not stopped(state):
    decision = model.next(state)

    if decision is final_answer:
        return decision.text

    for call in decision.tool_calls:
        observation = tools.run(call.name, call.arguments)
        state.history.append(call, observation)

return stopped_reason

model.next 每次只产生一个决定。tools.run 才接触外部世界。历史被追加,而不是被模型自己记在权重里。这场任务的过程,活在 state 里。

用一个小任务走一遍

目标:查明天上海会不会下雨。会下雨的话,写一条短提醒;不会就说明天不用带伞。

第 1 轮。 上下文里只有目标和两个工具:weather.lookup(city, date)、notes.write(text)。模型还没有观察,它不应该编一个降雨概率。合理的决定是调用天气工具,参数是上海和明天的日期。

第 2 轮。 运行时执行查询,观察写回,例如:「明天有雨,降水概率 80%。」模型看见的是这条观察,不是它自己的猜测。这时它决定调用 notes.write,写入一句提醒。

第 3 轮。 笔记工具返回「已写入」。目标里的两件事都有了对应观察:查过天气,也写下了提醒。模型给出最终答复,循环结束。

注意顺序。模型不能在第 1 轮就声称「已经查过了」。查过这件事,只存在于工具返回之后。

工具调用实际长什么样

模型输出的不是一段自然语言里的「请帮我搜一下」,而是运行时能解析的结构,大致是工具名加上参数:

{
  "name": "weather.lookup",
  "arguments": { "city": "上海", "date": "2026-10-10" }
}

运行时接着做三件事:

  • 这个名字在不在允许的工具列表里。
  • 参数是否符合约定,比如日期是不是缺了。
  • 调用是否越过权限。读公开天气和删除文件不是同一级动作。

然后才执行。返回值再被包成观察,例如「调用成功」或「参数错误:缺少 date」。失败也是观察。下一轮模型应当根据失败改参数或换一条路,而不是假装成功。

规划是怎么出现的

循环本身不规定模型要不要先写计划。常见有三种安排,差别在于提示和运行时约束,不是三套互斥的引擎。

边想边做。 每一步先写一句当前判断,再调用一个工具,看到结果再想下一步。适合目标清楚、但路径要看现场的任务,比如查资料、改一处报错。这种交错常被叫做 ReAct:推理和行动挨在一起。

先计划再执行。 模型先列出步骤,运行时按步骤推进,每步仍然可以调用工具。适合边界清楚的流程,比如「备份、修改配置、再检查服务是否起来」。计划写错了就要允许改计划,否则会按一份过时的清单走到底。

做完再看。 一轮行动之后,另一次模型调用专门对照目标:做成了没有,哪一条观察对不上。对不上就回到循环里补。这能拦住「工具其实失败了,却写出一份顺利的总结」。

三种可以叠在同一次任务里。先有个短计划,执行时边想边做,结束前再对一下目标。

记忆放在哪里

模型单次能看见的长度有限。执行一长,早期的工具输出会把后面的目标挤出去。所以记忆要分开看:

  • 工作记忆就是当前这次调用带上的上下文:目标、最近几步、还没消化的观察。
  • 外部记忆是运行时另外保存的东西:一份任务笔记、检索到的文档片段、代码仓库里的文件。需要时再取回工作记忆。

实用的做法是把已经确定的结论写短,把原始的大段输出留在外面,下一轮只带回结论和出处。这样循环还能继续,而不是在半路把上下文塞满。

什么时候该停

停止条件要在循环外面写死,不能只指望模型自己说「我好了」:

  • 模型给出最终答复,并且关键步骤都有观察支撑。
  • 步数、时间或费用到达上限。
  • 同一个工具带着同一组参数重复失败。
  • 下一个动作不可逆,或者会影响别人,需要人点头再继续。

上限尤其重要。没有上限的循环,会在一个错误观察上一直重试。

它为什么会跑偏

执行原理也解释常见的失败,而不只解释顺利的情况。

把猜测写成观察。 模型在工具返回之前就声称查到了结果。运行时如果把这种话当成事实收进历史,后面每一步都站在假观察上。

重复同一步。 观察里没有新信息,模型却再次发出同一个调用。运行时应当识别重复,并把「这次没有新结果」写进下一轮,或者直接停止。

计划和现场不一致。 计划写的是三条命令,环境里第二条已经不存在。不会改计划的执行,会在第二条上耗完步数。

上下文被早期错误污染。 一次错误的文件内容进了历史,后面的修改都基于它。外部记忆如果也不更新,错误会被一遍遍取回来。

这些都不是模型突然不聪明了。是循环把某一步的输出当成了下一步的输入,错误因此留下来。

人和运行时各自守哪一段

使用智能体时,人要给出的是目标和约束:做成什么样、哪些工具可以用、哪些动作必须先问。运行时要守住的是循环本身:解析工具调用、执行、记录观察、执行停止条件。

模型每一轮只回答「基于我现在看见的这些,下一步是什么」。它看不见自己没被送进上下文的文件,也看不见没有执行过的工具。

把这三句话记住,再去看任何一个具体产品,界面不同,执行原理都还是这条循环。