Agent 工具调用链路怎么搭?
从指令解析到错误处理,全流程实现与关键设计
原题:在基于大语言模型的智能体(LLM Agent)系统中,如何构建一个完整的工具调用链路?请描述从用户指令解析、工具选择、参数提取、API调用到结果反馈和错误处理的全流程实现方式。
Prompt工程 · 美团真题
30 秒回答
- 工具描述Schema设计(OpenAI格式)
- 意图识别与工具选择的Prompt工程
- 参数提取的约束与校验机制
- API执行的安全隔离与超时控制
回答与解析
答案要点
- 工具描述Schema设计(OpenAI格式)
- 意图识别与工具选择的Prompt工程
- 参数提取的约束与校验机制
- API执行的安全隔离与超时控制
- 结果回传与对话上下文的维护
- 错误分级处理与优雅降级策略
完整工具调用链路设计
1. 工具注册与描述(前置层)
- 每个工具按 OpenAI Function Calling Schema 注册:
name/description/parameters(required字段) - 关键:description要清晰说明工具能力边界,避免模型误选
2. 意图识别与工具选择
Prompt设计要点:
- 系统Prompt明确角色定位:"你是工具调度助手,从以下工具中选择..."
- 提供工具列表 + 当前对话上下文
- 强制输出格式:{"tool": "xxx", "reason": "..."} 或 直接走Function Call
- 复杂场景可用 两阶段:先意图分类,再细选工具
3. 参数提取与校验
- 结构化抽取:利用模型JSON输出能力,严格按schema生成参数
- 校验层:类型检查、必填项检查、业务规则校验(如日期格式)
- 失败处理:校验失败时把错误信息回传模型,要求重新生成
4. API执行与隔离
- 沙箱执行:工具代码运行在隔离环境,限制网络/文件访问
- 超时控制:设置硬超时(如5s),防止阻塞
- 异步设计:重IO工具走异步队列,避免阻塞主链路
5. 结果回传与上下文维护
- 工具返回结果 → 格式化为自然语言 → 注入对话历史
- 关键:保留原始调用记录(tool_call_id),支持多轮工具链
6. 错误处理策略(分层)
| 层级 | 处理方式 |
|---|---|
| 参数错误 | 回传模型自纠正,限3次 |
| 工具执行失败 | 返回错误摘要,询问用户或切换备选工具 |
| 系统异常 | 优雅降级:直接回复"该功能暂不可用" |
7. 进阶:ReAct模式扩展
Thought → Action(工具调用) → Observation → ... → Final Answer
- 适合多步推理场景,每步显式输出思考过程
口语版讲法(约4分钟)
- 一句话定位:本质是让模型学会用工具,不是简单的API调用
- 前置设计:工具注册与Schema要写对,否则模型选错
- 核心流程:意图识别、参数提取、执行与错误处理
- 边界与风险:ReAct适合多步,Function Calling适合单步,落地要混合
- 收尾与可延伸点:错误处理的分层策略,追问会引向自纠正机制
这个问题问的是工具调用链路,本质上就是在解决一个问题:怎么让大语言模型能准确地去调用外部工具,同时保证整个过程可控、可容错。它不是一个简单的API调用,而是一个从理解用户意图到最终返回结果的完整闭环。
先说前置设计。工具注册这块,我一般会用OpenAI的Function Calling Schema来定义每个工具,把name、description、parameters都写清楚。这里有个关键点:description一定要写到位,不能太含糊。比如一个查询订单的工具,你要是只写“查询订单”,模型可能就会在用户说“帮我查一下”的时候选它,但实际上用户想查的是物流状态,不是订单信息。所以description要精确描述工具的能力边界,不然模型很容易选错。
接下来是核心流程,我把它分成几步。第一步是意图识别和工具选择。系统Prompt里我会明确告诉模型它的角色是工具调度助手,然后给出当前可用的工具列表和对话上下文。输出格式我会强制成JSON,比如{"tool": "xxx", "reason": "..."},或者直接用Function Call。如果场景比较复杂,比如用户问“帮我安排下周的会议并通知参会人”,这就涉及两个工具,我会考虑用两阶段:先做意图分类,判断是要安排会议还是通知人,然后再细选工具。
第二步是参数提取和校验。模型输出参数的时候,我会利用它的JSON输出能力,严格按照Schema生成。但模型有时候会漏掉必填参数或者格式不对,比如日期写成了“明天”,工具需要的是“2025-03-28”。所以我会加一个校验层,做类型检查、必填项检查,还有业务规则校验。校验失败的时候,我不会直接报错,而是把错误信息回传给模型,让它重新生成。这样一般两三次就能纠正过来。
第三步是API执行。这块有一个重要的落地风险:安全隔离。工具代码一定要跑在沙箱里,限制网络和文件访问,不然恶意输入可能导致数据泄露。另外超时控制也很关键,我会设一个硬超时,比如5秒,防止模型死循环或者工具卡住。对于重IO的工具,比如要查数据库或者调外部API,我会设计成异步队列,避免阻塞主链路。
执行完拿到结果后,需要把结果格式化成自然语言,注入到对话历史里。同时要保留原始调用记录,比如tool call id,这样支持多轮工具链。比如用户先查了库存,发现不够,又让调货,这两步就能串起来。
这里我想说一下边界划分。ReAct模式适合多步推理的场景,比如用户问“帮我比较一下这两款手机的参数,然后推荐一个”,模型需要先查参数,再对比,再推荐,每一步都要显式输出思考过程。而Function Calling更适合单步、确定性的调用,比如“查一下明天北京的天气”。真正落地的时候,我通常会把两者结合起来:简单查询直接用Function Calling,复杂推理走ReAct,这样既高效又灵活。
最后是错误处理,我一般会做分层。参数级别的错误,比如格式不对,我会让模型自纠正,限制三次。工具执行失败,比如API返回500,我会把错误摘要返回给模型,让它询问用户或者切换备选工具。系统级别的异常,比如沙箱挂了,我就直接降级,回复用户“该功能暂不可用”。
这里有个值得深挖的点:错误处理中的自纠正机制。如果模型连续三次都生成错误的参数,比如一直把日期格式写错,这时候是继续让它重试还是直接报错?我的做法是看错误类型:如果是模型能力问题,比如它就是不理解日期格式,我会考虑给它few-shot示例;如果是工具本身的问题,比如参数设计不合理,那我会反过来优化Schema。
所以整体上,我会把工具调用链路看成是一个从意图到执行的工程化系统,核心是让模型在可控范围内发挥能力,同时做好兜底。
关键一句:错误处理中的自纠正机制:连续三次参数错误时,根据错误类型决定是给few-shot示例还是优化Schema。
面试官还可能这样问
- 问法 1 · 场景切入
假设你在做一个智能客服Agent,用户说‘帮我查一下上周三的订单,如果没发货就催一下’。这背后涉及解析指令、选查询工具、抽参数、调API,再把结果反馈回去。你整个链路会怎么设计?
- 问法 2 · 层层追问
用户让Agent调用工具时,你怎么知道该调哪个工具?……参数怎么从自然语言里准确抽出来?……调用失败了怎么办,比如接口超时或者参数不对?……从指令到结果,整个流程你一步步讲一下。
- 问法 3 · 直球架构
设计一个LLM Agent的完整工具调用链路,从用户指令解析、工具选择、参数提取、API调用到结果反馈和错误处理,描述清楚每一步的实现方式。