尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
在智能体中使用MCP工具:从工具发现到多工具协作,我的实战经验
在智能体中使用MCP工具从工具发现到多工具协作我的实战经验写在前面前面几篇文章把MCP的概念、客户端、传输方式都讲了。但有读者说“这些我都懂了可真到了把MCP工具塞进Agent里的时候还是一头雾水。大模型到底是怎么决定调用哪个工具的工具调用失败了怎么办一个任务需要好几个工具配合怎么搞”这些问题问得非常好。MCP协议本身只解决了工具怎么接入的问题但工具怎么用好是另一个层面的事。这篇文章我就结合自己的项目经验聊聊在智能体中真正使用MCP工具时会遇到的问题以及我的解决方案。一、第一步把MCP工具翻译给大模型听MCP的工具列表是给程序看的大模型看不懂。你需要做一次翻译把MCP的Tool对象转换成大模型的Function Calling格式。MCP的Tool长这样Tool(nameget_weather,description查询指定城市的当前天气,inputSchema{type:object,properties:{city:{type:string,description:城市名称}},required:[city]})转换成OpenAI格式的Function Calling是这样{type:function,function:{name:get_weather,description:查询指定城市的当前天气,parameters:{type:object,properties:{city:{type:string,description:城市名称}},required:[city]}}}看起来就是改了个壳子对吧但这里有几个细节要注意细节1工具名要全局唯一。如果你连了多个MCP Server不同Server可能有同名工具。我一般的做法是给工具名加上Server前缀比如weather.get_weather、fs.read_file。细节2描述要写清楚。大模型是靠description来判断什么时候该调用这个工具的。描述写得模糊大模型就容易选错。比如查询天气就不如查询指定城市的实时天气信息包括温度、湿度、天气状况来得清楚。细节3参数描述不能省。每个参数的description都要写大模型靠这个来判断该传什么值。我见过很多人只写参数名和类型不写描述结果大模型经常传错参数。我写了一个转换函数自动把MCP工具列表转成大模型能用的格式defmcp_tools_to_llm_format(mcp_tools,server_prefix):把MCP工具列表转换成大模型的Function Calling格式llm_tools[]fortoolinmcp_tools:full_namef{server_prefix}.{tool.name}ifserver_prefixelsetool.name llm_tools.append({type:function,function:{name:full_name,description:tool.description,parameters:tool.inputSchema}})returnllm_tools二、工具选择大模型是怎么思考的很多人以为大模型选择工具是靠魔法其实不是。它的逻辑很简单你把所有可用工具的名称和描述塞进Prompt大模型根据用户的问题匹配最相关的工具如果需要调用工具输出一个结构化的工具调用请求你的代码执行这个调用把结果返回给大模型大模型根据工具返回的结果生成最终回复这个过程就是所谓的ReActReasoning Acting模式——大模型先思考要不要调用工具、调用哪个然后执行再根据结果继续思考。但实际用起来工具选择经常出错。我总结了几个常见的错误和对策错误1该调用工具的时候不调用直接瞎编答案。比如用户问北京今天天气怎么样大模型可能直接回答北京今天晴25度而不是调用天气工具。这是因为大模型的训练数据里有大量天气相关的内容它倾向于自己回答。对策在System Prompt里明确告诉大模型“涉及实时信息、外部数据时必须调用工具不要凭记忆回答”。同时把工具描述写得更有吸引力比如加上这是获取实时天气的唯一途径。错误2调用了错误的工具。比如用户问帮我查一下订单状态大模型可能调用了查物流的工具而不是查订单的工具。对策工具之间的描述要有明显区分度。如果两个工具功能相近可以在描述里加上适用于XX场景不适用于YY场景。另外工具名也要有区分度query_order和query_logistics就比query1和query2好得多。错误3参数传错。比如该传字符串的传了数字该传城市名的传了城市代码。对策参数的JSON Schema要写详细包括类型、枚举值、描述。对于有固定取值范围的参数用enum限定。比如城市参数可以加上enum: [北京, 上海, 广州, 深圳]。三、完整的工具调用循环理解了工具选择之后我们来看完整的调用流程。一个典型的Agent工具调用循环是这样的asyncdefagent_run(user_message,mcp_manager,llm_client):messages[{role:system,content:你是一个智能助手可以使用工具来回答问题。},{role:user,content:user_message}]# 获取所有MCP工具并转换格式all_toolsawaitmcp_manager.get_all_tools()llm_toolsmcp_tools_to_llm_format(all_tools)whileTrue:# 调用大模型responseawaitllm_client.chat(messages,toolsllm_tools)# 如果大模型没有调用工具说明它已经有了最终答案ifnotresponse.tool_calls:returnresponse.content# 大模型调用了工具逐个执行fortool_callinresponse.tool_calls:tool_nametool_call.function.name argumentsjson.loads(tool_call.function.arguments)# 通过MCP执行工具调用try:resultawaitmcp_manager.call_tool(tool_name,arguments)tool_resultresult.content[0].textexceptExceptionase:tool_resultf工具调用失败{str(e)}# 把工具调用和结果加入对话历史messages.append({role:assistant,content:None,tool_calls:[tool_call]})messages.append({role:tool,tool_call_id:tool_call.id,content:tool_result})# 继续循环让大模型根据工具结果决定下一步这段代码的核心是一个while True循环把对话历史和工具列表发给大模型大模型决定是直接回答还是调用工具如果调用工具执行工具调用把结果加入对话历史回到第1步直到大模型给出最终答案这个循环看起来简单但有几个关键点关键点1对话历史要保留工具调用记录。大模型需要知道之前调用了什么工具、返回了什么结果才能决定下一步。所以每次工具调用的请求和响应都要加入messages。关键点2要设置最大循环次数。万一陷入死循环比如大模型反复调用同一个工具程序就卡住了。我一般设个上限比如最多调用10次工具超过就强制结束并提示用户。关键点3工具结果要简洁。工具返回的结果会被塞进Prompt里如果结果太长会占用大量token。对于返回大量数据的工具最好在Server端做摘要只返回关键信息。四、多工具协作一个任务需要多个工具怎么办简单的任务可能只需要调用一个工具但复杂的任务往往需要多个工具配合。比如用户说帮我订一张明天从北京到上海的机票然后订个酒店这就需要调用查询机票的工具调用预订机票的工具调用查询酒店的工具调用预订酒店的工具这种多工具协作大模型自己就能处理——它会在ReAct循环里一步步调用需要的工具。但前提是你的工具设计得合理。我总结了几个多工具协作的设计原则原则1每个工具只做一件事。不要搞一个订机票酒店的大工具要拆成查机票“订机票”“查酒店”订酒店四个小工具。工具粒度越小大模型越容易组合使用。原则2工具之间通过自然语言传递信息。不要假设工具A的输出可以直接作为工具B的输入。大模型会在中间做翻译——它看完工具A的结果后会提取关键信息组织成工具B需要的参数。所以工具的输入输出都要用自然语言描述清楚。原则3给大模型足够的思考空间。复杂任务可能需要多轮工具调用不要急于打断。在System Prompt里告诉大模型“可以分步骤调用多个工具每一步根据上一步的结果决定下一步”。我在项目里遇到过一个有意思的case用户让Agent分析一下最近一周的销售数据然后发邮件给老板。Agent先是调用了数据库查询工具拿到数据后又调用了数据分析工具分析完之后调用了邮件发送工具。整个过程完全自动我什么都没干预。那一刻我真的感觉到Agent的智能出来了。五、错误处理工具调用失败了怎么办理想很丰满现实很骨感。工具调用经常会失败——网络超时、参数错误、Server挂了、API限流……各种问题都有。如果不做错误处理大模型拿到一个报错信息可能会直接把报错原文转给用户体验很差。我的做法是分层处理第一层客户端重试。对于网络超时、临时不可用等瞬时错误自动重试2-3次。注意不要对所有错误都重试比如参数错误重试多少次都没用。asyncdefcall_with_retry(mcp_manager,tool_name,arguments,max_retries2):forattemptinrange(max_retries1):try:returnawaitmcp_manager.call_tool(tool_name,arguments)except(TimeoutError,ConnectionError)ase:ifattemptmax_retries:awaitasyncio.sleep(1*(attempt1))# 指数退避continueraise第二层给大模型友好的错误信息。如果重试还是失败不要把原始异常直接丢给大模型。要转换成大模型能理解的自然语言比如天气查询服务暂时不可用请稍后再试或者建议用户手动查询。第三层降级策略。对于关键工具可以准备降级方案。比如天气查询失败了可以告诉用户暂时无法查询实时天气根据历史数据北京这个季节通常是XX天气。第四层人工介入。如果连续多次失败或者涉及高风险操作比如支付、删除数据应该暂停并请求人工确认而不是让Agent自己硬扛。六、几个让工具调用更稳定的技巧最后分享几个我在项目中总结的、能显著提升工具调用稳定性的技巧技巧1工具数量控制在10个以内。工具越多大模型选错的概率越高。如果你的系统有很多工具考虑做工具路由——先用一个轻量模型判断用户意图属于哪个领域再只加载该领域的工具。技巧2在System Prompt里给几个示例。比如用户问天气时调用get_weather工具用户问文件内容时调用read_file工具。几个示例比长篇大论的规则管用得多。技巧3工具结果加上来源标注。比如【天气工具返回】北京今天晴22°C。这样大模型能清楚地知道哪些信息是工具给的哪些是自己推理的减少幻觉。技巧4定期刷新工具列表。MCP Server的工具可能会变化比如升级后加了新工具不要在启动时加载一次就不管了。可以每隔一段时间重新拉取一次工具列表。技巧5记录工具调用日志。把每次工具调用的参数、结果、耗时都记下来。出问题的时候日志是最好的排查工具。我还会定期分析日志看看哪些工具经常被调用、哪些经常失败、哪些从来没被用过。七、一个完整的例子把上面讲的内容整合起来我写了一个简化版的Agent MCP工具调用的完整示例importjsonimportasyncioclassMCPPoweredAgent:def__init__(self,mcp_manager,llm_client):self.mcp_managermcp_manager self.llm_clientllm_client self.max_tool_calls10asyncdefrun(self,user_message):messages[{role:system,content:你是一个智能助手。 规则 1. 涉及实时信息或外部数据时必须调用工具不要凭记忆回答。 2. 可以分步骤调用多个工具完成复杂任务。 3. 工具调用失败时向用户说明情况并给出建议。},{role:user,content:user_message}]# 获取并转换工具列表mcp_toolsawaitself.mcp_manager.get_all_tools()llm_toolsmcp_tools_to_llm_format(mcp_tools)for_inrange(self.max_tool_calls):responseawaitself.llm_client.chat(messages,toolsllm_tools)ifnotresponse.tool_calls:returnresponse.contentfortool_callinresponse.tool_calls:tool_nametool_call.function.nametry:argumentsjson.loads(tool_call.function.arguments)resultawaitself.call_with_retry(tool_name,arguments)tool_resultf【{tool_name}返回】{result.content[0].text}exceptExceptionase:tool_resultf【{tool_name}失败】{str(e)}请告知用户该工具暂时不可用。messages.append({role:assistant,content:None,tool_calls:[tool_call]})messages.append({role:tool,tool_call_id:tool_call.id,content:tool_result})return抱歉处理您的请求时超出了最大工具调用次数请简化您的问题后重试。asyncdefcall_with_retry(self,tool_name,arguments,retries2):foriinrange(retries1):try:returnawaitself.mcp_manager.call_tool(tool_name,arguments)except(TimeoutError,ConnectionError):ifiretries:awaitasyncio.sleep(1*(i1))continueraise这个例子虽然简化了但已经包含了工具转换、ReAct循环、错误重试、最大次数限制等核心机制。你可以在这个基础上根据自己的需求扩展。写在最后把MCP工具接入Agent只是第一步真正的挑战在于用好。工具选择的准确率、多工具协作的流畅度、错误处理的健壮性这些都需要在实践中不断调优。我的体会是不要指望大模型一次就能把工具调用做对。要把工具调用当成一个需要工程化保障的环节——重试、降级、日志、监控一个都不能少。大模型负责智能我们负责稳定。MCP给了我们一个标准化的工具接入方式但怎么把工具用出花来还得靠我们自己在项目里摸索。希望这篇文章里的经验能帮你少踩点坑。你们在Agent里用MCP工具的时候遇到过什么奇葩问题有什么好用的技巧欢迎在评论区交流。下一篇预告MCP社区生态。我们会看看MCP生态里都有哪些现成的工具服务器从官方维护的到社区贡献的帮你快速找到能用的轮子。
RELATED

