
99%的人以为“代理聪不聪明”取决于模型本身,其实真正决定上限的是那段看起来不起眼的循环。你可能已经在用Anthropic、Google、OpenAI的产品,却从没认真想过:它们底层几乎跑的是同一套逻辑。差距不在那行 while True,而在你给它装上的刹车、记忆和规则。理解这一点,你设计代理的方式会完全不一样。
一、所有代理都绕不开的那段循环
1. 代理的共同骨架:那段 while True
无论你用的是LangGraph、OpenAI Agents SDK,还是Claude Code,底层循环几乎长这样:
while True:
response = model(context)
if response.has_tool_calls():
context += run_tools(response.tool_calls)
else:
break
每一轮都在重复几件事:
- 把当前上下文丢给模型
- 模型决定要不要调用工具
- 如果要,就执行工具
- 把工具结果塞回上下文
- 再问一次模型
循环会一直跑,直到模型不再请求工具调用。表面上看,这段逻辑极其简单,也因此没人会在 while 语句本身上卷性能或花样。工程价值自然就被推到了别的地方。
2. 真正需要你写的,是循环外面的一切
模型和循环本身,越来越像“现成零件”,你直接拿来用就行。工程工作开始转移到:
- 什么时候强制让循环停下来
- 哪些内容应该留在上下文里,哪些要丢掉
- 模型到底能调用哪些工具、以什么方式调用
- 工具结果要怎么被检查、怎么反馈给下一轮
我自己第一次写多轮代理时,只盯着提示词和工具定义,结果代理要么跑飞,要么卡死在原地。后来回头看日志,才发现问题几乎都出在“循环怎么停”“上下文怎么管”这些地方。

据一些团队的内部统计,代理相关的bug里,超过一半不是模型“不会做”,而是循环条件、上下文管理和工具设计不当导致的“自我拖累”。
接下来,我们先把工程层次摊开,再看循环工程里最容易踩坑的四个关键点。
二、工程工作到底转移到了哪里?
1. 四层工程:从一句提示到一整套系统
工程重心,正在从“写好一条提示”变成“设计一整套包裹模型的系统”。可以粗略拆成四层:

- 提示工程:你直接写给模型的那段文字
- 上下文工程:模型每一轮真正能看到的所有内容,而不只是那条提示
- 框架工程:围绕模型写的代码,用来调工具、管状态、做错误恢复
- 循环工程:最外层的“调度者”,决定代理接什么任务、何时算结束
每一层都包着前一层,你的提示词只是整个系统的一个输入。很多人只在最里层打磨,却忽略了外面三层的设计空间,这就像只在意一句话怎么说,却不管说话的场景、流程和规则。
2. 常见故障点:不是模型笨,而是系统没设计好
这些系统里,最常见的故障点集中在:
- 循环停得太早或太晚
- 上下文越跑越脏,信息噪声爆炸
- 工具太多太乱,模型不知道该选谁
- 没有一个真正能说“不”的检查机制
有用户反馈过一个典型场景:代码代理信誓旦旦说“已修复所有错误”,但CI一跑,几十个测试照样挂。问题不是模型不会修,而是循环在“它自以为完成”的那一刻就停了,没有任何外部验证。

接下来,我们就从“循环什么时候停”开始拆。
三、循环工程的四个关键难点
1) 结束一轮 ≠ 任务完成
1. 模型说“好了”,不代表真的好了
默认情况下,循环停止的唯一条件是:模型这轮回复里不再包含工具调用。
while True:
response = model(context)
if response.has_tool_calls():
context += run_tools(response.tool_calls)
else:
break
换句话说,是模型自己在判断“我是不是做完了”。这听上去很自然,但在实践里问题巨大。一个编程代理可能:
- 改了几行代码
- 没跑测试,或者测试失败了
- 却给出一段自信的总结:“问题已修复”
循环就此结束,任务却远远没完成。我第一次在生产环境踩这个坑时,用户直接在群里问:“你们这代理是只会写README吗?”那一刻挺扎心。

所以需要加上一些模型无法单方面控制的“硬条件”:
- 最大迭代次数:防止代理陷入无限自言自语
- 预算和时间上限:对token、费用和真实时间设硬阈值
- 无进展检测:识别“重复同一工具+同一参数”的原地打转
- 真实完成检查:用可验证条件证明任务完成
2. 真正的“完成”,应该是测试通过
完成检查是唯一能用客观信号替代“模型自我感觉良好”的刹车。

“完成”应该意味着:测试通过、指标达标、文件存在且内容正确,而不是“模型说自己完成了”。
Claude Code 的 /goal 命令就是这么干的:
- 你先给一个可验证的目标
- 循环一直跑到满足这个条件
- 再用另一个模型做一次确认

