最近在折腾MCP(模型上下文协议)对接DeepSeek API,想搞个能自动查天气和数据库的Agent。环境是Python 3.10 + FastMCP库,DeepSeek用的是chat模型。结果设置完tools之后,发送查询请求,DeepSeek那边一直返回空response,偶尔报个“函数调用参数格式错误”。我查了官方文档,tool定义里parameters写的是JSON Schema格式,应该没毛病啊……是不是MCP的tool调用方式和普通function calling有区别?还是说DeepSeek本身对MCP支持不完善?有没有踩过坑的老哥指点一下,感激不尽。
MCP对接DeepSeek时,模型一直返回空响应,是我姿势不对吗?
全部回复
共 189 条我之前也遇到过一模一样的坑,折腾了两天才发现是FastMCP版本和DeepSeek的tool schema兼容性问题。你确认一下FastMCP的版本,0.3.x和0.4.x对parameters的解析逻辑差异挺大的,老版本会把JSON Schema里的$schema字段也塞给模型,DeepSeek看到这个就懵了。另外你检查下返回的空响应是不是带了个finish_reason,如果显示tool_calls但内容为空,大概率是模型生成的参数里带了非法的引号或者换行符,DeepSeek对这块特别敏感。还有个骚操作是,手动把tools列表里的description字段缩短到50字以内,我之前发现DeepSeek的chat模型对超长描述的处理有bug,容易直接放弃调用。最后如果还不行,试试把MCP的tool定义包装成OpenAI的function format再转发,虽然绕了一圈但稳定得多。
大概率是MCP把工具名带前缀传给DeepSeek了,它不认,试试把tool名改成纯函数名。
大概率是tools参数没按DeepSeek的function calling规范来,试试直接用官方chat补全接口调一次看看。
MCP那层封装有时会自作主张改格式,建议先绕过FastMCP裸调API排查下。
八成是MCP把tool的调用格式包了一层,DeepSeek那边只认OpenAI那种function calling的原始结构,你直接传JSON Schema它不买账。我之前也卡这儿,后来手动把tools参数重新映射成name+parameters的扁平结构就好了。另外空响应也可能是temperature设太低或者max_tokens不够,模型生成一半被截断,你看下返回的finish_reason是不是length。
我之前也卡在这过,多半是MCP返回的tool结果格式跟DeepSeek预期的function calling不完全一致,尤其是parameters里嵌套的object类型,它有时候会强行要求某些字段必填。建议你先别用FastMCP的自动转换,直接打印出MCP发给DeepSeek的原始请求体,看看tool定义是不是被包了一层多余的结构。另外空响应偶尔是DeepSeek那边的超时或限流,重试几次可能就正常了,但如果是参数格式错,那基本就是schema里的enum或default字段不兼容,删掉试试。
我之前也卡在这块过,后来发现问题多半不在MCP本身,而是DeepSeek的tool calling对JSON Schema的解析比OpenAI严格得多。你试试把parameters里的type字段显式写成"object",然后每个属性都加上description,缺了这玩意儿它有时候直接罢工。另外FastMCP在包装工具时可能会自动改函数签名,你得确认传给模型的tools数组里每个function的name和实际注册的完全一致,别让框架给你加前缀后缀。至于空响应,我怀疑是模型返回了tool_call但你的代码没处理content为null的情况,DeepSeek在要调用工具时主回复字段就是空的,你得看finish_reason是不是"tool_calls"再决定怎么解析。还有个坑,如果temperature调太高或者max_tokens设太小,模型可能生成到一半就断了,也会表现为空。建议你先把数据库查询去掉,只留一个最简单的get_weather工具,用curl直接打DeepSeek的chat接口,手动把工具定义传进去看返回,这样能快速定位是协议层问题还是框架层问题。要是curl都报参数格式错,那八九不离十是Schema里某个类型写得不兼容,比如枚举值里混了数字和字符串。
我之前也遇到过一模一样的坑,最后发现问题不在DeepSeek,而是FastMCP对tool返回值的封装方式跟DeepSeek预期的function calling格式对不上。你直接在FastMCP里定义tools,它内部可能会把参数再包一层,DeepSeek解析的时候就会觉得schema不匹配,报“参数格式错误”或者直接给空response。建议你先用裸的OpenAI SDK调一下DeepSeek的function calling,确认模型本身没问题,再回头排查FastMCP的版本——我记得0.6.x和0.7.x的tool调用链改动挺大的。另外,DeepSeek对tool_choice的默认行为有点迷,有时候你不显式指定force,它就真的不调用工具,然后给你个空content。你试试在请求里把tool_choice设为auto或者required,看看响应里是不是会多出tool_calls字段。要是还不行,抓一下实际发出去的payload,比对一下官方文档里的JSON Schema,十有八九是某个属性名被FastMCP改了。我之前就是卡在这里,最后直接绕开FastMCP,自己拼请求体才搞定的,虽然丑但至少稳。
查一下是不是把MCP的工具名和参数名搞混了,DeepSeek对这块校验很严格,报错基本就是这原因。
我之前也卡这,后来发现是FastMCP版本问题,升级到最新版就好了,你可以试试。
大概率是MCP的tool返回格式跟DeepSeek预期的function calling不完全一致,试试把参数直接塞成字符串而非嵌套对象。
之前我也卡这,后来发现得用parameters里的strict模式或者手动把工具定义拍平,你查下是不是JSON Schema里required写漏了。
大概率不是DeepSeek的问题,是MCP把tool的JSON Schema又包装了一层,DeepSeek那边收到的参数格式跟原生function calling不一样,尤其是嵌套的parameters结构容易翻车。我之前也卡在这,后来直接打印请求体看实际传过去的东西,发现MCP会把tools包成带name和input_schema的格式,得手动转换一下。你可以试试在FastMCP里直接对tool做一层dict映射,把schema拍平再传,或者干脆绕过FastMCP,自己拼原生function calling的payload,虽然麻烦点但至少能定位问题在哪。
大概率是FastMCP把tool schema又包了一层,比如把parameters塞进了inputSchema之类的字段,DeepSeek那边不认这个结构,直接按标准function calling解析就空了。你试试抓一下实际发给API的请求体,对比OpenAI格式,把tools数组里的type和parameters层级改平。另外DeepSeek对严格模式支持一般,把tool_choice设为auto或者干脆不传,有时候反而能跑通。我之前也卡这,后来发现是FastMCP版本太新,降级到0.3.2就正常了。
大概率是MCP工具返回格式跟DeepSeek的function calling规范没对齐,参数得直接平铺不能嵌套。
我之前也卡这儿,后来把tools定义改成OpenAI兼容格式就好了,你可以试试。
我之前也被这个坑过,重点检查下tools传参是不是被FastMCP包装成了MCP格式,而DeepSeek那边只认OpenAI那种function calling结构。建议直接抓包看下实际发给API的payload,参数名和嵌套层级很容易不对。另外试试把strict模式关掉,或者手动把parameters转成标准JSON Schema,有时候库版本之间会有兼容问题。
大概率是MCP的tool返回格式和DeepSeek的function calling不完全兼容,试试把参数校验严格点或者直接用OpenAI兼容接口。
我之前也卡这儿半天,后来发现FastMCP默认的tool schema跟DeepSeek要的有点出入,手动改下strict模式就好了。
大概率是DeepSeek的tool calling和MCP的格式没完全对齐,把参数schema精简成最小必填项再试试。
我之前也卡在这过,大概率不是MCP的问题,而是DeepSeek对tool calling的response格式要求比较死板。你检查下返回的content是不是纯文本,有时候模型会返回个空对象,得自己兜底处理一下。
另外FastMCP默认的tool schema可能跟DeepSeek解析器不完全兼容,建议直接打印出实际发给API的payload,对比下官方示例里的参数结构,尤其是“type”字段千万不能漏。我之前就是少了这个,一直报参数格式错误。
我之前也卡在这块好几天,最后发现问题是DeepSeek对tool choice的处理跟OpenAI不太一样,如果MCP那边没显式指定强制调用某个工具,模型经常会返回空content,但其实arguments字段里是有东西的。你可以试试把返回的完整JSON打出来看,别只看content,有时候函数调用结果藏在tool_calls里,FastMCP可能没帮你解析透。另外你说的参数格式错误,我猜是嵌套结构问题,MCP的tool schema要求所有属性都包在properties里,而且每个字段都要有type和description,你检查下是不是有一层多余的对象包裹,或者数组类型少写了items定义。我之前就是漏了items,DeepSeek直接报错,加上就好了。还有个小坑,如果工具返回的结果本身是空字符串,模型可能误判为没调用成功,建议在工具函数里强制返回一个JSON字符串,哪怕没查到数据也返回个空对象。你要是方便的话,把报错的完整堆栈贴出来,我帮你看看是不是FastMCP版本跟DeepSeek的API响应格式有兼容性问题,我用的0.8.3版本就遇到过response解析异常,升级到0.9.1就好了。
我之前也遇到过类似的坑,大概率不是DeepSeek不支持MCP,而是FastMCP底层把tool的输入输出包了一层,和原生function calling的格式不完全一样,你试试直接打印一下发给API的原始请求看看。另外空响应有时候是temperature设太低或者max_tokens不够,模型生成到一半截断了,但这跟你说的参数报错对不上,建议先单独测一下不带tools的普通对话能不能通。如果确认是参数格式问题,可以检查下MCP工具定义里是不是用了$ref或者嵌套object,DeepSeek对复杂JSON Schema的解析偶尔会抽风,改成扁平结构或者用strict模式试试。
同款坑我踩过,FastMCP和DeepSeek的tool调用确实不能直接画等号,它内部可能把参数包了一层,导致DeepSeek解析不到。你试试把tools定义改成完全平铺的JSON,别用MCP的嵌套结构,然后再检查下response里有没有隐藏的error字段。另外空响应大概率是模型在等一个tool结果但没等到,你可以先本地mock一个工具返回,看链路通不通。
我之前也卡在这过,问题多半出在MCP的tool返回格式跟DeepSeek预期的function calling不完全一样,它内部对参数校验挺严格的。你试试把parameters里的每个字段都加上description,尤其是必填项,空响应有时候就是因为它解析不到字段含义。另外检查下FastMCP版本,老版本对strict模式支持有bug,升级到最新版再试下,我这边升级后就好了。