最近在本地部署运行 Qwen 3.8 27B 的时候遇到了"未知" Bug!
我也不知道是什么原因,如何解决,因为这是一个比较新的内容,网上资料也不多。
而且是结合了自己开发的 JClaude,所以这个问题的复杂性大了很多。
最终是通过 Opus 5 自己分析、自己测试,根据我的错误描述,找到了正确答案,并且提供了两种可行的解决方案,最后全部修改完成!
解决了我们自身软件的一些潜在问题和兼容性,也可以在不修改 Ollama + Qwen 3.8 本地模型的情况下,解决这个 Claude Code 调用本地3.8模型的问题。
我觉得这个分析问题、解决问题的过程非常有意义,和大家分享一下。
1、背景信息
上面其实已经讲了一些了,但是可能还是过于抽象,我就讲得具体一下,后面的内容才好展开。
因为 Qwen 3.8 27B 发布了,各方面基准已经对标 Opus 4.6 Max 了。所以我也很感兴趣,就在 3090 上通过 Ollama 装了一个 q4 的量化版本,并且成功启动,而且通过投机解码,速度可以达到 50 t/s 左右,完全达到了可用状态。

但是 Ollama 主要是帮你做本地部署和简单对话。它本身没有智能体,所以我需要接入智能体工具,比如 Claude Code!
然后刚好我基于 Claude Code 手搓了一个界面版软件 JClaude:

这个软件是套壳了 Claude Code,然后完全模仿了 Claude 桌面的界面。但是允许接入任何第三方模型。
这不就是妥妥的对上了!
但是这个事情,并没有想象的那么简单。我在接入的过程中就遇到了一个奇怪的问题。
2、问题出现了
问题是这样的,我把 Ollama 的配置信息填好之后,在 JClaude 开始聊天,界面一直显示"Claude 正在思考......",很久看不到任何信息。

首先我人工做了一个判断,摸了摸显卡,是烫的。我看到 Ollama 的那台电脑 GPU 是有占用的,证明模型已经加载了,而且链路应该是通了。其次,这个问题的难点在于,它不报错。所以我就完全没有思路。
另外还有一个混淆信息。我之前通过 ollama launch claude 启动 Claude Code 成功了。所以我就怀疑只是我的软件本身的问题。其实我当时启动成功的是 qwen3.5 27B(没仔细看),误导了自己,也误导了 Opus 5,还好它有脑力。
3、分析问题
这个问题的复杂性在于,我不知道问题出在哪个环节,没有错误信息,不知道如何描述。如果给第三方模型,其实也很难问出个所以然。
所以只能请 O 哥出马!
由于我不清楚问题本身,我只能描述相关信息,而且我写的是很随意的:

我们可以看一下 O 哥的分析思路。它并不是直接给结论,而是分析了 15 轮!
less
1、我先看一下项目结构和模型调用机制,再来测你的 Ollama 地址。
2、现在我需要你的实际地址。先看看应用里是否已经存了这个 provider 配置:
3、本地没有存过 Ollama 配置。我先探测一下本机/常见地址:
4、本机 Ollama 在跑。看看有没有 qwen3:
5、核心问题来了 ------ 测试 Ollama 是否支持 Anthropic 协议 /v1/messages:
6、HTTP=000 ------ 请求没返回。看详细情况:
7、/v1/messages 路由是存在的(GET 返回 405 说明只接受 POST)。用小模型再测,排除加载耗时:
8、Ollama 确实支持 Anthropic 协议。现在测我们 app 实际发的那个 body(stream + adaptive thinking):
9、SSE 格式完全匹配我们的解析器。现在测关键嫌疑点 ------ thinking: adaptive:
10、现在用你要用的 qwen3.5:9b 实测,测首字节延迟:
11、qwen3.5:9b 强制先输出 thinking 块。看前端如何处理:
12、现在做一次完整的端到端复现(完全按 app 发的 body,max_tokens=4096):
13、协议本身完全通。现在验证冷加载耗时,以及 Code 侧的调用路径:
14、冷加载现在 6s(首次冷盘时超过 25s)。现在测 Code 侧真正需要的 tool use:
15、工具调用正常。最后测 Code 路径的关键点 ------ 大 system prompt 的 prefill 耗时(Claude Code 会发上万 token):
最后它告诉我诊断完成。
结论是:
Ollama 0.32.14 原生实现了 Anthropic 协议,不是只有 OpenAI 兼容层。实测:
| 测试项 | 结果 |
|---|---|
POST /v1/messages |
✅ 200,标准 Anthropic 响应体 |
stream: true SSE |
✅ 事件格式与我们 chat.rs:141 的解析器逐字段对得上 |
system 字段 |
✅ |
thinking: {type:"adaptive", display:"summarized"} |
✅ 不报错(Ollama 忽略,不会像老模型那样 400) |
tool_use / tool_result |
✅ 正确返回 stop_reason: "tool_use" + 标准 input |
| 13.5k token 大 prompt prefill | ✅ 首字节 4.9s |
模型名写错(如 qwen3.8) |
快速 404 not_found_error,不会卡 |
所以「不支持 Anthropic 协议」这个假设可以排除。
你要的模型是 qwen3.5:9b 或 qwen3.5:4b------qwen3.8 不存在,你本机的列表里没有这个 tag。
卡住的真正原因:qwen3.5 强制思考 + 我们写死 max_tokens=4096,这是复现出来的硬伤。
O 哥做事情就是严谨!
但是我脑子有问题,忘记告诉它,我用的 Ollama 地址不是本机的,而是局域网中的另一台电脑。
这一轮测试可以看出,O 哥并不是那种你说有问题,它就回答"你说得对"的模型。经过它的详细测试,调用本机的 Qwen 3.5 完全没有问题,而且还发现了我们软件中的一个 Bug,就是最大 Token 写死了,而且写得比较小,容易被截断。还有就是qwen3.5的思考过长,也会出现假死的状态。
这都是真实存在的,但是由于我没给他正确的地址,它无法分享今天的问题。
我的错误,O 哥买单!
我告诉它:
http://192.168.31.209:11434 我刚刚忘贴地址了,是局域网另外一个机器!
O 哥没有吐槽,而是立马重新测了一波:

