第一次看 agent demo,很像看一个聪明小孩第一次拿到螺丝刀:它会点按钮,会查网页,会改文件,甚至会一本正经地说“我已经完成了”。你兴奋三分钟,然后让它干一个稍微长一点的活,它开始绕圈、忘事、误判成功、把错误输出当成证据,最后还很自信。
这时候问题通常不在模型“笨”。问题在循环没有被设计。
Prompt Engineering 关心的是“这一句话怎么让模型答得更好”。Loop Engineering 关心的是另一件事:模型答完之后,下一步谁来检查?失败怎么回滚?工具结果怎么进入状态?什么时候停?停之前凭什么说自己真的完成了?
Loop Engineering 就是把 agent 的工作过程设计成可靠的闭环:观察状态,决定动作,调用工具,校验结果,更新记忆或计划,然后进入下一圈。真正的工程量往往藏在“下一圈”里。
Agent 不是一次调用,是一台会转的机器
普通聊天像点餐。你说“来碗面”,模型端上文字,事情结束。
Agent 更像厨房。它要看冰箱里有什么,决定先切菜还是先烧水,发现锅坏了要换锅,出餐前还得尝一口。这个过程不是一句 prompt 能兜住的,它需要一个循环。
最朴素的 loop 长这样:
state = load_state(task_id)
for step in range(max_steps):
observation = observe(state)
action = decide(observation, state)
if action.type == "finish":
break
result = run_tool(action)
verdict = verify(action, result, state)
state = update_state(state, action, result, verdict)
if verdict.needs_human:
pause_for_review(state)
代码看起来短,麻烦全在函数里面。observe 不是把所有日志塞回上下文,decide 不是让模型自由发挥,run_tool 不是裸奔调用系统权限,verify 更不是相信模型一句“看起来没问题”。
这就是 Loop Engineering 的味道:模型只是齿轮之一,循环才是机器。
一圈里应该有什么
我喜欢把一个可用 loop 拆成五个部件。少任何一个,demo 也许能跑,生产里迟早会撞墙。
| 部件 | 它解决什么 | 常见坏味道 |
|---|---|---|
| 状态 | 当前目标、计划、上下文、产物、错误记录放在哪里 | 全靠聊天记录硬撑,窗口一满就失忆 |
| 策略 | 下一步该做什么,什么时候该保守一点 | 工具列表全开放,模型想点哪个点哪个 |
| 工具 | 能真实改变世界的动作 | 权限太大,没有参数校验,没有幂等设计 |
| 校验 | 动作到底有没有成功 | “命令没报错”就当成功,“页面能打开”就当功能完成 |
| 停止条件 | 什么时候收手 | 越修越坏,越查越偏,循环跑到预算耗尽 |
这里最容易被低估的是“停止条件”。人写代码时知道什么时候该停:测试过了,diff 合理,业务目标对上了。Agent 不一定知道。你不给它一个明确的刹车,它就会像扫地机器人卡在椅子腿旁边,一边撞一边努力。
- 第一阶段:一次性回答
用户问,模型答。适合解释概念,不适合处理会改变状态的任务。
- 第二阶段:工具调用
模型可以查资料、读文件、跑命令。能力变强了,事故半径也变大了。
- 第三阶段:可控循环
系统开始记录状态、限制工具、校验结果、设置预算,并在危险动作前暂停。
- 第四阶段:可运营的 agent
循环能被观测、评估、回放、恢复。失败不是黑盒,而是可诊断的工单。
只给工具,不叫工程
很多 agent 项目的第一版都长得差不多:给模型一串工具说明,再写一句“请一步步完成任务”。这能做出令人开心的录屏,也能制造一些很隐蔽的坑。
比如文件编辑工具。模型可以改文件以后,它会天然倾向于“继续改”,因为修改是一种看得见的进展。可是工程里真正重要的常常是“不改”:先读测试,先确认复现,先缩小问题,先看 git diff。一个没有策略约束的 loop,会把“能行动”误解成“该行动”。
再比如搜索工具。搜索会带来信息,也会带来噪音。没有资料缓存和证据筛选,模型每一圈都可能被新材料带偏。最后它给你一份报告,语气很稳,引用很散,结论像从十个网页里揉出来的纸团。
模型调用工具失败,然后自己总结出一个看似合理的失败原因;下一圈又基于这个“原因”继续行动。错误不再是错误,而变成了状态的一部分。几圈之后,你调的已经不是 bug,而是幻觉的后代。
让 loop 有记忆,但别让它背着行李箱跑步
上下文窗口不是仓库。把所有工具输出、网页全文、日志、diff、计划都塞进去,短期看省事,长期看就是把厨房垃圾倒在案板上。
更好的做法是给 loop 分层记忆:
- 热状态:当前目标、下一步、最近错误,放在模型能直接看到的地方。
- 工作文件:搜索结果、长日志、草稿、测试输出,写到文件或数据库,需要时再读。
- 长期记忆:稳定规则和经验,比如项目约定、用户偏好、常用流程。
- 审计记录:每一步动作、参数、结果、校验结论,给人类和评估系统看。
这套分层听着麻烦,但它会让 agent 清醒很多。模型的上下文像手术台,只放本轮要用的器械;其他东西进器械柜,贴标签,随取随放。
Goal: 发布一篇文章 Plan: - 读取主题文档 - 写 Markdown - 本地构建 - 部署静态文件 Evidence: - build.log - generated/routes.json Guards: - 不覆盖未确认的用户改动 - 部署前确认目标目录 Stop: - 线上 URL 返回 200,页面标题和正文片段可见
注意最后的 Stop。没有它,agent 很容易把“我已经写了文件”当成“文章已经发布”。这两件事差了一个宇宙。
校验要像验收,不要像安慰自己
Loop Engineering 里最硬的一环是校验。不是因为技术多复杂,而是因为人很容易偷懒,模型也很容易配合你偷懒。
“构建成功”只能证明项目能构建。 “HTTP 200”只能证明页面能访问。 “正文里有标题”才开始接近“文章真的上线”。 如果文章还有代码块、组件、公式、图片,那就继续验:路由是否生成,静态资源是否可用,MDC 组件有没有被吃掉。
我更愿意把校验写成验收清单,而不是一句抽象的“检查结果”。例如:
route: /2026/loop-engineering checks: - status_code == 200 - title contains "Loop Engineering" - body contains "别再只会写 Prompt 了" - atom_feed contains route - raw_markdown exists rollback: - restore previous wwwroot snapshot
这类清单很土,但管用。Agent 需要的不是鼓励,而是边界清楚的验收标准。
预算是 loop 的氧气瓶
人类做任务会自然感到“差不多该停了”。Agent 没有这种身体感。它只会继续预测下一步。于是预算就成了氧气瓶:步数、时间、费用、工具调用次数、失败次数,都要有上限。
预算不是为了抠门,而是为了暴露问题。如果一个修复跑了 30 圈还没收敛,继续跑通常不会突然变聪明。更好的选择是停下来,把当前状态、尝试过的路径、失败证据交给人。
一个实用的失败处理规则
同一种错误连续出现两次,不要让模型只换一种说法继续试。让 loop 做三件事:
- 写下失败假设。
- 找一个能证伪这个假设的最小实验。
- 实验还是失败,就升级给人,或者切换到另一条策略。
这比“再试一次”靠谱。盲目重试只是把失败磨得更圆。
Prompt Engineering 没死,只是位置变了
说 Loop Engineering,不是说 prompt 不重要。Prompt 仍然重要,只是它从“全部工程”变成了“循环里的一个配置项”。
你仍然要写清楚角色、目标、约束和输出格式。但真正决定系统稳定性的,是 prompt 外面的东西:状态怎么存,工具怎么封装,错误怎么恢复,人怎么介入,结果怎么验收。
换个比喻:Prompt 像驾驶员的口令,Loop 像车。只训练驾驶员喊“稳一点、快一点、安全一点”,但车没有刹车、仪表盘和安全带,这不叫自动驾驶,叫许愿。
可以从哪里开始
如果要把一个一次性 agent 改造成可用 loop,我会先做这几件小事:
- 给每个任务一个
task_id,把计划、步骤、产物和错误挂在它下面。 - 所有工具返回结构化结果,至少有
ok、summary、evidence、error。 - 给危险工具加审批,给昂贵工具加预算,给外部写入加幂等键。
- 每一圈都写 trace,不要只保留最后回答。
- 为常见任务写验收清单,让模型按清单收尾。
- 失败时输出“已经试过什么”,而不是只输出“抱歉失败”。
这些东西不性感,但它们像地基。地基没打好,上面堆再多模型能力也会晃。
最后
Loop Engineering 其实是在承认一个朴素事实:智能不等于可靠。
一个模型可以很会说、很会猜、很会临场发挥,但工程系统要的是另一种品质:可重复、可观察、可恢复、可验收。Agent 想从玩具变成工具,就必须从“让模型回答”走向“让循环工作”。
等你开始关心每一圈怎么进、怎么出、怎么停,agent 才算真正上了工位。否则它只是穿着工牌的聊天框。
评论区
评论加载中...