Prompt 工程已死?我转投 Agent Loop 后的真实感受
我写过不少 prompt。去年有一段时间我特别沉迷"prompt 工程"这件事,觉得只要 system prompt 写得够好、few-shot 给得够全,模型就能稳定输出我想要的东西。有一回我给一个复杂任务写了将近 200 行的 system prompt——包含完整的工作流描述、输出格式模板、边界条件处理、甚至还有一套"自纠错"指令。
结果换了个模型版本,直接崩了。不是效果变差,是崩——输出格式不对、拒绝执行中间步骤、在同一个循环里反复打转。200 行 prompt,一个版本更新就全废了。
这事让我开始想一个问题:我们把太多逻辑塞进 prompt 里,是不是搞错了方向?
后来我接触到了 Agent Loop 的模式,花了大概一个月把一套生产级工具从"单次 prompt 调用"改成了"循环式 Agent"。这篇文章不打算讲理论,就想说说我踩的坑和真实的感受。
从 200 行 prompt 到 0 行
传统 prompt 工程的思路是你替模型想好每一步——告诉他"你先做 A,然后根据 A 的结果做 B,如果 B 出错就做 C……"。
这个思路在简单任务上没问题,但任务复杂度一上来你就会发现:你根本不可能穷举所有路径。用户的输入千奇百怪,工具返回的数据格式五花八门,一次 API 超时可能让整条链子断了。
Agent Loop 的思路刚好反过来:不给模型指路,给它工具和终点,让它自己绕。每次模型调用就是一步决策——看当前状态、选一个工具调用、看返回结果、再决策。
这个转变刚开始挺不适应的。毕竟你习惯了对模型的每一步输出都"掌控",现在要放手让它自己走,第一反应是不放心。但跑了几个测试用例之后我发现:效果居然比硬编码的 prompt 流程好很多,尤其是在处理意外情况的时候。
我写的最简 Agent Loop
贴一个我最早跑通的版本,去掉业务细节,只保留核心结构:
import json import openai class AgentLoop: def __init__(self, tools, system_prompt, max_iters=10): self.tools = tools # [{name, description, parameters, fn}] self.system_prompt = system_prompt self.max_iters = max_iters self.messages = [{"role": "system", "content": system_prompt}] def run(self, user_input): self.messages.append({"role": "user", "content": user_input}) for i in range(self.max_iters): # 这里踩了个坑:最开始没加 max_iters,结果有一次模型反复调用同一个工具 # 每次返回一样的错误,但它就是不终止——token 白白烧了 15 分钟 resp = openai.chat.completions.create( model="gpt-4", messages=self.messages, tools=[{ "type": "function", "function": { "name": t["name"], "description": t["description"], "parameters": t["parameters"] } } for t in self.tools] ) msg = resp.choices[0].message self.messages.append(msg) if not msg.tool_calls: # 模型决定不调用工具 → 返回最终答案 return msg.content for tc in msg.tool_calls: tool = next(t for t in self.tools if t["name"] == tc.function.name) args = json.loads(tc.function.arguments) # 另一个坑:工具返回值一定要统一格式,不然模型解析会出幻觉 result = tool["fn"](**args) self.messages.append({ "role": "tool", "tool_call_id": tc.id, "content": json.dumps({"status": "ok", "data": result}, ensure_ascii=False) }) return {"error": "max_iterations_reached", "messages": self.messages}这段代码大概 40 行,但已经是一个完整的 Agent Loop 骨架了。核心思路就是:给模型工具 → 让模型决定用哪个 → 把结果喂回去 → 直到模型自己说"好了"。
我一开始用的是递归实现,觉得优雅。结果线上跑了一个星期发现调用栈炸了——递归深度超过 Python 默认限制。后来改成迭代就稳了。这个教训告诉我:Agent Loop 的迭代控制不在算法层面,而在生产层面。
生产环境踩的 5 个坑
把 Agent Loop 从 demo 搬到生产,我踩了不少坑。下面这 5 个是最痛的:
1. 无限循环不是段子,是真的会发生
我第一次把 Agent Loop 部署上线,跑了大概三个小时就出事——同一个工具被反复调用了 40 多次,每次返回相同的错误。模型就是不停重试同一个已失败的步骤。我赶紧加了 max_iters,但后来发现单纯的次数限制不够:有些场景需要上下文感知的终止条件,比如"连续 3 次相同错误就熔断"。现在我的每个 Agent 都有两种终止条件:硬性次数上限 + 智能熔断策略。
2. 工具返回值格式必须统一,不然模型会疯
这点我吃过大亏。最开始不同的工具返回的格式不一样——有的返回纯文本,有的返回 JSON,有的什么都不返回。结果模型在循环中越来越困惑,开始出现幻觉:它会把一个工具的文本输出当成另一个工具的结果来解析,产生完全不相关的后续步骤。后来我强制所有工具返回统一的 JSON 格式({status, data, error}),这个问题就没了。其实说白了就是:你给模型的数据必须可预测。
3. Token 消耗比想象的大得多
一个 Agent Loop 每次迭代都在把历史对话塞进上下文。跑了 5 轮之后,上下文里就已经有了 5 次 tool call 的完整输入输出。我测了一个典型场景:单次 prompt 调用消耗约 2000 tokens,改成 Agent Loop 后一次完整任务平均消耗 8000–12000 tokens——3 到 6 倍。这还是顺利的情况,如果模型反复调用同一个工具,token 能到 5 万。我的应对策略是上下文压缩:定期把历史中的 tool call 详情摘要成一句话,只保留关键信息。
4. 调试比普通 prompt 难一个数量级
普通 prompt 的调试你已经熟悉了:prompt 进去了,输出出来了,不对就改 prompt。Agent Loop 的调试是:prompt → 模型决定调工具 A → 工具 A 返回 → 模型决定调工具 B → 工具 B 失败 → 模型决定重试工具 B → … 每一步都可能出错。我最初的做法是在每步打印日志,但一个任务跑下来日志上万行,根本看不出问题在哪。后来我给每个 Agent 加了一个"思维链可视化"——把每一步的"模型的想法"(即它的推理过程)和工具调用结果并列展示,调试效率一下子就上来了。
5. 成本失控比你想象的快
上面说的 token 消耗问题直接反映在账单上。我第一次跑了一周 Agent Loop 测试,看了一眼 API 消耗——是我的做法大概是我平时 prompt 做法的 10 倍。不是 10% 是 10 倍。后来我加了预算控制:每个 Agent 实例初始化时设定一个 max_cost,每次迭代前估算当前消耗,达到阈值就直接终止并返回 partial result。
class BudgetAgent(AgentLoop): def __init__(self, tools, prompt, max_cost=0.01): super().__init__(tools, prompt) self.max_cost = max_cost self.spent = 0 def estimate_cost(self, messages): # 粗略估算:input $3/M tokens, output $15/M tokens total_chars = sum(len(m["content"] or "") for m in messages) return total_chars * 1.5 / 1_000_000 * 3 def step(self): cost = self.estimate_cost(self.messages) if self.spent + cost > self.max_cost: return {"error": "budget_exceeded", "spent": self.spent} self.spent += cost return super().step()这比跑完了告诉你"对不起超预算了"要体面得多。
还得老实说,prompt 工程没那么容易死
说了这么多 Agent Loop 的好处,我也得老实承认:prompt 工程没死,也不需要死。
有些场景用 prompt 就是比 Loop 合适——简单的一问一答、格式转换、分类任务——你用 loop 反而是杀鸡用牛刀。Agent Loop 引入的复杂度(调试困难、token 消耗大、行为不确定性)在简单场景下完全划不来。
我现在的工作方式是:简单任务用 prompt,复杂任务用 loop。而且即使是 loop 的 Agent,我也会在 system prompt 里写清楚它的行为边界——这不是"prompt 工程"的回归吗?某种意义上是的。只不过这个 prompt 不是告诉模型每一步怎么走,而是告诉它:你有这些工具、这些约束、这个目标,你自己想办法。
所以与其说"prompt 已死",不如说是 prompt 的职责变了——从详细指令集变成了约束条件和目标定义。我觉得这才是 2026 年写 AI 应用的正确打开方式。
