想象你是一家餐厅新上任的主厨。后厨的工具墙上挂满了各色器具:蒸锅、烤箱、破壁机、细目筛……每一件都贴着一张小小的说明卡。客人点了一道“清蒸鲈鱼”,你扫一眼工具墙,目光在蒸锅上停住——就是它了。你顺手确认卡片上写着“适用于蒸制鱼类与蔬菜,需加水预热”,心里有了底,然后把火候、时间一一调好,再检查一遍燃气阀门才点火。这一连串“看菜单、挑工具、想参数、做检查、开火执行”的动作,正是大语言模型驱动的 Agent 在响应任务时做的事:从工具库中选择最合适的工具,生成调用参数,校验无误后执行。 这里面的每一步都有讲究:工具描述写得好不好,直接影响选择准不准;模型“觉得自己有把握”不等于真的有把握;参数不校验就调用,轻则报错重则闯祸;工具一旦多起来,光靠肉眼扫墙就来不及了。这篇文章带你走进 Agent 的后厨,把“工具选择与调用”这一核心工作流从头到尾讲透。
掌握工具选择与调用的工程方法,是把 Agent 从“能跑 Demo”推向“能上生产”的关键能力,也是 AI 应用工程师的核心竞争力。
可视化演示
观察Agent根据任务上下文从工具库选择工具、评估选择置信度,以及生成并校验调用参数的过程,可切换三种模式。
本节配有交互动效(进入视口后自动加载,约 3KB)。
工具描述与选择 Agent根据任务上下文从工具库动态选择工具 工具描述质量直接影响选择准确率 选择 = f(任务,描述) 高质量描述让LLM准确理解工具用途。
工具库与描述
工具墙上每件工具都挂着一张说明卡。新手主厨分不清蒸锅和高压锅时,全靠卡片上的字判断:“蒸锅——适合蒸鱼蒸蛋,需加水预热”“高压锅——适合炖肉,排气后再开盖”。卡片写得含糊,比如只写一个“锅”字,那主厨十有八九会拿错。
Agent 的工具库就是这么一面墙。每个工具(函数或 API)配一段文本描述,模型根据描述决定用谁。描述是工具与模型之间的“说明书”,写得好不好,直接决定模型能不能一眼认出“蒸锅”。
描述工程有四个要点:一是名称直白,像“查询天气”就优于“AtmosFetchV2“;二是写清适用场景和用户常见说法,比如”用户问明天会不会下雨时使用“;三是参数说明带格式示例,如 city: "北京";四是写明边界条件,比如”仅支持国内主要城市”。底层机制是模型把任务文本和每个工具描述都转成向量,再做相似度匹配。
说明卡写得准,主厨扫一眼墙就能锁定蒸锅;描述写得好,模型的向量匹配也一击即中。所以工具库上线后还要持续维护:新增工具补卡、下架工具摘卡、表述过时的卡片及时改写,让整面墙永远干净、准确。
- 嵌入成向量先用嵌入模型把任务文本 q 和工具描述 d_i 分别映射为高维向量,语义相近的文本在向量空间里方向也更接近。
- 点积算重合两个向量逐位相乘再求和,结果越大表示两个方向的投影重叠越多。
- 模长归一化分别算出两个向量的长度并相乘作为分母,把结果压到 [-1, 1] 区间,消除文本长度差异。
- 得到相似度分数点积除以模长乘积即得余弦相似度,接近 1 表示任务与描述高度契合。
选择决策机制
光看菜单还不够。老主厨会瞄一眼客人的表情、听一耳朵邻桌的闲聊、回忆一下今天备了什么菜。客人赶时间,就上快炒而不是炖盅;客人是常客,还记得他上次说“蒸鱼别放葱”。
Agent 选工具也一样。除了任务文本本身,还有三个信号参与决策:任务信号,用户这次具体说了什么;上下文信号,对话历史里流露的线索、用户画像、当前系统状态;先验信号,历史上这类任务、这类用户更常用哪个工具。三者各有各的参考价值。
工程上把三类信号各自打成 0 到 1 的分,再加权求和。权重体现业务偏重:通常任务相似度最重要,上下文次之,先验负责兜底和平滑。
主厨综合下单信息与现场情况做判断,Agent 综合任务、上下文和先验排队选工具——决策质量取决于信号是否丰富、权重是否合理。信号单一,判断就容易跑偏;权重失衡,选出的工具就容易不合时宜。
- 拆出三个信号把任务文本、上下文状态、历史分布分别变成可计算的分数,每一项都归一化到 0 到 1 之间。
- 设定权重权重满足加和为 1,体现业务上对三个信号的偏重。
- 逐项相乘再求和三个分数分别乘上自己的权重后相加,得到该工具的总分。
- 全部工具排序取最大对工具库里的每个工具算出总分,排序后取最高者作为选中对象。
置信度评估
主厨心里会掂量:清蒸鲈鱼闭着眼都能做,松鼠鱼却只有五成把握。把握不足时,他会转身问客人“要不换个做法”,而不是硬着头皮上。这份“自我掂量”,就是置信度的雏形。
模型选工具时也会产出类似“把握”的内部信号。原始的得分不好直接当门槛,需要换算成一个 0 到 1 的置信度,并设置阈值:高于阈值就执行,低于阈值就主动澄清或走备选方案。
常见做法是让模型在生成选择的同时输出一个 0 到 1 的置信度分值,再用 sigmoid 函数做平滑变换。阈值也不是拍脑袋定的:调低,工具调用更果断但误选变多;调高,更稳妥但频繁澄清影响体验。
主厨自评“把握不大”时会低头问客人,Agent 置信度低于阈值时也会停下来追问:“您是要查天气还是查航班?”把不确定性摊在桌面上,比硬着头皮用错工具体面得多,也更容易换来用户的一次确认。
- 算离阈值的距离先用得分减去阈值 θ,正数代表达标,负数代表不达标,差距越大选对的把握越大。
- 指数放大差距乘以系数 k 后取负、再取指数,差距越大 e 的幂次越接近 0,变换曲线越陡。
- 压缩到 0 到 1除以“1 加该指数”,把结果压进 (0,1) 区间,超过 0.5 即表示模型自认为达标。
参数生成与校验
主厨下了指令“用蒸锅蒸鱼”,帮厨要拧燃气、倒水、设定 8 分钟。任何一步出错——没水干烧、时间设成 80 分钟——都会翻车。所以行规是开火前必须检查一遍:水够不够、挡位对不对、时间合不合理。
Agent 选中工具之后,要生成一组参数,通常是一个 JSON 对象,比如 {"city": "北京", "date": "2025-01-10"}。模型生成的参数天然可能缺字段、类型错误、数值越界,因此调用之前必须校验,把“干烧”的风险掐灭在开火前。
工程上常用 JSON Schema 或自定义规则定义校验项:必填字段是否齐全、类型是否匹配、取值范围是否合法、格式是否符合要求(日期格式、枚举值)。全部规则通过才允许调用,否则进入“重新生成参数”或“向用户澄清”分支。
开火前检查一圈,蒸锅没水就加水、时间离谱就纠正——Agent 的参数校验就是那道“开火前的检查”,把模型的随口参数挡在真实世界之外。校验失败不是事故,而是流程里设计好的一道安全阀。
- 切出参数子集把参数包 P 按规则拆成 m 个被检查的子项,比如城市、日期、温度各是一项。
- 逐项判定每个子项过对应规则 r_k,返回真或假,就像检查表上一项一项打勾。
- 逻辑与合并结果用 ∧ 连接全部判定,只有 m 个结果全为真时 valid 才为真。
工具调用执行
蒸锅开始工作后,主厨不会转身就走。他看蒸汽有没有冒出来、听压力阀的声音、定时器响了就关火。火候不对就调整,设备半天没反应就换一口锅。执行不是一锤子买卖,而是盯着过程、随时应变。
调用执行阶段有三件事:把参数按工具要求的协议封装好发出去;把返回结果解析成模型能读的格式;调用失败时按策略重试或换工具。这是 Agent 与真实世界之间的最后一公里,也是最容易“翻车”的地方。
协议封装要兼容不同工具,HTTP、RPC、本地函数统一成一套调用接口和错误码;结果解析要把非结构化返回整理成结构文本喂回模型;失败重试要用指数退避,避免多个 Agent 同时重试把下游系统打崩。
主厨盯着蒸汽调整火候,Agent 盯着返回结果决定重试还是换路——执行层把“观察、判断、再行动”的闭环做得越稳,整个工作流就越扛得住真实世界的各种意外。
- 定初始等待设定第一次重试前的基础等待时间 t0,通常取几百毫秒到几秒。
- 翻倍增长第 n 次重试前等待时间按 2 的幂倍增,重试越频繁间隔越长。
- 封顶防无限取 min 防止等待时间无限膨胀,达到 t_max 后固定间隔,超过最大重试次数则放弃并上报。
规模化优化
苍蝇馆子的工具墙就 8 件,扫一眼全记住;五星级后厨的墙上有 800 件,光靠肉眼扫墙,主厨会看花眼。所以大后厨都会先设一道“分类索引”:你要蒸的往左走,你要烤的往右走,先到对应货架再细挑。
工具从几十个涨到几百甚至上千时,把全部工具描述塞进 Prompt 的做法会崩溃:上下文窗口放不下、注意力被稀释、选择准确率下降、延迟直线上升。数量是能力的天花板,也是决策的地板,必须引入新的机制。
工程上常用两阶段:先用轻量检索(关键词 BM25 或向量检索)从全量工具库召回 top-K 候选,再把这些候选交给模型精排。更进一步是分层路由:先按命名空间或领域(搜索类、计算类、办公类)粗选,缩小范围后再精排。
主厨靠“分类索引”从 800 件工具里先锁定货架,再精挑细选——Agent 在海量工具面前同样先粗筛后精排。工具墙再长,只要有索引和路由,就永远看得过来。
- 稀疏检索打分BM25 基于词频和稀有度计算关键字精确命中的强度,命中稀有词加分更多。
- 稠密检索打分向量余弦相似度从语义角度捕捉“换了说法但意思一样”的匹配关系。
- 加权融合排序用 λ 在两套分数间取平衡,融合后的分数作为召回排序的依据。
生产落地经验
后厨能稳定出餐,靠的不是某位主厨超常发挥,而是制度:每道菜留样、每天记台账、每周复盘客人投诉。制度让“好吃”从偶然变成必然。
生产环境的 Agent 也一样,靠三个支柱:可观测性,每个选择、每次调用都有日志和指标可查;金标回归,用一套固定的测试集挡住每次改动带来的退化;持续迭代,定期 review 失败样本,优化描述和阈值。三者缺一不可。
金标集是核心资产:人工标注一批“任务→期望工具→期望参数”的样本,作为回归测试集。每次改描述、调权重、换模型,都要先跑金标,通过率不能跌。否则今天改了 A 工具的描述,明天 B 工具的选择就悄悄变坏,团队却毫无察觉。
留样、台账、复盘让后厨越做越稳;日志、金标、迭代让 Agent 越跑越准。所谓生产级能力,不是一次写对的代码,而是一套能持续发现并修正问题的体系。
- 构造金标样本人工准备 N 条“任务→期望工具”的测试样本,覆盖常见场景与边界场景。
- 预测并判定对错让 Agent 对每条任务给出预测工具 \hat{t}_i,用艾佛森括号记录是否与期望一致。
- 求和取平均把 N 条样本的判定结果加总后除以 N,得到 0 到 1 的通过率,作为回归门禁。
AI 应用场景
智能客服工单自动分派
阶段:工具选择与调用(选择决策 + 参数校验)
解决的问题:传统客服靠人工判断工单类型并切换多个内部系统,速度慢且容易选错流程。Agent 根据用户描述,从工单系统、知识库、CRM 等工具中选择正确的工具并自动传参,完成录入和流转,让客服从“点鼠标”变成“做审核”。
具体案例:电商平台用户说“我上周的订单还没发货”,Agent 先选择“订单查询”工具,从对话上下文抽取用户 ID 和订单号,参数校验通过后调用查询接口,返回物流状态;若物流超时,再选择“催单”工具发起催办。整个链路从几分钟缩短到几秒。
数据分析助手自动出图
阶段:参数生成与校验
解决的问题:分析师手动选图表库、写绘图配置,门槛高且容易出错。Agent 选择“图表生成”工具,并生成图表类型、时间范围、聚合粒度等参数,校验通过后自动渲染,把“要一张图”变成一句话。
具体案例:运营同学说“看下最近 30 天日活趋势”,Agent 选择折线图工具,生成参数 {"类型": "line", "时间范围": "近30天", "粒度": "day"}。校验发现“粒度”字段合法、“时间范围”格式正确,随即调用绘图接口,输出趋势图。
企业内网工具机器人
阶段:规模化优化(两阶段检索 + 分层路由)
解决的问题:企业内有几十上百个内部 API(请假、会议室、报销、日历……),全部塞进 Prompt 既放不下也不准。Agent 用“先检索召回、再精排选择”的方式,从海量工具中快速锁定正确目标。
具体案例:员工说“帮我预约明天下午的会议室”,Agent 先从 200 多个工具中召回“日历查询”“会议室预订”等 5 个候选,精排后选择预订工具,生成 {"时间": "14:00-15:00", "人数": 6},校验通过后完成预订并回填日历。
Python 演示
# -*- coding: utf-8 -*-"""Agent 工具选择与调用的极简可运行示例."""import re class Tool: def __init__(self, name, keywords, required, func): self.name = name self.keywords = keywords self.required = required self.func = func def validate(self, params): return [k for k in self.required if k not in params] def fetch_weather(city): return "{} 晴, 22 摄氏度".format(city) def compute(expr): try: return str(eval(expr)) except Exception: return "表达式解析失败" def do_translate(text, target): return "[翻译] {} -> {}".format(text, target) def get_date(offset="0"): return "今天 + {} 天".format(offset) TOOLS = [ Tool("搜索", ["天气", "新闻", "百科"], ["city"], fetch_weather), Tool("计算", ["计算", "表达式", "等于"], ["expr"], compute), Tool("翻译", ["翻译", "英文", "日文"], ["text", "target"], do_translate), Tool("日期", ["日期", "几号", "星期"], ["offset"], get_date),] def score_task(tool, task): hits = [kw for kw in tool.keywords if kw in task] return hits, len(hits) / max(len(tool.keywords), 1) def select_tool(task): return max(TOOLS, key=lambda t: score_task(t, task)[1]) def extract_params(required, task): params = {} for key in required: m = re.search(key + r"[=::]\s*(\S+)", task) params[key] = m.group(1) if m else ("未知" + key) return params def run_agent(task): tool = select_tool(task) hits, conf = score_task(tool, task) print("任务: {}".format(task)) print("命中关键词: {}".format(hits)) print("选中工具: {}(置信度 {:.2f})".format(tool.name, conf)) params = extract_params(tool.required, task) missing = tool.validate(params) if missing: print("参数校验失败, 缺失: {}".format(missing)) return None print("参数校验通过: {}".format(params)) result = tool.func(**params) print("调用结果: {}".format(result)) return result if __name__ == "__main__": run_agent("city=北京 查一下北京天气") print() run_agent("expr=3*7+2 帮我计算这个表达式") print() run_agent("text=你好 target=英文 请翻译")
class Tool:把工具抽象成一个对象:名字、关键词、必填参数、执行函数都装在一起,对应工具库里的“一件工具”。def score_task(tool, task):用关键词命中率给工具打分,返回命中了哪些词和得分,这是最简版的任务匹配。max(TOOLS, key=lambda t: score_task(t, task)[1])在所有工具里挑得分最高的那个,这就是“选择决策”。re.search(key + r"[=::]\s*(\S+)", task)从任务文本里按“key=值”的模式抽取参数值,模拟参数生成。missing = tool.validate(params)在调用前检查必填参数是否齐全,缺了就报出来,对应参数校验环节。result = tool.func(**params)参数校验通过后,把参数展开传给工具函数执行,得到真实结果。
常见误区
误区“我担心模型看不懂工具,所以把描述写得越长越好,把实现代码、内部字段全塞进去,这样模型肯定选得准。”
正解描述是给模型看的“商品标签”,不是技术文档。过长会引入无关 token、稀释关键词,反而拉低语义匹配分数。好的描述像菜牌上的菜名:简短、说清“何时用、怎么用、别在什么时候用”。工程实测中,精炼描述的选择准确率通常优于长篇大论。
为何常见:新手从写文档的惯性出发,认为信息越全模型越懂,忽略了 embedding 是对整段文字的语义打包,噪音会干扰匹配。
误区“模型说自己有 0.95 的把握,那这次选择肯定有 95% 的正确率,直接执行就行。”
正解置信度是模型对自身选择的内部估计,不是统计出来的真实概率。它受训练分布和提示词影响,可能系统性过乐观。生产上必须用金标集实测校准:显示 0.95 但实测只有 0.7 时,就要调阈值或改映射。置信度是方向盘,不是里程表。
为何常见:名字里带“置信”让人误以为有统计意义,而且模型生成数字天然显得权威,容易让人放弃质疑。
误区“只要我把工具接得足够多,Agent 就什么都能干,能力肯定越来越强。”
正解工具越多,选择空间越大,但每个候选都占上下文窗口,还会增加误选概率和决策延迟。工程做法是“先检索召回、再精排选择”,并辅以分层路由;工具增长时同步优化选路策略,而不是无脑堆数量。数量是能力的天花板,也是决策的负担。
为何常见:“插件越多越好”的市场宣传强化了功能叠加的直觉,让人忽略了决策负担和上下文成本。
误区“Agent 参数校验失败说明代码写错了,我要去修函数,让每次调用都成功。”
正解校验失败是 Agent 工作流里的正常分支,不是故障。它和主厨发现“蒸锅没水”一样,是流程设计的一部分:触发重新生成参数、向用户澄清或换工具。把失败当作一等公民设计反馈回路,系统才稳健;强行追求“永远成功”反而掩盖了 LLM 输出的固有不确定性。
为何常见:传统软件的“异常即 Bug”思维根深蒂固,不了解大模型生成具有概率性,输出天然需要校验兜底。
误区“几百个工具我全写进 system prompt,让模型自己挑,一步到位,不用搭检索系统。”
正解长上下文虽然放得下,但工具描述会相互干扰、挤占注意力,导致“选择困惑”和幻觉,延迟也显著上升。生产上应做两阶段:先用轻量检索把上千工具砍到几十个候选,再让模型精排。这也符合人脑“先粗筛、再细看”的认知习惯。
为何常见:“上下文越长越好”的宣传让新手忽略注意力稀释和成本,而且本能上想少写代码、少搭组件。
面试题
Q1. Agent 进行工具选择时,最核心的依据是什么?
- A.任务与工具描述的语义匹配← 正确答案
- B.工具被调用的历史次数
- C.工具名称中包含的字符数
- D.工具部署上线的先后时间
答案:A。工具选择本质是判断“哪个工具最能完成当前任务”,语义匹配度是核心信号;调用次数、名字长短、上线早晚都是无关特征。就像主厨挑工具看的是“这道菜适合哪件工具”,而不是工具的采购顺序。
Q2. 关于工具描述工程,好的工具描述应该具备哪些特点?
- A.用词贴近用户的常见说法← 正确答案
- B.只写内部实现与源码细节
- C.覆盖工具的适用场景和典型用法← 正确答案
- D.包含边界条件与易错反例← 正确答案
答案:ACD。描述是给模型看的“商品标签”,要用用户语言写清“什么时候用、怎么用、别乱用”。内部实现细节对选择毫无帮助,反而稀释关键词、拉低语义匹配精度。
Q3. 关于工具选择的置信度,下列说法正确的是?
- A.置信度分数可以直接当作真实准确率
- B.置信度反映工具本身的执行速度
- C.置信度是模型自评信号,需用评测集校准← 正确答案
- D.置信度越高说明工具参数一定合法
答案:C。置信度是模型对“我选得对不对”的自我估计,不是统计概率,可能系统性过乐观,必须用金标数据集校准后再设阈值。就像主厨说“我很有把握”,也要等客人吃完才知道好不好吃。
Q4. 参数校验环节最主要的作用是什么?
- A.提升模型的推理运行速度
- B.在调用前拦截非法格式的参数← 正确答案
- C.简化工具的代码实现逻辑
- D.扩大模型的上下文窗口
答案:B。模型生成的参数可能缺字段、类型错、越界,校验在调用前拦截这些问题,避免把坏参数发给真实服务。相当于开火前检查燃气和水位,把风险挡在真实世界之外。
Q5. 当工具数量增长到数百个时,哪些策略可以有效保证选择准确率?
- A.把所有工具描述全部塞进一个 Prompt
- B.先检索召回候选再做精排选择← 正确答案
- C.按命名空间或领域分层路由缩小范围← 正确答案
- D.每次从工具库中随机挑选几个工具
答案:BC。全量塞 Prompt 会稀释注意力、增加延迟;随机挑选完全不可控。生产上常用“检索召回 + 精排”两阶段和分层路由,就像主厨先看分类索引,再在同类货架里精挑细选。
Q6. 工具调用返回结果解析失败时,正确的处理方式是?
- A.将错误信息反馈给模型重试或换工具← 正确答案
- B.立即终止整个任务流程
- C.忽略返回结果继续执行后续步骤
- D.把该工具从工具库中永久删除
答案:A。执行是“观察—判断—再行动”的闭环,解析失败要把错误喂回模型,让它重试、修参数或换工具。一失败就终止或删除,相当于菜没蒸好就掀桌,既浪费又草率。
Q7. 在工具选择中,所谓的“上下文感知”主要指什么?
- A.让工具自动识别用户输入的文字颜色
- B.结合对话历史、用户偏好与当前状态选工具← 正确答案
- C.检测工具所在服务器的运行温度
- D.通过增加 Prompt 字数来提升选择质量
答案:B。上下文感知就是除了看当前这句话,还结合历史对话、用户画像和系统状态来选工具。老主厨不光看菜单,还会观察客人神态和备菜情况,综合判断。
Q8. 评估工具选择效果时,以下哪些做法是合理且可落地的?
- A.在金标数据集上统计端到端通过率← 正确答案
- B.统计工具选择结果与期望工具的一致性← 正确答案
- C.随机抽一条 Prompt 用肉眼判断好坏
- D.对失败样本做系统性回归与归因分析← 正确答案
答案:ABD。金标通过率和选择准确率都是量化指标,失败样本回归是持续迭代的依据。肉眼看一两条既不稳定也不可复现,无法作为回归门禁,只能当辅助参考。
Q9. 为什么工具描述不宜写得过长?
- A.过长的描述会占用较多的磁盘空间
- B.工具执行函数会拒绝过长的描述
- C.过长的描述会增加模型输出的上限
- D.无关细节会稀释关键词降低匹配精度← 正确答案
答案:D。embedding 向量是对整段文字的语义打包,塞入大量无关细节会让向量方向“变模糊”。就像说明卡字太多,主厨反而找不到“蒸鱼”两个字,选择准确率随之下降。
Q10. 金标集显示某工具“置信度 0.9 但实际正确率仅 0.6”,最合理的工程动作是什么?
- A.立即删除该工具并永不使用
- B.把置信度显示值直接改成 0.6
- C.提高选择阈值并重新校准置信度← 正确答案
- D.忽略金标结果按原逻辑上线
答案:C。置信度偏高说明模型过度自信,工程上应提高阈值、校准映射或优化工具描述,让“自评”贴近“实测”。“直接改数字”是自欺欺人,删除工具是逃避问题,忽略金标则会让错误流向线上。