一个实用的小方法是:在设计任务时,强迫自己把“完成条件”写成机器可检查的表达式,而不是一句模糊的“写一个不错的报告”。说实话,这一步挺反人性的,但一旦坚持做,你会发现代理的可靠性肉眼可见地上去了。
2) 上下文腐败与“厄运循环”
1. 跑得越久,脑子越乱
循环跑得越久,上下文里就会堆越来越多的垃圾:
- 旧的工具输出
- 已经放弃的思路和死胡同
- 过时的推理和中间结论
这些东西一开始看着“也许以后有用”,结果越堆越多,模型每一轮都要在噪声里找信号,质量自然一路下滑。这种现象被很多人叫做“上下文腐败”。


循环会把腐败放大成“厄运循环”:
- 腐败的上下文 → 更差的决策
- 更差的决策 → 更多无用输出
- 更多无用输出 → 上下文更腐败
社区里已经有不少团队踩过这个坑,LangChain甚至专门在框架里加了“厄运循环检测”中间件,用来识别代理是不是已经开始胡言乱语。
2. 把上下文当预算,而不是垃圾桶
一个认知上的小翻转是:
上下文不是“能装多少装多少的桶”,而是一笔必须精打细算的预算。
比较常用的做法有:
- 压缩:长对话定期做摘要,后续只在摘要上继续
- 卸载:把大段输出写到文件或向量库,只保留必要片段在上下文
- 子代理:复杂子任务交给独立代理处理,只把干净结果带回来
有用户分享过一个案例:他们给客服代理加了“对历史对话做分段摘要”的策略后,平均响应token数下降了约40%,但问题解决率反而略有提升。这听起来有点反直觉,却非常符合“上下文预算”的思路。
3) 循环里的工具设计:少而精,且能重来
1. 工具越多,代理越迷茫
很多团队一上来就给代理塞一大堆工具,觉得“功能越多越聪明”。现实情况往往相反:

- 工具数量一多,且功能重叠
- 模型在“选哪个”这一步就开始摇摆
- 结果是频繁选错工具,或者来回切换

Anthropic内部的一个经验法则是:
如果人类工程师自己都拿不准该用哪个工具,代理也不会知道。
Vercel 在实践中也发现:减少代理可用工具的数量,反而显著提高了任务成功率。这一点我也有同感,虽然我也不太确定这个说法在所有场景都成立,但在工程类代理上几乎屡试不爽。
2. 写操作要可重复,错误信息要“教下一步”
因为是循环,失败步骤很可能会被重试,这会带来两个很现实的风险:
- 写操作如果不可重复,重试“创建客户”就可能生成重复记录,甚至双倍扣费
- 错误信息如果只说“哪里错了”,不说“接下来该干嘛”,下一轮模型就会在迷雾里乱试
更稳妥的设计方式是:
- 所有写操作尽量做成“幂等”的:同样的请求多次执行,结果保持一致
- 错误信息里明确告诉代理下一步建议,比如:“订单已存在,请改用 update_order(id=xxx)”
有团队统计过,把错误信息从“技术栈式报错”改成“面向代理的下一步建议”后,平均完成任务所需轮数减少了约30%。
4) 在循环中加入能说“不”的机制
1. 让产出者和审查者分开
前面提到的“完成检查”,其实是一个更大规则的具体例子:
决定“工作是否合格”的,不应该是产出它的同一个模型。
如果你让模型自己给自己打分,它大概率会给出一个还不错的评价。没有外部检查的循环,本质上就是“代理自我背书”。

更稳妥的做法是:
- 一个代理负责“写代码/生成方案”
- 另一个“信号源”负责打分,可以是:
- 测试失败、类型错误等硬指标
- 一个指令完全不同的第二模型
2. 有了能说“不”的人,你才敢放手
一旦有了这个检查机制,你就可以真正把循环放开跑:
- 生产代理只管往前做
- 审查代理或自动化测试负责踩刹车
风险当然也存在:检查器本身如果设计不当,会变成新的瓶颈,甚至误杀正确结果。所以在实践中,很多团队会先从“只报警不阻断”开始,让检查器先当观察者,再逐步升级为“有否决权的裁判”。

四、现在用户真正要做的工作
1. 从“写提示”到“写目标和规则”
在循环工程的视角下,你的角色有点像“系统导演”:
- 提示:用来引导代理一步步行动
- 循环工程:搭建好引导系统,然后退后一步,让它自己跑
工作内容会沉淀成三个关键产物:
- 明确写出的目标和成功标准,让代理可以自检
- 带刹车的循环逻辑,确保是因为“对了”才停,而不是“累了”才停
- 验证器:用客观信号确认“完成”,而不是听模型自述
Karpathy 的观点和这个高度一致:
“不要告诉它怎么做,告诉它什么叫成功,然后看它怎么自己摸索。”
他的 AutoResearch 项目就是这样运作的:代理自动调整训练脚本、跑实验、记录结果,保留有效配置、丢弃无效尝试,整个过程中人类不手动改代码。人做的事,是先把目标和评价标准想清楚,然后按下“开始”。
2. 循环工程的负面一面:不是万能药
说句冷静的话:循环工程不是银弹。
- 设计再精妙的循环,也救不了一个完全不懂领域知识的模型
- 过度复杂的循环和规则,会让系统难以调试,问题一多就没人敢动
- 在强监管或高风险场景(金融、医疗),完全放手自动循环本身就有合规风险
所以更现实的做法,是把循环工程当成“放大器”:模型本身越靠谱、工具越扎实,循环带来的收益越大;反之,它也会放大底层问题。

