领域 2 · 占比 18% · 免费预览

工具设计与 MCP 集成

Tool Design & MCP Integration · 5 个知识点

2 个免费知识点3 个知识点待解锁
开始前

先认识本章会用到的词

MCP

Model Context Protocol 的缩写,是让 AI 应用以统一方式发现和调用外部工具、数据源的协议。

GitHub

一个托管代码与版本历史的网站。团队用它保存项目、审阅改动和协作处理问题;它不是编程语言。

API

软件之间约定好的调用方式:请求包含什么、返回什么、出错时怎么表示,都由接口规则定义。

JSON

一种用键和值组织数据的文本格式,软件常用它交换结构化信息。

2.1

AI 老是选错工具?问题可能不在模型

名字太像、边界不清、一个工具塞三种模式,都会逼 Claude 在调用时靠猜。

工具描述,是大语言模型挑选工具时用到的主要机制——不是辅助性的元数据,也不是可有可无的附属品,就是主要机制本身。模型拿到一组工具时,是靠读描述来决定该调用哪一个的;如果描述写得太单薄,比如只写一句"获取客户信息",模型根本没办法分清楚两个用途有重叠的工具到底该选哪个。

什么样的描述算合格:一份生产级别的工具描述要包含五个要素——①这个工具是干什么的,主要用途表述得明确无歧义;②它期望什么样的输入,数据类型、格式、约束条件,哪些字段必填、哪些选填;③它擅长处理的示例查询,用具体的使用场景锚定模型的理解;④边界情况和局限,这个工具不做什么,输入超出预期范围时会发生什么;⑤明确的边界线,什么时候该用这个工具,而不是同一个工具箱里长得很像的另一个。对比一下最简单和生产级别的描述有什么区别:简单版(会导致选错工具)——get_customer: "获取客户信息";lookup_order: "获取订单详情"。生产级别版——get_customer: "按邮箱、电话号码或客户 ID 查找客户账户,返回客户档案(姓名、联系方式、账户状态、会员等级)。需要核实客户身份时用这个,不要用来查订单相关的问题,那种情况请用 lookup_order。"lookup_order: "按订单号(格式:#NNNNN)或运单号查询订单详情,返回订单状态、商品、物流信息和退款资格。客户问起具体某个订单时用这个,不要用来验证客户身份,那种情况请用 get_customer。"第二版给了模型明确的区分依据:它知道每个工具各自接受什么标识符、各自返回什么,最关键的是,知道什么时候不该用这个工具。

选错工具的问题:两个工具的描述互相重叠、或者几乎一模一样,就会造成选择上的混乱。官方样题 Q2 考的正是这个场景:get_customer 和 lookup_order 描述都很单薄,导致 Agent 把"帮我查一下我的订单 #12345"这句话路由到了错误的工具上。考试要考的是你能不能挑出正确的修法——四个看起来都说得通的选项,三个是错的:扩写描述——对,投入低、见效大,直接针对根本原因;加 few-shot 示例——错,只会增加 token 开销,没有解决模型为什么会困惑的根本问题,治的是症状不是病根;搭一个路由分类器——错,作为第一步来说是过度工程化,绕开了大语言模型本身的自然语言理解能力,还额外增加了基础设施复杂度;把工具合并——作为第一步是错的,长期来看是一个站得住脚的架构选择,但成本比扩写描述高得多。考试一贯偏爱投入小、见效大的修法:先改描述,而不是先上路由分类器;先做权限收窄,而不是先要求完整访问权限;先用社区服务器,而不是先自己动手搭。

拆分工具:职责宽泛的通用工具会制造歧义,修法是把它拆成几个各自目的明确、有清楚输入/输出约定的专用工具。拆分前:analyze_document: "分析一份文档并返回结果"。拆分后:extract_data_points: "从文档中提取结构化的数据字段(日期、金额、姓名)";summarize_content: "为文档的核心论点和结论生成一份简明摘要";verify_claim_against_source: "核对某条具体主张是否有原文档支持,返回支持或反驳的证据"。拆分出来的每一个工具,都只做一件范围窄、描述清楚的事,模型可以根据用户实际需要什么来挑对的那一个。

为了清晰而改名:当两个工具的名字长得容易混淆,改名能在接口层面直接解决重叠问题——把 analyze_content 改名成 extract_web_results,配上一份针对网页场景的描述,这个工具的用途就变得清清楚楚了,完全不用碰它背后的实现。

和系统提示词的相互影响:系统提示词里对关键词敏感的措辞,可能会制造出意料之外的工具联想,盖过写得很好的工具描述。如果系统提示词里写着"处理前务必先核对客户信息",模型可能会把任何和客户相关的查询都路由到 get_customer,不管工具描述实际上是怎么写的——所以更新完工具描述之后,记得回头重新读一遍系统提示词,看看有没有冲突,这是一种很隐蔽的翻车方式,也是考试会考的。

