快速结论:当 LiteLLM 通过 chat completions 处理工具调用、且模型把多个 JSON 参数对象拼接进同一个 tool_call 的 arguments 字符串时,parse_tool_call_arguments() 解析失败后返回 {},工具调用被静默丢弃(日志中可见 [Bug]: parse_tool_call_arguments silently drops tool calls with concatenated JSON arguments — split_concatenated_json_objects exists but is not used on this path)。优先排查代理日志中的解析警告,以及出问题的是不是 Ollama 模型路径。
适用环境:LiteLLM 1.101.0;镜像 ghcr.io/berriai/litellm:main-latest;路径为 chat completions + tool calling,工具通过 MCP 提供。报告中所有失败均来自 ollama_chat 路径;受影响模型(均经 Ollama):qwen3.8:27b、qwen3.6:27b、llama4:scout、mistral-large:123b。Bedrock、OpenRouter 及一条 OpenAI 兼容路径在约 35 轮工具调用 / 12 个模型上未观察到该问题。Issue 未提供操作系统、Python、CUDA 版本信息。
最快修复方案:暂无确认的一步修复方案。Issue 已关闭,但讨论中未给出已验证的合并补丁或版本号;报告者与接手者商定的方向是在 parse_tool_call_arguments() 抛错前回退调用 split_concatenated_json_objects()(对齐 factory.py:3628-3660 的 Bedrock 请求路径语义),并补充回归测试,但该改动是否已合并、发布在哪个版本,Issue 中没有明确证据。
注意事项:不要盲目按“取第一个对象”或“每个对象发一次调用”处理。报告者统计 70 个多对象负载:48 个(69%)各对象完全相同(同一调用重复 2–6 次),22 个(31%)各对象语义不同;0 个混合。取第一个会导致 31% 的场景执行了与调用方意图不同的请求;每个对象发一次会让 69% 的场景把同一调用重复最多 6 次。更关键的是,问题不止出现在只读搜索工具上——报告者称已触达 10 个不同工具,包含记忆写入(add / delete / replace),任意选择会造成错误的写入变更。若仅在测试环境下修复,注意失败在客户端与工具服务端都不可见,工具服务端日志不会出现任何请求,模型还会反馈调用“被后端拒绝”,容易误导排查方向。
问题场景
在 LiteLLM 中走 chat completions 接口做工具调用,工具通过 MCP 提供给模型。部分 Ollama 模型(尤其是带特定 chat template 的模型)在返回工具调用时,会把多个 JSON 参数对象拼接成一个 arguments 字符串,而不是拆成独立的 tool_calls[] 条目。此时响应路径上的解析函数失败,下游工具服务端收不到任何请求,模型也得不到可处理的错误,只能重试,往往再次产生同样形状的坏数据。
报告者在一个真实 agent 客户端(驱动 MCP 工具)场景下,单个模型一次会话中多次复现;后续统计窗口内共保留 70 个多对象负载,其中 2 个对象 26 次、3 个 36 次、4 个 4 次、5 个 2 次、6 个 2 次。
报错原文
Failed to parse tool call arguments for tool '<name>' (chat completions).
Error: Extra data: line 1 column 31 (char 30). Arguments: {...}{...}{...}
实际捕获到的 arguments 形状示例(字段名已泛化):
{"args": "{\"flag\": true}"}{"args": "{\"box\": \"A\", \"flag\": true, \"limit\": 50}"}{"args": "{\"since\": \"01-Jan-2025\", \"flag\": true}"}
原始标题与结论:
[Bug]: parse_tool_call_arguments silently drops tool calls with concatenated JSON arguments — split_concatenated_json_objects exists but is not used on this path
原因分析
核心原因是拼接 JSON 对象这一形状在两条路径上处理不一致:
- LiteLLM 已经能识别这种形状。
litellm_core_utils/prompt_templates/common_utils.py中定义了split_concatenated_json_objects(raw),其 docstring 明确提到部分提供方(尤其 Bedrock Claude Sonnet 4.5)会把多个工具调用参数对象拼进同一个arguments字符串,json.loads()会以JSONDecodeError: Extra data失败,该辅助函数用json.JSONDecoder.raw_decode()逐个提取对象。 - 但该辅助函数只接进了一个地方:Bedrock 请求转换逻辑(
factory.py:3628-3660,注释引用issues/20543),其行为是每个解析出的对象生成一个toolUse块,第一个保留原 tool id。 - 它没有接进
parse_tool_call_arguments()(common_utils.py:2108),也就是 chat completions 的响应路径。于是同一种提供方行为在一个方向上被修复,在另一个方向上被静默丢弃:解析抛错,调用方记录 warning 后return {}(factory.py:5368),工具调用消失。
至于为什么部分 Ollama 模型会产出拼接形状,报告者(与 Claude Code 共同分析)的可能原因假设是模型的 Ollama chat template:会输出多个工具调用的模板,可能把它们序列化进同一个 arguments 字符串,而不是分开的 tool_calls[] 条目。该假设未获官方确认,且失败不沿厂商边界分布(Qwen 3.6/3.8 失败而 Qwen3.5 未观察到,Llama 4 失败而 Llama 3.3 未观察到,Mistral-Large 经 Ollama 失败而 Mistral 经 Bedrock 未观察到)。
另一个值得注意的复现线索:简单请求无法复现。报告者对贡献了 70 次失败中 64 次的模型,用测试脚本尝试 18 次(单工具与十工具、嵌套与扁平 schema、temperature 0 与 0.7、多种提示风格包括明确要求并行调用)全部干净,并行请求在测试脚本下会正确拆成独立 tool_calls[]。同一个模型在真实 agent 客户端通过 MCP 驱动工具时几秒内就失败。触发条件可能不在工具 schema,而在更丰富的上下文(同时注册大量工具、带长前缀的工具名、多轮历史)。因此用单个工具调用构造的最小单元测试很可能通过,但证明不了什么。
环境排查
- 确认 LiteLLM 版本是否为 1.101.0、是否使用
ghcr.io/berriai/litellm:main-latest镜像。 - 确认请求走的是哪条提供方路径:报告中所有失败均来自
ollama_chat;Bedrock、OpenRouter、OpenAI 兼容路径在报告者的有限样本中未观察到,但非 Ollama 路径每模型样本仅 2–6 轮,应把“未观察到”理解为“未观察到”,而非“免疫”。 - 确认涉及的 Ollama 模型与 chat template,重点核对是否属于已报告失败的类型(qwen3.8:27b、qwen3.6:27b、llama4:scout、mistral-large:123b)。
- 确认调用方式是 chat completions + tool calling,且工具经 MCP 提供,并检查是否处于同时注册大量工具、工具名带长前缀、多轮历史的真实 agent 上下文中——简单测试环境可能无法复现。
- Issue 未提供操作系统、Python、CUDA、PyTorch、显卡信息,排查时无需假设具体版本,以实际部署为准。
解决步骤
- 先在代理日志中确认是否为解析失败而非工具未调用。搜索类似
Failed to parse tool call arguments for tool的 warning,并核对参数是否呈{...}{...}拼接形状。这是定位问题的关键一步——客户端和工具服务端都看不到任何痕迹。 - 不要只从工具服务端日志判断:请求根本没有到达,日志静默是必然的;也不要仅凭模型反馈“调用被后端拒绝”就换方向排查。
- 暂时降低影响面:若业务中包含记忆写入类(add / delete / replace)等有副作用的工具,在修复落地前谨慎开启,避免在拼接形状出现时产生错误变更。
- 可优先尝试在本地/自维护分支中,让
parse_tool_call_arguments()在抛错前回退调用split_concatenated_json_objects(),与factory.py:3628-3660的 Bedrock 请求路径语义保持一致(每个对象一个调用、第一个保留原 tool id)。该做法是 Issue 讨论中商定的方向,但未在此 Issue 中确认已合并,属可优先尝试而非确认修复。 - 如采用回退方案,注意区分对象是否完全相同:报告者建议先对结构完全相同的对象去重,这能确定性地覆盖 69% 的多数场景;剩余语义不同的场景再选择“每个对象一次调用”或“显式报错”,避免在多个不同请求中任意挑选。
- 若暂不做抢救式解析,至少不要再
return {}:把失败作为错误暴露给调用方(报告者的 option 2),使客户端能区分“模型什么都没请求”和“模型的请求被丢弃”,这本身也是明显改善。 - 若你愿意提交修复,按讨论中的约定在
test_litellm_core_utils_prompt_templates_common_utils.py增加回归测试,覆盖报告中的多对象拼接形状。
验证方法
确认代理日志中不再出现该工具的 Failed to parse tool call arguments warning,且拼接形状的参数被正确拆成多个(或经过去重后的)有效调用;同时确认工具服务端实际收到了请求(此前它的日志是完全静默的)。由于简单请求难以复现,验证时应在真实 agent 客户端通过 MCP 驱动工具、并保持较多工具注册和多轮历史的上下文,单工具最小用例通过并不足以证明修复有效。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。
![[ISSUE]: TextGen Fails to load GGUF models on multiple browsers, different textgen versions.](https://www.chat-gpts.plus/wp-content/uploads/2026/09/7530-3d63106e-768x403.jpg)

![Misc. bug: Vulkan ARGSORT ne=[2048,1,1,1] only sorts half of the array on some devices](https://www.chat-gpts.plus/wp-content/uploads/2026/09/29431-0e9cbdaa-768x403.jpg)