五、从零开始搭一个靠谱循环:可复用步骤

你不需要一上来就搞一个“完全自治”的超级代理,可以按这个顺序慢慢加:
- 先搭一个最基本的循环,同时立刻加上:最大迭代次数、超时、成本上限
- 在写任务之前,就把“完成”定义成自动可检查的条件,而不是事后肉眼判断
- 保护上下文:长任务做摘要,大输出写文件,复杂子任务交给子代理
- 审核工具:删掉重叠的,保留少而精的;写操作改成可重复;重写错误信息,让代理知道下一步
- 在循环里接入一个“批评者”:可以是测试、规则引擎或第二模型,只有当你信任它能说“不”时,才真正放手让循环跑长一点

很多现在被Anthropic、Google等采用的代理系统,本质上也就是在这几步上打磨得更细、更稳。差别不在“有没有循环”,而在“循环的边界和规则有多清楚”。
六、一个值得反复翻看的判断框架
循环工程,说白了就是把“告诉代理做什么”升级成“搭一个能自己完成任务的系统”。
当模型越来越像标准化基础设施,真正的竞争力就变成:

- 你能不能把目标和成功标准说清楚
- 你敢不敢让系统自己跑一阵子,而不是每一步都人工干预
- 你有没有一个可靠的“能说不”的机制,替你守住底线
这个判断框架在不少团队里已经被反复验证有效,很适合收藏下来,给自己做一个“代理系统体检表”。如果你正准备把某个工作流交给代理,这套思路往往比问身边人“你用哪个模型”更有用。
常见问题
Q:怎么判断一个代理循环是不是“跑飞了”,而不是还在正常探索?
A:可以从三个信号来判断:一是是否在重复调用同一个工具、且参数高度相似;二是上下文长度和费用是否在短时间内异常飙升;三是输出内容是否开始出现明显自相矛盾或与目标无关的片段。原因在于,正常探索会有多样化尝试和逐步收敛,而跑飞的循环往往表现为“原地打转+语义漂移”。建议在框架层加上无进展检测(对调用序列做去重统计)、费用和轮次上限,并在触发时自动触发人工审查或强制总结收尾。
Q:完成检查具体应该怎么设计,才不会卡死在“永远完不成”?
A:完成检查要“够硬”但不能“过严”,关键是把目标拆成几级:最低可用、预期完成、理想状态。直接用理想状态做唯一完成条件,很容易导致循环一直不满足而卡死。更好的做法是:先用“最低可用”作为自动停止条件,比如“所有测试通过且主流程可跑通”,再把“预期完成”和“理想状态”交给后续人工或异步任务慢慢打磨。技术上,可以用脚本化测试、文件存在性检查、关键字段校验等方式实现,必要时再加一个第二模型做语义层面的 sanity check。
Q:上下文压缩会不会丢掉关键信息,导致模型后面“忘事”?
A:会有这个风险,所以压缩策略要尽量结构化,而不是简单“总结一下”。原因在于,模型对结构化线索(如:决策列表、关键约束、已尝试方案)更敏感,也更容易在后续轮次中正确引用。建议做两层压缩:一层是“人类可读摘要”,一层是“机器可用要点”,比如用列表形式列出:当前目标、已验证事实、失败尝试及原因。实践中,可以定期让模型自己生成这两层摘要,再由一个轻量检查器验证是否包含关键字段,缺了就补问。
Q:工具太少会不会限制代理能力,导致很多事做不了?
A:工具数量不是越多越好,而是要和场景匹配。工具太少确实会限制上限,但工具太多、边界模糊会更快拖垮系统,因为模型会在“选哪个工具”上浪费大量轮次。更合理的做法是:围绕一个具体任务流,先挑出完成它所需的最小工具集,再通过日志分析逐步增减。可以定期审查调用分布:长期几乎不用的工具要么下线,要么合并;经常被误用的工具则需要改名、改描述或拆分。这样既保留能力,又不让代理在选择上迷路。
Q:什么时候适合引入“第二模型”做审查,而不是只靠规则和测试?
A:当任务结果高度依赖语义质量、风格或复杂多维约束时,就很适合引入第二模型。规则和测试擅长检查“硬条件”,比如字段是否存在、接口是否返回200,但对“这份报告是否逻辑自洽、是否符合品牌语气”就很难量化。第二模型可以在这些软指标上给出更细腻的判断。建议做法是:先用规则和测试过滤掉明显不合格的结果,再让审查模型在候选中打分或排序,必要时只保留高分样本进入下一步。这样既控制成本,又能显著提升整体质量。
写到这里,如果你脑子里已经开始盘点:自己的代理有没有刹车、有没有清理上下文、有没有一个真正能说“不”的人,那这篇文章的目的就达到了。剩下的,就是你愿意先从哪一个小改动开始。



