大模型工具使用的三次进化:从 Function Calling 到程序化编排
大模型的工具使用(Tool Use)是大模型落地中最有价值、也最具挑战的路径之一:它让模型从"会说"跃升到"能做",将自然语言理解与真实系统的查询、计算、执行真正连接起来。这条路径的标志性起点,是 OpenAI 在 2023 年推出的 Function Calling——模型在对话中自主决定调用哪些工具,并基于返回结果继续推理与决策。
随着 AI Agent 尝试解决的任务复杂度持续攀升(更多步骤、更长链路、海量数据、强时序依赖),工具使用范式也在快速演化。本文将这条演进路径划分为三个阶段:
- 阶段一:循环式工具选择(Function Calling) —— 单次调用 + 模型逐轮决策下一步
- 阶段二:计划驱动执行(Plan-then-Execute) —— 先生成全局计划,再串行/并行执行,支持动态调整
- 阶段三:程序化工具编排(Programmatic Tool Calling) —— 将多工具调用逻辑下沉到可执行代码,由代码完成循环、并发、过滤与聚合,只将关键摘要返回模型

这条演进路径揭示了一个趋势:编排逻辑从"模型逐步决策"转向"计划驱动、代码驱动",中间结果的处理从"全部塞进上下文"转向"执行侧预先消化"。这不仅显著提升了复杂任务的吞吐效率和成本控制,也带来了新的工程挑战——如何在可控性与灵活性之间找到平衡。
本文将通过直观的流程图和对比表,梳理这三种模式的核心差异、适用场景与工程实践要点,期待与大家探讨。
什么是工具使用,为什么需要演进
工具使用的核心思想很直观:让大模型在生成文本之外,获得与外部系统交互的能力。当用户问"今天北京天气如何",模型不再只能说"我不知道实时信息",而是可以调用天气 API 获取数据后再作答;当用户要求"帮我分析这份销售数据的趋势",模型可以调用 Python 解释器执行计算,而不是凭空臆测数字。这种"理解意图 → 选择工具 → 获取结果 → 综合回答"的闭环,是工具使用的基本形态。
早期实践中,单次查询、单个工具调用就能解决大部分问题——查天气、查汇率、简单计算。但随着应用场景深入,任务复杂度迅速攀升:用户可能要求"对比过去三年的销售数据,找出增长最快的品类,并生成可视化报告",这需要模型依次调用数据库查询、数据处理、图表生成等多个工具,甚至需要根据中间结果动态决定下一步。传统的"一问一答式"工具调用开始暴露出效率瓶颈、成本压力和可控性问题。正是这些痛点,推动了工具使用范式从简单到复杂的演进。
本文将这条演进路径归纳为三个阶段,但需要强调的是:这三个阶段并非线性替代关系,而是针对不同复杂度任务的最优解。对于简单的单步查询(如查天气、查汇率),循环式工具选择依然是最直接、成本最低的方案;对于需要明确步骤但步骤间依赖较弱的任务(如"查资料 + 总结 + 翻译"),计划驱动执行能显著提升并行效率;而对于涉及大规模数据处理、复杂过滤聚合的任务(如"从数万条日志中提取异常模式并生成报告"),程序化工具编排则能避免上下文爆炸、大幅降低延迟与成本。选择哪种模式,取决于任务的步骤数量、数据规模、依赖关系与实时性要求,而不是简单的"新技术替代旧技术"。
接下来,我们将逐一拆解这三个阶段的技术实现方式与核心特点,并通过对比表和实际案例,帮助你在工程实践中做出更合理的选择。
模式一:循环式工具选择(Function Calling)
循环式工具选择是最直观的工具使用范式,其核心逻辑可以用一句话概括:模型决策 → 执行工具 → 模型再决策,如此循环往复。用户输入问题后,模型会收到一份可用工具清单(包含工具名称、参数描述、功能说明),然后判断是否需要调用工具。如果需要,模型会输出结构化的调用请求(比如 get_weather(city="北京", date="明天")),应用层拿到这个请求后去执行真实的 API 调用或代码运行,再把结果以文本形式追加回对话历史。模型看到新结果后继续推理,决定是调用下一个工具,还是直接生成最终答案。
OpenAI 的 Function Calling API 就是这种模式的经典实现。开发者在请求中声明工具列表,模型返回 tool_calls 字段告诉你要调哪个工具、传什么参数,你执行完把结果以 tool 角色消息送回去,模型继续处理。整个过程就像一场"乒乓对话":你来我往,每一轮模型只能看到过去的所有对话和上一次工具的结果。
举个具体例子:用户问"帮我查一下北京明天的天气,如果会下雨就提醒我带伞"。第一轮,模型决定调用 get_weather(city="北京", date="明天"),工具返回 {"temperature": 15, "condition": "小雨"};第二轮,模型看到这个结果,生成最终回答:"北京明天15°C,有小雨,记得带伞哦"。整个过程清晰可控,调试起来也很直观。
这种模式的优势和局限都很明显。先说优势:
- 简单直观:逻辑清晰,几乎所有主流大模型都原生支持,开发门槛很低
- 灵活性强:模型可以根据每一步的实际结果动态调整策略,如果某个 API 返回错误可以尝试其他工具,如果数据不符合预期可以追加查询
- 适合探索性任务:这种"走一步看一步"的特性,让它特别适合处理高度不确定的任务,比如调试代码、探索性数据分析
但局限也同样突出:
- 串行执行瓶颈:每次只能调用一个工具,无法并行,多步任务的延迟会线性累加
- 上下文膨胀:每次工具调用的完整结果都要塞回上下文,当工具返回大量数据(比如数据库查询返回几百条记录)时,token 消耗会快速飙升
- 效率冗余:每一步都需要等待模型推理,对于步骤已经很明确的任务(比如"查数据 → 计算均值 → 生成图表"),反复等待显得有些浪费
因此,循环式工具选择最适合以下场景:
- 单步或少步查询:查天气、查汇率、简单计算、单次数据库查询
- 高度不确定的任务:需要根据每一步结果灵活调整策略的场景
- 工具返回数据量小:每次调用返回的结果简洁(几十到几百 tokens),不会撑爆上下文
典型案例包括智能客服(查订单 → 查物流)、简单的数据查询助手、代码执行与纠错等。但当任务步骤增多、数据规模增大时,这种"逐步决策"的模式就开始暴露效率问题了——这也正是阶段二"计划驱动执行"要解决的痛点。
模式二:计划驱动执行(Plan-then-Execute)
循环式工具选择的一个核心问题在于"边走边看":模型每次只能看到上一步的结果,然后决定下一步。这对于高度不确定的任务是优势,但对于步骤相对明确的任务却是效率杀手。比如用户要求"对比过去三年的销售数据,找出增长最快的品类,并生成可视化报告"——这个任务的步骤其实很清楚:查询数据 → 计算增长率 → 排序筛选 → 生成图表。但在循环模式下,模型必须等第一步查完数据、看到结果后,才能决定第二步;第二步算完增长率后,才能决定第三步。每一步都要完整推理一次,串行等待,延迟线性叠加。
计划驱动执行试图打破这个瓶颈:让模型先看清全局,生成一个完整的执行计划,然后再按计划执行,并支持并行调度与动态调整。具体流程是这样的:模型收到任务后,先不急着调用工具,而是基于任务需求和可用工具,输出一个结构化的执行计划(plan),明确列出需要哪些步骤、每一步调用什么工具、步骤之间的依赖关系(哪些可以并行、哪些必须串行)。应用层拿到这个计划后,交给执行引擎(executor)按依赖关系调度:没有依赖的步骤可以并行执行,有依赖的步骤等前置完成后再执行。所有步骤完成后,将结果汇总返回模型,模型基于全部结果生成最终答案——如果发现计划有问题或结果不符合预期,还可以要求模型调整计划、重新执行。
以刚才的销售数据分析为例。在计划驱动模式下:
第一阶段(Planning):模型生成计划
1. query_database(sql="SELECT category, year, sales FROM sales WHERE year >= 2022")
2. calculate_growth_rate(data=step1.result) # 依赖步骤1
3. sort_and_filter(data=step2.result, top_n=5) # 依赖步骤2
4. generate_chart(data=step3.result, type="bar") # 依赖步骤3
第二阶段(Execution):执行引擎按依赖关系调度,步骤1执行完后,步骤2、3、4依次执行(如果有多个无依赖步骤可以并行)
第三阶段(Synthesis):将所有结果返回模型,模型生成最终报告:"根据数据分析,过去三年增长最快的品类是电子产品(年均增长32%),以下是可视化图表……"
这种模式相比循环式的改进是显著的:
- 并行执行:没有依赖关系的步骤可以同时调用(比如同时查询多个数据库、同时调用多个 API),大幅降低总延迟
- 减少推理轮次:模型只需要推理两次(生成计划 + 生成答案),而不是每一步都推理一次,节省了 token 和时间
- 全局视角:模型在规划时能看到完整任务需求和所有可用工具,可以做出更优的资源分配决策
但这种模式也不是万能的,它带来了新的复杂度:
- 计划质量依赖强:如果模型生成的计划有误(比如步骤遗漏、依赖关系错误),整个执行过程可能失败,而且错误只能等全部执行完才能发现
- 灵活性下降:一旦计划确定,中间步骤无法根据实际结果动态调整(除非重新规划),不如循环模式灵活
- 工程复杂度:需要实现一个能解析依赖、调度执行、处理并发的执行引擎,开发成本比简单循环高
- 中间结果处理:虽然并行提升了效率,但如果某个步骤返回大量数据,仍然需要全部传回模型,上下文压力依然存在
因此,计划驱动执行最适合以下场景:
- 多步骤但步骤明确的任务:比如数据分析流程、文档处理流程(提取 → 翻译 → 总结 → 格式化)
- 有明显并行机会的任务:比如同时查询多个数据源、同时调用多个 API 进行对比
- 对延迟敏感的任务:通过并行和减少推理轮次,显著降低端到端响应时间
- 工具返回数据量可控:每个步骤的返回结果不会太大,汇总后不会撑爆上下文
典型案例包括:复杂的数据分析任务、多源信息聚合(比如对比多个电商平台的价格)、文档处理流水线等。目前不少 Agent 框架(如 LangGraph、AutoGPT)都在实现类似的计划-执行模式。
但问题还没有完全解决。当任务涉及大规模数据处理(比如"从1万条日志中提取异常模式"),即使做了并行优化,把所有中间结果都传回模型依然不现实——这就引出了第三阶段的核心思想:既然模型处理大规模数据吃力,为什么不把数据处理逻辑直接交给代码?
模式三:程序化工具编排(Programmatic Tool Calling)
计划驱动执行解决了并行调度的问题,但有一个根本矛盾它始终无法回避:中间结果的上下文爆炸。想象这样一个场景:用户要求"分析过去一个月的服务器日志,找出所有响应时间超过5秒的请求,统计它们的来源IP分布,并生成top10列表"。即使你用了计划-执行模式,查询日志可能返回1万条记录,过滤后还有500条,这些数据全部传回模型会占用几十万tokens——不仅成本高昂,模型处理起来也慢且容易出错。更关键的是,这些"过滤、循环、聚合"的逻辑本身非常机械,根本不需要模型的推理能力,却在消耗大量的推理资源。
程序化工具编排的核心思想很激进:既然模型擅长理解意图和生成逻辑,代码擅长执行循环和处理数据,那就让模型生成可执行代码,把多工具调用的编排逻辑完全交给代码。具体来说,模型不再输出"调用工具A → 调用工具B → 调用工具C"这样的步骤序列,而是直接生成一段Python(或其他语言)代码,这段代码里包含了所有的工具调用、循环、条件判断、数据过滤与聚合逻辑。应用层将这段代码放到沙箱环境中执行,代码可以自由调用工具、处理大规模数据、进行复杂计算,最后只把关键的摘要结果(比如top10列表、汇总统计)返回模型。模型基于这个精简的结果生成最终答案。
还是以刚才的日志分析为例。在程序化工具编排模式下:
第一步(Code Generation):模型生成代码
# 查询日志数据
logs = query_database("SELECT * FROM server_logs WHERE timestamp >= NOW() - INTERVAL 30 DAY")
# 过滤响应时间超过5秒的请求
slow_requests = [log for log in logs if log['response_time'] > 5]
# 统计来源IP分布
ip_counts = {}
for req in slow_requests:
ip = req['source_ip']
ip_counts[ip] = ip_counts.get(ip, 0) + 1
# 排序并取top10
top10 = sorted(ip_counts.items(), key=lambda x: x[1], reverse=True)[:10]
# 返回结果摘要
result = {
"total_slow_requests": len(slow_requests),
"top10_ips": top10,
"sample_request": slow_requests[0] if slow_requests else None
}
第二步(Execution):代码在沙箱中执行,处理1万条日志、过滤、聚合,最后只返回一个几百字节的摘要
第三步(Synthesis):模型收到摘要(而不是1万条原始记录),生成报告:"过去30天共有327次慢请求,来源主要集中在以下10个IP……"
这种模式的改进是革命性的:
- 彻底解决上下文爆炸:代码在执行侧完成所有数据处理,只把精简摘要返回模型,token消耗从几十万降到几千
- 执行效率大幅提升:循环、过滤、聚合这些操作在代码层面执行,比通过模型逐步决策快几个数量级
- 支持复杂逻辑:代码可以实现任意复杂的控制流(嵌套循环、条件分支、异常处理),模型只需专注于"生成正确的逻辑"而不是"逐步执行"
- 成本降低:减少了推理轮次和token传输,对于数据密集型任务,成本可能降低一个数量级
但这种模式也带来了新的挑战:
- 代码生成可靠性:模型需要生成语法正确、逻辑正确的可执行代码,容错率比生成工具调用序列更低
- 调试难度增加:当代码执行出错时,排查问题比简单的工具调用链更复杂,需要完善的错误处理和日志机制
- 沙箱环境要求:需要一个安全的代码执行环境,防止恶意代码、资源滥用等问题
- 适配性问题:不是所有模型都擅长生成高质量的可执行代码,对模型的代码能力有更高要求
- 可解释性下降:相比明确的步骤序列,一段代码的意图对于非技术用户来说更难理解
因此,程序化工具编排最适合以下场景:
- 大规模数据处理任务:需要对成千上万条数据进行过滤、聚合、分析的场景
- 复杂的计算密集型任务:涉及大量循环、嵌套逻辑、数学计算的任务
- 对成本和延迟极度敏感:通过代码执行可以大幅降低token消耗和响应时间
- 步骤清晰但数据量大:任务逻辑明确,但中间结果体积庞大,不适合直接传回模型
典型案例包括:日志分析、大规模数据清洗与转换、批量文件处理、复杂的数学建模与仿真等。Anthropic最近推出的Extended Thinking + Tool Use、OpenAI的Code Interpreter升级版,都在朝这个方向演进。
值得注意的是,程序化工具编排并不意味着完全替代前两种模式。实际工程中,很多系统会混合使用:对于简单查询用循环式,对于多步明确任务用计划驱动,对于数据密集型任务用程序化编排。选择哪种模式,归根结底取决于任务的复杂度、数据规模、实时性需求以及你愿意承担的工程复杂度。
一张图总结三种模式
这里给一个简单的对比表格总结三种不同的模式:
写在最后
从循环式工具选择到计划驱动执行,再到程序化工具编排,大模型的工具使用正在从"会调工具"走向"会编排系统"。这条演进路径背后的核心逻辑很清晰:把模型擅长的事情(理解意图、生成逻辑)和代码擅长的事情(执行计算、处理数据)分离开来,各司其职。循环式给了我们灵活性,让模型可以"走一步看一步";计划驱动带来了全局视角和并行能力;程序化编排则彻底解放了上下文,让模型不再被数据规模束缚。
但需要再次强调的是:没有一种模式适合所有场景。上面的对比表不是在告诉你"应该用哪个",而是在帮你理解"什么时候用哪个"。查个天气、问个订单状态,循环式足够了,简单高效;做数据分析、处理文档流水线,计划驱动能帮你省时间;分析海量日志、批量处理文件,程序化编排才能撑得住。实际工程中,很多优秀的 Agent 系统会根据任务特征动态选择模式,甚至在一个任务中混合使用——这才是成熟的工程实践。
工具使用的演进还远未结束。随着模型推理能力持续增强、执行环境越来越安全可靠、多模态工具逐渐成熟,我们可能会看到更激进的模式出现——比如模型直接生成完整的微服务、自主管理长期运行的后台任务、甚至跨系统的自动化编排。但无论技术如何演进,核心问题始终是那个:如何让 AI 更高效、更可靠地与真实世界交互。