这里有一个前提条件必须看清楚,考试两半都会考:描述是不是该改,要看你面对的是哪一种病。当 Agent 手里的工具数量还算合理,只是分不清其中两个的时候,改描述是对的修法;但当问题出在工具箱本身时,改描述就没用了——一旦一个 Agent 挂载的工具超过大约 4-5 个,选择的可靠性会单纯因为决策复杂度上升而下降,这时候把 22 份描述全部重写一遍,根本碰不到真正的病根。动手之前,先诊断清楚自己面对的是哪一种情况——工具数量本身导致的过载问题,在 2.3 会讲到该怎么应对。

✕ 两句模糊描述 "customer info" "order details" 模型分不清谁是谁 问订单却调用了客户接口 ✓ 扩写 + 划清边界 补上格式、示例、边界 "用这个,不要用那个" 成本最低的根因修复 few-shot/路由层/合并都不是
模型选错工具,几乎总是描述写得太弱——先把描述改清楚,别急着加别的机制。
模型靠"描述"选工具;选错了,先去改描述,而不是加机制。

常见考点陷阱,逐条对照:

  • 工具描述太单薄导致选错工具时,选择用 few-shot 示例来修——few-shot 示例只会增加 token 开销,没有解决模型为什么分不清这两个工具的根本原因;应该先把描述本身写清楚。
  • 把路由分类器当成修复工具选择问题的第一步——路由分类器作为第一反应是过度工程化,绕开了模型自身的自然语言理解能力,还引入了考试认为不成比例的基础设施复杂度。
  • 把相似的工具合并当成第一步的修法——工具合并是站得住脚的长期架构选择,但比起扩写描述,需要付出的成本高得多,考试偏爱投入小、见效大的第一步。
  • 更新完工具描述之后,没有回头检查系统提示词的措辞——系统提示词里对关键词敏感的指令,可能悄悄盖过写得很好的工具描述,制造出意料之外的工具联想。

快速检查

  1. 1模型挑选工具,主要依据的是什么?

  2. 2get_customer 和 lookup_order 经常被选错,最有效、成本最低的第一步修法是什么?

  3. 3一个工具被塞进了好几种不相关的用法(万能工具),正确做法是?

  4. 4更新完工具描述之后,容易被忽视但也该检查的地方是什么?

  5. 5一个 Agent 只有 5 个工具,其中两个选择混淆;另一个 Agent 有 22 个工具,选择也很混乱。两者的修法一样吗?

2.2

工具报错别只写"失败了"

超时该重试、参数错该改、业务拒绝不该重试:错误结构必须直接告诉 Agent 下一步。

一个 MCP 工具失败时,它返回的错误响应,决定了 Agent 是能聪明地恢复,还是只能盲目地失败。像"操作失败"这种笼统的提示对大语言模型毫无用处——没有任何信号能说明到底哪里出了问题、该不该重试、或者该试点别的什么。MCP 协议专门提供了 isError 这个标志位,用来把工具失败的信息传回给 Agent:设置了它,模型就知道这次执行确实失败了,可以据此推理该怎么恢复,而不是把错误文本当成一次正常的成功结果来处理。

四类错误,每一类都需要不同的恢复策略,Agent 需要结构化的元数据才能把它们区分开:①临时性错误(transient)——超时、服务不可用、限流,底层系统暂时连不上,但请求本身是合法的,恢复方式是稍等片刻再重试,例如 {"isError":true,"errorCategory":"transient","isRetryable":true,"description":"订单数据库负载过高,请求本身有效,重试应该能成功。"};②校验错误(validation)——输入格式不对、必填字段缺失、数值超出范围,请求本身格式有误,恢复方式是修正输入之后再重试,例如 {"isError":true,"errorCategory":"validation","isRetryable":true,"description":"订单 ID 必须是 #NNNNN 格式(如 #12345),收到的是 order-abc,请改好格式再试。"};③业务错误(business)——违反了政策、超出限额、和业务规则冲突,请求在技术上合法,但违反了一条业务约束,恢复方式是不要重试——同样的请求永远都会失败,Agent 需要走一条完全不同的流程,例如 {"isError":true,"errorCategory":"business","isRetryable":false,"description":"退款金额 £750 超过了 £500 的自动退款上限,需要经理审批,请把退款详情升级给人工客服。"};④权限错误(permission)——访问被拒、凭证不够、授权失败,工具因为调用方缺少所需权限而没法执行,恢复方式是升级或者换一套凭证,例如 {"isError":true,"errorCategory":"permission","isRetryable":false,"description":"当前服务账号没有权限访问财务记录,请升级给拥有财务系统权限的高级客服。"}。

