Tool Use实战:用 Function Calling 让 Agent 调用外部工具,我踩了 6 个坑
搞了大模型快两年了我觉得真正让 AI 从聊天机器人变成能干活的人的不是模型有多聪明而是它能不能调用工具。Function Calling 就是干这个的。简单说它让大模型不只是输出文字而是输出一个结构化的工具调用请求然后你的程序去执行这个请求再把结果喂给模型。听起来简单实际落地的时候踩了一堆坑。今天聊一聊我踩过的和解决了的。先看一个具体场景上周在做一个内部运维助手需求很直接让用户用自然语言查服务器状态。用户说帮我查一下线上服务的 QPS 和错误率Agent 需要做三件事调用监控 API 查 QPS调用日志 API 查错误率把结果汇总回复给用户没有 Function Calling 之前你只能做关键词匹配——写死一堆 if-else。有了 Function Calling模型自己决定要调什么工具、按什么顺序调。这就是 Tool Use 的意义把判断和执行分开。实战从零搭一套 Tool Use 系统Step 1: 定义工具描述最关键的一步。工具描述写得烂模型就乱调用。{type:function,function:{name:query_qps,description:查询指定服务的每秒请求数QPS用于监控服务负载,parameters:{type:object,properties:{service_name:{type:string,description:服务名称如 api-gateway、user-service},time_range:{type:string,enum:[5min,1hour,24hour],description:查询的时间范围}},required:[service_name]}}}踩坑1description 要写人话别写空话我一开始写的 description 是查询 QPS 数据结果模型老是在不该调用的时候调用。改成查询指定服务的每秒请求数QPS用于监控服务负载一般与错误率查询配合使用之后准确率提升了不止一点半点。模型是通过 description 来理解什么时候调用这个工具的。写得越具体越好。Step 2: Multi-turn 工具调用一个请求可能需要调用多个工具。核心伪代码如下messages[{role:user,content:查一下 API 网关的 QPS 和错误率}]whileTrue:responseclient.chat.completions.create(modelgpt-4o,messagesmessages,toolsTOOLS,tool_choiceauto)choiceresponse.choices[0]ifchoice.finish_reasonstop:# 模型直接回复了流程结束print(choice.message.content)breakelifchoice.finish_reasontool_calls:# 模型想调用工具messages.append(choice.message)fortool_callinchoice.message.tool_calls:func_nametool_call.function.name argsjson.loads(tool_call.function.arguments)resultexecute_tool(func_name,args)messages.append({role:tool,tool_call_id:tool_call.id,content:json.dumps(result)})这个循环就是 Tool Use 的核心。踩坑2Timeout 怎么处理这是个大坑。一个工具调用可能跑很久比如查全量日志模型在那儿等着用户很暴躁。我的解决方案给每个工具调用设超时超时后返回 “timeout” 给模型让模型决定是重试还是换个方案。try:resultawaitasyncio.wait_for(execute_tool(func_name,args),timeout15# 最多等 15 秒)exceptasyncio.TimeoutError:result{error:timeout,message:查询超时请缩小时间范围后重试}模型收到 timeout 后会主动问用户要不缩小一下时间范围——体验好很多。Step 3: 工具执行结果的处理踩坑3返回结果太大查一次全量日志返回几十 MB 的 JSON你传回模型token 直接爆炸。解决方案自动摘要。工具执行的结果不直接返回先做摘要defsummarize_for_model(result,max_tokens2000):把工具返回的大结果压缩成模型能看的版本ifisinstance(result,list)andlen(result)20:return{total:len(result),summary:f共{len(result)}条记录,sample:result[:5],stats:compute_stats(result)}returnresult踩坑4错误要优雅工具挂了返回个 500 错误页模型看到会一脸懵。API 返回的错误信息一般是给程序看的不是给模型看的。我做了个统一的错误包装层defwrap_error(exception):ifisinstance(exception,ConnectionError):return{error:service_unavailable,message:该服务暂时不可用请稍后重试}elifisinstance(exception,PermissionError):return{error:permission_denied,message:你没有该操作的权限}else:return{error:unknown,message:f操作失败{str(exception)[:100]}}模型看到这种格式的错误信息能更好地向用户解释问题。Step 4: 安全性踩坑5模型生成的参数可能是 SQL 注入如果工具是直接拼接 SQL 的模型调用时可能传一个恶意的参数值。解决方案所有工具执行前做参数校验特别是有数据库操作的工具。defvalidate_tool_args(func_name,args):iffunc_namequery_database:asserttable_nameinargsassertisinstance(args[table_name],str)# 白名单只允许查询预定义的表assertargs[table_name]inALLOWED_TABLES不要信任模型生成的参数该校验的得校验。Step 5: 让工具真正好用*踩坑6工具太多模型选不对*工具数量超过 15 个时模型选错的概率明显上升。我试过的几个策略策略A分组把工具按功能分组监控组、数据库组、消息组先调用路由工具决定用哪个组再调具体工具。效果最好但延迟多一轮。策略B降采样每次只用最相关的 5-8 个工具。基于用户当前的对话上下文做语义匹配。工程复杂度高但效果最稳。策略Crank 排序我最后的方案——给每个工具加一个热度分数根据历史调用频率排序热门工具优先级更高。简单粗暴但实用。实际效果数据这套系统跑了一周后的数据工具调用准确率91.3%工具超时率2.1%用户满意度人工标注89%平均每次用户请求调用工具数2.3 次最常用的工具 Top 3query_logs(34%)、get_metric(28%)、send_notification(12%)写在最后Function Calling 让 Agent 真正有了手。但从能调用工具到调得好用中间有一堆工程化的坑。我的核心建议是不要把工具调用当黑盒。每步都做校验、摘要、错误处理这些不性感的工作才是系统稳定运行的保障。如果你刚开始做 Tool Use建议从 3-5 个工具开始试跑通了再慢慢加。一口吃不成胖子工具多了模型也懵。有问题评论区聊。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2576621.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!