Claude Code + CCR + AWS Bedrock 踩坑复盘:上下文超限、模型路由、Mantle 端点与 Qwen3 Coder Next

最近在使用 Claude Code + Claude Code Router(CCR)+ AWS Bedrock 模型 做代码开发时,遇到了一连串和上下文长度、模型路由、AWS 端点类型相关的问题。表面上看只是一个 context length exceeded 报错,实际排查下来牵扯到:

  • Claude Code 如何组织上下文;
  • CCR 如何判断长上下文并切换模型;
  • AWS Bedrock 上不同模型的上下文窗口;
  • Bedrock Mantle endpoint 与 Bedrock Runtime endpoint 的差异;
  • OpenAI 兼容接口、Responses / Chat Completions、Converse / InvokeModel 之间的调用方式差别;
  • CCR 日志应该怎么看;
  • 如何查询自己能用哪些 Mantle 模型。

这篇文章把这次排查过程整理下来,作为后续使用 Claude Code + CCR + AWS Bedrock 的避坑记录。


一、问题背景

我的调用链路大致是:

text 复制代码
Claude Code
  -> Claude Code Router
  -> AWS Bedrock Mantle endpoint
  -> 后端模型,例如 GLM-5 / MiniMax / Qwen3 Coder Next

一开始我使用的是 GLM-5,后来尝试 MiniMax,最后临时换成 Qwen3 Coder Next 才稳定解决上下文超限问题。

Claude Code Router 本身的作用就是把 Claude Code 的请求路由到不同模型,并可以通过 transformer 适配不同供应商 API。CCR 官方说明它支持模型路由、多 provider、请求/响应转换、动态模型切换和插件系统。(GitHub)

我的典型 CCR 配置结构类似这样:

json 复制代码
{
  "PORT": 3456,
  "LOG": true,
  "API_TIMEOUT_MS": 1200000,
  "Providers": [
    {
      "name": "aws-bedrock",
      "api_base_url": "https://bedrock-mantle.us-east-1.api.aws/v1/chat/completions",
      "api_key": "$BEDROCK_MANTLE_API_KEY",
      "max_tokens": 31000,
      "models": [
        "zai.glm-5",
        "minimax.minimax-m2",
        "qwen.qwen3-coder-next"
      ],
      "transformer": {
        "use": [
          ["openai"]
        ]
      }
    }
  ],
  "Router": {
    "default": "aws-bedrock,qwen.qwen3-coder-next",
    "background": "aws-bedrock,qwen.qwen3-coder-next",
    "think": "aws-bedrock,qwen.qwen3-coder-next",
    "longContext": "aws-bedrock,qwen.qwen3-coder-next",
    "longContextThreshold": 60000
  }
}

注意:实际使用时不要把 API key 明文写进配置文件,建议放环境变量。


二、最开始遇到的错误:上下文超过模型限制

最典型的错误如下:

text 复制代码
This model's maximum context length is 202752 tokens.
However, you requested 32000 output tokens and your prompt contains at least 170753 input tokens,
for a total of at least 202753 tokens.
Please reduce the length of the input prompt or the number of requested output tokens.

这个错误很直观:

text 复制代码
模型最大上下文:202752
输入 token:170753
请求输出 token:32000
总计:202753

刚好多了:

text 复制代码
202753 - 202752 = 1

后来换 MiniMax 时也遇到类似问题:

text 复制代码
This model's maximum context length is 196608 tokens.
However, you requested 32000 output tokens and your prompt contains at least 164609 input tokens,
for a total of at least 196609 tokens.

同样是刚好多 1:

text 复制代码
196609 - 196608 = 1

这个现象很容易让人怀疑是 CCR、transformer 或 provider 适配层里的 off-by-one 边界问题。

GLM-5是203K上下文,MINIMAX-2号称是256K上下文。从GLM-5换成MINIMAX-2是试图通过改用更大大上下文的模型来解决本次会话中上下文超大的问题。不幸的是,MINIMAX-2实际只有196K上下文。这里的信息来源有点不太属实--AWS上文档可能写错了,MINIMAX-2.5可能才是256K。

