Loop Engineering(运行循环工程)
Loop Engineering 是专门设计和调优 Agent 那个”想一步→做一步→看结果→再想”的循环的工程实践。它不新造一个概念,而是把 agent.md 里提到的”运行循环(Loop)“当成一个要认真设计的一等公民来对待。
一句话类比:如果 Agent 是一辆自动驾驶的车,模型是”大脑”,工具是”手脚”,那 Loop 就是这辆车的”驾驶节奏”——什么时候踩油门(继续调用工具)、什么时候刹车(停止并回答)、迷路了怎么办(纠错重试)。Loop Engineering 就是把这个节奏调好。
定位:Loop Engineering 关注循环本身的逻辑(要不要再来一轮、这一轮喂什么);承载这个循环运行的”外壳/运行时”叫 Agent Harness,见
agent_harness.md。两者是”循环的规则” vs “跑循环的机器”的关系。
1. 一个最朴素的循环长什么样
ReAct 循环(见 agent.md)用伪代码写出来,本质就是一个 while:
state = init_state(user_input) # 初始状态:用户问题 + 空的历史
while True:
action = model.decide(state) # 想:模型看当前状态,决定下一步
if action.is_final_answer: # 判停:够了就跳出
return action.answer
observation = run_tool(action) # 做 + 看:执行工具,拿到结果
state = state.append(action, observation) # 更新状态,进入下一轮Loop Engineering 要回答的,就是这段代码里每一处看起来简单、实则要命的决策:
| 循环中的环节 | 朴素做法 | 真正要工程化的问题 |
|---|---|---|
| 判停(何时结束) | 模型说”我答完了”就停 | 模型不肯停 / 提前乱停怎么办?要不要设最大轮数? |
| 更新状态 | 把所有历史全塞回去 | 上下文越滚越长、越贵,怎么裁剪?(见 Context Engineering) |
| 执行工具 | 直接调用 | 工具报错、超时、返回一坨垃圾怎么办? |
| 下一轮决策 | 全交给模型 | 要不要强制某些步骤、要不要人来确认? |
2. 循环设计的核心决策点
2.1 判停条件(Termination)
最容易被忽视、也最容易翻车的地方。常见几种停法,通常组合使用:
- 模型主动收尾:模型这一轮不再请求工具,直接给出最终答案 → 自然结束。
- 最大轮数 / 步数上限(max iterations):兜底,防止无限循环烧钱。必须有。
- 预算上限:达到 token 或时间预算就停。
- 达成显式目标:某个校验条件满足(如测试通过、文件已生成)就停。
常见坑:只靠”模型自己说停”。模型可能陷入”反复调同一个工具→拿到同样结果→再调”的死循环,或者相反——过早收尾,工具还没跑完就急着回答。所以硬性的 max iterations 是底线。
2.2 一轮里做几件事:串行 vs 并行
- 串行:一次只决定一个动作,看到结果再决定下一个。逻辑清晰,但慢。
- 并行:一轮里同时发起多个独立工具调用(如同时查北京和上海天气,见
agent.md的例子),再一起聚合。快,但要求这些调用互不依赖。
判断标准:后一个动作是否依赖前一个的结果。不依赖就并行,依赖就串行。
2.3 错误处理与重试(这是 Loop 和 Harness 的交界)
工具失败不该直接让整个 Agent 崩掉。常见策略:
- 把错误信息当成 observation 喂回给模型,让它自己换个方式重试(很有效)。
- 有限次重试 + 退避(backoff):网络类错误重试,逻辑类错误就别硬试。
- 降级:某工具挂了,换个工具或直接告诉用户”这部分做不了”。
把报错原文喂回模型,往往比你写一堆 if-else 更聪明——模型能读懂”参数写错了”并自己改。这是 agentic 循环相比传统 workflow 的一大优势。
2.4 状态在循环里怎么滚
每轮都要更新 state(历史、工具结果、中间产物)。核心矛盾:信息要够全(不然模型失忆)vs 不能太长(贵、慢、稀释注意力)。
- 早期简单做法:全量拼接(把所有历史塞回去)——短任务够用。
- 工程化做法:摘要压缩旧历史、只保留关键结果、外置记忆(写到文件/DB,需要时再读回)。
- 这部分正是 Context Engineering 的地盘,Day 2 会专门学(计划见
context_engineering.md)。
⚠️ 边界澄清(易混):状态更新的”策略”归 Loop Engineering,“执行”归 Harness。 也就是说”保留多少、怎么压缩、何时外置”是这里要设计的规则;真正把 state 存下来、每轮追加、读写记忆,是
agent_harness.md模块⑥那台机器干的。一句话记:Loop 定策略,Harness 管执行。
3. 循环的两种形态:固定 vs 自主
| 维度 | Workflow(固定流程) | Agentic Loop(自主循环) |
|---|---|---|
| 下一步谁决定 | 代码写死的路径 | 模型每轮动态决策 |
| 可预测性 | 高(见 AI 可预测性) | 低,但更灵活 |
| 适用 | 步骤固定、可枚举 | 步骤不定、需随机应变 |
| 调试 | 容易,路径确定 | 难,每次路径可能不同 |
呼应
agent.md的判断原则:流程路径固定就用 workflow,不固定才用 agent。真实系统常是”大流程写死(workflow)+ 某几个节点内部放一个小 agentic loop”的混合体。这正是”流程编排”(Day 3,计划见orchestration.md)要处理的。
4. 常见坑(复习重点)
- 没有 max iterations 兜底 → 死循环烧 token。任何生产循环都要有硬上限。
- 状态无脑全量拼接 → 上下文爆炸,越到后面越慢越贵越蠢。
- 工具报错直接抛出 → Agent 一遇错就整个挂掉,而不是让模型尝试自愈。
- 该并行的串行做 → 明明互不依赖的调用一个个排队,白白变慢。
- 只看”最终答案”不看”循环轨迹” → 出了问题无从排查。循环一定要可观测(记录每轮的 thought/action/observation),这是 Harness 要提供的能力。
5. 明天实操钩子 🔧
不用任何框架,纯 Python 手写一个最小 ReAct 循环,亲手体会上面这些决策点:
- 定义 1~2 个假工具(如
get_weather(city)返回写死的数据)。 - 写一个
while循环:调用模型 → 解析它想调哪个工具 → 执行 → 把结果拼回去 → 再问模型。 - 故意制造三种情况,观察循环行为:①模型不肯停(加 max_iterations 兜底)②工具报错(把错误喂回去看它会不会改)③需要两个独立查询(试试并行)。
- 做完对照
agent.md里 LangChain 的AgentExecutor——你会发现它帮你封装的正是这个循环。这就自然过渡到agent_harness.md。
关联概念
agent.md:Agent = 模型 + 工具 + 循环 + 状态;ReAct 机制。agent_harness.md:承载并驱动这个循环的运行时外壳。../computer-architecture/state-machine.md:循环在”状态间按条件流转”,本质是状态机。tool_calling.md:循环里”做一步”靠的就是 tool call。