2026.08.26 · WRITING

一个 LLM Agent,是怎样一步步把任务做完的?

从读取代码、运行测试到根据报错调整方案,Agent 的能力藏在每一次“做完再看”的循环里。本文把模型、工具、状态、记忆、运行时和停止条件逐一拆开。

如果只把 Agent 理解成“LLM 加几个工具”,很容易漏掉最关键的一部分:谁在反复推进任务,又是谁决定什么时候停下来。

单次、不带工具循环的 LLM 调用,通常只根据已有输入生成一次响应。Agent 则由运行时把多轮模型调用与工具执行连接起来,让系统围绕目标选择行动、读取结果、更新状态,再决定下一步。

这两者的差别,可以从一个常见的编程任务看出来。

从一个 GitHub Issue 开始

假设任务是:

修复用户登录后偶发跳回登录页的问题,并说明修改了什么。

一次普通的 LLM 调用,只能根据你提供的代码和描述生成建议。它不会自己知道仓库里有哪些文件,也不会真的运行测试。

一个拥有代码仓库访问权限的 Agent,则可能这样推进:

  1. 读取 Issue 和项目目录,寻找登录、Session 与路由相关的代码。
  2. 打开可疑文件,形成一个可以验证的原因假设。
  3. 运行现有测试或复现命令,观察错误输出。
  4. 修改代码,再次运行测试。
  5. 如果测试失败,根据新结果调整修改;如果通过,生成变更说明。

真正重要的不是一共有多少个步骤,而是这些步骤无法在任务开始前全部写死。Agent 必须看到仓库结构和测试结果之后,才能决定下一步打开哪个文件、执行什么命令。

Agent 读取 Issue、定位代码、运行测试,并在失败后修改代码重新测试
测试不是最后一道验收,而是 Agent 判断下一步的环境反馈。

Agent 的核心,是一个有反馈的执行循环

不同产品对 Agent 的定义并不完全相同。一个实用的工程判断是:

当 LLM 能够根据当前状态选择下一步行动,并利用环境返回的结果继续推进任务时,我们就进入了 Agent 的工作方式。

它的最小运行循环可以写成:

state = 任务目标 + 当前已知信息

while 任务尚未结束:
    action = 模型根据 state 选择下一步行动
    observation = 运行时执行行动并取得结果
    state = 用 observation 更新当前状态

这个循环的常见出口包括:

因此,Agent 不是一个单独的模型能力,而是模型与运行时共同构成的系统行为。模型生成候选行动,运行时负责执行工具、保存状态、控制循环和处理异常。

Agent 在目标、状态、行动、工具和观察结果之间循环,并在完成、请求确认或超限时退出
每次工具调用都会产生新的 Observation,它会成为下一轮决策的一部分。

一个可运行的 Agent,需要哪些部分

把 Agent 固定成“LLM、规划、记忆、工具”四个模块,适合快速记忆,却不够完整。本文从工程实现角度,把一个可运行的 Agent 拆成下面六部分。

以运行时为中心的 Agent 系统,由模型、指令与状态、工具、记忆、控制与可观测性共同构成
六部分不是并排摆放的能力清单,它们通过运行时持续交换状态、决策和结果。

1. 模型:在不确定信息中做选择

模型负责理解目标、比较候选行动、解释工具结果,并生成下一步可执行的指令。模型能力确实重要,但它不是系统表现的唯一上限。

同一个模型,搭配含糊的工具说明、过长的无关上下文或混乱的执行逻辑,仍然会频繁选错工具。反过来,清晰的指令、有限而明确的工具和可验证的反馈,往往能让系统稳定许多。

2. 指令与状态:告诉模型“要做什么”和“做到哪了”

指令规定任务目标、角色边界和输出要求;状态记录执行到哪一步、已经获得哪些结果、还有哪些问题没有解决。

状态不只是聊天记录。它也可以包含:

如果没有可靠的状态,Agent 每一轮都像刚刚醒来,容易重复搜索、忘记约束,甚至对同一个操作执行两次。

3. 工具:把文字决策变成外部行动

工具可以是搜索、数据库查询、HTTP API、代码执行器、文件操作,也可以是另一个专门处理子任务的服务。

常见的 Tool Calling 流程是:

  1. 应用把工具名称、用途和参数结构提供给模型。
  2. 模型返回一个结构化调用,例如工具名和 JSON 参数。
  3. 应用检查参数与权限,然后真正执行函数。
  4. 执行结果回到模型,作为下一轮决策的依据。

所以,并不是语言模型的文本生成过程亲自访问数据库或操作文件。外部操作由宿主应用、本地运行时或服务商托管的工具环境执行。

