Agent Loop:推理、行动、观察与停止条件
一个 Agent 最像“Agent”的地方,不是它会调用工具,而是它能根据工具返回的结果继续决定下一步。
查一次天气只是函数调用。查天气后发现有雨,再读取日历、判断冲突、请求改期、验证结果,这才形成循环。
Agent Loop 看上去只是一个 while。真正的工程难题却集中在循环内部:动作怎样表示,错误怎样反馈,状态怎样更新,重复怎样识别,以及谁有资格让循环结束。
这一讲只研究一次 Agent Run 内部的循环。跨小时、跨天的外部任务循环,留到第 11、12 讲。
一、ReAct 为什么成为一个重要起点
Section titled “一、ReAct 为什么成为一个重要起点”2022 年公开的 ReAct 把 reasoning 与 acting 交替组织。模型不再只在内部生成推理,也不再只盲目发出动作,而是根据环境返回的 Observation 修正后续选择。[1]
最常见的教学写法是:
Thought -> Action -> Observation -> Thought -> ... -> Final Answer这个写法直观,但工程实现要补两点说明。
第一,Thought 不必等同于完整、可见的内部思维过程。生产系统更适合保存简短计划、动作理由或结构化决策,不应依赖记录模型的隐藏推理。
第二,Final Answer 只是模型的一种动作。任务是否真的完成,仍要由测试、数据库状态、文件工件或用户确认来决定。
因此,工程版 Agent Loop 更接近:
读取状态 -> 请求模型选择候选动作 -> 校验动作 -> 执行动作 -> 记录环境观察 -> 更新状态 -> 检查终态与预算 -> 继续或停止这几个动词看起来朴素,却决定系统能不能被调试和控制。
二、最小 Loop 可以很短
Section titled “二、最小 Loop 可以很短”很多框架的核心循环都能压缩成类似伪代码:
while steps < max_steps: decision = model(messages, tools)
if decision.is_final: return verify_or_return(decision)
action = validate(decision.tool_call) observation = execute(action) messages.append(observation)
return budget_exhausted()mini-swe-agent 的源码很适合观察这种骨架。它围绕模型查询、命令执行、Observation 回填和退出条件组织循环,代码量不大,却已经包含 Agent 的主要运动方式。[2]

图 1:mini-swe-agent 的 query:execute:observe 循环。来源见文末。
代码短不代表问题简单。每一行背后都藏着需要明确的契约。
三、一次循环里到底有哪些对象
Section titled “三、一次循环里到底有哪些对象”1. Messages:模型看见的运行上下文
Section titled “1. Messages:模型看见的运行上下文”Messages 可能包含用户目标、系统规则、工具结果和先前动作。它们帮助模型决策,但不应该承担全部业务状态。
如果订单金额、审批状态或剩余预算只藏在自然语言消息里,系统很难可靠恢复,也难防止模型误读。
2. Decision:模型给出的候选决策
Section titled “2. Decision:模型给出的候选决策”Decision 通常有两类:调用工具,或者给出最终回复。
一个成熟接口还会表达拒绝、请求澄清、转交其他 Agent、等待审批等状态。把所有情况都塞进一段自由文本,后续控制会非常脆弱。
3. Action:通过校验后的实际动作
Section titled “3. Action:通过校验后的实际动作”模型输出不应直接等于动作。Harness 至少要检查工具是否存在、参数是否符合 Schema、当前身份是否有权限,以及动作是否需要审批。
只有通过检查的候选决策,才会成为 Action。
4. Observation:环境返回的事实
Section titled “4. Observation:环境返回的事实”Observation 不是“工具执行成功”一句话。它应该包含足够的结构,让模型和程序知道发生了什么:
{ "status": "success", "order_id": "order_demo_1024", "new_state": "refunded", "transaction_ref": "txn_demo_88"}失败也要结构化:是参数错误、权限不足、网络超时、业务拒绝,还是结果未知?不同错误需要不同处理。
5. State:循环之外的权威状态
Section titled “5. State:循环之外的权威状态”State 记录目标、当前步骤、工件、预算、重试和终态。Messages 可以从 State 生成,但 State 不应只能从 Messages 猜回来。
6. Trace:事后能否还原过程
Section titled “6. Trace:事后能否还原过程”Trace 保存每次模型、工具、Guardrail 和状态变化的关联。它用来调试和评估,而不是把所有敏感内容原样记录。
四、Observation 的质量决定下一步的质量
Section titled “四、Observation 的质量决定下一步的质量”Agent 常见的失败,不是模型完全不会推理,而是环境反馈不完整。
例如命令执行失败,只返回:
Something went wrong.模型无法判断应该修改参数、换工具、稍后重试还是请求人工处理。它只能猜。
更有用的返回是:
{ "status": "failed", "error_type": "permission_denied", "operation": "write_file", "path": "/protected/config.yml", "retryable": false, "next_allowed_action": "request_approval"}这并不是为了迁就模型,而是正常的接口设计。程序员调用 API,也需要错误码和可恢复语义。
Tool Result 设计应回答四件事:
- 发生了什么;
- 环境现在是什么状态;
- 这个错误能否重试;
- 下一步允许做什么。
含糊的 Observation 会制造含糊的下一步。
五、停止条件比“继续努力”更重要
Section titled “五、停止条件比“继续努力”更重要”Agent Loop 至少应有六类出口。
1. Success
Section titled “1. Success”目标由可信证据满足。比如测试通过并且补丁存在,订单状态已经更新,报告文件已生成且引用检查通过。
2. Failed
Section titled “2. Failed”出现不可恢复错误,例如身份无效、工具不存在、输入违反业务规则。
3. Budget Exhausted
Section titled “3. Budget Exhausted”达到最大轮次、Token、费用或总时长。预算耗尽是正常终态,不应伪装成成功。
4. Paused
Section titled “4. Paused”等待用户补充信息、人工批准或外部事件。暂停必须保存恢复所需状态。
5. Cancelled
Section titled “5. Cancelled”用户或上游系统取消任务。取消后还要处理已经发生的副作用。
6. No Progress
Section titled “6. No Progress”系统不断重复相同工具、相同错误或等价方案。即使预算还有剩余,也应触发 Circuit Breaker。
一个 Loop 如果只有 success 和“继续”,迟早会把失败变成成本。
六、模型说“完成”以后,还要发生什么
Section titled “六、模型说“完成”以后,还要发生什么”假设 Coding Agent 回复:“修复完成,所有测试通过。”
Harness 不应直接接受这句话。它至少要检查:
- 工作区是否真的有改动;
- 运行的是哪组测试;
- 测试退出码是否为零;
- 测试对应的源码版本是否就是当前版本;
- 是否存在未跟踪的失败或跳过项;
- 修改是否超出允许范围。
模型的 Final Answer 是一项 Claim。测试记录、环境终态和工件才是 Evidence。
No evidence, no success.没有证据,不进入成功终态。这条规则会贯穿后面的 Loop Engineering、Evaluation 和可靠性章节。
七、主流框架怎样实现 Loop
Section titled “七、主流框架怎样实现 Loop”OpenAI Agents SDK:Runner 拥有循环
Section titled “OpenAI Agents SDK:Runner 拥有循环”SDK 内置 Agent Loop,处理模型调用、工具调用、Handoff、Guardrail 和最终输出。开发者可以使用 Runner,也可以在需要确定性控制时用普通代码编排。[3]

