GLM-4-Z1 模型设计做错了一件事

DeepSeek-R1 API 在 OpenAI 兼容 API 基础上为思考模型增加了 "reasoning_content" 字段,可以将 "<think>" "</think>" 中间的内容独立返回,非思考部分通过 "content" 字段返回。

SGLang/vLLM 等框架也支持了这样的返回,比如 SGLang 可以在启动时增加参数 "--reasoning-parser deepseek-r1",让服务器像 DeepSeek-R1 API 那样返回。

Chatbox 等支持 OpenAI 兼容 API 的聊天 APP,对 DeepSeek-R1 风格的返回结果支持也更好,上面截图就是一个例子,当思考部分以 "reasoning_content" 字段返回时,显示效果与正文不同,背景是灰色,而且可折叠。

上一篇博客中提到我给 SGLang 添加了 GLM-Z1 模型的支持,然后我发现 GLM-Z1 系列模型无法做到思考内容和非思考内容分开输出。如果你在启动服务时增加了 "--reasoning-parser deepseek-r1" 参数,那么所有生成的内容都会放在 "reasoning_content" 字段返回,而 "content" 为空。Chatbox 显示效果如下所示:

我仔细研究了一下,发现了问题在 GLM-Z1 模型上:GLM-Z1 系列模型在设计时,没有像 DeepSeek-R1 那样将 "</think>" 编码为一个独立的 Token。

GLM-Z1 系列模型输出的 "</think>" 由 3 个 Token 组成:"</"、 "think" 和 ">",这就会导致 框架在流式逐字输出时,没法简单地判断一个新生成的 Token 是否为 "</think>",以决策在何时结束 "reasoning_content" 字段。

可以通过下面代码简单验证:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("GLM-Z1-9B-0414")
print(tokenizer("</think>\n"))

DeepSeek-R1 是在 tokenizer.json 中标记了 "</think>" 作为 "added_tokens",QwQ-32B 则把 "</think>" 放在了 added_tokens.json 中。这就意味着,DeepSeek-R1 和 QwQ-32B 输出的 "</think>" 是 1 个 token,很方便框架去完整地比对它是否存在。框架的确也可以兼容非一个 token 的 "</think>",但编码更为复杂,效率也会偏低。

建议思考模型的设计者都注意一下这个小小的细节。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注