工具也不是越多越好。功能重叠、命名模糊的工具会增加选择难度;能够修改数据的工具还会扩大权限边界。一个小而清晰的工具集,通常比堆满几十个相似接口更容易控制。

4. 运行时:让“决定—行动—观察”继续转动

运行时也常被称为 Runner、Orchestrator 或 Agent Loop。它负责:

只让模型生成一次工具调用,不一定构成 Agent。能够根据工具结果继续选择行动,才形成真正的反馈循环。

5. 记忆:保存什么,比“存下来”更重要

记忆可以分成两个范围:

长期记忆并不等于向量数据库。用户的语言偏好可以存成一条结构化记录,任务状态可以放在 SQL 或 KV 存储中,文档片段才可能适合用向量检索。先判断要记住的内容是什么,再决定存储和召回方式。

记忆还需要写入规则。把每一次对话都永久保存,不会自然产生“越用越聪明”的效果,反而可能带来过期信息、错误累积和隐私问题。

6. 控制与可观测性:知道它做了什么,也限制它能做什么

Agent 会执行真实操作,因此系统需要明确的控制面:

日志只告诉你“发生了错误”,完整的 Trace 还应该帮助你还原:模型当时看到了什么、选择了哪个工具、工具返回了什么,以及状态如何进入下一步。

Planning 不是先写一份永远不变的计划

复杂任务需要 Planning,但规划不一定是独立模块,也不一定要在开始时生成一份完整步骤表。

下面只介绍两种常见思路。

ReAct:走一步,看一步,再调整

ReAct 把推理与行动交错进行。Agent 选择一个行动,从环境得到 Observation,再用新信息更新后续计划。

这意味着 ReAct 本身就是带反馈的循环,并不是“无反馈规划”。它适合搜索、排错和代码修改这类中间结果会改变后续路径的任务。

例如,Agent 原本认为登录问题来自 Cookie 过期;运行测试后却发现是反向代理没有转发协议头。新的 Observation 会直接改变下一步调查方向。

Plan-and-Execute:先拆任务,再逐项执行

另一种方式是先生成较高层计划,再由执行器逐步完成。它适合目标清晰、阶段边界明确的任务。

计划仍然不该被当作不可修改的清单。遇到失败或新证据时,系统需要重新规划,否则“按计划执行”只是在自动重复错误。

反思与重试也可以加入这两种方式,但它们不是免费的能力。没有可验证的反馈时,让模型反复评价自己,可能只是用更多 token 生成另一种说法。

Workflow 和 Agent,应该选哪一个

不是所有多步骤 LLM 应用都需要 Agent。

如果步骤固定、分支有限,并且每个条件都能用代码表达,优先使用 Workflow。例如:上传合同、提取字段、检查完整性、写入数据库。这条路径更容易预测、测试和审计。

如果任务的下一步取决于不断出现的新信息,无法提前列出完整路径,Agent 才更有价值。例如:调查线上故障、修复陌生代码库、进行多轮资料研究。

可以先问三个问题:

  1. 下一步能否在执行前由代码确定?
  2. 如果不能,是否需要模型根据新信息动态选择行动?
  3. 任务是否有可观察、可验证的完成条件?

第一个问题回答“能”,通常更适合 Workflow;第一个问题回答“不能”、第二个问题回答“是”,才更像 Agent 的用武之地。第三个问题不决定系统叫什么,却决定这条执行过程能否被可靠评估和停止。

Workflow 使用预先确定的路径,Agent 根据观察结果持续调整下一步
能提前写死的路径交给 Workflow;必须看完结果再决定的部分,才值得交给 Agent。

多 Agent 不是默认升级路线

把一个 Agent 拆成多个角色,有时能隔离上下文和工具权限,也能并行处理独立任务。但它同时增加了交接、冲突、延迟和调试成本。

在单个 Agent 已经无法清楚管理上下文,或者任务确实存在可以独立验证的专业分工时,再考虑多 Agent。否则,一个模型加一组设计良好的工具和一条清晰的执行循环,通常更容易落地。

最后,用运行过程判断它是不是 Agent

判断一个系统是不是 Agent,不必纠结产品名称。看它是否形成了下面这条链路:

目标
  → 读取当前状态
  → 选择行动
  → 调用工具
  → 获得环境结果
  → 更新状态
  → 继续、完成或请求人工确认

LLM 为系统提供语言理解与决策能力;工具让它能够影响外部世界;运行时把每次行动连接成过程;状态和记忆保持连续性;权限、确认与 Trace 则让这个过程能够被控制和解释。

真正值得设计的,不是一个听起来聪明的“智能体角色”,而是一条能根据事实推进、能在错误时停下、也能让人看清发生了什么的执行链路。

参考资料