图 2:框架可以封装循环,但应用仍要定义工具权限、业务状态和成功证据。来源见文末。
smolagents:代码动作与工具动作
Section titled “smolagents:代码动作与工具动作”smolagents 提供 CodeAgent 和 ToolCallingAgent。前者让模型生成代码组合动作,表达能力更强;后者用结构化 Tool Call,边界更容易检查。[4]
两种方式没有绝对优劣。动作越通用,沙箱和审计要求越高。
LangGraph:循环是图中的边
Section titled “LangGraph:循环是图中的边”LangGraph 不把所有循环隐藏在 Runner 里。节点返回状态更新,条件边决定继续、转向或结束。Checkpoint 又让循环可以暂停和恢复。[5]
这种设计牺牲了一些轻量性,换来显式控制。
Google ADK:Agent Loop 与 Workflow Agent 并存
Section titled “Google ADK:Agent Loop 与 Workflow Agent 并存”ADK 允许 LLM Agent 自主选择,也提供 Sequential、Parallel、Loop 等确定性 Workflow Agent。[6]
这代表一种常见生产思路:需要开放判断的地方交给模型,必须经过的步骤交给程序。
八、真实实验:两个 Loop,只差一个停止规则
Section titled “八、真实实验:两个 Loop,只差一个停止规则”本讲附带一个不调用外部模型的可运行实验:minimal_agent_loop.py。脚本用固定决策模拟模型,避免 API 和模型版本干扰。
成功案例先调用天气工具,再给出答案:
{ "terminal": "success", "trace_steps": 2}第二个案例不断重复天气工具。Harness 在第三步触发最大步数:
{ "terminal": "budget_exhausted", "reason": "max_steps", "trace_steps": 3}完整结果见 experiment-result.json。首次运行还发现系统 Python 3.9 不支持 str | None 联合类型语法,修正过程保存在 validation-notes.md。
这个小失败很有代表性:运行环境也是 Harness 的一部分。示例代码看起来正确,不等于在目标环境中可运行。
读者可以继续修改实验:
- 加入未知工具,观察
invalid_action; - 让工具返回
retryable: true,实现最多一次重试; - 检测连续相同动作,提前触发
no_progress; - 把 Trace 中的敏感字段替换成摘要。
九、Agent Loop 的四条工程规则
Section titled “九、Agent Loop 的四条工程规则”动作先校验,再执行。
Observation 要能指导恢复,不能只有自然语言抱怨。
模型可以申请成功,验证器决定是否成功。
每个循环都必须有预算和失败出口。
下一讲会把 Agent Loop 放回更大的系统,严格区分 Workflow、Agent、Harness 与 Loop Engineering。只有把四个层级分开,后面讲状态图、长任务和多 Agent 才不会绕成一团。
[1] Yao et al., ReAct. https://arxiv.org/abs/2210.03629
[2] SWE-agent, mini-swe-agent default loop. https://github.com/SWE-agent/mini-swe-agent/blob/main/src/minisweagent/agents/default.py
[3] OpenAI, Running agents. https://openai.github.io/openai-agents-python/running_agents/
[4] Hugging Face, smolagents. https://huggingface.co/docs/smolagents/index
[5] LangChain, LangGraph Graph API. https://docs.langchain.com/oss/python/langgraph/graph-api
[6] Google, ADK Workflow Agents. https://google.github.io/adk-docs/agents/workflow-agents/