但从服务端角度看,它只是严格按照下面这个规则校验:

text 复制代码
input_tokens + requested_output_tokens <= maximum_context_length

只要超过 1 token,也会直接返回 400。

所以这类问题不能靠侥幸贴边解决,必须给上下文和输出留安全余量。


三、CCR 日志怎么解读

CCR 开启日志后,可以看到类似下面的日志:

json 复制代码
{
  "level": 30,
  "time": 1777363452122,
  "pid": 92877,
  "hostname": "BILLY",
  "reqId": "req-8",
  "msg": "Using long context model due to token count: 168448, threshold: 60000"
}

这条日志非常关键,它说明:

text 复制代码
CCR 估算当前请求 token 数是 168448
longContextThreshold 配置的是 60000
因为 168448 > 60000
所以 CCR 使用 Router.longContext 配置的模型

也就是说,这条日志是 CCR 触发长上下文路由的证据

CCR 官方文档里有对应配置示例:

json 复制代码
{
  "Router": {
    "longContextThreshold": 100000,
    "longContext": "gemini,gemini-1.5-pro"
  }
}

官方说明这是用于将长上下文请求路由到指定模型。

所以这条日志不是错误,而是在告诉你:

text 复制代码
CCR 认为当前请求已经是长上下文请求,并且正在切到 longContext 模型。

四、CCR 中表明"切换到另一个模型"的证据

判断 CCR 是否切换模型,主要看两类日志。

第一类是长上下文路由日志:

text 复制代码
Using long context model due to token count: 168448, threshold: 60000

这说明它使用了:

json 复制代码
"Router": {
  "longContext": "provider,model"
}

第二类是 provider 报错中的模型名。例如:

text 复制代码
Error from provider(aws-glm5,minimax.minimax-m2: 400)

这说明这次请求最终打到了:

text 复制代码
provider = aws-glm5
model = minimax.minimax-m2

如果你看到:

text 复制代码
Error from provider(aws-bedrock,qwen.qwen3-coder-next: 400)

那说明请求最终打到了:

text 复制代码
provider = aws-bedrock
model = qwen.qwen3-coder-next

所以要判断模型是否切换成功,不要只看 Claude Code 欢迎页显示什么,还要看 CCR 日志里的 provider/model。

CCR 的路由格式是:

text 复制代码
provider,model

官方文档也明确说明 fallback 和路由模型使用 provider,model 格式,并且 backup model 必须存在于 Providers 配置里。(MusiStudio)


五、longContextThreshold 不是上下文上限

我一开始很容易误解:

json 复制代码
"longContextThreshold": 60000

这个配置不是说模型最大上下文是 60000,也不是说输入超过 60000 会被自动压缩。

它只是说:

text 复制代码
当 CCR 估算请求 token 超过 60000 时,切到 Router.longContext 指定的模型。

例如:

json 复制代码
"Router": {
  "default": "aws-bedrock,zai.glm-5",
  "longContext": "aws-bedrock,qwen.qwen3-coder-next",
  "longContextThreshold": 60000
}

含义是:

text 复制代码
普通请求走 GLM-5
超过 60000 token 的请求走 Qwen3 Coder Next

如果你这样配置:

json 复制代码
"Router": {
  "default": "aws-bedrock,zai.glm-5",
  "longContext": "aws-bedrock,zai.glm-5",
  "longContextThreshold": 60000
}

那虽然 CCR 会判断"这是长上下文",但最终还是走同一个模型,实际上不会解决上下文不够的问题。


六、为什么最后换 Qwen3 Coder Next

这次排查中,我先后尝试了 GLM-5、MiniMax,最后发现 Qwen3 Coder Next 的上下文达到256,能够解决本次的问题。

AWS Bedrock 官方模型卡显示,Qwen3 Coder Next 是面向代码生成、调试和软件工程能力优化的模型。官方文档中它的模型 ID 是:

text 复制代码
qwen.qwen3-coder-next

并且文档写明:

text 复制代码
Context window: 256K tokens
Max output tokens: 32K

同时它支持 ResponsesChat CompletionsInvokeConverse 等接口类型,并支持 bedrock-runtimebedrock-mantle 端点。AWS 文档还特别提示,尽可能使用 bedrock-mantle endpoint。(AWS 文档)

这里有一个有趣的体验:

实测下来,Claude Code + Qwen3 Coder Next 的效果不差。我的感觉是,Claude Code 本身对上下文组织得比较好,它会把文件、工具调用、历史信息组织成模型比较容易理解的形式。也就是说,模型本身重要,但 Claude Code 的上下文组织方式也非常关键。

这次我看到一条请求达到:

text 复制代码
168448 tokens

一行日志甚至达到:

text 复制代码
约 690K 字符

这说明 Claude Code + CCR 这种链路里,上下文膨胀是非常真实的问题。尤其是 Claude Code 读取大文件、长文档、多轮工具调用之后,输入 token 很容易暴涨。


七、为什么 max_tokens 配了没生效

我曾经在 CCR Provider 里配置:

json 复制代码
"max_tokens": 8192

但报错里仍然显示:

text 复制代码
requested 32000 output tokens

这说明 provider 级别的 max_tokens 并不一定能覆盖 Claude Code 上游传入的输出上限,或者在当前 transformer 链路里被透传了。

比较稳妥的做法是两边都配:

CCR 侧

json 复制代码
"max_tokens": 31000

Claude Code 侧

bash 复制代码
export CLAUDE_CODE_MAX_OUTPUT_TOKENS=31000

因为我是在WSL下的相应代码目录里执行code . 拉起claude插件的,所以还要source ~/.bashrc才能让配置生效。不过最后这个方法没能解决上下文控制的问题。与我的聊天历史有关,因为历史已经走到要发送大的上下文了,此时的配置已经控制不到历史消息了,只能对新消息有效果。

如果还看到服务端报:

text 复制代码
requested 32000 output tokens

说明最终请求体里仍然是 32000,这时需要进一步检查 CCR 的 transformer,甚至需要自定义 transformer,在请求转发前强制 clamp:

js 复制代码
body.max_tokens = Math.min(body.max_tokens || 31000, 31000)

八、Bedrock Mantle endpoint 和 Runtime endpoint 的坑

这次另一个很大的坑,是 AWS Bedrock 上有不同类型的端点。

我实际踩到的是:

text 复制代码
一种是 bedrock-mantle endpoint
一种是 bedrock-runtime endpoint

例如 Qwen3 Coder Next 的 AWS 官方文档中就明确列出了两类 programmatic access:

text 复制代码
bedrock-runtime -> qwen.qwen3-coder-next -> https://bedrock-runtime.{region}.amazonaws.com
bedrock-mantle  -> qwen.qwen3-coder-next -> https://bedrock-mantle.{region}.api.aws/v1

并且官方文档写明,如果 region 是 us-east-1,对应 endpoint 分别是:

text 复制代码
https://bedrock-runtime.us-east-1.amazonaws.com
https://bedrock-mantle.us-east-1.api.aws/v1

AWS 文档还提示:Whenever possible, use the bedrock-mantle endpoint。(AWS 文档)

这两类端点的使用方式不一样:

1. Mantle endpoint

Mantle endpoint 更像 OpenAI 兼容接口,例如:

text 复制代码
https://bedrock-mantle.us-east-1.api.aws/v1/chat/completions

它适合 CCR 这类 OpenAI-compatible router 使用。

CCR 配置里通常是:

json 复制代码
{
  "api_base_url": "https://bedrock-mantle.us-east-1.api.aws/v1/chat/completions",
  "api_key": "$BEDROCK_MANTLE_API_KEY",
  "transformer": {
    "use": [
      ["openai"]
    ]
  }
}

