点 Stop 刷 stop_sequences 400?TaoToken 这样改通道再对照 LiteLLM 源码
2026/9/19 8:50:56 网站建设 项目流程

在 Claude Code 里敲完一段长回答,点下 Stop,后台 LiteLLM 立刻抛litellm.BadRequestError: Unsupported parameter(s): stop_sequences。这种报错最难受的地方在于:你只是按了一个停止按钮,实际却把 Anthropic 格式里的stop_sequences参数一路透传到了不支持它的 NVIDIA NIM 端点。先别一头扎进源码,打开 https://taotoken.net/?utm_source=taotoken_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 400

1.1 报错长什么样,别把锅先甩给 Claude Code

原文里的现场很典型:Claude Code 正常聊天没问题,一旦点击 Stop,LiteLLM 后台就打印:

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_URL,LiteLLM 的model_list指向 NVIDIA NIM 的某个模型,drop_params: true也加了,但点 Stop 仍然报错。这里的关键不是“能不能聊天”,而是“Stop 这个动作有没有触发额外参数”。

1.2 为什么 drop_params=true 在这个链路里像没生效

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_source=taotoken_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 与占位 Key

Claude Code 支持通过环境变量或~/.claude/settings.jsonenv配置 Anthropic 兼容入口。推荐先写配置文件,避免每次开终端都重新 export:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_MODEL_ID" } }

这里三个点别写错:

  • ANTHROPIC_BASE_URLhttps://taotoken.net/api,末尾不要加/v1
  • ANTHROPIC_AUTH_TOKEN用你在 TaoToken 创建的 Key,示例里统一写YOUR_API_KEY
  • ANTHROPIC_MODEL写模型广场里真实存在的模型 ID,不要自己编gpt-5或随意日期后缀。

如果你更习惯环境变量,也可以这样:

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="YOUR_API_KEY" export ANTHROPIC_MODEL="YOUR_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_LOG="DEBUG"

然后在 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。你要确认三件事:

  1. Claude Code 发到 LiteLLM 的原始请求里有没有stop_sequences
  2. LiteLLM 发到上游的最终请求里有没有它。
  3. 报错信息里的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_sequences

grep -R "stop_sequences" litellm/llms/anthropic/chat/

大概率会看到它在transform_requestmap_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.pylitellm/utils.pyget_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_source=taotoken_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_KEY
404 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。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询