它又经过了 10 几轮的测试,基本复现了我说的问题。就是用 Claude Code 打这台 Ollama 直接 500,而且重试退避消耗了 3 分钟,这就是你看到的"一直在思考"。
它已经从现象定位到具体的问题了!
为了查清楚这个问题,它直接写了一个代理,然后让 Claude Code 走代理,代理再去请求 Ollama,这样它就能通过代理搞清楚 Claude Code 的请求特征了。
眼看就快要有结果了,被我打断了。
因为同时我也在问我在线版本的 G 哥,我给G 哥的信息比 O 哥多。因为刚刚 O 哥分析的时候,三分钟等待之后,我已经拿到错误信息了,我就直接把错误信息给了 G 哥。

错误信息是:
500 system message must be at the beginning
然后 G 哥是查到了 Ollama Issue 里面确实有人反馈类似的 Bug。
这不就好了,我直接把 G 哥的信息给 O 哥同步了一下。
O 哥上来就说了一句:
明白,先纠正一个事实:这不是 MTP 专属问题 。我上一轮的最小复现用的就是普通版
qwen3.8:27b,一样 500:messages=user, system → HTTP 500 "system message must be at the beginning" messages=system, user → HTTP 200
所以那篇资料里"换普通版就好"的建议在你这台机器上不成立。真正的变量是那条
role:"system"消息为什么会出现在中间。
到这里,我其实已经知道问题的关键了。我也是一个知识很丰富的人类。
大概的核心原因是,Claude Code 它有一个很特别的机制,就是可以中途插入 system 字段。这么一搞,如果服务端不做兼容就会出现错误。大的服务商都会同步跟进,但是 Ollama 中的Q3.8还没做这个优化处理,所以直接抛出错误。
O 哥经过一顿分析,也推理出了这个结论:
一句话:Claude Code 把一条
role:"system"的消息放在了messages数组的第二位,而 Ollama 的 Anthropic 适配层规定 system 只能在第一位,直接抛 500。
O 哥不是依赖搜索知道的,而是分析整个系统,经过多轮测试总结出来的。还辟谣了 G哥听来的说法!中途我其实也给了一些误导信息,我以为 Ollama 调用 Claude Code 是对的,只是我自己的软件调用 Claude Code 有问题。(我总是喜欢从自身找问题!)
4、解决方案
既然问题已经清楚了,那么怎么改。在上面诊断问题的时候,说到了 Qwen 3.8 的模板问题。好像说是它自带的模板有问题,所以导致 Qwen 3.5 可以,Qwen 3.8 就不行。
既然 O 哥在手,我就直接大胆问了,能不能直接修改这个模板,然后让它兼容 Claude Code。
O 哥是这么回答的:
能不能改要看它用的是「模板」还是「内置渲染器」。查一下:
查到了确切答案 ------ 改不了模板,因为它根本没有模板:
TEMPLATE {{ .Prompt }} ← 只是个透传占位符 RENDERER qwen3.8 ← 真正干活的在这 PARSER qwen3.5 requires 0.32.12
Ollama 从 0.32 开始,新模型不再用 Modelfile 里的 Go 模板拼 prompt,而是改用编译进 Ollama 二进制里的 Go 渲染器 。
RENDERER qwen3.8指向的就是这么一段 Go 代码,requires 0.32.12也是在说"你的 Ollama 二进制里必须有这个渲染器"。那句
system message must be at the beginning就抛在这段 Go 代码里。
凉凉了!改不了。
还好机智的 O 哥又想出了另外一个方法:
真正能改的只有两条,都是建一个派生模型
方案 A --- 换渲染器
FROM qwen3.8:27b RENDERER qwen3.5 PARSER qwen3.5
方案 B --- 完全手写 TEMPLATE,去掉 RENDERER
既然 O 哥这么说,我就直接让它干了,没想到它还真干成了。
它自己搞了一个 Qwen3.8-cc 模型,成功跑通。我都没给它那台机器的权限,它居然通过 Ollama 的接口和方法创建了另一个符合 Ollama 规范的模型,借用了 Qwen 3.5 的一些东西,成功跑通了 Qwen 3.8!!!
这么一来核心思路就通了。但是这里还有一个问题。目前只是修复了 Ollama 加载 Qwen 3.8 的问题。我们的软件可能还是会在其他服务商那里面临同样的问题。
O 哥高瞻远瞩,已经想到了所有的点:
五个方案对比 ------ A 换模型 / B 建兼容副本(已采用) / C 本地翻译代理 / D 等上游 / E 手写模板,每个都标了优缺点和验证状态
其中的 C 方案本地翻译代理,就是根除这些问题的关键!
就是不管 Claude Code 发什么请求,我都把它转换成标准格式,这样服务商不需要特殊处理。
既然思路清晰了,剩下的事情,我就不用操心了,直接交给 O 哥。
顺便让它帮我把几个 P0~P2 的问题也一起修复一下:

