Skip to content

Commit 866ba20

Browse files
committed
feat: add qwen-long sample
1 parent 5527132 commit 866ba20

File tree

6 files changed

+315
-9
lines changed

6 files changed

+315
-9
lines changed

README.zh-Hans.md

Lines changed: 169 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ public class YourService(IDashScopeClient client)
6767
## 支持的 API
6868

6969
- [文本生成](#文本生成) - QWen3, DeepSeek 等,支持推理/工具调用/网络搜索/翻译等场景
70+
- [多轮对话](#多轮对话)
71+
- [深度思考](#深度思考)
72+
- [联网搜索](#联网搜索)
73+
- [工具调用](#工具调用)
74+
- [前缀续写](#前缀续写)
75+
- [长上下文(Qwen-Long)](#长上下文(Qwen-Long))
76+
7077
- [多模态](#多模态) - QWen-VL,QVQ 等,支持推理/视觉理解/OCR/音频理解等场景
7178
- [语音合成](#语音合成) - CosyVoice,Sambert 等,支持 TTS 等应用场景
7279
- [图像生成](#图像生成) - wanx2.1 等,支持文生图,人像风格重绘等应用场景
@@ -1129,15 +1136,170 @@ Usage: in(31)/out(34)/reasoning()/total(65)
11291136
*/
11301137
```
11311138

1139+
### 长上下文(Qwen-Long)
1140+
1141+
尽管 QWen-Long 支持直接传入字符串,但还是推荐先将文件上传后再通过 FileId 的形式传入 `message` 数组中。
1142+
1143+
上传文件,使用 `UploadFileAsync()` 方法传入文件(注意不是 `UploadTemporaryFileAsync`, 后者是用于上传媒体文件的):
1144+
1145+
```csharp
1146+
var file1 = await client.UploadFileAsync(File.OpenRead("1024-1.txt"), "file1.txt");
1147+
```
1148+
1149+
然后将文件作为 `system` 消息传入消息数组中,注意第一条 `system` 消息不能省略,否则模型可能会将文件里的内容当作 System prompt 。
1150+
1151+
```csharp
1152+
var messages = new List<TextChatMessage>();
1153+
messages.Add(TextChatMessage.System("You are a helpful assistant"));
1154+
messages.Add(TextChatMessage.File(file1.Id));
1155+
messages.Add(TextChatMessage.File(file2.Id));
1156+
// 也可以传入文件数组 messages.Add(TextChatMessage.File([file1.Id, file2.Id]));
1157+
```
1158+
1159+
再以 `user` 消息添加与文件内容相关的问题。
1160+
1161+
```csharp
1162+
messages.Add(TextChatMessage.User("这两篇文章分别讲了什么?"));
1163+
```
1164+
1165+
最后向模型发送请求,注意这个接口获得的文件 ID 只有 `qwen-long` 模型可以访问,其他模型是访问不到的。
1166+
1167+
```csharp
1168+
var completion = client.GetTextCompletionStreamAsync(
1169+
new ModelRequest<TextGenerationInput, ITextGenerationParameters>()
1170+
{
1171+
Model = "qwen-long",
1172+
Input = new TextGenerationInput() { Messages = messages },
1173+
Parameters = new TextGenerationParameters()
1174+
{
1175+
ResultFormat = "message",
1176+
IncrementalOutput = true
1177+
}
1178+
});
1179+
```
1180+
1181+
最后可以通过 `DeleteFileAsync()` 方法删除上传的文件
1182+
1183+
```csharp
1184+
var result = await client.DeleteFileAsync(file1.Id);
1185+
Console.WriteLine(result.Deleted ? "Success" : "Failed");
1186+
```
1187+
1188+
完整示例
1189+
1190+
```csharp
1191+
Console.WriteLine("Uploading file1...");
1192+
var file1 = await client.UploadFileAsync(File.OpenRead("1024-1.txt"), "file1.txt");
1193+
Console.WriteLine("Uploading file2...");
1194+
var file2 = await client.UploadFileAsync(File.OpenRead("1024-2.txt"), "file2.txt");
1195+
Console.WriteLine($"Uploaded, file1 id: {file1.Id.ToUrl()}, file2 id: {file2.Id.ToUrl()}");
1196+
1197+
var messages = new List<TextChatMessage>();
1198+
messages.Add(TextChatMessage.System("You are a helpful assistant"));
1199+
messages.Add(TextChatMessage.File(file1.Id));
1200+
messages.Add(TextChatMessage.File(file2.Id));
1201+
messages.Add(TextChatMessage.User("这两篇文章分别讲了什么?"));
1202+
1203+
messages.ForEach(m => Console.WriteLine($"{m.Role} > {m.Content}"));
1204+
var completion = client.GetTextCompletionStreamAsync(
1205+
new ModelRequest<TextGenerationInput, ITextGenerationParameters>()
1206+
{
1207+
Model = "qwen-long",
1208+
Input = new TextGenerationInput() { Messages = messages },
1209+
Parameters = new TextGenerationParameters()
1210+
{
1211+
ResultFormat = "message",
1212+
IncrementalOutput = true
1213+
}
1214+
});
1215+
var reply = new StringBuilder();
1216+
var reasoning = false;
1217+
TextGenerationTokenUsage? usage = null;
1218+
await foreach (var chunk in completion)
1219+
{
1220+
var choice = chunk.Output.Choices![0];
1221+
if (string.IsNullOrEmpty(choice.Message.ReasoningContent) == false)
1222+
{
1223+
// reasoning
1224+
if (reasoning == false)
1225+
{
1226+
Console.Write("Reasoning > ");
1227+
reasoning = true;
1228+
}
1229+
1230+
Console.Write(choice.Message.ReasoningContent);
1231+
continue;
1232+
}
1233+
1234+
if (reasoning)
1235+
{
1236+
reasoning = false;
1237+
Console.WriteLine();
1238+
Console.Write("Assistant > ");
1239+
}
1240+
1241+
Console.Write(choice.Message.Content);
1242+
reply.Append(choice.Message.Content);
1243+
usage = chunk.Usage;
1244+
}
1245+
1246+
Console.WriteLine();
1247+
messages.Add(TextChatMessage.Assistant(reply.ToString()));
1248+
if (usage != null)
1249+
{
1250+
Console.WriteLine(
1251+
$"Usage: in({usage.InputTokens})/out({usage.OutputTokens})/reasoning({usage.OutputTokensDetails?.ReasoningTokens})/total({usage.TotalTokens})");
1252+
}
1253+
1254+
// Deleting files
1255+
Console.Write("Deleting file1...");
1256+
var result = await client.DeleteFileAsync(file1.Id);
1257+
Console.WriteLine(result.Deleted ? "Success" : "Failed");
1258+
Console.Write("Deleting file2...");
1259+
result = await client.DeleteFileAsync(file2.Id);
1260+
Console.WriteLine(result.Deleted ? "Success" : "Failed");
1261+
1262+
/*
1263+
Uploading file1...
1264+
Uploading file2...
1265+
Uploaded, file1 id: fileid://file-fe-b87a5c12cc354533bd882f04, file2 id: fileid://file-fe-f5269f9996d544c4aecc5f80
1266+
system > You are a helpful assistant
1267+
system > fileid://file-fe-b87a5c12cc354533bd882f04
1268+
system > fileid://file-fe-f5269f9996d544c4aecc5f80
1269+
user > 这两篇文章分别讲了什么?
1270+
这两篇文章都围绕“中国程序员节”的设立展开,但内容侧重点不同:
1271+
1272+
**第一篇文章《file1.txt》:**
1273+
这篇文章是一篇征求意见稿,标题为《中国程序员节,10月24日,你同意吗?》。文章回顾了此前关于设立中国程序员节的讨论背景——受俄罗斯程序员节(每年第256天)启发,有网友提议设立中国的程序员 节。文中提到曾有人建议定在10月10日(因为“1010”类似二进制),但作者认为10月24日更具意义:
1274+
- 因为1024 = 2^10,是计算机中“1K”的近似值;
1275+
- 1024在二进制、八进制和十六进制中都有特殊表示;
1276+
- 节日时间上避开国庆后的调整期。
1277+
因此,文章向读者征求是否同意将**10月24日**作为中国程序员节,并邀请大家参与投票和提出庆祝活动建议。
1278+
1279+
**第二篇文章《file2.txt》:**
1280+
这篇文章是第一篇的后续,标题为《程序员节,10月24日!》,属于正式 announcement(公告)。它宣布:
1281+
- 根据前一次讨论的反馈结果,正式确定将**每年的10月24日**定为“中国程序员节”;
1282+
- 博客园将在该日组织线上庆祝活动;
1283+
- 文章进一步升华主题,强调程序员的社会价值和责任感,呼吁尊重程序员群体,肯定他们是“用代码改变世界的人”,并表达了对技术创造力的敬意。
1284+
1285+
**总结:**
1286+
- 第一篇是**征求意见**,探讨是否将10月24日设为中国程序员节;
1287+
- 第二篇是**正式确认**节日日期,并倡导庆祝与认同程序员的价值。
1288+
Usage: in(513)/out(396)/reasoning()/total(909)
1289+
Deleting file1...Success
1290+
Deleting file2...Success
1291+
*/
1292+
```
1293+
11321294

11331295

1134-
### 多模态
1296+
## 多模态
11351297

11361298
使用 `dashScopeClient.GetMultimodalGenerationAsync``dashScopeClient.GetMultimodalGenerationStreamAsync` 来访问多模态文本生成接口。
11371299

11381300
相关文档:[多模态_大模型服务平台百炼(Model Studio)-阿里云帮助中心](https://help.aliyun.com/zh/model-studio/multimodal)
11391301

1140-
#### 视觉理解/推理
1302+
### 视觉理解/推理
11411303

11421304
使用 `MultimodalMessage.User()` 可以快速创建对应角色的消息。
11431305

@@ -1198,7 +1360,7 @@ await foreach (var modelResponse in response)
11981360
}
11991361
```
12001362

1201-
### 语音合成
1363+
## 语音合成
12021364

12031365
通过 `dashScopeClient.CreateSpeechSynthesizerSocketSessionAsync()` 来创建一个语音合成会话。
12041366

@@ -1235,9 +1397,9 @@ Console.WriteLine($"audio saved to {file.FullName}, token usage: {tokenUsage}");
12351397
break;
12361398
```
12371399

1238-
### 图像生成
1400+
## 图像生成
12391401

1240-
#### 文生图
1402+
### 文生图
12411403

12421404
我们针对通义万相提供了快捷 API `dashScopeClient.CreateWanxImageSynthesisTaskAsync()``GetWanxImageSynthesisTaskAsync()`
12431405

@@ -1286,7 +1448,7 @@ Console.WriteLine($"Task timout, taskId: {task.TaskId}");
12861448

12871449
图像背景生成 - `CreateWanxBackgroundGenerationTaskAsync``GetWanxBackgroundGenerationTaskAsync`
12881450

1289-
### 应用调用
1451+
## 应用调用
12901452

12911453
`GetApplicationResponseAsync` 用于进行应用调用。
12921454

@@ -1354,7 +1516,7 @@ var response = await client.GetApplicationResponseAsync("your-application-id", r
13541516
Console.WriteLine(response.Output.Text);
13551517
```
13561518

1357-
### 文本向量
1519+
## 文本向量
13581520

13591521
使用 `GetTextEmbeddingsAsync` 来调用文本向量接口。
13601522

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
中国程序员节,10月24日,你同意吗?
2+
大家好!
3+
4+
国庆长假之后,我们来确定一下中国程序员节的日子吧。
5+
6+
9月份的时候,我们针对中国程序员节进行了讨论与投票。
7+
8+
起因是一条新闻“今天是程序员节”,俄罗斯把每年的第256(0x100th)天作为程序员节,通常是9月12日,也有可能是9月13日。
9+
10+
园友贤达在评论中说:
11+
12+
想想这么多年中国程序员这么辛苦,怎么就没有个法定的程序员节日呢?
13+
可执行文件的代码只有0和1,希望有一个10.10为中国程序员节。
14+
于是,很多朋友支持把10月10日作为中国程序员节。
15+
16+
但10月10日紧接着中秋节与国庆节之后,大家正在恢复调整进入工作状态之中。
17+
18+
所以我们觉得10月24日可能更合适(今年的10月24日是星期天),1024是很有意义的一个数字,1K=1024,1024=2的10次方,二进制10000000000,八进制2000,十六进制0x400。
19+
20+
所以在这里征询一下大家意见,如果你同意10月24日作为中国程序员节,请点击随笔下面的推荐按钮,如果不同意,请点击反对按钮。
21+
22+
如果确定了中国程序员节,我们会在那天组织网上的庆贺活动。如果大家对活动形式有好的建议,也欢迎在这里提出。
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
程序员节,10月24日!
2+
根据大家在“中国程序员节,10月24日,你同意吗”中的反馈,现在确定中国程序员节放在每年的10月24日。博客园将在10月24日那天组织网上庆祝活动。
3+
4+
希望通过程序员节,代表着我们的一种努力,努力将程序员们凝聚在一起,为社会创造更多价值,得到更多的认可。我们是程序员,不是代码工人,不是IT民工,是一群用代码改变世界的人。我们的代码可以给社会带来进步,也可能给社会带来灾难,我们的责任重于泰山;我们生活于现实世界,却在创造虚拟世界,我们的创造力无限...如果阿基米德是程序员,他会说“给我一台电脑,我就能改变世界”。

sample/Cnblogs.DashScope.Sample/Cnblogs.DashScope.Sample.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
<None Update="Lenna.jpg">
2121
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
2222
</None>
23+
<None Update="1024-1.txt">
24+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
25+
</None>
26+
<None Update="1024-2.txt">
27+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
28+
</None>
2329
</ItemGroup>
2430

2531
<ItemGroup>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System.Text;
2+
using Cnblogs.DashScope.Core;
3+
4+
namespace Cnblogs.DashScope.Sample.Text;
5+
6+
public class LongContextSample : ISample
7+
{
8+
/// <inheritdoc />
9+
public string Description => "File upload and long context model sample";
10+
11+
/// <inheritdoc />
12+
public async Task RunAsync(IDashScopeClient client)
13+
{
14+
Console.WriteLine("Uploading file1...");
15+
var file1 = await client.UploadFileAsync(File.OpenRead("1024-1.txt"), "file1.txt");
16+
Console.WriteLine("Uploading file2...");
17+
var file2 = await client.UploadFileAsync(File.OpenRead("1024-2.txt"), "file2.txt");
18+
Console.WriteLine($"Uploaded, file1 id: {file1.Id.ToUrl()}, file2 id: {file2.Id.ToUrl()}");
19+
20+
var messages = new List<TextChatMessage>();
21+
messages.Add(TextChatMessage.System("You are a helpful assistant"));
22+
messages.Add(TextChatMessage.File(file1.Id));
23+
messages.Add(TextChatMessage.File(file2.Id));
24+
messages.Add(TextChatMessage.User("这两篇文章分别讲了什么?"));
25+
26+
messages.ForEach(m => Console.WriteLine($"{m.Role} > {m.Content}"));
27+
var completion = client.GetTextCompletionStreamAsync(
28+
new ModelRequest<TextGenerationInput, ITextGenerationParameters>()
29+
{
30+
Model = "qwen-long",
31+
Input = new TextGenerationInput() { Messages = messages },
32+
Parameters = new TextGenerationParameters() { ResultFormat = "message", IncrementalOutput = true }
33+
});
34+
var reply = new StringBuilder();
35+
var reasoning = false;
36+
TextGenerationTokenUsage? usage = null;
37+
await foreach (var chunk in completion)
38+
{
39+
var choice = chunk.Output.Choices![0];
40+
if (string.IsNullOrEmpty(choice.Message.ReasoningContent) == false)
41+
{
42+
// reasoning
43+
if (reasoning == false)
44+
{
45+
Console.Write("Reasoning > ");
46+
reasoning = true;
47+
}
48+
49+
Console.Write(choice.Message.ReasoningContent);
50+
continue;
51+
}
52+
53+
if (reasoning)
54+
{
55+
reasoning = false;
56+
Console.WriteLine();
57+
Console.Write("Assistant > ");
58+
}
59+
60+
Console.Write(choice.Message.Content);
61+
reply.Append(choice.Message.Content);
62+
usage = chunk.Usage;
63+
}
64+
65+
Console.WriteLine();
66+
messages.Add(TextChatMessage.Assistant(reply.ToString()));
67+
if (usage != null)
68+
{
69+
Console.WriteLine(
70+
$"Usage: in({usage.InputTokens})/out({usage.OutputTokens})/reasoning({usage.OutputTokensDetails?.ReasoningTokens})/total({usage.TotalTokens})");
71+
}
72+
73+
// Deleting files
74+
Console.Write("Deleting file1...");
75+
var result = await client.DeleteFileAsync(file1.Id);
76+
Console.WriteLine(result.Deleted ? "Success" : "Failed");
77+
Console.Write("Deleting file2...");
78+
result = await client.DeleteFileAsync(file2.Id);
79+
Console.WriteLine(result.Deleted ? "Success" : "Failed");
80+
}
81+
}
82+
83+
/*
84+
Uploading file1...
85+
Uploading file2...
86+
Uploaded, file1 id: fileid://file-fe-b87a5c12cc354533bd882f04, file2 id: fileid://file-fe-f5269f9996d544c4aecc5f80
87+
system > You are a helpful assistant
88+
system > fileid://file-fe-b87a5c12cc354533bd882f04
89+
system > fileid://file-fe-f5269f9996d544c4aecc5f80
90+
user > 这两篇文章分别讲了什么?
91+
这两篇文章都围绕“中国程序员节”的设立展开,但内容侧重点不同:
92+
93+
**第一篇文章《file1.txt》:**
94+
这篇文章是一篇征求意见稿,标题为《中国程序员节,10月24日,你同意吗?》。文章回顾了此前关于设立中国程序员节的讨论背景——受俄罗斯程序员节(每年第256天)启发,有网友提议设立中国的程序员 节。文中提到曾有人建议定在10月10日(因为“1010”类似二进制),但作者认为10月24日更具意义:
95+
- 因为1024 = 2^10,是计算机中“1K”的近似值;
96+
- 1024在二进制、八进制和十六进制中都有特殊表示;
97+
- 节日时间上避开国庆后的调整期。
98+
因此,文章向读者征求是否同意将**10月24日**作为中国程序员节,并邀请大家参与投票和提出庆祝活动建议。
99+
100+
**第二篇文章《file2.txt》:**
101+
这篇文章是第一篇的后续,标题为《程序员节,10月24日!》,属于正式 announcement(公告)。它宣布:
102+
- 根据前一次讨论的反馈结果,正式确定将**每年的10月24日**定为“中国程序员节”;
103+
- 博客园将在该日组织线上庆祝活动;
104+
- 文章进一步升华主题,强调程序员的社会价值和责任感,呼吁尊重程序员群体,肯定他们是“用代码改变世界的人”,并表达了对技术创造力的敬意。
105+
106+
**总结:**
107+
- 第一篇是**征求意见**,探讨是否将10月24日设为中国程序员节;
108+
- 第二篇是**正式确认**节日日期,并倡导庆祝与认同程序员的价值。
109+
Usage: in(513)/out(396)/reasoning()/total(909)
110+
Deleting file1...Success
111+
Deleting file2...Success
112+
*/

src/Cnblogs.DashScope.Core/IDashScopeClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,11 @@ public Task<ModelResponse<BackgroundGenerationOutput, BackgroundGenerationUsage>
208208
CancellationToken cancellationToken = default);
209209

210210
/// <summary>
211-
/// Upload file for model to reference.
211+
/// OpenAI compatible upload api, for model to reference.
212212
/// </summary>
213213
/// <param name="file">File data.</param>
214214
/// <param name="filename">Name of the file.</param>
215-
/// <param name="purpose">Purpose of the file, use "file-extract" to allow model access the file.</param>
215+
/// <param name="purpose">Purpose of the file, use "file-extract" to allow model access the file. Use "batch" for uploading batch operations .jsonl file.</param>
216216
/// <param name="cancellationToken">The cancellation token to use.</param>
217217
/// <returns></returns>
218218
public Task<DashScopeFile> UploadFileAsync(

0 commit comments

Comments
 (0)