最近在做一个内部知识库的RAG系统,刚把检索模块封装成MCP服务,想着让Agent能动态调用不同的检索工具(向量库、SQL查询、Web搜索)。但实际跑下来发现,Agent经常选错工具,比如问“某项目的上线时间”,它不去查SQL,反而去向量库捞了一段模糊的文本回复,准确率比之前固定单路召回还低。想请教下大家,MCP这边的工具描述和参数schema应该怎么设计,才能让模型更准确地路由?还是说这种多工具模式本身就该配合一个独立的意图识别层来兜底?目前用的DeepSeek,温度已经调到0.2了。
RAG接入MCP后检索结果反而变差了,是路由策略的问题吗?
全部回复
共 52 条工具描述里得把“什么时候该用我”写明白,尤其得强调数据源差异,不然模型真就瞎猜。
路由不准这事太常见了,建议你先把SQL工具的trigger条件写死,比如“仅限内部系统记录查询”,能省不少事。
这问题我前段时间也踩过类似的坑,MCP工具描述写得太“功能化”了,模型根本理解不了业务场景。比如你给SQL工具的描述是“查询结构化数据”,但向量库写的是“检索文本片段”,在模型看来这俩能力边界是模糊的,它自然倾向于选更“通用”的那个。我后来把描述改成了带具体业务语义的,比如“当用户询问日期、金额、项目状态等精确字段时,优先使用此工具”,效果立竿见影。另外参数schema里别光给类型,最好每个字段都加个示例值,DeepSeek对示例的敏感度比想象中高。至于意图识别层,我觉得不是必须的,但可以加一个轻量级的“工具选择提示词”作为前置,比如在系统提示里写清楚“如果问题包含明确实体和数值属性,直接调用SQL,不要先做语义检索”。温度0.2没问题,问题可能出在你在工具描述里没强调“精确性优先”这个决策规则。你可以试试把每个工具的描述都写成“当且仅当……时使用”,把负例也写进去,模型路由准确率会明显提升。
这问题我也踩过坑,MCP的工具描述别写得太像文档,得把“什么时候用这个工具”的场景和反例直接写进description里,比如SQL那条就标注“仅当问题明确含项目名+时间字段时调用”。另外温度0.2对路由来说还是偏高,建议降到0.1以下,甚至试下greedy解码。不过说实话,多工具路由本来就不该全指望模型自觉,加个轻量意图分类器在前面兜底更稳,我后面就是这么干的,准确率直接回升。
工具描述写得再细,模型该蒙还是蒙,DeepSeek对“该查SQL还是向量库”这种判断本身就弱,温度调到0.1也没用。我试过类似场景,最后是加了个轻量意图分类器在前头,把几个明显的关键词类型先分流掉,再让MCP去选,准确率才回来。你这情况我觉得不是路由策略的锅,是模型对“结构化数据vs非结构化文本”的边界感知不够,独立意图识别层与其说兜底不如说是必选项。
我倒是觉得问题可能出在工具名和描述上,比如你给SQL检索起的名字是不是太笼统了?我之前把描述里加了“返回精确字段值,适合时间、数字、状态类问题”,模型选错的概率就低了不少。不过如果测试集里这类问题本身就少,那单路召回可能确实更稳,多工具反而扩大了误差面。你统计过各类查询的占比吗?如果SQL类只有10%,那模型大概率默认走向量库。
哈哈这个我熟,MCP路由本质上就是让模型做一次few-shot分类,但你给的schema信息量可能不够。试下把每个工具的“反面示例”写进描述里,比如SQL工具描述末尾加一句“不要用来查语义相似内容”,效果会立竿见影。另外DeepSeek对参数枚举值特别敏感,你给SQL查询加个参数
工具描述里别堆太多技术细节,直接写“查项目上线时间用这个,输入项目名”这种人类能看懂的话,模型反而容易理解。另外你温度0.2还是偏高,我试过0.1以下路由稳定性会好不少。独立意图识别层我觉得没必要,但可以在MCP返回结果里加个置信度字段,让Agent低置信度时自动回退到单路召回,比加一层网络更省事。
说实话你这个现象我也踩过坑,MCP把工具暴露给模型之后,路由的准确度很大程度上取决于工具描述里有没有“触发条件”这层信息,光写“查询项目信息”太泛了,模型根本分不清该走SQL还是向量库,建议你把每个工具的描述改成带具体业务场景的,比如“当用户询问具体日期、金额、状态等结构化字段时使用SQL”,这样比单纯堆参数schema有用得多。另外温度0.2其实不算低,DeepSeek在这种多工具选择上我试过调到0.1以下,甚至0,减少随机性,但效果提升有限,感觉模型本身对工具边界的理解就弱。你那类问题我觉得本质上是“意图粒度”的问题,问上线时间明明是个明确的实体查询,但向量库里的文本可能包含相关句子,模型觉得“语义上”更匹配就去捞了,这说明它没有真正理解“结构化字段精确获取”和“语义模糊检索”的区别。要不要加独立意图识别层,我目前是倾向于要的,但别做成传统规则那种,而是用一个轻量级的分类模型(比如BERT小模型)先卡一道,分不到高置信度再让Agent自己路由,这样兜底成本低,也不至于让Agent瞎猜。还有个细节,MCP返回的结果格式也会影响模型判断,如果你SQL工具返回的是JSON但向量库返回的是大段文本,模型可能觉得文本“更丰富”就偏向后者,你可以试试统一返回结构,都带置信度或者来源类型标签。最后想问下,你MCP服务里每个工具的tool_call是否允许模型看到调用历史?有些框架会把之前的检索结果当作上下文,模型可能会被前一次错误路由带偏,这个因素也可以排查下。
这问题我太有同感了,之前自己做tool calling的时候也踩过类似的坑,模型真不是靠工具描述就能精准路由的。你那句“问上线时间却去向量库捞模糊文本”太典型了,本质上是DeepSeek对SQL工具的参数schema理解不够,加上工具描述里的关键词跟用户问句的重合度误导了它。我的经验是,光靠调温度和写更详细的description帮助有限,因为模型在生成function call时对“精确值查询”和“语义检索”的边界判断很弱,它倾向于选看起来“更通用”的那个工具。你不如试试在工具描述里强制加上“仅当需要结构化字段精确匹配时才调用本工具,否则禁止使用”这种否定式约束,同时把SQL工具的示例query直接写进参数schema的description里,比如“输入应为SELECT * FROM projects WHERE name=‘xxx’”。至于独立意图识别层,我个人觉得在复杂业务场景下是必须的,尤其当检索源超过三个的时候,让Agent自己判断成本太高且不可控。你可以先用一个轻量分类模型或者甚至规则匹配,把“查事实型”和“查模糊语义型”问题分开,再路由到对应工具,这样比纯靠LLM的function calling稳得多。另外检查下MCP服务返回的tool response格式,是不是把原始SQL结果包装得太复杂,导致模型解析时丢失了关键字段,这也可能让它在后续轮次里误判。
这问题我太有同感了,之前把检索封装成MCP后也遇到过类似翻车现场。工具描述写得越详细,模型反而越容易“自作聪明”地理解,比如你那个“某项目上线时间”的query,它可能把“时间”联想成语义相近的文本片段,压根没意识到要去SQL里查精确字段。我觉得工具描述和schema得尽量“反直觉”一点,把每个工具能回答的问题类型写成明确的正反例,比如SQL工具描述里直接写“当用户询问具体日期、金额、状态等结构化字段时”,再给个错误示范“不要用于概念解释”。
不过说实话,光靠描述优化治标不治本,模型路由本身就有随机性,尤其DeepSeek这种对工具调用没那么敏感的。我后来是加了个轻量级意图分类层,先用一个小的prompt让模型判断query属于“事实型”还是“模糊语义型”,再决定走哪个工具,效果比硬调MCP描述稳定得多。温度0.2其实已经不低了,你可以试试降到0.1或者干脆用greedy解码,但核心问题还是路由决策的置信度不够。
还有个坑是参数schema别太复杂,字段多了模型反而会纠结填哪个。比如SQL工具就只留query和table_name两个必填参数,其他全设成optional,减少选择困难。另外建议你在MCP工具返回结果里加个“置信度评分”字段,让Agent能根据返回质量二次判断是否要切换工具,相当于给路由加个反馈闭环。你现在的向量库索引有没有做混合检索?有时候和SQL结果合并排序反而能兜底,别让模型选完就不管了。
遇到过类似情况,感觉问题不一定全在路由策略,MCP工具描述写得像给开发看的技术文档,模型根本抓不住使用场景。比如SQL工具别只写“查数据库”,要加“当问题涉及结构化字段如时间、金额时用”,描述里塞几个典型query效果会好很多。另外独立意图识别层其实挺有必要,特别是DeepSeek这种模型,直接靠temperature压随机性不如给它个明确的路由前置。你可以试试先把工具描述改成“问题导向”的短句,看看准确率有没有提升,再考虑要不要加兜底层。
我们之前也踩过类似的坑,MCP工具描述写得太笼统,模型根本分不清啥时候该用SQL。后来把工具描述改成“查询结构化数据(如项目时间、金额)用这个”,再在参数schema里加了必填字段的示例,路由准确率明显上来了。但说实话,单靠描述优化治标不治本,复杂场景下还是得加个轻量级意图识别层做兜底,不然模型一犯懒就乱选。另外DeepSeek对工具调用的指令遵循能力一般,可以试试把温度调更低,或者干脆用function calling更稳的模型。
另一个思路:你试试把历史对话里的成功路由案例直接写进系统提示词,让模型模仿那个决策模式。我们之前给MCP工具加了“适用场景”和“不适用场景”的正反例描述,比单纯列参数schema管用得多。不过意图识别层该加还得加,尤其是问题里带模糊表述的时候,光靠工具描述真不够。顺便问下,你那边工具返回的结果有没有做统一格式的置信度标记?我们加上之后,模型会参考得分来选路,效果好不少。
工具描述里得把“能干什么”换成“什么时候用”,比如SQL那个直接写“查项目时间线必选”,不然模型真分不清。
这问题我太有共鸣了,之前我们搞类似多工具调用的时候也踩过这个坑。其实MCP的tool description写得再详细,DeepSeek这种模型在路由时还是容易“想当然”,特别是当用户query泛化一点的时候,它更倾向去向量库那种“看似万能”的检索里碰运气。我建议你先把每个工具的描述改成“带明确限制条件”的句式,比如SQL那个写成“仅用于查询结构化字段,如日期、金额、项目名称精确匹配”,把“上线时间”这类关键词直接放进示例里,模型对示例的敏感度远高于抽象描述。不过说实话,光靠描述优化上限有限,我们后来还是加了个轻量级的意图分类层,先用一个few-shot分类器判断该走哪个工具,再让Agent去调MCP,准确率直接提了十几个点。另外你温度0.2其实可以再试试0.1,但我觉得更关键的还是让Agent在路由前先复述一下用户需求,强制它“思考”一下,不然就是纯赌博式选择。还有个细节,你参数schema里如果有些必填项,模型有时会因为不知道填什么而乱选工具,可以试着把必填字段改成可选,并给个默认值,减少决策压力。
工具描述写得再细也架不住模型瞎猜,建议先加一层轻量意图分类,命中再走工具,别全指望路由。
光调工具schema没用,这种场景真得加个意图识别兜底,不然就是模型拿概率硬猜。
遇到过类似的坑,工具描述写得太笼统模型确实容易懵。我后来把每个工具的描述改成带具体示例的短句,比如“查项目时间用这个,返回精确日期”,参数schema里也加上必填字段的枚举值,路由准了不少。不过说实话,多工具场景下纯靠模型自觉还是不稳,我这边最后加了个轻量级意图分类器做前置过滤,效果比单纯调prompt靠谱多了。你那个温度0.2其实已经很低了,问题大概率出在描述和实际能力的映射上,可以试试把SQL工具的名字改得更直白点,比如“精确查询业务数据库”。
遇到过类似的坑,工具描述写得越像人话,模型越容易选对,比如SQL工具里直接写明“查询结构化业务数据(项目时间、金额等)”,别光写“执行SQL”。另外感觉你这个问题不光是schema的事,DeepSeek本身在复杂工具选择上就偏保守,建议把意图识别做成显式的前置步骤,哪怕简单用关键词分类都行,比让模型自己猜稳得多。还有个细节,温度0.2可能还是高了点,我这边降到0.1之后工具调用稳定性明显好一些,你可以试试。
这问题我也踩过坑,工具描述写得太笼统的话模型根本分不清边界。后来我把每个工具的描述都改成带具体查询意图的示例句子,比如SQL那边直接写“当问到具体日期、金额、状态时用这个”,效果立刻好了不少。另外你温度0.2其实已经很低了,但DeepSeek对工具选择的置信度可能还是不够,我建议在MCP前面加个轻量的规则层做硬路由兜底,只把模糊场景丢给模型,不然纯靠它决策确实容易飘。
可以试试在工具描述里加上具体业务关键词和反例,比如“查时间用SQL别用向量库”。另外路由不准的话,独立意图识别层确实更稳。
碰到过类似的情况,当时也是把检索工具拆细了,结果模型跟个选择困难症似的,专挑描述最长的那个工具用,后来发现问题出在tool description太“模板化”了,全是“检索相关文档”这种,模型根本分不清边界。你那个SQL查询的描述里,建议直接写清楚“仅当问题包含具体项目名称、时间、状态等结构化字段时使用”,甚至可以把表结构的关键列名直接塞进去,让模型一眼看出这是个精确查询渠道。另外参数schema也别只给个query字段,加个可选的“查询类型”枚举,强制模型在生成参数时先做个轻量分类,虽然会增加一点推理消耗,但比它瞎路由强。至于意图识别层,我觉得短期兜底可行,但长期看你会多维护一个模型和一个规则集,反而把系统搞重了,不如先试试把工具描述按“触发条件+反例”重写一遍,比如向量库那边加一句“不要用于回答具体日期、金额、人员等可枚举信息”。还有个小坑,DeepSeek对工具调用的格式比其他模型更敏感,你温度0.2没问题,但max_tokens如果设太小,模型可能在生成工具参数时被截断,然后强行返回一个模糊答案,这个也排查下。
这题我太有同感了,之前搞MCP也是栽在工具描述上。你试试把“查询项目上线时间”这种具体场景直接写进工具description里,再加个参数示例,模型理解会准很多。但说实话,指望纯靠提示词路由不现实,DeepSeek在这种多工具选择上确实容易犯迷糊,我后来还是加了个轻量级意图分类器兜底,准确率才拉回来。另外你温度0.2还是偏高,可以再压到0.1试试。
这问题我也踩过坑,MCP的工具描述别写得太“功能化”,得把典型查询样例和边界条件塞进去,比如SQL工具里明确写“当问题涉及具体日期/金额/状态时优先选我”,模型吃这套。另外DeepSeek对多工具路由确实偏弱,独立意图识别层不是兜底,是刚需,先把高频问题分类硬编码,再让模型处理长尾,效果会稳很多。