Skip to content

Commit eadc0fb

Browse files
authored
Merge pull request #11 from cnblogs/provide-pure-api-access-for-sk
feat: provide pure api access for semantic kernel
2 parents 0b0b3e3 + c628b31 commit eadc0fb

File tree

122 files changed

+512
-154
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

+512
-154
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: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ English | [简体中文](https://github.com/cnblogs/dashscope-sdk/blob/main/READ
77

88
An unofficial DashScope SDK maintained by Cnblogs.
99

10-
# Usage
10+
**Warning**: this project is under active development, **Breaking Changes** may introduced without notice or major version change. Make sure you read the Release Notes before upgrading.
11+
12+
# Quick Start
1113

1214
## Console App
1315

14-
Install Cnblogs.DashScope.Sdk package.
16+
Install `Cnblogs.DashScope.Sdk` package.
1517

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

README.zh-Hans.md

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
# Cnblogs.DashScopeSDK
77

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

10-
# 使用方法
10+
使用前注意:当前项目正在积极开发中,小版本也可能包含破坏性更改,升级前请查看对应版本 Release Note 进行迁移。
11+
12+
# 快速开始
1113

1214
## 控制台应用
1315

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

0 commit comments

Comments
 (0)