O 哥"做手术"是非常细腻精准的,从上面的记录可以看到它不是一次生成代码,而且每次都精准定位和修改特定的代码。这只是一部分,其实整个修改过程有好几屏的内容。 问题不算大,但是工作量不小,改起来还是涉及到好多点!
接下来我们就翘二郎腿等结果了:
bash
通过了
------ 真实 CLI + 真实 Rust 代理 + 原始的 `qwen3.8:27b`(直连必 500 的那个模型),完整跑通并返回了 PROXY_OK。139 秒。
跑最终全量回归:
Rust 42 通过、JS 133 通过。但测试文件数没变,我确认一下新测试确实被收录了:
新增的 50 个 JS 测试全部通过,fmt 已修正。按 AGENTS.md 收紧行数上限,并更新文档:
P0--P2 全部实施完毕,外加你要的本地兼容代理。
中途它还自己发现了两个相关 Bug,顺带修复了!
提出问题,分析文件,最后解决问题,并验收修改。
我主要负责提出问题,然后选择 ABC!最后成功解决了这个"未知"的新问题,软件升级也做好了,打包也打好了。

已经一切正常!
只要在添加提供商的时候勾选一下系统字段兼容处理:

就不用管服务器支不支持了,我们本地代理会自动优化。如果服务器支持,那就不用勾选这个了,让服务器去做这个兼容优化。
终于做到了既要又要!
为了改这个 JClaude,我已经消耗了不少 Token 了。

从这个对话记录就可以看出来,session 就有几十个了,对话轮数就更多了。
我和 Claude 的总对话已经有 8 万多次,这还是最近几个月的。Claude Code 默认会自动删除一个月以上的记录!
O 哥还是很可靠!尤其是自主分析问题的能力。这次的问题,其实也不是完全它自主解决,毕竟我也打字,做了选择的。
不行,以后我不能老是说O哥多强,我应该强调我的重要性!
我换个表述:O哥主要是在我英明神武的领导下,解决了这个棘手的bug。
另外一个重要点的,过程真的很重要,因为结果完全由过程决定。它能自己搞清楚各种因果就不容易出错。它废 Token 是有道理的!
最后有一个好消息:当我改完这个兼容性的第二天,G 哥告诉我 Ollama 已经修复这个问题。(G哥有个定时任务,专门打听这种消息)
好吧,这个问题大家可能已经遇不到了!同时,你们也收获不到这个宝贵的经验了。
收工! 最近在玩一个还没发布的模型~~