如何设计一个不断提示 Agent 的循环
单个提示词只是一招,循环才是让 Agent 处理多步骤任务的系统。定义完成条件、构建上下文、执行并捕获结果、反馈进入下一轮,再加上停止条件。


来源链接: X - Amit Shekhar
这一篇讲如何设计一个用来提示 Agent 的循环:循环到底是什么,为什么单个提示词不够,以及构建一个能持续推动 Agent 工作的循环,需要哪五个部分。
会覆盖这些内容:
- 循环的五个部分
- 第 1 步:定义“完成”是什么样子
- 第 2 步:构建上下文,别只写指令
- 第 3 步:让 Agent 执行动作,并捕获一切结果
- 第 4 步:用反馈关闭循环
- 第 5 步:设置停止条件
- 完整循环代码
- 跑一遍示例
- 运行循环的成本
- 可复用技能
- 常见错误
我是 Amit Shekhar,Outcome School 创始人。我教过并指导过许多开发者,他们拿到了高薪技术工作,很多技术公司也通过他们的努力拿到过上百万美元的收入。
我在 Outcome School 教 AI 和机器学习。
开始吧。
进入细节之前,先看整体图景。
大多数人以为,和 AI Agent 协作就是写一个特别好的提示词。我们输入请求,Agent 回复,事情结束。对于快速问答,这样没问题。但真实任务会复杂得多。
真实任务通常是:写代码,运行测试。测试失败,读取错误。修代码,再运行测试。反复做,直到全部通过。
我们不想手动输入每一轮提示。那很慢,也扩展不了。循环的价值就在这里:系统会一次又一次自动提示 Agent 。
新的技能,是搭建一个能持续替我们提示 Agent 的系统,而不只是写出一个完美提示词。
这个系统就是循环。下面看怎么设计它。
先从最重要的概念开始。
想象一盘国际象棋。单个提示词就像一步棋。你看棋盘,走一步,这一回合结束。如果永远只走一步,就赢不了一整局棋。
循环不一样。循环是一套策略。它定义每一步怎么走,每一步之后怎么检查棋盘,并持续执行,直到棋局结束。
提示词是一步棋。循环是一套策略。
我们不再一回合一回合手动玩这盘棋。我们设计 Agent 行动时遵守的规则。规则只设置一次,Agent 就能在里面持续运行。
那么,这套规则怎么设计?
下面看循环的五个部分。
循环的五个部分
一个用来提示 Agent 的循环有五个部分。不用担心,后面会逐个拆开。
- 定义“完成”:告诉循环什么时候该停下来的检查条件。
- 构建上下文:每一轮喂给 Agent 的新信息。
- 执行并捕获:运行这一步,并拿到结果。
- 用反馈关闭循环:把结果变成下一轮提示。
- 设置停止条件:保护循环安全运行的护栏。
这五个部分的关系如下:
+--------------------------------------------------+
| The Loop |
| |
| Build Context ---> +-------+ |
| | Agent | |
| +-------+ |
| | |
| | acts |
| v |
| Capture Result |
| | |
| v |
| Check "Done"? ----- Yes ---> Stop
| | |
| | No (feedback) |
| | |
| +---------------------+
| (next turn) |
+--------------------------------------------------+
Stop conditions wrap the whole loop
可以看到,这是一个周期。我们构建上下文,Agent 执行动作,系统捕获结果,然后检查是否完成。完成就停止;没有完成,就把结果反馈进下一轮。
下面逐个看。
第 1 步:定义“完成”是什么样子
任何东西开始运行之前,先回答一个问题:循环怎么知道自己已经完成?
这是第一步,也是最重要的一步。如果不能描述“完成”,Agent 就没有明确目标。它可能一直跑下去,也可能停在错误的地方。
所以,先写成功检查,再写其他部分。这个检查必须在代码里,不要只留在脑子里。假设我们在做一个修 bug 的 Agent,“完成”可以是:
- 测试通过。
- 输出符合某个 schema 。
- 分数超过某个阈值。
用一个简单函数表示:
def is_done(result):
# done means all tests passed
return result.tests_passed
这个小函数在工作完成时返回 True,没有完成时返回 False 。循环每一轮都会调用它。
这个检查就是循环的心跳。每一轮,循环都检查一次心跳。如果心跳说完成,循环停止;如果还没完成,循环继续。
所以要从这里开始:先定义检查条件。循环的其他部分都建立在它之上。
这就是“完成”的定义。接着看上下文。
第 2 步:构建上下文,别只写指令
很多人会在这里走错。他们不停手动喂 Agent,每一次都重新输入指令,再把文件和错误日志粘进去。
要停下来。我们要构建上下文,别一遍遍手写指令。
这里的上下文是什么意思?它指的是 Agent 在这一轮做出好决策所需要的一切信息:
- 正在处理的文件。
- 可以使用的工具。
- 上一次运行留下的错误日志。
- 已经尝试过的方案。
于是,提示词由系统当前状态拼出来,不再靠我们手动输入。
代码可以这样写:
def build_prompt(state):
return f"""
Goal: {state.goal}
Files: {state.files}
Last error: {state.last_error}
Past attempts: {state.past_attempts}
Decide the next step and make the change.
"""
这里可以看到,提示词来自 state 。我们不用手动输入错误,系统会从状态里读取错误,再自动放进提示词。状态改变,提示词也随之改变。
所以,每一轮的循环结构是一样的,变化的是上下文。同一个 build_prompt 函数每次都会生成不同的提示词,因为背后的 state 不同。
这就是构建上下文。接下来,让 Agent 开始行动。
第 3 步:让 Agent 执行动作,并捕获一切结果
现在运行这一步。把刚才构建好的提示词发给 Agent,让 Agent 做事。它可能写代码、调用工具、修改文件。
但执行动作只完成了一半。另一半是捕获所有输出:
- 改了什么,也就是 diff 。
- 运行代码后的标准输出。
- 如果失败,失败信息是什么。
- 系统的新状态。
代码如下:
def act_and_capture(prompt, state):
output = agent.run(prompt) # the agent does the work
result = run_checks(output) # run tests, grab logs, get the diff
return result
这里先运行 Agent,再捕获结果。这个 result 里有 diff 、输出,以及检查是否通过。
关键点在于:这个输出会变成下一轮提示的原材料。刚捕获到的失败,正是下一轮要喂给 Agent 的信息。
这就是执行和捕获。下面把循环关上。
第 4 步:用反馈关闭循环
现在已经有了一个结果。接下来,把这个结果送回第 1 步的“完成”检查。这个动作让它成为循环,避免停在单次执行。
这里只有两条路:
- 通过?停止,任务完成。
- 失败?把失败自动变成下一轮提示。
第二条路是关键。工作失败时,不要放弃。把失败转换成下一条指令。类似这样:“测试失败,因为预期是 X,实际是 Y 。请根据这个信息修改。”
Agent 会根据刚发生的事情重新提示自己。这个新提示由循环从失败结果里构建出来,不需要我们手打。
代码如下:
def loop(state):
while True:
prompt = build_prompt(state) # Step 2: build context
result = act_and_capture(prompt, state) # Step 3: act and capture
if is_done(result): # Step 1: check done
return result # passed, so we stop
# failed, so turn the failure into the next prompt
state.last_error = result.error
state.past_attempts.append(result)
这里可以看到,循环把自己闭合起来了。如果完成,就 return 并停止。如果没有完成,就把错误保存进 state 。下一轮的 build_prompt 会读取这个错误,并把它放进新的提示词。
这就是用反馈关闭循环。但上面的代码还有一个问题:如果 Agent 一直失败,它没有出口。下面补上这个出口。
第 5 步:设置停止条件
没有出口的循环,本质上是一笔停不下来的成本。如果 Agent 一直失败,循环一直跑,它会消耗时间和费用,却没有进展。
所以要先设置停止条件,再让循环安全运行。几个重要护栏:
- 限制重试次数。即使任务没完成,到固定轮数也停止。
- 监控成本。超过时间或费用预算就停止。
- 加入人工检查点。涉及关键调用时,先暂停,让人确认后再继续。
把这些护栏加进循环:
def loop(state, max_turns=10, max_cost=5.0):
turns = 0
cost = 0.0
while turns < max_turns and cost < max_cost:
turns += 1
prompt = build_prompt(state)
result = act_and_capture(prompt, state)
cost += result.cost
if is_done(result):
return result # success
state.last_error = result.error
state.past_attempts.append(result)
return "stopped: hit a guardrail" # safe exit
这里给循环加了两个护栏:重试次数上限和成本上限。任务完成时,循环停止;轮数或成本用完时,也会停止。
这就是让循环安全运行的方法。
注意:人工检查点对难以撤销的操作最重要。删除文件、转账、推送到生产环境,都是好例子。遇到这类动作,循环应该暂停,请人确认。
完整循环代码
现在已经看过五个部分,把它们放在一起:
# Step 1: define done
def is_done(result):
return result.tests_passed
# Step 2: build the context from state
def build_prompt(state):
return f"""
Goal: {state.goal}
Files: {state.files}
Last error: {state.last_error}
Past attempts: {state.past_attempts}
Decide the next step and make the change.
"""
# Step 3: act and capture
def act_and_capture(prompt, state):
output = agent.run(prompt)
return run_checks(output)
# Step 4 and 5: close the loop with feedback, inside the guardrails
def loop(state, max_turns=10, max_cost=5.0):
turns = 0
cost = 0.0
while turns < max_turns and cost < max_cost:
turns += 1
prompt = build_prompt(state)
result = act_and_capture(prompt, state)
cost += result.cost
if is_done(result):
return result
state.last_error = result.error
state.past_attempts.append(result)
return "stopped: hit a guardrail"
这里就是完整图景。五个部分合成一个系统:定义完成、构建上下文、让 Agent 执行、捕获结果、反馈给下一轮,同时用护栏包住整个过程。
代码只写一次,Agent 就能独立完成多步骤任务。
跑一遍示例
最好的学习方式,是拿一个例子走一遍。假设目标是“修复登录失败的 bug”。
第 1 轮:state 里有目标和文件,还没有错误。系统构建提示词并发送给 Agent 。 Agent 修改代码。系统捕获结果。测试仍然失败:empty password returns true。
第 2 轮:build_prompt 现在会带上第 1 轮的新错误。 Agent 读到“空密码时 password check 返回 true”,然后修复对应代码行。系统捕获结果。这一次测试通过。
第 3 轮:没有第 3 轮。is_done 在第 2 轮返回 True,循环自己停下了。
这里最重要的是:整个运行过程中,我们没有手动输入任何一条新提示。第 1 轮的错误自动变成了第 2 轮的提示。
运行循环的成本
有一点常常让人意外:写代码本身很便宜。让循环一遍又一遍写代码,并不便宜。
原因很简单。模型几秒钟就能写一段代码,成本很小。但循环会让模型一轮又一轮运行。有时任务很快完成,有时会卡住。卡住时,每一轮都会继续花钱。
这就是第 5 步的停止条件如此重要的原因。停不下来的循环不只是 bug,它还是一笔在睡觉时继续增长的账单。
所以,我们最重要的工作已经变了。重点是确保循环会停,而不只是写一个聪明提示词。限制轮数、监控成本、对高风险操作加人工检查,这些都要做。
可复用技能
接下来是长期最有价值的部分。循环本身只是接线,价值在它调用的技能里。
这里的技能是什么?技能是一个小型、可复用、能把一件事做好的工具。与其每一轮都让模型从头想同一个问题,不如把那个动作做成技能,让循环调用它。
规则很简单:当同一步骤反复出现,就把它抽出来做成技能。当一个难题被解决,就把解决办法保存为技能。下次循环遇到同类问题,就直接调用。
没有技能的循环,会让模型每一轮重复解决同样的问题。带有一组清晰、经过测试的技能的循环,会随着时间越来越强。
常见错误
设计循环时,常见错误有这些:
- 没有“完成”检查。没有代码里的检查条件,循环不知道什么时候停止。第 1 步必须先写。
- 手动喂提示词。如果每一轮都靠人输入提示,那就是人在继续干活,循环没有真正接管。提示词应该由 state 构建。
- 丢掉输出。失败就是下一轮提示。如果不捕获失败,就没有东西可以反馈。
- 没有停止条件。没有出口的循环会持续运行、持续计费。要限制重试次数,并监控成本。
- 把一次性任务强行做成循环。只有工作会重复、结果可检查时,循环才划算。一次性任务用普通提示词就够了。
- 循环里没有技能。如果每一轮都从头解决同样的问题,会浪费时间和 token 。把重复工作变成可复用技能。
所以,我们不再一步一步手动走棋。我们设计一次循环,给它检查自己的方式,也给它停止的方式,然后让它运行。
这样,就能用一种很简单的方式,设计出一个持续提示 Agent 、解决真实多步骤问题的循环。
这次先到这里。
谢谢。
Amit Shekhar
Outcome School 创始人