Agent Loop:推理、行动、观察与停止条件
一个 Coding 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] 看图的时候只盯这条顺序:先 query,再 execute,接着把环境结果放回去。

图 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 和状态变化的关联。它用来调试和评估,不是把所有敏感内容原样记录下来。
Tool Result 要回答什么
Section titled “Tool Result 要回答什么”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 应该回答四件事:发生了什么;环境现在是什么状态;这个错误能否重试;下一步允许做什么。
一个可靠的 Loop 不是只有 success 和“继续”。至少要事先写清下面六类出口。
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。
Final Answer 只是一项 Claim
Section titled “Final Answer 只是一项 Claim”假设 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,只差一个停止规则(15 分钟)
Section titled “动手:两个 Loop,只差一个停止规则(15 分钟)”本讲附带一个不调用外部模型的可运行实验:minimal_agent_loop.py。脚本用固定决策模拟模型,避免 API 和模型版本干扰。进入本讲的 experiments/ 目录后运行:
python3 minimal_agent_loop.py先别急着改代码。先确认一个案例在两步进入 success,另一个案例在第三步因为 max_steps 进入 budget_exhausted,再去看两条 Trace 有什么不同。
成功案例先调用天气工具,再给出答案:
{ "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 中的敏感字段替换成摘要。
边界与下一步
Section titled “边界与下一步”四条规则可以先记住:动作先校验再执行;Observation 要能指导恢复,不能只有一句自然语言抱怨;模型可以申请成功,验证器决定是否成功;每个循环都必须有预算和失败出口。
本讲实验用固定决策模拟模型,只验证 Loop 控制,不比较模型能力;Thought 也是教学标签,不要求记录或展示模型的隐藏推理。不同框架对循环和终态的命名会不同,共同问题没有变:动作要可校验,反馈要可恢复,成功要有证据。
下一讲会把 Agent Loop 放回更大的系统,区分 Workflow、Agent、Harness 与 Loop Engineering。先分清这四层,后面讲状态图、长任务和多 Agent 才不会绕成一团。
资料与延伸阅读
Section titled “资料与延伸阅读”以下链接均为本章已引用的原始论文、官方文档或源码。建议先读 [1] 理解 ReAct 的起点,再对照 [2] 的源码和 [3]-[6] 的框架实现。
[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/