Agent 开发学习站
Agent 开发›基础›入门

Agent 解剖:think-act-observe 循环

入门基础

一句话定义

Agent 循环是"模型推理 → 发起工具调用 → 执行并回填结果 → 再次推理"直至产出最终回复的驱动机制——think、act、observe 三拍子无限反复,是所有 Agent 框架共同的心跳。

为什么重要

kp-001 说"Agent 是 while 循环",本篇把循环拆开看清楚。你要能精确回答:每一步模型实际收到了什么消息?工具结果如何回到上下文?循环何时终止、何时不终止?90% 的 Agent bug 定位发生在循环的消息流层面——工具结果没回填、终止条件缺失导致死循环、状态没保存导致重跑。理解了循环,框架(kp-021)对你而言只是语法糖。

前置知识

kp-001(四要件)、kp-002(上下文)、kp-005(结构化输出)。

核心概念

循环的消息流

以"查北京明天的天气并推荐穿搭"为例,消息数组在循环中的演化:

messages = [system, user]           # 第 1 次调用
  ↓ 模型返回: tool_use(get_weather, {city:"北京"})
messages += [assistant(tool_use)]   # 记录模型的调用意图
  ↓ 你的代码执行工具
messages += [user(tool_result)]     # ★ 工具结果以 user/tool 角色回填
  ↓ 第 2 次调用(模型看见了天气数据)
  ↓ 模型返回: tool_use(get_forecast_advice, {temp:"-2~5℃"})
  … 重复 …
  ↓ 第 N 次调用,模型返回: 纯文本回复
循环结束 → 文本展示给用户

三个不变式:

  1. 工具结果是消息:执行结果必须 append 回 messages 再进入下一轮——忘了回填,模型会重复请求同一工具(经典新手 bug)
  2. 历史全程在场:每次调用都携带完整历史(因此有 kp-003 的成本与腐烂问题)
  3. 终止由模型信号或代码条件决定:模型返回无 tool_use 的纯文本 = "我认为做完了";代码侧必须有最大轮数/超时兜底(防死循环烧钱)

Agent 的状态(State)

循环之外,Agent 还有跨轮存活的状态:

  • 消息历史(会话短期记忆)
  • 持久状态:任务进度、变量、文件(checkpoint,kp-027 中的断点续跑)
  • 环境状态:浏览器会话、工作目录、容器——它们不在上下文里,但影响工具结果

框架的差异大多体现在"状态如何组织":LangGraph 是显式图 + checkpoint,Responses API 是服务端托管状态,自研是消息数组 + 数据库(kp-021)。

单轮 vs 多轮调用

一次用户请求可能触发 1 次(纯问答)到 50+ 次(深度研究)模型调用。轮数是 Agent 的第一成本杠杆:每轮都重放全部历史(kp-027 的缓存与压缩策略都为此而生)。

原理与机制

为什么循环能"自我纠正"?因为每一步的条件分布里都包含了之前所有观察:工具报错 404 进入上下文后,模型下一步的概率质量明显移向"换一个 URL / 搜索一下"——纠错不需要显式编程,它是条件生成的涌现性质。同理,它也可能错上加错(错误观察诱导错误续写),所以要配合反思(kp-014)与护栏。

循环的伪代码骨架(完整可运行版见 kp-017):

pythonmessages = [system_prompt, user_task]
while steps < MAX_STEPS:
    resp = llm(messages, tools=toolset)
    if resp.stop_reason == "end_turn":        # 模型宣布完成
        return resp.text
    for call in resp.tool_calls:              # 可能一次多个调用
        result = execute(call)                # ★ 你写的胶水代码
        messages.append(tool_result(call, result))
    steps += 1
raise TaskTooLong()                           # 兜底:强制终止

直观类比

循环 = 医生问诊:问一句(act:化验单)、看报告(observe)、再决定下一步(think:加查一项还是下诊断)。化验结果会留在病历本上(消息历史),病历越厚医生越了解病情,但也越来越贵(每次都要重读整本病历)。好医生知道何时收手(终止条件),庸医会无限开单(死循环)。

实例与案例

三类典型循环故障与诊断:

症状病因修复
同一工具被连续调用 10+ 次结果未回填 / 结果含糊使模型"再试一次"检查回填代码;工具返回明确成功/失败标志
永不终止,绕圈换参数重试无最大轮数;错误信息无指导性MAX_STEPS + 工具错误写明"该怎么办"(kp-010)
第 30 轮开始答非所问上下文腐烂压缩/隔离(kp-022/019)

常见误区

  • 误区一:"循环 = while True 简单得很"。循环本身 20 行,工程难点在终止、状态、错误传播与成本——这正是 kp-021 框架存在的理由。
  • 误区二:把中间每步都展示给用户。用户要看的是最终答案与关键进度,不是 50 次工具调用流水。
  • 误区三:并行调用不重要。模型一次可返回多个独立 tool_use(如同时查三个航班),串行执行是双倍延迟(kp-027)。
  • 误区四:状态只存在内存。进程重启一切归零,生产要 checkpoint(kp-027)。

自测题

  1. 工具结果以什么角色、什么方式进入上下文?
  2. 循环的两个终止条件分别是什么?
  3. 为什么说"自我纠正"是条件生成的涌现性质?

(参考答案:1. 作为新消息(tool/user 角色)append 进消息数组;2. 模型返回纯文本(end_turn)或代码侧触发最大轮数/超时;3. 错误观察改变下一步的条件分布,纠错概率自然上升,无需显式错误处理分支。)

与其他知识点的关系

  • 可运行实现 → kp-017;推理模式如何填充 think 拍 → kp-012
  • 状态持久化 → kp-027;框架对循环的封装 → kp-021
  • 上下文随循环膨胀的问题 → kp-003/022

延伸阅读

  • Anthropic, Building Effective Agents(agent loop 一节)
  • OpenAI, Responses API 文档(服务端循环的形态)