Opus5自主解决Qwen3.8 27B本地接入Claude Code的BUG!

0 阅读12分钟

最近在本地部署运行 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 左右,完全达到了可用状态。

image-20260821124051447

但是 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 轮!

1、我先看一下项目结构和模型调用机制,再来测你的 Ollama 地址。
2、现在我需要你的实际地址。先看看应用里是否已经存了这个 provider 配置:
3、本地没有存过 Ollama 配置。我先探测一下本机/常见地址:
4、本机 Ollama 在跑。看看有没有 qwen35、核心问题来了 —— 测试 Ollama 是否支持 Anthropic 协议 /v1/messages6HTTP=000 —— 请求没返回。看详细情况:
7、/v1/messages 路由是存在的(GET 返回 405 说明只接受 POST)。用小模型再测,排除加载耗时:
8Ollama 确实支持 Anthropic 协议。现在测我们 app 实际发的那个 bodystream + adaptive thinking):
9SSE 格式完全匹配我们的解析器。现在测关键嫌疑点 —— thinkingadaptive10、现在用你要用的 qwen3.5:9b 实测,测首字节延迟:
11qwen3.5:9b 强制先输出 thinking 块。看前端如何处理:
12、现在做一次完整的端到端复现(完全按 app 发的 bodymax_tokens=4096):
13、协议本身完全通。现在验证冷加载耗时,以及 Code 侧的调用路径:
14、冷加载现在 6s(首次冷盘时超过 25s)。现在测 Code 侧真正需要的 tool use15、工具调用正常。最后测 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:9bqwen3.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 哥“做手术”是非常细腻精准的,从上面的记录可以看到它不是一次生成代码,而且每次都精准定位和修改特定的代码。这只是一部分,其实整个修改过程有好几屏的内容。 问题不算大,但是工作量不小,改起来还是涉及到好多点!

接下来我们就翘二郎腿等结果了:

通过了

—— 真实 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哥有个定时任务,专门打听这种消息)

好吧,这个问题大家可能已经遇不到了!同时,你们也收获不到这个宝贵的经验了。

收工! 最近在玩一个还没发布的模型~~