Agent 循环
思考、行动、观察、重复。这个循环实现起来简单得很,难的部分全在什么时候停下来。
用户问订单 #4021 的状态。我得去查一下——它不在我的上下文里。
每个 agent 的核心循环大约只有十五行:
messages = [system_prompt, user_request]
while True:
response = model(messages, tools=available_tools)
messages.append(response)
if not response.tool_calls:
return response # model produced an answer
for call in response.tool_calls:
result = execute(call)
messages.append(result)调用模型。如果它想用工具,就把工具跑一遍并追加结果。重复,直到它不再要工具、直接给出答案。
真的就这么点东西。所有的难点都在它周围的细节里。
思考、行动、观察
每一轮包含三部分。
思考——模型检视整段对话并做出决定。推理过程可以是显式的,要求它写出来会有帮助,原因和思维链(chain-of-thought)管用一样:每个 token 都是一次额外的前向计算,而循环会让这段推理在下一轮里变得可见。
行动——模型发出一次工具调用,由你的代码执行它。
观察——结果被追加进去。模型现在知道了一些它原先不知道的东西。
不断增长的消息列表就是 agent 的记忆。没有别的状态。agent 对自己进展的全部了解,都活在这份对话记录里,每一轮完整重发一次。
难的是停下来
上面写的那个循环,除了模型主动选择回答之外没有别的出口。实际用起来这远远不够。
迭代上限。 永远都要设一个硬性最大值。没有它,一个晕头转向的 agent 会一直循环到你发现为止。十到二十是常见值。
token 预算。 上下文每一轮都在长。跟踪它,在溢出之前停下来,而不是一头撞上去。
墙钟超时。 它独立于迭代次数,因为单次工具调用可能会卡住。
重复检测。 最常见的真实失效:同一个工具带着同一组参数反复调用,因为结果没帮上忙,模型也没有更好的主意。检测到就中断——对最近的调用做一次循环检测开销很小,却能拦住一大堆问题。
显式的完成信号。 别再从「没有工具调用」去推断完成,给模型一个 finish 工具,把答案作为参数传进去。这样「完成」就是一个有意为之、你可以验证的动作。
最后一条值得采纳。把「没有工具调用」当完成信号,混淆了做完了和卡住了,而这两者需要不同的处理。
上下文的增长
每一轮都会追加模型的回复,加上所有工具结果。十轮啰嗦的工具输出就能吃掉一整个上下文窗口。
更糟的是,整份对话记录每一轮都要重发,所以总的 token 成本随循环长度按平方增长。二十步的跑法不是十步的两倍。
缓解手段,大致按投入从低到高排:
让工具返回紧凑的结果。 最省事也最有效的修法。一个工具本该返回 200 token 就够,却返回了 10,000 token 的 JSON,会毒害后面的一切。
截断旧结果。 近期的观察结果完整保留,更早的压缩成一行。
定期做总结。 每 n 步,用一份进展与发现的总结替换掉历史。会丢细节,但能把可跑的距离拉长。
把状态外置。 让 agent 把发现写进一个文件或草稿区,之后还能重新读回来,对话记录就能保持简短。工程量大一些,但这是唯一能真正撑住长任务的做法。
可靠性为什么会向下复利
如果每一步有 95% 的成功率,十步下来大约只有 60%。二十步,大约 36%。
这道算术是 agent 设计的核心约束,也解释了为什么长距离的自主运行无论 prompt 写得多好都不够可靠。prompt 这一层没有任何东西能改变一个指数。
真正有效的应对:把循环压短,让每一步更可靠而不是加更多步,并且做检查点,这样第 8 步失败时不会把第 1 到第 7 步一起丢掉。
围绕它搭结构
每一轮都带上目标。 长循环会漂移。原目标待在system prompt里有帮助,明确重述一遍帮助更大。
记录每一轮。 思考、调用和结果的对话记录,是你唯一能拿来调试的东西。没有它,agent 的失效方式根本无从理解。
让进展看得见。 任何面向用户的东西,都要把 agent 正在做什么流式输出出来。一个十二步的运行里全程静默,这是不可接受的用户体验。
给有后果的步骤设确认闸门。 只读工具可以随便跑。任何不可逆的操作都需要确认——见Agent 如何失效。
要点回顾
- 循环本身很简单:调用模型、执行工具、追加结果,重复到它给出答案为止。
- 消息列表就是全部的记忆,每一轮都要重发。
- 停下来需要显式的机制:迭代上限、token 预算、超时、重复检测,最好再加一个
finish工具。 - 上下文随循环长度按平方增长;紧凑的工具结果是收益最高的修法。
- 可靠性向下复利——单步 95%,十步就只有 60%。宁可要短循环和可靠的每一步。
下一篇: 把工具定义写好