Skip to content

feat: support reasoning switch for qwen3 models #100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,6 @@ var completion = await client.GetQWenCompletionAsync(QWenLlm.QWenMax, prompt);
Console.WriteLine(completion.Output.Text);
```

## Reasoning

Use `completion.Output.Choices![0].Message.ReasoningContent` to access the reasoning content from model.

```csharp
var history = new List<ChatMessage>
{
ChatMessage.User("Calculate 1+1")
};
var completion = await client.GetDeepSeekChatCompletionAsync(DeepSeekLlm.DeepSeekR1, history);
Console.WriteLine(completion.Output.Choices[0]!.Message.ReasoningContent);
```

## Multi-round chat

```csharp
Expand All @@ -153,6 +140,36 @@ var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, histor
Console.WriteLine(completion.Output.Choices[0].Message.Content); // The number is 42
```

## Reasoning

Use `completion.Output.Choices![0].Message.ReasoningContent` to access the thoughts from reasoning model.

```csharp
var history = new List<ChatMessage>
{
ChatMessage.User("Calculate 1+1")
};
var completion = await client.GetDeepSeekChatCompletionAsync(DeepSeekLlm.DeepSeekR1, history);
Console.WriteLine(completion.Output.Choices[0]!.Message.ReasoningContent);
```

### QWen3

Use `TextGenerationParameters.EnableThinking` to toggle reasoning.

```csharp
var stream = dashScopeClient
.GetQWenChatStreamAsync(
QWenLlm.QWenPlusLatest,
history,
new TextGenerationParameters
{
IncrementalOutput = true,
ResultFormat = ResultFormats.Message,
EnableThinking = true
});
```

## Function Call

Creates a function with parameters
Expand Down Expand Up @@ -182,7 +199,7 @@ public enum TemperatureUnit
}
```

Append tool information to chat messages.
Append tool information to chat messages (Here we use `JsonSchema.NET` to generate JSON Schema).

```csharp
var tools = new List<ToolDefinition>()
Expand Down
19 changes: 18 additions & 1 deletion README.zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,23 @@ var completion = await client.GetDeepSeekChatCompletionAsync(DeepSeekLlm.DeepSee
Console.WriteLine(completion.Output.Choices[0]!.Message.ReasoningContent);
```

### QWen3

使用 `TextGenerationParameters.EnableThinking` 决定是否使用模型的推理能力。

```csharp
var stream = dashScopeClient
.GetQWenChatStreamAsync(
QWenLlm.QWenPlusLatest,
history,
new TextGenerationParameters
{
IncrementalOutput = true,
ResultFormat = ResultFormats.Message,
EnableThinking = true
});
```

## 工具调用

创建一个可供模型使用的方法。
Expand All @@ -182,7 +199,7 @@ public enum TemperatureUnit
}
```

对话时带上方法的名称、描述和参数列表,参数列表以 JSON Schema 的形式提供。
对话时带上方法的名称、描述和参数列表,参数列表以 JSON Schema 的形式提供(这里使用 `JsonSchema.Net` 库,您也可以使用其它具有类似功能的库)

```csharp
var tools = new List<ToolDefinition>()
Expand Down
18 changes: 13 additions & 5 deletions sample/Cnblogs.DashScope.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
switch (type)
{
case SampleType.TextCompletion:
Console.WriteLine("Prompt > ");
Console.Write("Prompt > ");
userInput = Console.ReadLine()!;
await TextCompletionAsync(userInput);
break;
case SampleType.TextCompletionSse:
Console.WriteLine("Prompt > ");
Console.Write("Prompt > ");
userInput = Console.ReadLine()!;
await TextCompletionStreamAsync(userInput);
break;
Expand Down Expand Up @@ -97,9 +97,14 @@ async Task ChatStreamAsync()
history.Add(TextChatMessage.User(input));
var stream = dashScopeClient
.GetQWenChatStreamAsync(
QWenLlm.QWenMax,
QWenLlm.QWenPlusLatest,
history,
new TextGenerationParameters { IncrementalOutput = true, ResultFormat = ResultFormats.Message });
new TextGenerationParameters
{
IncrementalOutput = true,
ResultFormat = ResultFormats.Message,
EnableThinking = true
});
var role = string.Empty;
var message = new StringBuilder();
await foreach (var modelResponse in stream)
Expand All @@ -112,7 +117,10 @@ async Task ChatStreamAsync()
}

message.Append(chunk.Message.Content);
Console.Write(chunk.Message.Content);
var write = string.IsNullOrEmpty(chunk.Message.ReasoningContent)
? chunk.Message.Content
: chunk.Message.ReasoningContent;
Console.Write(write);
}

Console.WriteLine();
Expand Down
5 changes: 5 additions & 0 deletions src/Cnblogs.DashScope.Core/ITextGenerationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public interface ITextGenerationParameters
/// </summary>
public bool? EnableSearch { get; }

/// <summary>
/// Thinking option. Valid for supported models.(e.g. qwen3)
/// </summary>
public bool? EnableThinking { get; }

/// <summary>
/// Available tools for model to call.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// Output details for text generation api.
/// </summary>
/// <param name="ReasoningTokens">Token count of reasoning content.</param>
public record TextGenerationOutputTokenDetails(int ReasoningTokens);
3 changes: 3 additions & 0 deletions src/Cnblogs.DashScope.Core/TextGenerationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public class TextGenerationParameters : ITextGenerationParameters
/// <inheritdoc />
public bool? EnableSearch { get; set; }

/// <inheritdoc />
public bool? EnableThinking { get; set; }

/// <inheritdoc />
public IEnumerable<ToolDefinition>? Tools { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// Token usage details.
/// </summary>
/// <param name="CachedTokens">Token count of cached input.</param>
public record TextGenerationPromptTokenDetails(int CachedTokens);
7 changes: 0 additions & 7 deletions src/Cnblogs.DashScope.Core/TextGenerationTokenDetails.cs

This file was deleted.

7 changes: 6 additions & 1 deletion src/Cnblogs.DashScope.Core/TextGenerationTokenUsage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ public class TextGenerationTokenUsage
/// <summary>
/// Input token details.
/// </summary>
public TextGenerationTokenDetails? PromptTokensDetails { get; set; }
public TextGenerationPromptTokenDetails? PromptTokensDetails { get; set; }

/// <summary>
/// Output token details.
/// </summary>
public TextGenerationOutputTokenDetails? OutputTokensDetails { get; set; }

/// <summary>
/// The number of output token.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
]
},
"parameters": {
"incremental_output": false
"incremental_output": false,
"result_format": "message"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"model": "deepseek-r1",
"model": "qwen-plus-latest",
"input": {
"messages": [
{
Expand All @@ -9,6 +9,8 @@
]
},
"parameters": {
"incremental_output": true
"incremental_output": true,
"result_format": "message",
"enable_thinking": true
}
}
Loading