这里的认证方式一般是:

http 复制代码
Authorization: Bearer XXXX

2. Runtime endpoint

Runtime endpoint 是 AWS 原生 Bedrock Runtime API,例如:

text 复制代码
https://bedrock-runtime.us-east-1.amazonaws.com

它不是简单的 OpenAI-compatible chat/completions 调用方式,而是 AWS Bedrock Runtime 的 API,例如 Converse。AWS Converse API 的请求路径是:

text 复制代码
POST /model/modelId/converse

请求体中有 messagessysteminferenceConfig.maxTokenstoolConfig 等字段。(AWS 文档)

这类接口通常走 AWS SDK 或 SigV4 签名,也就是使用:

text 复制代码
aws_access_key_id
aws_secret_access_key
region

这种方式,而不是简单的 HTTP Bearer token。

所以我的理解是:

text 复制代码
CCR + OpenAI transformer 更适合接 Mantle endpoint
AWS SDK / boto3 / 原生 Bedrock 调用更适合接 Runtime endpoint

把 Runtime endpoint 当成 Mantle/OpenAI endpoint 配进 CCR,很容易出现模型不支持、接口不匹配、认证方式不对等问题。


九、如何列出自己能用哪些 Mantle 模型

这是最实用的一条命令。

如果你使用 Bedrock Mantle endpoint,可以直接调用:

bash 复制代码
curl -X GET https://bedrock-mantle.us-east-1.api.aws/v1/models \
  -H "Authorization: Bearer XXXX"

注意:

text 复制代码
XXXX 替换成自己的 Mantle API Key
不要把真实 key 发到博客、GitHub、聊天工具里

如果返回成功,会看到当前 API key 能访问的模型列表。然后你就可以从里面挑模型 ID,写进 CCR 的 modelsRouter 里。

例如:

json 复制代码
"models": [
  "qwen.qwen3-coder-next",
  "zai.glm-5",
  "minimax.minimax-m2"
]

Router 里再写:

json 复制代码
"Router": {
  "default": "aws-bedrock,qwen.qwen3-coder-next",
  "longContext": "aws-bedrock,qwen.qwen3-coder-next",
  "longContextThreshold": 60000
}

另外,如果你走的是 AWS 原生 Bedrock API,也可以用 AWS 的 ListFoundationModels API。AWS 官方说明 ListFoundationModels 用于列出可使用的 Amazon Bedrock foundation models,并支持按 provider、output modality、inference type 等过滤。(AWS 文档)

AWS CLI 方式通常类似:

bash 复制代码
aws bedrock list-foundation-models --region us-east-1

但要注意:这列的是 Bedrock 原生模型视图,不一定等同于 Mantle OpenAI-compatible endpoint 下当前 API key 可访问的模型列表。所以如果你是 CCR + Mantle,优先用:

bash 复制代码
curl -X GET https://bedrock-mantle.us-east-1.api.aws/v1/models \
  -H "Authorization: Bearer XXXX"

十、如何查看模型上下文大小

不要靠猜,也不要只看模型名。一定要查官方模型卡。

以 Qwen3 Coder Next 为例,AWS 官方模型卡中明确写了:

text 复制代码
Context window: 128K tokens
Max output tokens: 16K

并且列出了 programmatic access 的模型 ID 和 endpoint。(AWS 文档)

查看方式:

  1. 打开 AWS Bedrock 文档;
  2. 搜索模型名,例如 Qwen3 Coder Next Amazon Bedrock
  3. 找到模型卡;
  4. 看以下字段:
text 复制代码
Context window
Max output tokens
APIs supported
Endpoints supported
Programmatic Access
Regional Availability

尤其要注意:

text 复制代码
Context window 不等于 max output tokens
input_tokens + output_tokens 不能超过 context window

例如某模型:

text 复制代码
Context window: 128K
Max output tokens: 16K

