
在 Claude Code 里敲完一段长回答点下 Stop后台 LiteLLM 立刻抛litellm.BadRequestError: Unsupported parameter(s): stop_sequences。这种报错最难受的地方在于你只是按了一个停止按钮实际却把 Anthropic 格式里的stop_sequences参数一路透传到了不支持它的 NVIDIA NIM 端点。先别一头扎进源码打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 用 TaoToken 创建一把 API Key把 Claude Code 的ANTHROPIC_BASE_URL改成https://taotoken.net/api让会话先有一条稳定通道然后按原文 2.3 节的办法抓 Stop 时的请求体保留stop_sequences字段再回到 LiteLLM 的transformation.py对照参数映射。这样排查时你能分清到底是模型通道不通还是 LiteLLM 把不该传的参数放进了 payload。1. 复现点 Stop 后 LiteLLM 日志里的 stop_sequences 4001.1 报错长什么样别把锅先甩给 Claude Code原文里的现场很典型Claude Code 正常聊天没问题一旦点击 StopLiteLLM 后台就打印litellm.BadRequestError: Unsupported parameter(s): stop_sequences很多人第一反应是 Claude Code 发错了请求或者 NVIDIA NIM 太挑。其实 Claude Code 走的是 Anthropic Messages API 形状stop_sequences在 Anthropic 侧是合法参数用来告诉模型遇到哪些字符串就停。问题出在 LiteLLM 把它代理到 OpenAI 兼容端点时没有在正确的层把这个参数丢掉或改名。NVIDIA NIM 的 OpenAI 兼容接口不认识stop_sequences于是返回 400。复现路径可以写得很清楚Claude Code 配置 LiteLLM 作为ANTHROPIC_BASE_URLLiteLLM 的model_list指向 NVIDIA NIM 的某个模型drop_params: true也加了但点 Stop 仍然报错。这里的关键不是“能不能聊天”而是“Stop 这个动作有没有触发额外参数”。1.2 为什么 drop_paramstrue 在这个链路里像没生效drop_params在 LiteLLM 里不是万能开关。它通常在litellm.completion主入口附近检查 provider 支持的参数列表然后把不支持的字段删掉。但 Claude Code 打到 LiteLLM 的可能是/v1/messages这条路径会走 Anthropic 直通或 Anthropic 适配器不一定经过你印象里的completion参数过滤。换句话说你在config.yaml里写了drop_params: true只代表“如果走到那个过滤逻辑就丢”。问题是这次调用可能压根没走到。要确认这件事不能靠猜必须把 Stop 时的请求体和 LiteLLM 内部转换链一起抓出来。后面第 3 节和第 4 节就是干这个的。注意不要一上来就改 NVIDIA NIM 的模型配置也不要反复重启 Claude Code。先把请求体拿到再决定改 LiteLLM 的哪一层。2. 先把 Claude Code 的请求通道切到 TaoToken排除模型侧干扰2.1 去官网创建 Key 并确认模型 ID原文让你去 NVIDIA 侧申请 Key、找模型名这里把动作换到同一个位置打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册后进入控制台创建 API Key。Key 只用于占位演示写成YOUR_API_KEY。模型 ID 不要凭记忆写也不要用网上抄来的日期后缀以模型广场当时列表为准。拿到 Key 后先不要急着接 LiteLLM。你可以把 TaoToken 当成 Claude Code 的上游通道让 Claude Code 能正常发起会话。这样做的目的不是“绕过问题”而是把模型通道本身变成已知量如果普通对话能通说明 Base URL、Key、模型 ID 三件事没填错那么 Stop 报错就更可能落在 LiteLLM 的参数转换层。2.2 ~/.claude/settings.json 里填 ANTHROPIC_BASE_URL 与占位 KeyClaude Code 支持通过环境变量或~/.claude/settings.json的env配置 Anthropic 兼容入口。推荐先写配置文件避免每次开终端都重新 export{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID } }这里三个点别写错ANTHROPIC_BASE_URL填https://taotoken.net/api末尾不要加/v1。ANTHROPIC_AUTH_TOKEN用你在 TaoToken 创建的 Key示例里统一写YOUR_API_KEY。ANTHROPIC_MODEL写模型广场里真实存在的模型 ID不要自己编gpt-5或随意日期后缀。如果你更习惯环境变量也可以这样export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENYOUR_API_KEY export ANTHROPIC_MODELYOUR_MODEL_ID保存后重开一个终端让 Claude Code 重新读取配置。2.3 用一次普通对话验证通道不要急着点 Stop先发一句普通问题比如“用三句话解释什么是消息队列”。能正常返回说明通道已经通了。此时再打开 LiteLLM 的调试日志把 Claude Code 的请求指向 LiteLLM或者让 LiteLLM 的上游指向 TaoToken 兼容通道方便对照。这一步的验证价值很高如果普通对话都 401 或 404你后面看到的stop_sequences报错可能只是另一个错误的副作用。把通道问题和参数问题分开是排障里最省时间的一步。3. 抓 Stop 请求体原文 2.3 节那只“黑匣子”怎么打开3.1 LiteLLM 详细日志与请求转储开关原文 2.3 节的核心是抓 Stop 时的请求体。LiteLLM 可以用详细日志把请求 dump 出来。启动时加参数litellm --config config.yaml --detailed_debug或者设置环境变量export LITELLM_LOGDEBUG然后在 Claude Code 里触发一次长回答再点 Stop。观察 LiteLLM 终端日志重点找POST /v1/messages或对应的上游请求记录。日志里会带一段 JSON body里面通常能看到{ model: YOUR_MODEL_ID, max_tokens: 1024, messages: [ { role: user, content: 写一段较长的解释 } ], stop_sequences: [\n\nHuman:] }注意stop_sequences字段。原文让你保留它是因为只有看到它确实还在 body 里才能继续往下追LiteLLM 是在转换时没删还是删了但上游又生成了。3.2 在日志里只盯 stop_sequences 字段日志很长别从头读到尾。用搜索过滤grep -n stop_sequences litellm.log或者直接在终端里搜stop_sequences。你要确认三件事Claude Code 发到 LiteLLM 的原始请求里有没有stop_sequences。LiteLLM 发到上游的最终请求里有没有它。报错信息里的Unsupported parameter(s)是在哪一步抛出的。如果原始请求有、最终请求也有说明 LiteLLM 没有丢弃它如果原始请求有、最终请求没有但上游还报错那可能是另一个参数或另一个模型通道的问题。本文场景要盯的是第一种。3.3 用 TaoToken 通道做对照区分通道错和参数错把 LiteLLM 的其中一个model_name指到 TaoToken 兼容通道配置里填model_list: - model_name: claude-code-stop-test litellm_params: model: openai/YOUR_MODEL_ID api_base: https://taotoken.net/api api_key: YOUR_API_KEY drop_params: true再让 Claude Code 通过 LiteLLM 走这个model_name发普通请求。如果普通请求正常点 Stop 时观察日志里stop_sequences是否仍然透传。这里 TaoToken 的作用是提供一条可用的模型通道让请求能到达模型侧方便你把“通道错”和“参数错”分开。真正定位stop_sequences在哪一层被塞进 payload仍然要回到第 4 节的 LiteLLM 源码。4. 回到 LiteLLM 源码transformation.py 里 stop_sequences 到底被谁透传4.1 anthropic 到 openai 兼容格式的参数映射链LiteLLM 的 Anthropic 适配通常在litellm/llms/anthropic/chat/transformation.py附近。你可以先搜stop_sequencesgrep -R stop_sequences litellm/llms/anthropic/chat/大概率会看到它在transform_request或map_openai_params里被处理。Anthropic 的stop_sequences对应 OpenAI 风格的stop。如果目标 provider 不支持stop正确做法是在映射层丢掉或者在 provider 支持列表里排除它。但 Claude Code 打到/v1/messages时请求可能先经过 Anthropic endpoint 的直通逻辑再进 transformation顺序一变drop_params就可能来不及生效。4.2 drop_params 的生效位置与 /v1/messages 直通路径drop_params常见生效位置在litellm/main.py或litellm/utils.py的get_optional_params附近。它依赖get_supported_openai_params返回的列表。如果 Anthropic 直通路径没有调用这套过滤或者调用时把stop_sequences当成 Anthropic 原生参数而不是 OpenAI 可选参数它就不会被删。原文说drop_params无效根因通常就在这里你以为它管的是“所有参数”实际它只管“走 OpenAI completion 参数映射的那部分”。要修得干净不能在业务层反复传drop_params而要在转换层补一刀。4.3 源码级修复思路在映射层丢掉或重命名一个最小 patch 思路是在 Anthropic 转换逻辑里判断目标 provider 是否支持停止序列。伪代码可以写成# 文件litellm/llms/anthropic/chat/transformation.py def transform_request(self, ...): optional_params super().transform_request(...) if stop_sequences in optional_params: if self.supports_stop_sequences(): optional_params[stop] optional_params.pop(stop_sequences) else: optional_params.pop(stop_sequences, None) return optional_params真实实现要按你安装的 LiteLLM 版本调整。关键是补在“Anthropic 参数进入 OpenAI 兼容 payload 之前”的那一层。改完以后不要只重启 Claude Code还要重启 LiteLLM 进程否则 Python 模块缓存不会更新。提示本地 patch 优先放在自己的 fork 或虚拟环境里升级 LiteLLM 前先记录 diff避免下次覆盖。5. 修完后验证Stop、继续、恢复会话三个动作5.1 重启 LiteLLM 与 Claude Code 会话修改transformation.py后先停掉 LiteLLM 服务再重新运行litellm --config config.yaml --detailed_debug然后退出 Claude Code 会话并重开。环境变量和~/.claude/settings.json都要重新读取。如果只重启 Claude Code 不重启 LiteLLM日志里可能还是旧逻辑验证会误判。5.2 看日志里 stop_sequences 是消失还是变成 stop再次发长回答并点 Stop。搜索日志grep -n stop_sequences\|stop litellm.log如果补丁正确你会看到两种结果之一stop_sequences在发往不支持它的上游前被丢掉或者它被改写成目标 provider 认识的stop。如果仍然报 400检查 patch 是否放在正确的类、是否被其他分支提前返回覆盖以及目标 provider 的get_supported_openai_params是否真的排除了stop。5.3 去控制台对一下这次调用有没有记上账通道验证做完后打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 进入控制台看这次 Claude Code 调用有没有出现在用量记录里。模型 ID 是否选对、Base URL 是否误写成https://taotoken.net/api/v1、Key 是否复制完整都会在这里暴露。如果你发现普通对话有记录、Stop 测试没有记录那说明请求还没到通道层问题仍在 LiteLLM 参数转换或本地代理上。6. 排障对照401、404、/v1、模型 ID 与 stop_sequences 误判6.1 通道类错误通常长什么样现象可能原因处理401 UnauthorizedANTHROPIC_AUTH_TOKEN为空或 Key 复制错回到控制台重新创建YOUR_API_KEY404 Not FoundANTHROPIC_BASE_URL多写了/v1改回https://taotoken.net/api模型不存在ANTHROPIC_MODEL写了不存在的 ID以模型广场当时列表为准400 stop_sequencesLiteLLM 把 Anthropic 参数透传给不支持的供应商查transformation.py映射层这张表只服务本文场景你先把 Claude Code 的通道切到 TaoToken再用 LiteLLM 做参数对照。不要看到 400 就反复换 Key也不要看到 401 就跑去改transformation.py。6.2 本文场景专属的误判别把参数问题当鉴权问题stop_sequences报错最像鉴权问题的地方是它也在 LiteLLM 日志里以红色堆栈出现。但它的文本明确写了Unsupported parameter(s)说明请求已经到达了上游或上游适配层Key 大概率是通的。真要验证可以用同一把 Key 在模型对话里发一条普通消息如果普通消息正常Stop 才报错那就把精力放回 LiteLLM 源码而不是继续换 Key。另一个误判是“模型不支持停止序列所以 Claude Code 不能用”。Claude Code 发stop_sequences是它的协议行为正确做法是让代理层适配而不是要求 Claude Code 改行为。7. 下一步把模型对话、Coding Plan 和接入文档串起来如果你已经抓到 Stop 时的请求体也确认了transformation.py里是哪一段把stop_sequences透传出去接下来最值得做的是打开 TaoToken 模型对话 用同一把 Key 发一条测试消息确认模型 ID 和 Base URL 没填错。长期用 Claude Code 写代码可以看 Coding Plan 是否够用Key 在 控制台 API Keys 创建Claude Code 环境变量对照见 接入文档。等你把 patch 跑通再回控制台看这次 Stop 测试有没有被正常计费然后决定是把补丁停在本地还是整理成 issue 或 PR 推回 LiteLLM。