-
Notifications
You must be signed in to change notification settings - Fork 244
Description
先说结论:ollama/lmstudio为了支持gpt-oss官方的建议,返回json中代表思考的字段为reasoning,而go-openai目前只提取了reasoning_content作为思考的内容,导致在用eino基于gpt-oss做项目时,无法提取到思考的内容。
测试过程:
调用工具,同时获取reasoning数据:
{
"model": "gpt-oss-20b",
"messages": [
{
"role": "system",
"content": "你是一个天气专家,你会回答用户的天气问题。"
},
{
"role": "user",
"content": "今天北京天气如何"
}
],
"stream": true,
"tools": [
{
"type": "function",
"function": {
"name": "weather",
"description": "天气查询",
"parameters": {
"properties": {
"city": {
"description": "城市",
"type": "string"
}
},
"additionalProperties": false,
"required": [
"city"
],
"type": "object"
}
}
}
],
"tool_choice": "auto",
"stream_options": {
"include_usage": true
}
}lmstudio:
{
"id": "chatcmpl-0gv7f3t8apifdtcveosk0ue",
"object": "chat.completion.chunk",
"created": 1756909993,
"model": "mlx-community/gpt-oss-20b",
"system_fingerprint": "mlx-community/gpt-oss-20b",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"reasoning": "The"
},
"logprobs": null,
"finish_reason": null
}
]
}ollama:
{
"id": "chatcmpl-429",
"object": "chat.completion.chunk",
"created": 1756909343,
"model": "gpt-oss:20b",
"system_fingerprint": "fp_ollama",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"content": "",
"reasoning": "We"
},
"finish_reason": null
}
]
}
对应的结构体定义在:github.com/meguminnnnnnnnn/go-openai/chat_stream.go
type ChatCompletionStreamChoiceDelta struct {
Content string `json:"content,omitempty"`
Role string `json:"role,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
Refusal string `json:"refusal,omitempty"`
// This property is used for the "reasoning" feature supported by deepseek-reasoner
// which is not in the official documentation.
// the doc from deepseek:
// - https://api-docs.deepseek.com/api/create-chat-completion#responses
ReasoningContent string `json:"reasoning_content,omitempty"`
}可以看到字段为reasoning_content而不是reasoning,导致提取错误。
在github.com/meguminnnnnnnnn/go-openai/stream_reader.go文件中进行的处理
func (stream *streamReader[T]) Recv() (response T, err error) {github.com/meguminnnnnnnnn/go-openai 是从 github.com/sashabaranov/go-openai fork的,看到:
https://github.com/sashabaranov/go-openai/blob/master/chat_stream.go#L8
也是同样的。说明字段不兼容。
https://cookbook.openai.com/articles/gpt-oss/verifying-implementations
OpenAI 的官方建议:关键在于,OpenAI 在其关于如何验证 gpt-oss 实现的文档中,推荐使用 reasoning 作为字段名。 OpenAI 指出,社区内对于使用 reasoning 还是 reasoning_content 尚未形成统一规范,但为了与 OpenAI Agents SDK 等客户端兼容,他们推荐使用 reasoning。
结论是:Ollama 和 LM Studio 等服务遵循了 OpenAI 对 gpt-oss 的建议,使用了 reasoning 字段。而 sashabaranov/go-openai 库在早前添加相关支持时,采用了 reasoning_content 的命名,并且尚未更新以完全兼容 gpt-oss 的这一推荐标准。
There is currently no generally agreed upon specification in the community with the general properties on a message being either reasoning or reasoning_content. To be compatible with clients like the OpenAI Agents SDK we recommend using a reasoning field as the primary property for the raw CoT in Chat Completions.
目前,社区中没有普遍商定的规范,消息的一般属性要么是reasoning,要么是reasoning_content。为了与 OpenAI Agents SDK 等客户端兼容,我们建议使用reasoning字段作为聊天完成中原始 CoT 的主要属性。
那其他模型也是一样吗?比如deepseek或者qwen,也测试一下:
lmstudio测试
qwen3
{
"id": "chatcmpl-h2icevkqvv6mxd8320pfdh",
"object": "chat.completion.chunk",
"created": 1756950934,
"model": "qwen3-0.6b",
"system_fingerprint": "qwen3-0.6b",
"choices": [
{
"index": 0,
"delta": {
"reasoning_content": "好的"
},
"logprobs": null,
"finish_reason": null
}
]
}可以看到,reasoning_content是有字段的。
也就是说:lmstudio实现了两个字段来提供reasoning信息(reasoning_content/reasoning),且ollama也是为gpt-oss提供了reasoning字段,这与go-openai只提供了reasoning_content字段的行为不一致。
我想着既然github.com/meguminnnnnnnnn/go-openai已经fork出来了,是在这个仓库改还是让go-openai来改更合适一点。仅供参考。