1. 项目概述当大模型需要“动手”时我们如何为它挑选工具如果你最近在关注大语言模型LLM的应用可能会发现一个有趣的现象模型本身越来越“聪明”但让它真正去完成一个具体的、需要与外部世界交互的任务时比如帮你查一下明天的天气、订一张机票或者分析一份刚上传的PDF报告它往往就“束手无策”了。这就像一个知识渊博的顾问却无法亲手操作电脑或拨打电话。为了解决这个问题“工具调用”Tool Calling或“函数调用”Function Calling的能力应运而生它让LLM学会了“使用工具”。quchangle1/LLM-Tool-Survey这个项目正是对这个关键领域进行系统性梳理和总结的成果。它不是一个可以直接运行的代码库而是一份详尽的“调查报告”或“知识图谱”。想象一下你正准备为你的AI助手赋予“动手能力”面对市面上纷繁复杂的工具调用框架、五花八门的工具定义方式以及各家模型厂商不同的接口规范你该从何入手这份调查报告的价值就在于此——它帮你理清脉络对比优劣指明方向。这份报告适合所有正在或计划将LLM应用于实际生产场景的开发者、研究员和产品经理。无论你是想为自己的聊天机器人添加一个简单的天气查询功能还是构建一个能够自动化处理复杂工作流的智能体Agent这份关于工具调用的全面调研都能为你提供坚实的理论基础和实用的选型参考。它回答的核心问题是为了让大模型更好地“做事”我们有哪些技术方案它们各自如何工作又该如何选择2. 工具调用生态全景与核心范式解析在深入细节之前我们有必要站在高处俯瞰一下整个“LLM工具调用”的生态全景。这不仅仅是几个API调用那么简单它涉及模型能力、交互协议、执行环境等多个层面的协作。2.1 核心范式从提示工程到标准化接口早期让LLM使用工具完全依赖于精巧的提示词Prompt Engineering。开发者需要在系统提示中详细描述工具的用途、输入格式和输出示例并期望模型在回复中以一种约定的格式比如JSON返回调用指令。这种方式灵活但脆弱模型输出的格式不稳定需要复杂的后处理来解析和校验。随后产业界迅速向标准化演进形成了两种主流范式1. 函数调用Function Calling范式这是目前最主流、最接近“一等公民”地位的方式。以OpenAI的GPT系列为代表模型在API层面原生支持“工具”Tools或“函数”Functions作为输入参数。开发者预先定义好函数的名字、描述和参数JSON Schema模型在理解用户意图后会在其回复流中一个独立的字段如tool_calls里结构化地返回它决定调用的函数名和参数。这种方式将工具调用从自然语言文本中剥离出来变成了API协议的一部分极大地提高了可靠性和开发效率。2. 智能体Agent框架范式这是一个更上层的抽象。诸如LangChain、LlamaIndex、AutoGPT等框架将工具调用、记忆、决策流程、任务分解等能力封装成一套完整的体系。在这里LLM作为一个“大脑”或称为“代理”框架则提供了“手脚”工具和“工作流程”。开发者通过框架提供的统一接口来定义和使用工具框架负责处理与LLM的复杂交互、工具的选择与串联、以及状态管理。这种范式适合构建复杂的多步任务应用。LLM-Tool-Survey报告会清晰地对比这两种范式。简单来说如果你需要快速、稳定地为模型添加几个简单功能直接使用模型原生的函数调用接口是最直接的选择。但如果你要构建一个能够自主规划、使用多种工具完成复杂目标的智能体那么选择一个成熟的Agent框架会是更高效的起点。2.2 工具生态的层次结构工具本身也可以被分层看待基础工具层单一功能的原子操作如get_weather(city),search_web(query),read_file(path)。复合工具层由多个基础工具组合而成完成一个更复杂的子任务。例如一个analyze_financial_report(pdf_path)工具内部可能依次调用read_file,extract_tables,calculate_metrics等基础工具。工作流/智能体层这是最高层由框架驱动动态地根据任务目标串联调用不同的基础或复合工具。例如一个“旅行规划智能体”可能会自动依次调用搜索、地图、日历、支付等工具。报告的价值在于它不仅列出了有哪些工具和框架更分析了它们在不同层次上的适用性和连接方式。注意工具定义的质量至关重要。给工具起一个清晰易懂的名字撰写一段精准描述其功能和适用场景的说明设计一个结构良好、类型明确的参数Schema这些“元信息”会直接决定LLM能否正确理解和使用该工具。这往往是实践中容易忽略但效果差异巨大的细节。3. 主流工具调用框架深度横评市面上框架众多各有侧重。LLM-Tool-Survey报告的核心内容之一就是对主流框架进行深度对比。这里我们可以基于报告的思路展开分析几个代表性项目。3.1 LangChain全功能生态的“瑞士军刀”LangChain 无疑是这个领域知名度最高的框架之一。它的设计理念是提供构建LLM应用所需的一切组件并将它们以“链”Chain的方式灵活组合。在工具调用方面LangChain提供了极其丰富的内置工具如搜索引擎、维基百科、Python REPL等同时也让自定义工具变得非常简单。核心优势生态丰富拥有最大数量的集成各种数据库、API、文件格式等几乎“开箱即用”。抽象层次高提供了多种智能体类型如ReAct、Plan-and-Execute开发者无需从头设计推理循环。社区活跃遇到问题容易找到解决方案和讨论。潜在考量学习曲线陡峭概念较多Chains, Agents, Tools, Memory等初期需要时间理解其设计哲学。运行时开销为了追求灵活性某些抽象可能带来额外的性能开销在简单场景下可能显得“重”。版本迭代快API有时变化较大需要关注版本兼容性。实操心得对于快速原型验证和构建复杂的、需要多种集成的生产应用LangChain是强有力的选择。但对于只需要核心工具调用功能的简单场景可能会觉得它“杀鸡用牛刀”。3.2 LlamaIndex专注于数据感知的“专家”如果说LangChain是通用型框架那么LlamaIndex则更专注于让LLM与你的私有数据对话。它的核心能力是数据的索引、检索和上下文增强。因此它的工具调用能力也紧密围绕这一核心展开。核心优势数据连接器强大对PDF、PPT、Word、数据库等各种数据源的支持和解析能力非常出色。检索质量高提供了多种高级检索策略如子查询、多步检索能更精准地为LLM提供上下文。智能体与工具集成其“智能体工作流”能很好地利用检索到的数据来调用工具完成基于知识的任务比如“帮我分析一下最近季度销售数据.pptx并总结趋势”。潜在考量场景相对聚焦在非数据密集型的通用工具调用场景下其优势可能不那么明显。与LangChain部分功能重叠两者生态有交叉有时需要根据项目主需求进行选择。实操心得如果你的应用核心是让LLM查询、分析、总结你自己的文档、数据库或知识库那么LlamaIndex几乎是首选。它的工具调用功能是为数据任务量身定制的。3.3 轻量级与新兴框架更直接的选择除了两大巨头还有许多轻量级或设计理念独特的框架值得关注报告里应该会涵盖例如AutoGen由微软推出主打“多智能体协作”。在这个框架里你可以创建多个具备不同角色和工具的智能体让它们彼此对话、协作完成任务。这对于需要模拟团队工作或复杂协商的场景非常有力。Semantic Kernel同样是微软出品强调将传统编程技能与LLM的语义能力“内核”式地结合。它提倡用原生代码C#/Python定义插件工具理念上更贴近传统软件开发。简易自定义方案对于需求极其简单的场景你可能完全不需要框架。直接利用OpenAI API的函数调用能力搭配一个简单的路由和执行器几十行代码就能实现核心功能。报告应会指出这种方案的适用边界。框架选型决策树基于报告思路提炼你的核心需求是处理私有数据吗是 - 优先考虑LlamaIndex。你需要构建多智能体协同工作的复杂系统吗是 - 重点考察AutoGen。你的应用需要集成大量不同的外部服务API、数据库等吗是 -LangChain的丰富生态最有优势。你只需要为数不多的几个工具且追求极致的简洁和可控吗是 - 可以考虑轻量级框架或原生API自定义。你的团队主要背景是传统软件开发希望平滑过渡可以看看Semantic Kernel。4. 工具定义、发现与编排的工程实践选好了框架下一步就是具体地定义和使用工具了。这是将想法落地的关键环节包含许多工程细节。4.1 如何高质量地定义一个工具一个工具定义通常包含以下部分每一部分都需精心设计名称动词开头清晰无歧义如calculate_compound_interest。描述用自然语言准确说明工具的功能、输入输出和适用场景。这是LLM理解工具的主要依据。例如“根据本金、年利率、投资年限和复利周期计算复利终值。”参数Schema严格按照JSON Schema定义每个参数的名称、类型、描述、是否必需等。类型要尽可能精确如number而非string。执行函数实际的代码实现负责接收解析后的参数调用真实API或执行计算并返回结果。一个常见的坑是描述过于简略或参数类型模糊。例如一个搜索工具如果只描述为“搜索信息”模型可能无法判断何时该用它如果参数类型是字符串但实际需要的是一个结构化的查询对象就会导致调用失败。4.2 工具的动态发现与注册在复杂应用中工具的数量可能很多且可能动态变化。我们不可能每次都把所有工具的描述都塞进提示词有上下文长度限制。因此需要一套工具的发现和注册机制。集中式注册表在应用启动时将所有工具加载到一个全局注册表中。智能体需要时从中查询或获取全部列表。这是最简单的方式。基于向量的语义检索当工具数量庞大时比如有上百个让LLM从一长串列表里挑选变得低效。此时可以将每个工具的描述转换成向量嵌入Embedding当用户提出请求时先将请求本身向量化然后从工具向量库中检索出最相关的几个工具再交给LLM做最终选择和调用。这能显著提升大规模工具集的调用准确率和效率。分层/分组的工具包将工具按功能域分组如“文件操作工具包”、“网络搜索工具包”、“计算工具包”。LLM可以先选择工具包再在包内选择具体工具。这模仿了人类使用工具箱的思维。4.3 工具调用的编排与流程控制单个工具调用是基础真正的威力来自于工具的编排——让多个工具按顺序或条件执行。顺序执行最简单的编排A工具的输出作为B工具的输入。在Agent框架中这通常通过“链”或“工作流”来实现。条件分支根据某个工具的执行结果决定下一步调用哪个工具。这需要LLM或框架具备一定的推理和决策能力。并行与循环同时调用多个独立工具以提升效率或者循环调用某个工具直到满足条件例如持续搜索直到找到满意答案。错误处理与重试工具调用可能失败网络超时、API限流、参数错误。良好的编排机制需要包含错误处理策略例如重试、降级换用备用工具、或向用户报告清晰错误。实操心得在设计编排流程时务必考虑“边界情况”。例如一个需要用户确认的支付工具在自动编排流程中应该如何中断并等待交互工具执行超时应该设置多久这些非功能性需求对系统鲁棒性至关重要。5. 评估与挑战我们如何知道它工作得好不好为LLM装备了工具并不意味着任务就能完美完成。我们需要一套方法来评估工具调用系统的性能。5.1 评估维度LLM-Tool-Survey报告应会系统性地阐述评估指标主要包括工具选择准确率给定一个用户请求系统是否选择了正确的工具这是最基础的指标。参数填充准确率选择的工具其参数是否被正确地从用户请求中提取并填充例如用户说“查询北京天气”系统是否调用了get_weather并传入了city“北京”。任务完成成功率从用户提出请求到最终返回满意结果的端到端成功率。这综合了工具选择、参数填充、工具执行、结果解析和回复生成所有环节。效率平均完成一个任务需要调用多少次工具耗时多长安全性/可控性系统是否会错误调用高危工具如删除文件、发送邮件是否有恰当的权限控制和用户确认机制5.2 主要挑战与前沿方向报告也会指出当前领域面临的挑战这也是开发者在实际中会遇到的坑幻觉与错误调用LLM可能误解用户意图调用完全不相关的工具或生成不合法的参数。缓解方法包括提供更优质的示例、在调用前增加验证步骤、使用更强大的模型。长上下文与大量工具当工具描述列表很长时会占用大量上下文窗口影响模型处理核心任务的能力。动态工具检索和分层管理是解决方案。复杂参数提取用户请求可能是模糊的、隐含的或需要推理的如“帮我订一家这附近评价好的意大利餐厅”。这需要模型对世界知识有更深的理解或结合更复杂的语义解析技术。工具组合的规划难题对于需要多步工具组合的任务LLM的规划能力仍然有限容易陷入死循环或选择次优路径。将大型任务分解为子任务或结合传统规划算法是当前的研究热点。工具执行的可靠性工具本身尤其是依赖外部API的可能存在不稳定、延迟或变更。系统需要具备重试、回退和优雅降级的能力。6. 从调研到实战构建你的第一个工具调用智能体理论说了这么多我们动手搭建一个最简单的例子感受一下整个流程。这里我们选择使用OpenAI的原生函数调用API因为它最直接不依赖特定框架。假设我们要构建一个能查询天气和计算数学公式的智能助手。6.1 第一步定义工具我们首先用Python字典定义两个工具函数的Schema。# 工具定义 tools [ { type: function, function: { name: get_current_weather, description: 获取指定城市的当前天气情况, parameters: { type: object, properties: { location: { type: string, description: 城市名称例如北京 San Francisco, }, unit: {type: string, enum: [celsius, fahrenheit], description: 温度单位}, }, required: [location], }, }, }, { type: function, function: { name: evaluate_math_expression, description: 计算一个数学表达式的值, parameters: { type: object, properties: { expression: { type: string, description: 一个合法的数学表达式例如2 3 * (5 - 1), } }, required: [expression], }, }, }, ]注意看每个工具都有清晰的名称、描述和严格的参数定义。enum限制了unit参数只能取两个值这能有效减少模型出错的概率。6.2 第二步实现工具的执行函数定义好了接口我们需要实现它们背后的真实逻辑。# 工具执行函数 def execute_tool(tool_call): 根据工具调用信息执行对应的真实函数 function_name tool_call.function.name arguments json.loads(tool_call.function.arguments) # 解析模型传来的参数 if function_name get_current_weather: # 这里应该调用真实的天气API例如OpenWeatherMap # 为了演示我们模拟一个返回 location arguments.get(location) unit arguments.get(unit, celsius) # 模拟API调用和数据处理 weather_info f{location}的天气模拟数据晴朗温度25{unit[0]} return weather_info elif function_name evaluate_math_expression: # 警告直接eval有安全风险生产环境应用安全的表达式求值库如ast.literal_eval或numexpr # 此处仅作演示 expression arguments.get(expression) try: result eval(expression) # 危险仅用于演示 return f表达式 {expression} 的计算结果是{result} except Exception as e: return f计算表达式 {expression} 时出错{e} else: return f错误未知的工具 {function_name}重要安全提示上面的evaluate_math_expression函数为了演示使用了危险的eval()。在实际生产中绝对禁止这样做因为它会执行任意代码带来严重安全漏洞。必须使用安全的替代方案如ast.literal_eval仅支持字面量或专门的数学表达式解析库如numexpr。6.3 第三步与LLM交互并处理工具调用现在我们将工具定义传给LLM并处理它的回复。import openai import json # 初始化OpenAI客户端假设已设置API Key client openai.OpenAI() # 用户请求 user_query “北京今天天气怎么样顺便算一下(128)*3等于多少。” # 第一步将用户请求和工具定义发送给模型 response client.chat.completions.create( modelgpt-3.5-turbo, # 或 gpt-4-turbo messages[{role: user, content: user_query}], toolstools, # 关键传入我们定义的工具列表 tool_choiceauto, # 让模型自动决定是否调用工具 ) # 第二步检查模型的回复 assistant_message response.choices[0].message print(模型原始回复对象:, assistant_message) # 第三步如果模型决定调用工具 if assistant_message.tool_calls: print(\n模型请求调用工具...) all_tool_results [] for tool_call in assistant_message.tool_calls: print(f - 调用工具 {tool_call.function.name} 参数: {tool_call.function.arguments}) # 执行工具 tool_result execute_tool(tool_call) print(f 工具执行结果: {tool_result}) # 收集结果准备传回给模型 all_tool_results.append({ tool_call_id: tool_call.id, role: tool, name: tool_call.function.name, content: tool_result, }) # 第四步将工具执行结果作为新的消息再次发送给模型让它生成最终回答 second_response client.chat.completions.create( modelgpt-3.5-turbo, messages[ {role: user, content: user_query}, # 原始用户消息 assistant_message, # 模型刚才的回复包含工具调用请求 *all_tool_results, # 所有工具执行的结果 ], ) final_answer second_response.choices[0].message.content print(f\n模型的最终回答:\n{final_answer}) else: # 模型没有调用工具直接回复 print(f\n模型直接回答:\n{assistant_message.content})运行这段代码你会看到模型首先分析用户请求发现需要调用两个工具get_current_weather和evaluate_math_expression。它会在tool_calls字段里返回这两个调用请求。我们的程序捕获到后分别执行模拟的天气查询和数学计算然后将结果返回给模型。模型最后综合这些信息生成一段连贯的自然语言回复给用户。这个过程清晰地展示了“用户请求 - 模型规划并请求工具 - 执行工具 - 结果反馈给模型 - 模型生成最终回答”的完整闭环。通过LLM-Tool-Survey这类报告你能系统地了解在这个简单闭环的背后工业界和学术界已经发展出了多少种架构、框架和优化策略来让这个闭环更强大、更可靠、更高效。