Windsurf 换 Qwen3.7 Plus 当后端,这几个 context window 字段不设对就静默截断
上周三我把 Windsurf Cascade 的后端模型从 Claude Sonnet 换成 Qwen3.7 Plus,想省点钱跑日常的代码补全和重构任务。结果折腾了大半天——Cascade 生成到一半突然停了,不报错,不提示,就是静默截断。查了两个小时才发现是 settings.json 里 customModels 的 contextLength 和 maxTokens 字段跟 Qwen3.7 Plus 的实际上限对不上。这篇把我踩的坑全拆一遍,直接贴配置。
先说结论
| 坑点 | 现象 | 根因 | 修复 |
|---|---|---|---|
| contextLength 设小了 | 长文件送进去后回复被截断,无报错 | 未显式设置时 Windsurf 使用了较小的 fallback 值,Qwen3.7 Plus 实际支持 131072 | 显式设为 131072 |
| maxTokens 未设置 | 输出到一定 token 数就停 | Windsurf 对未知模型使用了较小的 fallback 值 | 显式设为 8192(Qwen3.7 Plus 最大输出) |
| apiBase 末尾多了斜杠 | 直接 404 或返回 HTML | 拼接路径变成 //v1//chat/completions |
去掉末尾 / |
环境准备
- Windsurf(请以官网当前发布版本为准)
- 模型:Qwen3.7 Plus(通义千问,131K 上下文)
- API 提供方:任何兼容 OpenAI 格式的服务都行
sequenceDiagram
participant W as Windsurf Cascade
participant G as API Gateway
participant Q as Qwen3.7 Plus
W->>G: POST /v1/chat/completions
Note over W,G: headers: Authorization Bearer
G->>Q: 转发请求
Q-->>G: streaming chunks / complete JSON
G-->>W: 返回结果
Note over W: 按 maxTokens 截断显示
坑一:contextLength 不设就静默截断
Windsurf 的 ~/.windsurf/settings.json 里有个 customModels 数组。你加一个自定义模型进去,如果不写 contextLength,它会使用一个内置的 fallback 值。根据我的实际测试,对于未识别的模型 ID,这个 fallback 值相当小(我遇到的情况是上下文被限制在 4096 token 左右),但 Windsurf 并未在公开文档中说明该行为,具体数值可能随版本变化。
Qwen3.7 Plus 支持 131072 token 的上下文窗口。你把一个 3000 行的文件丢进 Cascade,token 数轻松超过这个 fallback 值,Windsurf 不会报错,它直接把输入截断然后发请求。模型收到的是被砍过的上下文,回复自然是残缺的。
我当时看到的提示(其实算不上报错,是 Cascade 面板底部一行灰色小字):
[Cascade] Context truncated to fit model window (4096 tokens).
这行字太不起眼了,我盯着屏幕看了好几遍才注意到。
修复:显式声明 contextLength。
坑二:maxTokens 的 fallback 值过小
这个更隐蔽。Qwen3.7 Plus 的最大输出 token 是 8192,但根据我的测试,Windsurf 对自定义模型的 maxTokens 在未显式设置时会使用一个较小的 fallback 值(我遇到的情况是输出在 2048 token 左右停止)。同样,Windsurf 未在公开文档中说明该默认值,具体数值可能随版本变化。
你让 Cascade 生成一个比较长的函数(比如一个 200 行的 React 组件),到这个 fallback 上限它就停了,没有 finish_reason: length 的提示,面板上看就是"生成完毕"。
我一开始以为是模型能力问题,还去通义的 playground 试了同样的 prompt——人家输出得好好的,一直到结尾。回来对比才发现是 Windsurf 这边限制了。
坑三:apiBase 末尾斜杠 + streaming 开关
经典的 URL 拼接问题。Windsurf 内部会把你的 apiBase 和 /chat/completions 拼起来。如果你写成:
"apiBase": "https://api.ofox.io/v1/"
它拼出来的实际请求地址是 https://api.ofox.io/v1//chat/completions——双斜杠。有些网关能容忍,有些直接返回 404 或者一段 HTML 错误页。我当时收到的是:
Error: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
看到这个报错就知道了,服务端返回了 HTML 而不是 JSON。
streaming 开关也要注意:Qwen3.7 Plus 的 API 默认支持 SSE streaming,但如果你在 settings 里写了 "streaming": false,返回的是完整 JSON 一次性给回来。Windsurf Cascade 的 UI 对这两种格式都能处理,但 streaming: true 时体验明显好——你能看到逐字输出,不用干等。反过来如果网关不支持 streaming 你又开了,会收到:
Error: Expected event stream but received application/json
完整配置(直接抄)
打开 ~/.windsurf/settings.json,找到或新建 customModels 字段:
{
"customModels": [
{
"id": "qwen3.7-plus",
"name": "Qwen3.7 Plus",
"provider": "custom",
"apiBase": "https://api.ofox.io/v1",
"contextLength": 131072,
"maxTokens": 8192,
"streaming": true,
"capabilities": ["chat", "code", "reasoning"]
}
]
}
几个关键点:
- id 必须跟 API 端的模型名完全匹配(区分大小写),通义那边的 model name 是 qwen3.7-plus
- apiBase 末尾不要加斜杠
- contextLength 设 131072,这是 Qwen3.7 Plus 的实际窗口
- maxTokens 设 8192,单次最大输出
验证是否生效
改完 settings 后重启 Windsurf(不是 reload window,是完全退出再打开)。然后在 Cascade 里输入:
用 Qwen3.7 Plus 写一个完整的 Express.js CRUD API,包含用户注册、登录、JWT 鉴权、错误处理中间件,代码要完整可运行。
如果输出能超过之前被截断的 token 数(大概 150+ 行代码)且没有中途停止,说明 maxTokens 生效了。
想确认 contextLength 也生效了,可以先粘贴一个 2000 行的文件进对话,再让它基于这个文件做修改。之前窗口过小时它会忽略文件后半部分,现在应该能完整引用。
用 Python 脚本验证 API 连通性
如果你不确定是 Windsurf 的问题还是 API 本身的问题,先用脚本单独测:
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.io/v1"
)
response = client.chat.completions.create(
model="qwen3.7-plus",
messages=[{"role": "user", "content": "写一个快速排序,Python"}],
max_tokens=4096,
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
这个脚本能正常跑通且输出完整,那问题就锁定在 Windsurf 的配置上。
踩坑记录:model id 冲突的坑
还有个小坑差点忘说。根据我的测试,如果你在 id 字段写了一个 Windsurf 内置模型列表里已有的名字,它可能会用内置的参数覆盖你的自定义参数。这一行为在 Windsurf 的公开文档里没有说明,我无法确认其具体触发条件,但实际遇到过类似问题。
我第一次写的是 "id": "qwen-plus",结果发现 contextLength 并没有按我设置的 131072 生效,实际表现像是被覆盖成了一个更小的值。改成 qwen3.7-plus 之后才正常。
如果你发现设了 131072 但实际还是被截断,可以检查一下 id 是否与 Windsurf 内置的某个模型名称相近或重合,换一个更具体的 id 再试试。
关于 API 服务选择
我这边用的是 ofox.io 作为 API 网关,OpenRouter 和 Together AI 也都支持 Qwen3.7 Plus。选 ofox 主要是因为它对齐官方价格、不额外加价;OpenRouter 的费率结构因模型而异且会随时间调整,建议直接查阅 OpenRouter 官网当前定价再做决定。改个 base_url 就能切换,协议都是 OpenAI 兼容格式。
小结
三个字段:contextLength 设 131072、maxTokens 设 8192、apiBase 末尾不加斜杠。就这三个东西折腾了我大半天,Windsurf 的静默截断机制真的挺烦人的——至少给个明显的 warning 吧。目前这套配置跑了一周多,Cascade 里用 Qwen3.7 Plus 写代码体验还行,速度比 Claude Sonnet 快不少,复杂推理差一点但日常够用了。
更多推荐




所有评论(0)