你看到的 128K 上下文窗口,可能只是猜的:Hermes 现在会把话说清楚


你在 Bedrock 上试一个新模型,Hermes 的状态栏写着 ctx 128K。你照着这个数字行事:往一个三万 token 的仓库里问一个跨文件的问题,结果它回答到一半就开始压缩历史。回头翻 AWS 的模型卡才发现,这个模型的窗口是 1,050,000 token —— 差了八倍。

更麻烦的是当时那句话写的是“检测到的”。看起来是事实,其实只是一个默认值。

一个数字决定三件事

上下文窗口不只是一个展示用的数字。它决定:什么时候开始压缩历史、一次能塞多少文件进提示词、以及溢出之后怎么恢复。窗口被低估,压缩就来得太早,长任务中途失忆;窗口被高估,请求会被服务商直接拒掉。

所以“这个数字是探测到的,还是猜的”不是学术问题。它能解释两种完全不同的症状。

这个数字是从哪来的

解析器按顺序试几个来源,命中就停:

  1. 探测:真的问一次服务商,拿到确切值。
  2. 服务商静态表:比如 Bedrock 维护的那张模型表。
  3. 目录里同家族的窗口:同一个模型家族在 Hermes 模型目录里的窗口值。
  4. 静态默认值:Bedrock 是 128K,通用路由是 256K。

第 3 步是这次新补上的一层。在此之前,Bedrock 上一个还没进静态表的新模型会直接从第 2 步掉到第 4 步的 128K,哪怕模型目录里明明写着同家族的窗口。

而且这一层只对 Anthropic、OpenAI、xAI 三家的模型生效——无论模型 ID 是裸的、带 geo 或 global 前缀的,还是包在 foundation-model 或 inference-profile ARN 里的。原因在下一节。

“fallback” 这两个字是什么意思

新标注只表达一件事:这个数字不是任何本地来源报告给你的,它是兜底值。

会出现这个词的地方包括网关的会话行(措辞是“fallback, not a detected limit”,即兜底、不是探测到的上限)、/usage、宽版状态栏、欢迎横幅、/model 切换摘要,后续修复又补上了 /status 和 /context。状态栏里它显示为一个短后缀。

它和另一个后缀要区分开:pinned 是你自己用配置钉住的值,fallback 是系统兜底的值。两个都不等于“服务商亲口说的”。

标注本身只做本地读取,失败时放行,从不发起探测,所以不会拖慢状态栏;它按“profile 家目录 + 模型 + base_url”记录,多 profile 并行时不会串味。这条是后续修复的重点之一:最初的实现用了一个 60 秒缓存,键里没带 profile 家目录,结果一个 profile 的判断会给另一个 profile 的窗口贴上标签。

一个真实案例:GPT-6.1 Terra 被当成 128K 的九天

Terra 发布当天(10 月 26 日),模型目录里加了它的窗口:1,050,000。但 Bedrock 的静态表没动,而 Bedrock 的解析器根本不查模型目录。于是 v0.22.6、v0.22.7 和 main 都把 Terra 在 Bedrock 上解析成 128K —— 压缩阈值取窗口的 75%,也就是 96K 就开始压。

修复后,Bedrock 上属于 Anthropic、OpenAI、xAI 的模型如果在静态表里查不到,会先取同家族的目录窗口,再落到 128K 默认值。Terra 现在拿回 1,050,000,GPT-5.4 同样。裸 ID 的 Terra 也补上了路由:它的模型卡只列了 Mantle 这个端点。

为什么只对这三家开放这一层?因为它们的目录行和 Bedrock 卡片基本对得上:34 张卡里 27 张相等、6 张低于、1 张高于。唯一偏高的那张是 GPT-6.1 Sol(目录 1,050,000,卡片 1M),而它自己在静态表里有行,表行优先。

其他厂商不能这么借。它们的目录窗口是“厂商直连”的窗口,可能大于 Bedrock 实际提供的:Llama 3 8B 卡片写 8K,而 llama 目录行是 131,072;Qwen3 32B 卡片写 32K,而 qwen 目录行是 131,072。借过来就等于把一个“过早压缩”的问题,换成一个“请求太大被拒”的问题。

为什么默认值不干脆调到一百万

有人提过这个方向:既然新模型动辄上百万,索性把兜底抬到 1M。答案在一百张 Bedrock 文本模型卡里:32 张 ≥1M,但 36 张 ≤128K,还有 8 张更低(Llama 3 8B/70B 是 8K,Mistral 7B、Mixtral、Small、Large 2402 是 32K,Qwen3 32B 是 32K,Palmyra Vision 是 4K)。

1M 的兜底会让这些模型收到大 8 到 250 倍的请求。而 Bedrock 对超大 payload 的回应很不友好:一个不带数字的 InternalServerException,或者一句“Input is too long for requested model.”。溢出恢复只会采纳错误里明确报出的窗口数字,报不出来就无从修正 —— 结果是每一轮都压缩、每一轮都失败。

所以默认值留在 128K,改用“家族窗口兜底”来救新模型:真正会踩到默认值的,基本都是刚发布的前沿模型,而它们会先进模型目录。

修复前后对着卡片核了一遍的结果:

与卡片相等 低于卡片 高于卡片
修复前 55 37 8
修复后 77 15 8

那 8 个“高于卡片”的全是卡片本身低于 128K、于是命中默认值的模型,这次没有动它们。

你自己怎么改

没有新增配置键,还是老办法,先钉单个模型:

model:
  context_length: 200000

或者按 provider 和模型精确覆盖:

model_overrides:
  bedrock:
    us.openai.gpt-6.1-terra:
      context_window: 1050000

通用 provider 同理:model_overrides 下面先 provider、再模型,最后是 context_window。

钉住的值优先于兜底值,界面上会显示 pinned 而不是 fallback。如果你在网关里切了模型或路由,配置的钉子会先被摘掉,避免旧窗口的数字配新模型的名字。

怎么判断你现在这个数字靠不靠谱

一个四步的检查顺序:

  1. 在 /usage、/status、/context 里看这个数字后面有没有 fallback。
  2. 有的话,去模型卡或服务商文档查真实窗口。
  3. 查到了就用 model_overrides 钉住。
  4. 对照症状确认方向:压缩比预期早很多,说明数字偏小;请求被拒且错误里提到输入过长,说明数字偏大。

这批改动 11 月 4 日合并进 main,晚于 v0.22.7 的发布点,写这篇时还没进正式版本。等下一版更新即可。

想再往下挖一层,站内的上下文用量与锚点那篇讲压缩之后如何保住关键信息,压缩瘦尾指南讲怎么让历史留得更值钱;如果你跑的是 Codex 一类的模型,上下文窗口默认值那篇是同一套机制的另一个入口。