我第一次让 GPT 调用外部 API 时,觉得这玩意儿是要上天——我说“查一下明天的天气”,它没有直接编一个晴天,而是返回了一串 JSON:{"function":"get_weather","arguments":{"city":"北京"}}。代码拿到这个 JSON,去调天气 API,再把结果塞回给模型,模型组织成一句人话。整个过程行云流水。我当时想:这不就是智能体吗?

直到我试图让它做一件需要连续调用好几次工具的事,比如“帮我安排一趟旅程:先查一下明天北京飞上海的航班,再根据航班订一个靠近机场的酒店。”模型当场卡壳了。因为它只支持“一次调用”。那次之后我才意识到,function calling 和 Agent 编排之间,横着一条巨大的河。
函数调用只解决了一件事:让模型能说出“我想用哪只手”
在你接入函数调用之前,让模型用工具的常见做法是:提示词规定“如果用户想查天气,输出 get_weather("北京")”,然后代码用正则去抽。这种玩法非常脆:模型不一定按格式来,如果你有几十个工具,它可能瞎蒙。OpenAI 在 2023 年 6 月推出函数调用,用专门微调过的模型,直接把“该调哪个函数、传什么参数”变成结构化的 JSON 输出。这是很大的进步。
但注意:模型只负责输出意图,真正执行还是在你的代码里。这就像模型手里拿着一张“行动计划卡”,它说“我想查天气”,你替它跑腿。然后把结果喂回去,它再说下一句。如果你需要它连续做三件事,它每做一件事,都要等你把结果粘回去,它才能决定下一句。
这种模式相当于“单步工具使用”:一次对话 = 一次工具调用 + 一次结果回填。如果任务是单步的(查天气、算面积、翻译一段话),完全够用。但你需要想一个问题:如果任务需要三步呢?
单步工具使用的天花板:模型不知道下一步是什么
考虑一个任务:“把订单列表里所有未发货的订单汇总成一个 PDF,然后发到邮箱”。你需要调用列表 API、PDF 生成 API、邮件 API。用单步函数调用,流程是死的:代码收到模型返回的第一步调用,执行完,把结果喂回去;模型生成下一步;代码再执行。直到模型说没有下一步了。
这其实也是一种“循环”,但它不是模型在编排,而是你的代码被动地跑循环。真正的难点在于:
- 模型要能记住已经做过的每一步,否则它会重复调用同一个 API。
- 模型要能根据中间结果调整计划。比如列表 API 返回 500 条,PDF 一次只能处理 20 条,模型得想到分批。
- 出错时要能自行纠正。比如 API 返回 401 未授权,模型应该知道换个方式。
单步工具使用默认“模型一次只做一步,结果交给外部循环”。而 Agent 编排,就是让模型自己主导这个循环。
Agent 编排:把循环开关交给模型自己
整个过程通常长这样:
- 系统给模型一个任务 + 一批工具的说明。
- 模型在每一步先“思考”:现在该做什么,需要哪个工具,参数是什么。
- 模型输出一个工具调用(这就是 function calling 的一部分)。
- 你的程序执行工具,把观察结果(observation)作为新消息喂回模型。
- 模型再思考……一直到模型认为任务结束。
这个循环在 ReAct 论文(Yao et al.,2022)里被明确为“reason + act”交替。ReAct 让模型一边推理一边行动:每一步都生成一个文本解释(reason),然后选择一个动作(act)。这样做的价值是,模型有“自己的草稿纸”,每一步都写下为什么这么做,而不是盲猜。
从实现角度看,Agent 循环里的每一步,本质上就是一次带消息历史的函数调用。最小实现甚至不到二十行伪代码:
messages = [{'role':'user','content':'查上海明天天气'}]; while True: response = model.chat(messages, tools); if response.tool_call: result = execute(response.tool_call); messages.append(result); continue; else: print(response.content); break
真正复杂的是工具的选择、参数的生成、消息历史的压缩,以及循环终止的判断。这也是 Agent 编排比单步调用难的地方。
下面用一张表看清两者的区别:
| 维度 | 函数调用(单步) | Agent 编排(多步) |
|---|---|---|
| 决策回合 | 一次 | 多次,由模型决定何时停止 |
| 上下文 | 只有当前请求 + 前一结果 | 维护完整消息历史(包括所有思考和观察) |
| 错误恢复 | 外部代码处理 | 模型能看到报错,尝试换一种方法 |
| 任务规划 | 无法进行 | 可以拆解、排序、调整计划 |
注意,“任务规划”不是 Agent 自动就有的能力,而是多步循环的自然结果。你给模型足够长的上下文,它就能在消息历史里“看到”已经完成的部分,然后接着规划下一步。这就是为什么 Agent 编排工具(如 LangChain)核心组件不是某个模型,而是“agent executor”——它负责跑这个循环。
一个最大的认知陷阱:工具多 ≠ 聪明
我最早以为,函数调用之后,只要把公司所有 API 都塞给模型,它就能变成一个全能数字员工。后来我在实际项目中被教育了:模型面对 30 个工具时,会频繁选错;面对 API 返回的复杂 JSON 时,会解析偏;当上下文变得很长时,它会忘掉最初的任务。工具多只是增加了模型的“选择难度”,没有增加模型“更好思考”的能力。
Agent 编排真正的瓶颈是模型自己的推理质量。ReAct 循环中,每一步决策都依赖模型的语言理解和逻辑判断。如果模型在步骤 2 里已经错了,后面所有步骤都会跟着错。这让我想起一个比喻:Agent 就像一个蒙着眼走迷宫的人,function calling 是给他一根手杖,而编排循环是让他每走一步睁开眼看一下——但如果方向感本来就差,睁眼也没用。
更关键的是,许多框架把 Agent 编排包装成“零代码拖拽”,好像只要串几个节点就成了。真正可靠的多步规划,需要开发者对每一步的输入输出都做校验和容错,而不是把全局控制权完全交给概率模型。
这个跨越的本质是什么?
我认为核心跨越有三点:
- 从“表达意图”到“维护状态”
- 函数调用只负责表达“我要调用 X”,Agent 编排要求模型记住状态——已经做过什么、还剩什么、下一步该做什么。
- 从“一次选择”到“全局规划”
- 单个函数调用是局部决策,Agent 循环让模型基于中间结果重新评估全局目标。
- 从“工具执行”到“自我纠错”
- 单步时出错只能由外部兜底,Agent 编排里模型可以直接看到报错消息并尝试新策略。
一句话总结:函数调用把“模型的想法”变成了“可执行的动作”;Agent 编排把“多个可执行的动作”变成了“一个模型自己控制的过程”。
但这不等于 Agent 编排“更高级,所以更好”。它的代价很具体:
- 调用次数变多,成本提高;
- 每一步都有概率出错,错误是累积的;
- 上下文越长,模型性能下降越快。
很多生产系统仍然只用单步函数调用,因为简单、可预期。Agent 编排适合那些没有固定流程、需要灵活决定下一步的任务。
常见误解
“Agent 编排会取代所有函数调用流程?”
不会。大量场景是已知流程,写死代码比让模型自由发挥更可靠、更便宜。Agent 编排适合流程不太确定的任务。
“ReAct 是唯一的编排模式?”
不是。还有 Plan-and-Execute(先生成分步计划再逐步执行)、Reflexion(执行后反思并修正)等。ReAct 是基础,但不是终点。
“给模型加个工具,它就能当 Agent?”
远远不够。工具只是手,循环是身体,模型是大脑。缺一不可。
所以,如果你在开发中遇到了“什么时候该从函数调用升级到 Agent 编排”的困惑,我的判断是:先问自己任务是否需要多步决策。如果流程固定,写死。如果流程不确定、需要模型根据中间结果不断调整,再上 Agent。但一定要为每一步设置检查点和退出条件。Agent 的可靠性天花板,短期内仍然卡在模型推理的稳定性和上下文记忆上,这不是工程框架能完全填平的。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/2031.html