Skip to content

Commit 1a273cc

Browse files
committed
refactor: provide pure api access for semantic kernel
1 parent 0b0b3e3 commit 1a273cc

File tree

122 files changed

+507
-153
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+507
-153
lines changed

Cnblogs.DashScope.Sdk.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.Sample",
1414
EndProject
1515
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.AspNetCore", "src\Cnblogs.DashScope.AspNetCore\Cnblogs.DashScope.AspNetCore.csproj", "{C910495B-87AB-4AC1-989C-B6720695A139}"
1616
EndProject
17+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.Core", "src\Cnblogs.DashScope.Core\Cnblogs.DashScope.Core.csproj", "{CC389455-A3EA-4F09-B524-4DC351A1E1AA}"
18+
EndProject
1719
Global
1820
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1921
Debug|Any CPU = Debug|Any CPU
@@ -24,6 +26,7 @@ Global
2426
{BC102292-E664-47F5-B0C7-C4D7A2301002} = {CFC8ECB3-5248-46CD-A56C-EC088F2A3804}
2527
{8885149A-78F0-4C8E-B9AA-87A46EA69219} = {2E15D1EC-4A07-416E-8BE6-D907F509FD35}
2628
{C910495B-87AB-4AC1-989C-B6720695A139} = {008988ED-0A3B-4272-BCC3-7B4110699345}
29+
{CC389455-A3EA-4F09-B524-4DC351A1E1AA} = {008988ED-0A3B-4272-BCC3-7B4110699345}
2730
EndGlobalSection
2831
GlobalSection(ProjectConfigurationPlatforms) = postSolution
2932
{FA6A118A-8D26-4B7A-9952-8504B8A0025B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -42,5 +45,9 @@ Global
4245
{C910495B-87AB-4AC1-989C-B6720695A139}.Debug|Any CPU.Build.0 = Debug|Any CPU
4346
{C910495B-87AB-4AC1-989C-B6720695A139}.Release|Any CPU.ActiveCfg = Release|Any CPU
4447
{C910495B-87AB-4AC1-989C-B6720695A139}.Release|Any CPU.Build.0 = Release|Any CPU
48+
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49+
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
50+
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
51+
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Release|Any CPU.Build.0 = Release|Any CPU
4552
EndGlobalSection
4653
EndGlobal

README.md

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ English | [简体中文](https://github.com/cnblogs/dashscope-sdk/blob/main/READ
77

88
An unofficial DashScope SDK maintained by Cnblogs.
99

10-
# Usage
10+
# Quick Start
1111

1212
## Console App
1313

14-
Install Cnblogs.DashScope.Sdk package.
14+
Install `Cnblogs.DashScope.Sdk` package.
1515

1616
```csharp
1717
var client = new DashScopeClient("your-api-key");
@@ -55,8 +55,109 @@ public class YourService(IDashScopeClient client)
5555
- Text Generation API(qwen-turbo, qwen-max, etc.) - `dashScopeClient.GetQwenCompletionAsync()` and `dashScopeClient.GetQWenCompletionStreamAsync()`
5656
- BaiChuan Models - Use `dashScopeClient.GetBaiChuanTextCompletionAsync()`
5757
- LLaMa2 Models - `dashScopeClient.GetLlama2TextCompletionAsync()`
58-
- Multimodal Generation API(qwen-vl-max, etc.) - `dashScopeClient.GetQWenMultimodalCompletionAsync` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync`
58+
- Multimodal Generation API(qwen-vl-max, etc.) - `dashScopeClient.GetQWenMultimodalCompletionAsync()` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync()`
5959
- Wanx Models(Image generation, background generation, etc)
6060
- Image Synthesis - `CreateWanxImageSynthesisTaskAsync()` and `GetWanxImageSynthesisTaskAsync()`
61-
- Image Generation - `CreateWanxImageGenerationTaskAsync` and `GetWanxImageGenerationTaskAsync()`
62-
- Background Image Generation - `CreateWanxBackgroundGenerationTaskAsync` and `GetWanxBackgroundGenerationTaskAsync`
61+
- Image Generation - `CreateWanxImageGenerationTaskAsync()` and `GetWanxImageGenerationTaskAsync()`
62+
- Background Image Generation - `CreateWanxBackgroundGenerationTaskAsync()` and `GetWanxBackgroundGenerationTaskAsync()`
63+
64+
65+
# Examples
66+
67+
Visit [tests](./test) for more usage of each api.
68+
69+
## Single Text Completion
70+
71+
```csharp
72+
var prompt = "hello"
73+
var completion = await client.GetQWenCompletionAsync(QWenLlm.QWenMax, prompt);
74+
Console.WriteLine(completion.Output.Text);
75+
```
76+
77+
## Multi-round chat
78+
79+
```csharp
80+
var history = new List<ChatMessage>
81+
{
82+
new("user", "Please remember this number, 42"),
83+
new("assistant", "I have remembered this number."),
84+
new("user", "What was the number I metioned before?")
85+
}
86+
var parameters = new TextGenerationParameters()
87+
{
88+
ResultFormat = ResultFormats.Message
89+
};
90+
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
91+
Console.WriteLine(completion.Output.Choices[0].Message.Content); // The number is 42
92+
```
93+
94+
## Function Call
95+
96+
Creates a function with parameters
97+
98+
```csharp
99+
string GetCurrentWeather(GetCurrentWeatherParameters parameters)
100+
{
101+
// actual implementation should be different.
102+
return "Sunny, 14" + parameters.Unit switch
103+
{
104+
TemperatureUnit.Celsius => "",
105+
TemperatureUnit.Fahrenheit => ""
106+
};
107+
}
108+
109+
public record GetCurrentWeatherParameters(
110+
[property: Required]
111+
[property: Description("The city and state, e.g. San Francisco, CA")]
112+
string Location,
113+
[property: JsonConverter(typeof(EnumStringConverter<TemperatureUnit>))]
114+
TemperatureUnit Unit = TemperatureUnit.Celsius);
115+
116+
public enum TemperatureUnit
117+
{
118+
Celsius,
119+
Fahrenheit
120+
}
121+
```
122+
123+
Append tool information to chat messages.
124+
125+
```csharp
126+
var tools = new List<ToolDefinition>()
127+
{
128+
new(
129+
ToolTypes.Function,
130+
new FunctionDefinition(
131+
nameof(GetCurrentWeather),
132+
"Get the weather abount given location",
133+
new JsonSchemaBuilder().FromType<GetCurrentWeatherParameters>().Build()))
134+
};
135+
136+
var history = new List<ChatMessage>
137+
{
138+
new("user", "What is the weather today in C.A?")
139+
};
140+
141+
var parameters = new TextGenerationParamters()
142+
{
143+
ResultFormat = ResultFormats.Message,
144+
Tools = tools
145+
};
146+
147+
// send question with available tools.
148+
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
149+
history.Add(completion.Output.Choice[0].Message);
150+
151+
// model responding with tool calls.
152+
Console.WriteLine(completion.Output.Choice[0].Message.ToolCalls[0].Function.Name); // GetCurrentWeather
153+
154+
// calling tool that model requests and append result into history.
155+
var result = GetCurrentWeather(JsonSerializer.Deserialize<GetCurrentWeatherParameters>(completion.Output.Choice[0].Message.ToolCalls[0].Function.Arguments));
156+
history.Add(new("tool", result, nameof(GetCurrentWeather)));
157+
158+
// get back answers.
159+
completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
160+
Console.WriteLine(completion.Output.Choice[0].Message.Content);
161+
```
162+
163+
Append the tool calling result with `tool` role, then model will generate answers based on tool calling result.

README.zh-Hans.md

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
由博客园维护并使用的非官方灵积服务 SDK
99

10-
# 使用方法
10+
# 快速开始
1111

1212
## 控制台应用
1313

@@ -55,8 +55,105 @@ public class YourService(IDashScopeClient client)
5555
- 通义千问(`qwen-turbo``qwen-max` 等) - `dashScopeClient.GetQwenCompletionAsync()` and `dashScopeClient.GetQWenCompletionStreamAsync()`
5656
- 百川开源大模型 - Use `dashScopeClient.GetBaiChuanTextCompletionAsync()`
5757
- LLaMa2 大语言模型 - `dashScopeClient.GetLlama2TextCompletionAsync()`
58-
- 通义千问 VL 和通义千问 Audio(`qwen-vl-max``qwen-audio`) - `dashScopeClient.GetQWenMultimodalCompletionAsync` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync`
58+
- 通义千问 VL 和通义千问 Audio(`qwen-vl-max``qwen-audio`) - `dashScopeClient.GetQWenMultimodalCompletionAsync()` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync()`
5959
- 通义万相系列
6060
- 文生图 - `CreateWanxImageSynthesisTaskAsync()` and `GetWanxImageSynthesisTaskAsync()`
61-
- 人像风格重绘 - `CreateWanxImageGenerationTaskAsync` and `GetWanxImageGenerationTaskAsync()`
62-
- 图像背景生成 - `CreateWanxBackgroundGenerationTaskAsync` and `GetWanxBackgroundGenerationTaskAsync`
61+
- 人像风格重绘 - `CreateWanxImageGenerationTaskAsync()` and `GetWanxImageGenerationTaskAsync()`
62+
- 图像背景生成 - `CreateWanxBackgroundGenerationTaskAsync()` and `GetWanxBackgroundGenerationTaskAsync()`
63+
64+
65+
# 示例
66+
67+
查看 [测试](./test) 获得更多 API 使用示例。
68+
69+
## 单轮对话
70+
71+
```csharp
72+
var prompt = "你好"
73+
var completion = await client.GetQWenCompletionAsync(QWenLlm.QWenMax, prompt);
74+
Console.WriteLine(completion.Output.Text);
75+
```
76+
77+
## 多轮对话
78+
79+
```csharp
80+
var history = new List<ChatMessage>
81+
{
82+
new("user", "Please remember this number, 42"),
83+
new("assistant", "I have remembered this number."),
84+
new("user", "What was the number I metioned before?")
85+
}
86+
var parameters = new TextGenerationParameters()
87+
{
88+
ResultFormat = ResultFormats.Message
89+
};
90+
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
91+
Console.WriteLine(completion.Output.Choices[0].Message.Content); // The number is 42
92+
```
93+
94+
## 工具调用
95+
96+
创建一个可供模型使用的方法。
97+
98+
```csharp
99+
string GetCurrentWeather(GetCurrentWeatherParameters parameters)
100+
{
101+
// implementation is irrenlvent
102+
return "Sunny"
103+
}
104+
105+
public record GetCurrentWeatherParameters(
106+
[property: Required]
107+
[property: Description("The city and state, e.g. San Francisco, CA")]
108+
string Location,
109+
[property: JsonConverter(typeof(EnumStringConverter<TemperatureUnit>))]
110+
TemperatureUnit Unit = TemperatureUnit.Celsius);
111+
112+
public enum TemperatureUnit
113+
{
114+
Celsius,
115+
Fahrenheit
116+
}
117+
```
118+
119+
对话时带上方法的名称、描述和参数列表,参数列表以 JSON Schema 的形式提供。
120+
121+
```csharp
122+
var tools = new List<ToolDefinition>()
123+
{
124+
new(
125+
ToolTypes.Function,
126+
new FunctionDefinition(
127+
nameof(GetCurrentWeather),
128+
"获取当前天气",
129+
new JsonSchemaBuilder().FromType<GetCurrentWeatherParameters>().Build()))
130+
};
131+
132+
var history = new List<ChatMessage>
133+
{
134+
new("user", "杭州现在天气如何?")
135+
};
136+
137+
var parameters = new TextGenerationParamters()
138+
{
139+
ResultFormat = ResultFormats.Message,
140+
Tools = tools
141+
};
142+
143+
// 向模型提问并提供可用的方法
144+
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
145+
146+
// 模型试图调用方法
147+
Console.WriteLine(completion.Output.Choice[0].Message.ToolCalls[0].Function.Name); // GetCurrentWeather
148+
history.Add(completion.Output.Choice[0].Message);
149+
150+
// 调用方法并将结果保存到聊天记录中
151+
var result = GetCurrentWeather(JsonSerializer.Deserialize<GetCurrentWeatherParameters>(completion.Output.Choice[0].Message.ToolCalls[0].Function.Arguments));
152+
history.Add(new("tool", result, nameof(GetCurrentWeather)));
153+
154+
// 模型根据调用结果返回答案
155+
completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
156+
Console.WriteLine(completion.Output.Choice[0].Message.Content) // 现在浙江省杭州市的天气是大部多云,气温为 18 摄氏度。
157+
```
158+
159+
当模型认为应当调用工具时,返回消息中 `ToolCalls` 会提供调用的详情,本地在调用完成后可以把结果以 `tool` 角色返回。

sample/Cnblogs.DashScope.Sample/Program.cs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
using System.Text;
2+
using System.Text.Json;
3+
using Cnblogs.DashScope.Core;
24
using Cnblogs.DashScope.Sample;
35
using Cnblogs.DashScope.Sdk;
46
using Cnblogs.DashScope.Sdk.QWen;
7+
using Json.Schema;
8+
using Json.Schema.Generation;
59

6-
const string apiKey = "your api key";
10+
const string apiKey = "sk-eeff76d62cc946e5af8d1444f079a34e";
711
var dashScopeClient = new DashScopeClient(apiKey);
812

913
Console.WriteLine("Choose the sample you want to run:");
@@ -12,6 +16,7 @@
1216
Console.WriteLine($"{(int)sampleType}.{sampleType.GetDescription()}");
1317
}
1418

19+
Console.WriteLine();
1520
Console.Write("Choose an option: ");
1621
var type = (SampleType)int.Parse(Console.ReadLine()!);
1722

@@ -31,6 +36,9 @@
3136
case SampleType.ChatCompletion:
3237
await ChatStreamAsync();
3338
break;
39+
case SampleType.ChatCompletionWithTool:
40+
await ChatWithToolsAsync();
41+
break;
3442
}
3543

3644
return;
@@ -88,3 +96,47 @@ async Task ChatStreamAsync()
8896

8997
// ReSharper disable once FunctionNeverReturns
9098
}
99+
100+
async Task ChatWithToolsAsync()
101+
{
102+
var history = new List<ChatMessage>();
103+
var tools = new List<ToolDefinition>
104+
{
105+
new(
106+
ToolTypes.Function,
107+
new FunctionDefinition(
108+
nameof(GetWeather),
109+
"获得当前天气",
110+
new JsonSchemaBuilder().FromType<WeatherReportParameters>().Build()))
111+
};
112+
var chatParameters = new TextGenerationParameters() { ResultFormat = ResultFormats.Message, Tools = tools };
113+
var question = new ChatMessage("user", "请问现在杭州的天气如何?");
114+
history.Add(question);
115+
Console.WriteLine($"{question.Role} > {question.Content}");
116+
117+
var response = await dashScopeClient.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, chatParameters);
118+
var toolCallMessage = response.Output.Choices![0].Message;
119+
history.Add(toolCallMessage);
120+
Console.WriteLine(
121+
$"{toolCallMessage.Role} > {toolCallMessage.ToolCalls![0].Function!.Name}{toolCallMessage.ToolCalls[0].Function!.Arguments}");
122+
123+
var toolResponse = GetWeather(
124+
JsonSerializer.Deserialize<WeatherReportParameters>(toolCallMessage.ToolCalls[0].Function!.Arguments!)!);
125+
var toolMessage = new ChatMessage("tool", toolResponse, nameof(GetWeather));
126+
history.Add(toolMessage);
127+
Console.WriteLine($"{toolMessage.Role} > {toolMessage.Content}");
128+
129+
var answer = await dashScopeClient.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, chatParameters);
130+
Console.WriteLine($"{answer.Output.Choices![0].Message.Role} > {answer.Output.Choices[0].Message.Content}");
131+
132+
string GetWeather(WeatherReportParameters parameters)
133+
{
134+
return "大部多云,气温 "
135+
+ parameters.Unit switch
136+
{
137+
TemperatureUnit.Celsius => "18 摄氏度",
138+
TemperatureUnit.Fahrenheit => "64 华氏度",
139+
_ => throw new InvalidOperationException()
140+
};
141+
}
142+
}

sample/Cnblogs.DashScope.Sample/SampleType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ public enum SampleType
1212

1313
[Description("Conversation between user and assistant")]
1414
ChatCompletion,
15+
16+
[Description("Conversation with tools")]
17+
ChatCompletionWithTool
1518
}

sample/Cnblogs.DashScope.Sample/SampleTypeDescriptor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public static string GetDescription(this SampleType sampleType)
99
SampleType.TextCompletion => "Simple prompt completion",
1010
SampleType.TextCompletionSse => "Simple prompt completion with incremental output",
1111
SampleType.ChatCompletion => "Conversation between user and assistant",
12+
SampleType.ChatCompletionWithTool => "Function call sample",
1213
_ => throw new ArgumentOutOfRangeException(nameof(sampleType), sampleType, "Unsupported sample option")
1314
};
1415
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.Text.Json.Serialization;
2+
using Json.More;
3+
using Json.Schema.Generation;
4+
5+
namespace Cnblogs.DashScope.Sample;
6+
7+
public record WeatherReportParameters(
8+
[property: Required]
9+
[property: Description("要获取天气的省市名称,例如浙江省杭州市")]
10+
string Location,
11+
[property: JsonConverter(typeof(EnumStringConverter<TemperatureUnit>))]
12+
[property: Description("温度单位")]
13+
TemperatureUnit Unit = TemperatureUnit.Celsius);
14+
15+
public enum TemperatureUnit
16+
{
17+
Celsius,
18+
Fahrenheit
19+
}

src/Cnblogs.DashScope.AspNetCore/ServiceCollectionInjector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Net.Http.Headers;
2-
using Cnblogs.DashScope.Sdk;
2+
using Cnblogs.DashScope.Core;
33
using Microsoft.Extensions.Configuration;
44

55
// ReSharper disable once CheckNamespace

0 commit comments

Comments
 (0)