相关推荐

python函数闭包概念

python函数闭包概念

前言 闭包(closure)是函数式编程里最常被提起、也最容易被含糊带过的概念。很多人第一次接触时的理解是「函数里套函数」,这个说法只描述了长相,没有说明它为什么特殊。真正关键的一点是:内层函数在离开外层函数之后&a…

📅 2026/10/13 3:27:12
FT6336电容触控Linux驱动实战:从设备识别到多点校准

FT6336电容触控Linux驱动实战:从设备识别到多点校准

简介:本资源为嵌入式Linux平台下FT6336电容式触摸控制器的完整I2C驱动源码包,面向嵌入式驱动开发工程师、Linux内核初学者及智能终端硬件适配人员,解决触控设备在定制化硬件平台上快速移植与功能调优的核心问题。压缩包共5个文件(…

📅 2026/10/13 3:27:12
C++一元多项式计算器:链表设计与加减乘除实现详解

C++一元多项式计算器:链表设计与加减乘除实现详解

上周帮一位正在做数据结构课设的学弟看代码,他提交的“一元多项式计算器——C实现”卡在了加法运算上:两个多项式相加后,某些项凭空消失,某些项又重复出现。我扫了一眼他的代码,发现他把新节点直接插在了原链表上&…

📅 2026/10/13 3:27:12
MORE NEWS

更多资讯

📰

测试文章怎么写?从用例设计到报告落地的完整实践指南

写这篇内容之前,我刚从一场差点翻车的线上验收测试里缓过来。测试文章001,这个编号不是随意起的——我给自己的测试总结文档排了个序列,这是我写下的第一篇完整测试文章。过去几年我零零散散记过不少测试笔记,但真正把一次测试从设…

📰

CUC_Paraconc V0.3:面向教学的参数化并发模型仿真工具

简介:CUC_Paraconc V0.3是一款面向语言学、文体学研究者及高校相关专业师生的轻量级语料库检索与分析工具,专为解决大规模文本中词汇、短语、句法模式的精准定位与跨文本对比分析问题而设计。资源包共6个文件(868KB),含…

📰

中港无缝清关系统底层逻辑与实操避坑指南

去年有段时间,我几乎每天都会接到类似的电话:"车到了,单还没放,能帮我催一下吗?"打电话的人着急,接电话的人更头疼,因为海关端的审核进度不在我们手里,只能干等。后来团队…

📰

中文Meme生态迎来平台入局?从共识到流动性拆解热潮真相

最近圈子里讨论最多的话题之一,就是某头部加密资产交易平台旗下Labs部门(就是标题里这家平台Labs)高调宣布扶持中文社区Meme生态。消息一出,各路解读马上集中火力:有人看到了“中文Meme热潮真的来了”的号角&#xff0…

📰

Spring Boot + Vue酒店预订系统实战:从设计到部署全流程解析

前段时间帮朋友做了一个内部管理用的酒店预订小系统,技术栈就是现在最主流的 Spring Boot Vue。做完之后感觉这套组合非常适合中小型业务系统,尤其是酒店预订这种有大量状态流转、前后端交互频繁的场景。整个过程踩了不少坑,也总结出一些可以…

📰

顺序表增删查改详解:从内存布局到动态数组实现

顺序表大概是所有数据结构教材里的第一座山,也是很多人第一次意识到“原来数据还能这么存”的地方。它的增删查改,代码看起来不多,但每一行都藏着内存布局、边界条件、复杂度分析这些基本功。我见过不少初学者,链表写得飞起&#…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