资讯动态

大模型Tool Use面试实战:三种实现方案与避坑指南

发布时间:2026/10/22 5:26:08 来源:尧图企业网站定制
1. 面试现场从“八股文”到“真刀真枪”的转变这几年技术面试的风向变得特别快。早些年大家准备面试背一背“进程与线程的区别”、“TCP 三次握手”再刷几百道算法题基本就能应付大多数场面。但这套打法在最近一两年明显失灵了尤其是涉及到 AI 应用开发、大模型落地相关的岗位面试官越来越不满足于听你讲概念而是直接把电脑推到你面前“来手写一个 Tool Use 的实现语言不限思路讲清楚就行。”我第一次遇到这种要求的时候脑子是懵的。Tool Use说白了就是让大模型能够调用外部工具——查天气、算数学、搜数据库、发邮件。听起来好像不难不就是让模型输出一段 JSON然后我去解析执行吗但真当你坐在那里面对一张白纸或者一个空白的编辑器面试官在旁边盯着你你会发现要考虑的东西远比想象中多模型怎么知道有哪些工具可用工具的参数格式怎么定义模型输出的调用请求怎么解析执行结果怎么回传给模型多轮调用怎么管理错误怎么处理那次面试我用了三种方案来回答从最朴素的字符串匹配到基于结构化输出的函数调用再到基于 Agent 框架的完整实现。面试官最后说了一句话我印象很深“你不是在写代码你是在设计一个协议。”这句话点醒了我Tool Use 的本质确实不是简单的“调个 API”而是一套模型与外部世界交互的协议设计。这篇文章就把我当时面试的思路完整还原出来再加上我后来在实际项目中踩过的坑和总结的经验。如果你也在准备类似的面试或者正在做 AI 应用开发需要让模型调用外部能力那这篇内容应该能帮你少走不少弯路。我会从最基础的原理讲起把三种方案的实现细节、适用场景、优缺点都拆开揉碎最后再分享一些只有真正上手做过才会知道的避坑技巧。2. 先搞明白Tool Use 到底在解决什么问题2.1 大模型的三条“硬伤”与工具调用的必要性要理解 Tool Use 的价值得先承认大模型有几个绕不过去的硬伤。第一个是知识截止。模型的训练数据是有时间边界的你问它今天的天气、最新的股价、某个刚发布的库的用法它要么不知道要么一本正经地胡说八道。这不是模型笨是它的知识被冻结在了训练完成的那一刻。第二个是计算不可靠。你让模型算 1234 乘以 5678它可能会给你一个看起来很像那么回事但完全错误的答案。因为模型本质上是概率模型它在“预测下一个 token”而不是在“做数学运算”。对于需要精确计算的任务靠模型自己算就是碰运气。第三个是无法与外部世界交互。模型不能帮你发一封邮件、不能查数据库、不能调用你公司内部的 API、不能操作文件系统。它只能输出文本而文本本身不产生任何实际动作。Tool Use 就是来解决这三个问题的。它的核心思路很朴素既然模型自己不擅长这些事那就让它学会“求助”。当模型遇到自己搞不定的问题时它不硬答而是输出一个结构化的请求告诉外部系统“我需要调用某个工具参数是这些”外部系统执行完把结果返回给模型模型再基于结果继续回答。打个比方模型就像一个知识渊博但手脚被绑住的顾问Tool Use 就是给他配了一个助理。顾问说“帮我查一下上个月的销售数据”助理去查了把结果拿回来顾问再基于数据给出分析。顾问不需要自己会查数据库他只需要知道“什么时候该让助理去查”以及“怎么把需求说清楚”。2.2 一个完整的 Tool Use 闭环包含哪些环节很多人以为 Tool Use 就是“模型输出 JSON我解析执行”这只说对了一半。一个完整的闭环至少包含五个环节工具注册与描述你得告诉模型有哪些工具可用每个工具是干什么的需要什么参数。这个描述的质量直接决定了模型能不能正确选择工具。意图识别与工具选择模型根据用户的输入判断是否需要调用工具以及调用哪个工具。参数生成与格式化模型生成调用工具所需的参数并且要符合预定义的格式。执行与结果返回外部系统解析模型的输出执行实际的操作把结果整理成模型能理解的格式返回。结果整合与最终回答模型基于工具返回的结果生成最终给用户的回答。这五个环节里任何一个出问题都会导致整个流程失败。比如工具描述写得含糊模型就会选错工具参数格式没定义清楚解析就会失败返回结果太长可能会超出模型的上下文窗口。所以 Tool Use 不是一个单点技术而是一套需要精心设计的系统工程。2.3 为什么面试官偏爱这道题站在面试官的角度让你手写 Tool Use 是一道性价比极高的题。它能在短时间内考察你多个维度的能力对大模型原理的理解你是否清楚模型的输出本质上是 token 序列你是否理解结构化输出和自由文本输出的区别。协议设计能力你能否设计一套清晰的工具描述格式和调用协议这直接反映你的抽象能力。工程实现能力解析、错误处理、多轮管理这些都是实打实的编码功夫。边界情况考虑模型输出了非法 JSON 怎么办工具执行失败了怎么办模型陷入循环调用怎么办技术选型判断你选择哪种方案为什么选它这体现了你的技术判断力。所以这道题没有标准答案面试官想看的是你的思考过程和技术品味。下面我就把当时用的三种方案逐一拆解。3. 方案一基于提示词工程的字符串解析方案3.1 核心思路与实现原理这是最原始、最不依赖任何框架的方案核心思路就一句话在提示词里约定好输出格式然后从模型返回的文本里把工具调用请求抠出来。具体来说你需要在系统提示词里写清楚你有哪些工具可用每个工具的参数是什么当你需要调用工具时请按照特定的格式输出。比如约定用tool_call标签包裹 JSON你可以使用以下工具 - get_weather(city: string): 查询指定城市的天气 - calculate(expression: string): 计算数学表达式 当你需要调用工具时请输出 tool_call {name: 工具名, arguments: {参数名: 参数值}} /tool_call然后模型返回的文本里如果包含这个标签你就用正则表达式把它提取出来解析 JSON执行对应的函数再把结果拼回对话历史里。这个方案的实现大概长这样import re import json def parse_tool_call(text): pattern rtool_call\s*(\{.*?\})\s*/tool_call match re.search(pattern, text, re.DOTALL) if not match: return None try: return json.loads(match.group(1)) except json.JSONDecodeError: return None def execute_tool(tool_call, tools_registry): name tool_call.get(name) args tool_call.get(arguments, {}) if name not in tools_registry: return {error: f未知工具: {name}} try: result tools_registry[name](**args) return {result: result} except Exception as e: return {error: str(e)}3.2 提示词设计的几个关键细节这个方案看起来简单但提示词的设计有很多讲究写不好模型根本不按你的格式来。第一工具描述要具体且互斥。如果你有两个工具一个叫search一个叫query模型很容易搞混。描述里要写清楚每个工具的适用场景最好给出正例和反例。比如“查询天气用 get_weather不要用 search”。第二参数类型要明确。模型对类型的理解有时候很模糊你要在描述里写清楚是字符串、数字还是布尔值。对于枚举类型的参数把所有可选值都列出来。第三给出完整的输出示例。模型是模仿高手你给它一个标准的输出样例它照着模仿的准确率会高很多。样例要覆盖单工具调用、多工具调用、不需要调用工具这几种情况。第四强调格式的严格性。明确告诉模型“必须严格按照上述格式输出不要添加任何额外的解释文字”。否则模型很可能在 JSON 前后加一堆“好的我来帮你查询”之类的话增加解析难度。3.3 这个方案的优缺点与适用场景先说优点。零依赖不需要任何特定的模型 API 支持只要模型能输出文本就能用。灵活格式完全由你定义想怎么改就怎么改。透明整个流程你都能看到调试起来直观。再说缺点而且缺点很明显。解析脆弱模型稍微不听话输出格式偏一点正则就匹配不上。没有类型保证模型可能给你一个字符串类型的数字或者漏掉必填参数。多轮调用管理麻烦你得自己维护对话历史判断什么时候该停止调用。提示词占用上下文工具描述和格式说明会吃掉不少 token。这个方案适合什么场景适合快速原型验证或者你用的模型不支持原生的函数调用能力。在实际生产环境里如果模型本身支持结构化输出我不太推荐用这个方案维护成本太高。实操心得用这个方案的时候一定要在解析失败时做重试。我的做法是把解析错误的信息作为新的用户消息发回给模型让它重新按格式输出。通常重试一两次就能成功但一定要设置最大重试次数防止死循环。4. 方案二基于原生函数调用能力的结构化方案4.1 函数调用协议的工作机制方案一的痛点在于“靠约定”而方案二的核心进步在于“靠协议”。现在主流的大模型服务基本都支持原生的函数调用能力你不需要在提示词里教模型怎么输出格式而是通过 API 的参数把工具定义传进去模型会在内部处理好工具选择直接返回结构化的调用请求。这个机制的工作流程是这样的你在调用模型时除了传消息还传一个tools参数里面用 JSON Schema 描述每个工具的名称、功能、参数。模型在生成回复时如果判断需要调用工具它不会返回普通文本而是返回一个特殊的结构里面包含工具名和参数。你解析这个结构执行工具把结果作为一条特殊角色的消息传回去模型再继续生成。用伪代码表示大概是这样tools [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气, parameters: { type: object, properties: { city: { type: string, description: 城市名称如北京、上海 }, unit: { type: string, enum: [celsius, fahrenheit], description: 温度单位 } }, required: [city] } } } ] response model.chat(messagesmessages, toolstools) if response.tool_calls: for call in response.tool_calls: result execute(call.function.name, call.function.arguments) messages.append({ role: tool, tool_call_id: call.id, content: result }) response model.chat(messagesmessages, toolstools)4.2 JSON Schema 定义工具的实战技巧方案二的关键在于工具定义的 JSON Schema 写得好不好。Schema 写得好模型选工具又准又快写得烂模型要么选错工具要么参数填错。description 字段是重中之重。这是模型判断“什么时候该用这个工具”的唯一依据。写 description 的时候要站在模型的角度想用户在什么情况下会需要这个功能把典型的使用场景写进去。比如不要只写“查询天气”而要写“当用户询问某个城市的天气、温度、是否下雨时使用此工具”。参数描述要消除歧义。如果参数是日期要写清楚格式是YYYY-MM-DD还是MM/DD/YYYY。如果参数有单位要写清楚是摄氏度还是华氏度。如果参数有取值范围要写清楚上下限。我见过太多因为参数描述不清导致模型传错值的案例。required 字段要谨慎。只把真正必需的参数放进 required可选参数给默认值。如果把太多参数标为必需模型可能会为了凑参数而编造值。枚举类型要列全。如果一个参数只能是几个固定值之一用 enum 列出来模型就不会自由发挥了。下面是一个对比表格展示写得差和写得好的工具定义维度差的写法好的写法功能描述“搜索”“根据关键词搜索产品数据库返回匹配的产品列表适用于用户询问产品信息、价格、库存时”参数描述“city: 城市”“city: 城市名称使用中文全称如‘北京市’而非‘北京’”类型定义“count: 数量”“count: 返回结果数量整数范围 1-50默认 10”枚举值“type: 类型”“type: 搜索类型可选值product产品、order订单、user用户”4.3 多轮工具调用的状态管理方案二相比方案一最大的工程挑战变成了多轮调用的状态管理。因为模型可能连续调用多个工具也可能调用一个工具后基于结果再调用另一个你需要维护一个清晰的状态机。核心要管理的东西包括对话历史包括用户的原始问题、模型的工具调用请求、工具的执行结果、当前轮次防止无限循环、已调用工具的记录防止重复调用同一个工具。我的做法是维护一个消息列表每次模型返回工具调用请求时把请求和对应的执行结果都追加进去然后再次调用模型。同时设置一个最大轮次限制比如 10 轮超过就强制让模型基于已有信息给出回答。MAX_ROUNDS 10 rounds 0 while rounds MAX_ROUNDS: response model.chat(messagesmessages, toolstools) if not response.tool_calls: break for call in response.tool_calls: result execute(call.function.name, call.function.arguments) messages.append({role: tool, tool_call_id: call.id, content: result}) rounds 1 if rounds MAX_ROUNDS: messages.append({role: user, content: 请基于已有信息直接回答不要再调用工具。}) response model.chat(messagesmessages)注意事项工具返回的结果一定要做长度控制。有些工具返回的数据特别长比如查询数据库返回几百条记录直接塞回上下文会瞬间撑爆 token 限制。我的做法是在工具执行层做截断或摘要只返回最相关的部分并在结果里注明“已截断”。5. 方案三基于 Agent 框架的完整编排方案5.1 从“单次调用”到“自主规划”的跃迁方案一和方案二本质上都是“被动响应式”的用户问一个问题模型判断要不要调工具调完给答案。但真实场景往往更复杂用户的需求可能需要多个步骤、多个工具协作才能完成。比如“帮我分析一下上个月的销售情况如果同比下降超过 10% 就发邮件通知我”这里面涉及查数据库、做对比计算、条件判断、发邮件四个步骤。方案三的思路是把 Tool Use 升级成 Agent 编排。模型不再只是“选择工具”而是“规划任务”。它会先把复杂任务拆解成子任务然后决定每个子任务用什么工具按什么顺序执行中间结果怎么传递。这个方案通常需要借助 Agent 框架来实现比如 ReAct推理行动模式、Plan-and-Execute 模式等。核心思想是给模型一个“思考-行动-观察”的循环模型先思考当前该做什么然后选择一个行动调用工具观察行动的结果再决定下一步。5.2 ReAct 循环的实现骨架ReAct 是目前最常用的 Agent 编排模式它的核心是一个循环Thought思考→ Action行动→ Observation观察→ 再 Thought直到任务完成。实现上你需要给模型一个特殊的提示词模板引导它按这个格式输出你可以使用以下工具[工具列表] 请按以下格式回答 思考我需要做什么 行动工具名[参数] 观察工具返回的结果由系统填充 当你得出最终答案时用 最终答案你的回答然后你的代码循环解析模型的输出遇到“行动”就执行工具把结果作为“观察”拼回去继续下一轮直到出现“最终答案”。def react_loop(question, tools, max_steps15): prompt build_react_prompt(question, tools) for step in range(max_steps): output model.generate(prompt) if 最终答案 in output: return extract_final_answer(output) action parse_action(output) if action: observation execute_tool(action, tools) prompt f\n{output}\n观察{observation}\n else: prompt f\n{output}\n请继续思考或给出最终答案。\n return 达到最大步数限制任务未完成。5.3 任务规划与工具编排的进阶玩法ReAct 是“走一步看一步”适合步骤不太确定的探索性任务。但如果任务流程相对固定可以用 Plan-and-Execute 模式先让模型制定一个完整的计划把任务拆成有序的步骤列表然后逐步执行每执行完一步检查是否需要调整计划。这种模式的好处是全局视野更强不会因为中间某一步的结果而迷失方向。缺点是如果计划制定得不好后面全盘皆输。所以通常会在执行过程中加入“重新规划”的机制允许模型在发现计划不可行时重新制定。还有一种更高级的玩法是多 Agent 协作。把不同的工具分配给不同的 Agent每个 Agent 负责一个领域由一个协调者 Agent 来分配任务。比如一个负责查数据的 Agent、一个负责分析的 Agent、一个负责发通知的 Agent。这种架构适合工具数量特别多、职责边界清晰的场景。不过要提醒一句Agent 框架虽然强大但调试难度和不确定性也成倍增加。模型可能在循环里绕圈子可能调用不存在的工具可能把简单任务复杂化。我在实际项目里的经验是能用方案二解决的就不要上方案三。Agent 编排是给真正复杂的多步骤任务准备的杀鸡用牛刀反而容易出问题。6. 三种方案横向对比与选型建议6.1 多维度对比表格把三种方案放在一起对比能更清楚地看出各自的定位对比维度方案一字符串解析方案二原生函数调用方案三Agent 编排实现复杂度低中高依赖条件无特殊要求模型需支持函数调用需 Agent 框架解析可靠性低依赖格式约定高结构化返回中依赖循环控制多工具协作需手动管理支持需状态管理原生支持复杂任务规划不支持不支持支持调试难度低中高上下文消耗高提示词占用量大中高适用场景原型验证、简单场景生产环境、单步调用复杂多步任务推荐指数两颗星四颗星三颗星按需6.2 选型决策树什么场景用什么方案选型其实可以按几个问题来决策第一个问题你的模型支持原生函数调用吗如果支持直接上方案二不要犹豫。方案一在可靠性上完全没法比。如果不支持那只能先用方案一顶着同时考虑换模型。第二个问题你的任务需要多步规划吗如果用户的一个请求需要多个工具按顺序协作且步骤不固定那考虑方案三。如果只是单次工具调用方案二足够。第三个问题你对稳定性的要求有多高生产环境对稳定性要求高方案二的确定性更强。方案三的不确定性较大需要更多的测试和兜底机制。第四个问题你的团队有 Agent 开发经验吗方案三的调试成本很高如果团队没有相关经验贸然上马可能会陷入无尽的调试泥潭。6.3 面试时怎么回答才加分回到面试场景面试官让你手写 Tool Use你如果能把三种方案都讲清楚并且说明各自的适用场景和选型理由基本就稳了。我的建议是先讲方案二因为它是当前的主流实践。把函数调用的协议、JSON Schema 的设计、多轮状态管理讲透。然后提一下方案一说明它是没有原生支持时的降级方案以及它的局限性。最后提方案三展示你对复杂场景的思考但明确说明它适合什么场景、有什么风险。这样回答的好处是既展示了你的工程能力方案二的细节又展示了你的技术视野知道有方案一和方案三还展示了你的判断力知道什么场景用什么。面试官想听的从来不是“你会几种方案”而是“你为什么选这个方案”。7. 实操避坑指南与常见问题排查7.1 工具描述写不好导致模型选错工具这是最常见的问题。模型选错工具十有八九是工具描述的问题而不是模型的问题。排查思路先把所有工具的描述拿出来假装自己是一个完全不了解业务的人只看描述能不能准确判断每个工具的使用场景如果连你都判断不了模型更判断不了。解决技巧给每个工具的描述里加上“什么时候用”和“什么时候不用”。比如“查询订单状态用 get_order_status不要用 search_orders后者只用于模糊搜索订单列表”。另外工具名称本身也要有区分度不要用query1、query2这种无意义的名字。7.2 参数格式错误与类型不匹配的修复模型传错参数类型是另一个高频问题。比如需要整数的地方传了字符串需要数组的地方传了单个值。解决技巧在 JSON Schema 里把类型定义得尽可能严格用 enum 限制取值范围用 pattern 限制字符串格式。同时在工具执行层做参数校验和类型转换比如把字符串10自动转成整数10。如果转换失败把错误信息返回给模型让它重新生成参数。实操心得我习惯在工具执行层加一层“参数清洗”对每个参数做类型检查和默认值填充。这样即使模型偶尔传错也能兜住大部分情况不至于整个流程崩溃。7.3 模型陷入循环调用怎么破方案三最容易出现的问题就是模型在循环里出不来反复调用同一个工具或者在不同的工具之间来回跳。解决技巧设置最大轮次限制是必须的但光限制轮次不够还要检测重复调用。我的做法是记录每次调用的工具名和参数如果发现连续两次调用完全相同就强制中断把已有信息整理后让模型直接回答。另外在提示词里明确告诉模型“不要重复调用已经成功执行过的工具”。7.4 工具返回结果过长撑爆上下文这个问题在查询类工具上特别常见。用户问“帮我看看最近的订单”工具返回了 500 条记录直接塞回上下文token 瞬间爆掉。解决技巧在工具执行层做结果处理。可以按相关性排序后截断只返回前 N 条也可以做摘要把关键信息提取出来还可以分页先返回第一页告诉模型“还有更多结果如需继续请指定页码”。核心原则是返回给模型的结果要精炼只包含模型做决策所需的最少信息。7.5 常见问题速查表问题现象可能原因排查方向解决方案模型不调用工具直接回答工具描述不清晰或提示词未强调检查工具 description 是否说明了使用场景补充场景描述在系统提示词里强调“需要实时信息时必须调用工具”解析工具调用失败输出格式不符合约定打印模型原始输出检查格式偏差方案一加强格式约束和重试方案二检查 API 参数参数类型错误Schema 定义不严格检查 JSON Schema 的 type 和 required严格定义类型执行层做类型转换和校验循环调用同一工具缺少循环检测机制记录调用历史检查是否重复设置最大轮次检测重复调用并中断上下文超限工具返回结果过长检查工具返回的数据量截断、摘要或分页返回结果多轮调用后回答质量下降对话历史太长模型注意力分散检查消息列表长度压缩历史消息只保留关键信息8. 我踩过的坑与实战经验总结8.1 工具数量不是越多越好刚开始做的时候我恨不得把所有能用的功能都封装成工具觉得工具越多模型能力越强。结果发现工具一多模型选错的概率直线上升。后来我把工具数量控制在 10 个以内把一些低频功能合并或者去掉准确率明显提升。经验是工具的描述空间是有限的工具越多每个工具分到的“注意力”就越少。与其堆数量不如把核心工具做精。如果确实需要很多工具考虑用方案三的多 Agent 架构把工具分组管理。8.2 错误处理比正常流程更重要正常流程谁都能写但 Tool Use 的稳定性恰恰取决于错误处理。模型输出格式错了怎么办工具执行超时了怎么办网络断了怎么办这些边界情况如果不处理线上环境分分钟教你做人。我的做法是给每个环节都加兜底解析失败就重试重试失败就降级为让模型直接回答工具执行超时就返回超时信息让模型决定下一步网络异常就捕获异常并记录日志。核心原则是任何单点失败都不能让整个流程崩溃。8.3 日志记录是调试的生命线Tool Use 的调试比普通功能难得多因为中间涉及模型的“黑盒”决策。你只能看到输入和输出看不到模型为什么这么选。所以完整的日志记录至关重要。我习惯记录这些东西每次模型调用的完整输入输出、每次工具调用的名称参数和结果、每次解析的成功失败情况、整个流程的轮次和耗时。这些日志在排查问题时能帮你快速定位是模型的问题、解析的问题还是工具的问题。8.4 给准备面试的朋友几句实在话如果你正在准备这类面试我的建议是不要只背概念一定要动手写一遍。三种方案都自己实现一个最小可运行的版本哪怕代码很粗糙。只有真正写过你才能体会到方案一解析失败时的抓狂、方案二状态管理的繁琐、方案三循环控制的微妙。面试的时候面试官更看重的是你的思考过程而不是代码的完美程度。你可以一边写一边说“这里我考虑用正则解析但我知道它很脆弱如果模型支持函数调用我会优先用方案二。”这种表达方式比闷头写完再解释要好得多。最后说一个我自己的体会Tool Use 这个技术点表面上是“让模型调工具”本质上是在设计一套人机协作的协议。你要考虑模型能理解什么、不能理解什么要考虑信息怎么传递、错误怎么恢复。把这套协议设计好了模型的能力边界就能大大扩展。这也是为什么面试官喜欢考这道题——它考的不是某个 API 的用法而是你设计系统的能力。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