并不代表你可以输入 128K 再输出 16K。实际请求仍然要满足:

text 复制代码
input_tokens + requested_output_tokens <= context_window

十一、一次请求 168K token 意味着什么

我这次日志里看到:

text 复制代码
Using long context model due to token count: 168448, threshold: 60000

这个 token 数已经非常大了。

如果此时还请求:

text 复制代码
max_tokens = 32000

那总预算至少要:

text 复制代码
168448 + 32000 = 200448

所以:

  • 196K 上下文的模型会炸;
  • 202K 上下文的模型理论上勉强够,但只剩 2000 多 token 的余量,非常危险;
  • 更大上下文模型会更稳。

这也是我最后换更大上下文模型的原因。


十二、推荐的 CCR 配置模板

下面是我现在更推荐的写法。

1. .bashrc 环境变量

bash 复制代码
export BEDROCK_MANTLE_API_KEY="XXXX"
export ANTHROPIC_BASE_URL="http://127.0.0.1:3456"
export ANTHROPIC_API_KEY="dummy"
export CLAUDE_CODE_MAX_OUTPUT_TOKENS=16000
export API_TIMEOUT_MS=1200000

如果用更大上下文模型,可以酌情调整:

bash 复制代码
export CLAUDE_CODE_AUTO_COMPACT_WINDOW=262000
export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80

这里不要盲目设到模型极限。因为实际请求里还有:

text 复制代码
system prompt
tool schema
工具调用历史
文件内容
CCR transformer 包装
provider tokenizer 误差

2. CCR 配置

json 复制代码
{
  "PORT": 3456,
  "LOG": true,
  "API_TIMEOUT_MS": 1200000,
  "Providers": [
    {
      "name": "aws-bedrock",
      "api_base_url": "https://bedrock-mantle.us-east-1.api.aws/v1/chat/completions",
      "api_key": "$BEDROCK_MANTLE_API_KEY",
      "max_tokens": 16000,
      "models": [
        "qwen.qwen3-coder-next",
        "zai.glm-5",
        "minimax.minimax-m2"
      ],
      "transformer": {
        "use": [
          ["openai"]
        ]
      }
    }
  ],
  "Router": {
    "default": "aws-bedrock,qwen.qwen3-coder-next",
    "background": "aws-bedrock,qwen.qwen3-coder-next",
    "think": "aws-bedrock,qwen.qwen3-coder-next",
    "longContext": "aws-bedrock,qwen.qwen3-coder-next",
    "longContextThreshold": 60000
  }
}

如果你希望普通任务走一个模型,长上下文走另一个模型,可以写成:

json 复制代码
"Router": {
  "default": "aws-bedrock,zai.glm-5",
  "think": "aws-bedrock,zai.glm-5",
  "background": "aws-bedrock,qwen.qwen3-coder-next",
  "longContext": "aws-bedrock,qwen.qwen3-coder-next",
  "longContextThreshold": 60000
}

十三、调试时的检查清单

以后再遇到类似问题,我建议按这个顺序查。

1. 看 CCR 日志是否触发 long context

搜索:

text 复制代码
Using long context model due to token count

看到类似:

text 复制代码
Using long context model due to token count: 168448, threshold: 60000

说明 longContext 路由生效。

2. 看最终打到哪个模型

看错误里:

text 复制代码
Error from provider(providerName,modelId)

例如:

text 复制代码
Error from provider(aws-bedrock,qwen.qwen3-coder-next)

这才是实际请求模型。

3. 看上下文计算

把错误里的三项拿出来算:

text 复制代码
maximum context length
input tokens
requested output tokens

公式:

text 复制代码
input_tokens + requested_output_tokens <= maximum_context_length

只要不满足,就会 400。

4. 不要贴边

如果模型最大上下文是:

text 复制代码
196608

不要配置成:

text 复制代码
输入 164608 + 输出 32000 = 196608

看起来刚好,实际一定容易炸。

