Skip to content

不支持gpt-oss的reasoning提取 #437

@LubyRuffy

Description

@LubyRuffy

先说结论: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来改更合适一点。仅供参考。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions