最近在折腾把公司内部的RAG知识库通过MCP暴露给Claude用,本来想着能直接让模型调工具查资料,省得每次手动喂上下文。结果实测发现,走MCP通道后,检索回来的chunk相关性明显不如之前在本地pipeline里的效果。我用的还是同一个embedding模型和向量库,只是把检索逻辑封装成了MCP tool。怀疑是MCP那边为了标准化,把一些过滤参数(比如top_k、相似度阈值)给简化掉了?或者是我对MCP的tool描述写得太简单,导致模型传参时不够精确?有没有大佬踩过类似的坑,指点一下调试方向,谢谢!
RAG接入MCP后检索质量反而下降了,是我姿势不对吗?
全部回复
共 27 条这个方向我试过,大概率不是MCP的锅,而是tool描述和参数映射的问题。模型在调用工具时,如果描述里没明确写清楚top_k和阈值的作用,它就会按自己的理解传一个通用值,比如默认取5条,但本地pipeline里你可能是按余弦相似度0.7过滤后再排序的,这俩逻辑完全不是一回事。建议你先把tool描述写得像接口文档一样细,把每个参数的范围、单位、影响都交代清楚,再在服务端把缺省值强制设成和本地一致,看看能不能找回效果。另外也可以打印一下模型实际传参的日志,对比下和本地调用的差异,基本能定位问题。
大概率是tool描述的问题,模型不知道每个参数该怎么填,就会按自己的理解瞎传,跟本地pipeline固定逻辑肯定没法比。你可以试试在描述里把top_k写成具体业务场景,比如“检索前20条最相关的,但只返回相似度大于0.7的”,让模型有明确依据。另外MCP那层如果真把阈值砍了,不如自己包装一层,把过滤逻辑留在tool内部,而不是依赖模型传参。我之前也遇到过类似情况,最后是直接给tool加了个默认参数兜底才救回来。
大概率是tool描述和参数映射的问题,MCP只是传输层,不会动你检索逻辑的。你试试把top_k和阈值写死在tool描述里,让模型只能选query,别让它自由发挥传参。另外检查下Claude调用时是不是把query自动做了改写,有时候模型会为了“理解意图”把原问题扩写,反而跟知识库里的chunk对不上。我之前也遇到过类似情况,最后是强制让模型传原始query不加任何润色才恢复效果的。
这问题我太熟了,十有八九是MCP把query预处理那层给吞了,比如本地pipeline里可能做了query改写或者去噪,封装成tool后模型直接拿原始问题去检索了。你可以先抓一下MCP实际传进检索函数的参数,跟本地跑的对比下,大概率能找到差异。另外tool描述里最好把检索意图、关键词权重这些写明确,不然模型瞎猜参数确实会掉点。
这个坑我太熟了,MCP封装检索不是简单把函数包一层就完事。你怀疑的方向大概率没错,尤其tool description写得太简陋时,模型根本不知道该怎么填参数,最后经常拿默认值或者瞎传一个模糊query进去,相关性自然就崩了。我建议你先在tool描述里把“什么时候用这个工具”“应该传什么格式的检索词”写得像给实习生看一样具体,甚至可以把历史有效query的例子直接塞进去。另外top_k和阈值被简化掉这个推测也合理,很多MCP实现为了让schema通用会砍掉自定义过滤字段,你可以试着在描述里暗示模型“如果结果不够精准,请降低相似度阈值重试”,让模型自己调参来弥补。还有个容易忽略的点是,本地pipeline里你可能有rerank或者关键词混合检索,但MCP工具里只暴露了向量检索,这一步降质往往比参数丢失更致命。我最后是直接在MCP server内部把rerank逻辑也封装进去,而不是只暴露一个裸的相似度搜索,效果才回到原来的水平。你可以先抓一下Claude实际传过来的参数日志,看看它到底是怎么调你的工具的,往往一眼就能看出问题。
先看看MCP tool的description里有没有把top_k和阈值写清楚,模型传参不准很常见,我当初也是描述太糊导致召回跑偏。
先查查MCP传参时top_k有没有被默认值覆盖,我踩过这坑,tool描述里没写清模型就乱猜。