isRetryable 这个字段真正回答的问题,只有一个:重试有没有可能走通?它不是在保证"同样的请求原样重试就一定能成功"。有两类错误都标着 isRetryable: true,却需要完全不同的恢复方式:临时性错误只要系统恢复了,原样重试就行;校验错误只有在 Agent 修正了输入之后重试才有意义(比如把 order-abc 改成 #12345)。业务错误和权限错误都是 isRetryable: false,原因也是对称的:业务规则会彻底拦住这个请求,重试没有用;权限错误需要换一个不同的主体——一个拥有正确权限的账号,而不是把调用换个说法重发一遍。读这个字段时,先问"重试有没有可能成功",再看 errorCategory 知道具体该怎么做:重发、自我修正、升级,还是走别的路径。

访问失败 vs 合法的空结果:这是本领域里最需要吃透的一组区分,考试会直接考它。访问失败:工具没能连上数据源——发生了超时、身份验证失败,或者服务挂了;数据可能存在,只是工具没法去核实,Agent 需要决定要不要重试。合法的空结果:工具成功查询了数据源,但没有找到匹配项;查询本身执行得完全正确,只是没有符合条件的数据,Agent不应该重试,正确的答案就是"没有查到结果"。把这两者搞混,会让整套恢复逻辑彻底失灵:一次客户查找返回了一个空数组,Agent 重试了 3 次,然后升级给人工,事后分析发现,这个客户的账户根本就不存在——工具其实是成功的,它查询了数据库,没找到匹配的客户,正确地返回了一个空结果;但因为响应没有区分"我没能连上数据库"和"我连上了数据库、但什么都没找到",Agent 把两者一视同仁地当成"值得重试的失败"来处理了。修法是:把工具响应设计成,一次成功但没有结果的查询,看起来和一次失败的查询完全不一样。合法的空结果——不是错误:{"isError":false,"content":[{"text":"没有找到匹配邮箱 john@example.com 的客户。查询成功执行,只是没有匹配结果。"}],"resultCount":0};访问失败——是错误:{"isError":true,"errorCategory":"transient","isRetryable":true,"description":"连接客户数据库超时(5秒),查询没有真正执行。"}。

多智能体系统里的错误传播,遵循"本地恢复优先,选择性向上传播"的原则:子智能体应该在本地处理临时性失败——如果一次网页搜索超时了,搜索子智能体应该先自己重试,而不是立刻去麻烦协调者;只有本地解决不了的错误,才应该向上传播——如果所有重试都失败了,子智能体才向上汇报这次失败;上报时要带上部分结果和已经尝试过什么——协调者需要这样的上下文才能做判断,例如"我成功搜索了 5 个来源里的 3 个,来源 4 和 5 超时了,这是那 3 个成功来源给出的部分结果"。这能防止两种反面模式:悄悄压下错误(把空结果当成功返回)和因为单次失败就终止整个流程——两者都会让协调者在信息不全的情况下盲目做决定。

✕ 笼统报错 "操作失败" Agent 不知道该重试 还是该放弃、该升级 ✓ 结构化错误 category: transient/business… isRetryable: true/false description: 说明原因 Agent 能自己判断怎么恢复
能不能自动恢复,取决于错误信息里有没有"分类"和"能不能重试"这两个字段。
报错要带上"分类"和"能不能重试",业务/权限错误永远不重试。

常见考点陷阱,逐条对照:

  • 一次成功查询返回空结果时,让 Agent 去重试——成功查询的空结果意味着"没有符合条件的数据",重试只会得到同样的空结果,Agent 应该接受这个结果并据此回应。
  • 用"操作失败"这种笼统的错误信息,不带任何结构化元数据——没有 errorCategory、isRetryable 和 description,Agent 没法分清这是临时性失败还是业务规则冲突,也就没法做出合适的恢复决定。
  • 把业务错误当成可以重试的错误来处理——业务错误(比如退款超出政策限额)永远不会因为重试而解决——同样的政策约束每次都会挡住它,Agent 必须走升级这类完全不同的路径。
  • 子智能体把失败悄悄压下、返回一个假装成功的空结果——这会把失败信息瞒着协调者,让它没法做出聪明的恢复决定;协调者分不清"查了没有"和"根本没查成",很可能产出不完整或者不准确的结果。

快速检查

  1. 1一句"操作失败"式的错误信息,对 Agent 来说问题在哪?

  2. 2业务错误(比如退款超出政策限额)应不应该重试?

  3. 3一次客户查找返回空数组,Agent 重试了 3 次才升级给人工,结果发现这个客户账户根本不存在。问题出在哪?

  4. 4一个工具返回 {results: [], status: 'success'},但实际上是因为超时没有真正查询。这属于哪种反面模式?

  5. 5多智能体场景下,子智能体遇到临时性失败(比如超时)应该怎么做?

免费预览到这里

继续学习本章剩余 3 个知识点

登录后保存学习身份,并继续完成课程解锁。

登录并继续学习