建议至少留:

text 复制代码
2000 - 10000 tokens

安全余量。

5. 确认 endpoint 类型

CCR + OpenAI transformer:

text 复制代码
bedrock-mantle endpoint
/v1/chat/completions
Authorization: Bearer XXXX

AWS 原生 SDK:

text 复制代码
bedrock-runtime endpoint
Converse / InvokeModel
aws_access_key_id / aws_secret_access_key / region

不要混用。


十四、这次踩坑后的结论

这次最大的问题不是单个模型不行,而是整个链路里有多个边界:

text 复制代码
Claude Code 上下文组织
CCR token 估算
CCR longContext 路由
transformer 请求转换
AWS Mantle endpoint
模型真实上下文限制
max output tokens

只要其中任何一层没有留余量,就会出现:

text 复制代码
只差 1 token 也被拒绝

最终我的处理方式是:

  1. 不再强行贴 32K 输出极限;
  2. 用 CCR 日志确认是否触发 longContext;
  3. 用 Mantle /v1/models 查询当前 key 可用模型;
  4. 查 AWS 模型卡确认上下文大小和 max output;
  5. 对长上下文任务切到 Qwen3 Coder Next;
  6. 发现 Claude Code + Qwen3 Coder Next 的实际代码体验并不差。

尤其是最后一点很有意思:

虽然模型很重要,但 Claude Code 对上下文的组织能力也很关键。即使换成非 Claude 原生模型,只要 CCR 适配得好,实际编码体验也可以接受。


十五、保留命令

查看 Mantle 模型

bash 复制代码
curl -X GET https://bedrock-mantle.us-east-1.api.aws/v1/models \
  -H "Authorization: Bearer XXXX"

重启 CCR

bash 复制代码
ccr restart

查看 CCR 配置

bash 复制代码
cat ~/.claude-code-router/config.json

搜索 CCR 日志

bash 复制代码
grep -R "Using long context model" ~/.claude-code-router 2>/dev/null

查看 Claude Code 当前模型

在 Claude Code 里:

text 复制代码
/model

AWS 原生方式列模型

bash 复制代码
aws bedrock list-foundation-models --region us-east-1

结语

这次问题看起来只是一个 400 报错,实际上暴露了 Claude Code + CCR + AWS Bedrock 组合使用时最容易踩的几个坑:

text 复制代码
上下文窗口不是无限的
max output 会占用总上下文
longContextThreshold 只是路由阈值
Mantle endpoint 和 Runtime endpoint 不是一回事
CCR 日志能证明是否切换模型
模型 ID 要以实际 endpoint 可访问列表为准
不要把请求卡在模型极限边界

后续再配置模型时,我会优先做三件事:

text 复制代码
先 curl /v1/models 看 Mantle 可用模型
再查 AWS 模型卡确认 context window / max output
最后根据 CCR 日志确认真实路由到哪个模型

这能少走很多弯路。

相关推荐
Flynt9 小时前
接手28万行遗留代码:我用codebase-memory-mcp把代码理解时间从3天压到2小时
ai编程·claude·mcp
uccs20 小时前
流式响应的三次进化:EventSource → ReadableStream → TransformStream
openai·ai编程·claude
洛卡卡了1 天前
我们在用 AI 写代码时,为什么建议要好好维护 AGENTS.md 呢?
面试·agent·claude
ZzT1 天前
让 AI 少写一半代码:拆解爆火的 ponytail
ai编程·claude
我不是外星人1 天前
我把 Claude Code 搬到网页!自研高颜值 Web 交互工作台
前端·ai编程·claude
counterxing3 天前
最近发现一个 Mac 工具,有点像把 Raycast、语音输入法、截图和录屏塞到了一起
macos·ai编程·claude
码哥字节3 天前
为什么 Claude Code 读你的代码库,光靠 embedding 根本不够?
claude·代码规范
用户223586218204 天前
Loop Engineering:从 Prompt 到 Loop
claude