Avalonia是什么?
Avalonia是一個跨平臺的UI框架,專為.NET開發打造,提供靈活的樣式系統,支持Windows、macOS、Linux、iOS、Android及WebAssembly等多種平臺。它已成熟并適合生產環境,被Schneider Electric、Unity、JetBrains和GitHub等公司采用。
許多人認為Avalonia是WPF的繼任者,它為XAML開發人員提供了一種熟悉且現代的跨平臺應用開發體驗。盡管與WPF相似,但Avalonia并非完全復制,而包含了許多改進。
SemanticKernel是什么?
Semantic Kernel是一個SDK,它可以將大型語言模型(如OpenAI、Azure OpenAI和Hugging Face)與常規編程語言(如C#、Python和Java)整合。特殊之處在于,Semantic Kernel通過允許定義和鏈式調用插件,能夠自動調度并組合這些AI模型。其功能是,用戶可以向LLM提出個性化目標,由Semantic Kernel的規劃器生成實現目標的計劃,然后由系統自動執行這份計劃。
硅基流動介紹
硅基流動致力于打造大模型時代的AI基礎設施,通過算法、系統和硬件的協同創新,跨數量級降低大模型應用成本和開發門檻,加速AGI普惠人類。
SiliconCloud是集合主流開源大模型的一站式云服務平臺,為開發者提供更快、更便宜、更全面、體驗更絲滑的模型API。
目前,SiliconCloud已上架包括DeepSeek-Coder-V2、Stable Diffusion 3 Medium、Qwen2、GLM-4-9B-Chat、DeepSeek V2、SDXL、InstantID在內的多種開源大語言模型、圖片生成模型,支持用戶自由切換符合不同應用場景的模型。同時,SiliconCloud提供開箱即用的大模型推理加速服務,為生成式AI應用帶來更高效的用戶體驗。
我們知道在國內使用OpenAI不太方便同時成本也比較高。現在已經有很多開源的大模型了,但是對于個人開發者而言,部署它們的一大難點是硬件資源。沒有顯卡,也能部署一些參數少一些的開源大模型,但是推理速度肯定是很慢的,這里選擇硅基流動的原因是第一,之前注冊送了42元的額度,該額度不會過期,可以一直使用,第二,試了一下推理速度真的很快,第三(也是最重要的一點)(白嫖),硅基流動宣布:SiliconCloud平臺的Qwen2(7B)、GLM4(9B)、Yi1.5(9B)等頂尖開源大模型免費使用。
構建什么樣的工具
最近在學習Avalonia,動手做一個小工具實現自己的需求是一個很好的開始。同時對SemanticKernel也比較感興趣,所以選擇從最基本的制作一個基于大模型的聊天應用開始。個人對大模型的一大需求就是翻譯,在查看英文網站時,遇到不太理解的地方,總喜歡問大模型,將某某某翻譯為中文。因此選擇構建解決自己這個需求的Avalonia練手小工具。該工具的效果如下所示:
聊天
英譯中
中譯英
開始實踐
在SemanticKernel中使用SiliconCloud提供的API服務
要解決的第一個問題就是如何在SemanticKernel中使用SiliconCloud提供的服務。
SemanticKernel中并沒有告訴我們如何連接其他的大模型,但由于SiliconCloud提供的接口是與OpenAI兼容的,因此可以通過在發送請求時,改變發送請求的地址來實現。
添加OpenAIHttpClientHandler類:
public class OpenAIHttpClientHandler : HttpClientHandler
{protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){UriBuilder uriBuilder;switch (request.RequestUri?.LocalPath){case "/v1/chat/completions":uriBuilder = new UriBuilder(request.RequestUri){// 這里是你要修改的 URLScheme = "https",Host = "api.siliconflow.cn",Path = "v1/chat/completions",};request.RequestUri = uriBuilder.Uri;break;}HttpResponseMessage response = await base.SendAsync(request, cancellationToken);return response;}
}
kernel通過這種方式構建:
var handler = new OpenAIHttpClientHandler();
var builder = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(modelId: "Qwen/Qwen1.5-7B-Chat",apiKey: "你的apikey",httpClient: new HttpClient(handler));
_kernel = builder.Build();
_kernel為全局私有變量:
private Kernel _kernel;
構建頁面
axaml如下所示:
<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:vm="using:AvaloniaChat.ViewModels"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:views="clr-namespace:AvaloniaChat.Views"mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"x:Class="AvaloniaChat.Views.MainWindow"Icon="/Assets/avalonia-logo.ico"Title="AvaloniaChat"><Design.DataContext><!-- This only sets the DataContext for the previewer in an IDE,to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) --><vm:MainViewModel /></Design.DataContext><StackPanel><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><Grid Grid.Column="0"><StackPanel><StackPanel Orientation="Horizontal"><Button Content="問AI" Margin="10"Command="{Binding AskCommand}"></Button><!--<Button Content="翻譯為:"></Button>--><Label Content="翻譯為:"HorizontalAlignment="Center"VerticalAlignment="Center"></Label><ComboBox ItemsSource="{Binding Languages}"SelectedItem="{Binding SelectedLanguage}"HorizontalAlignment="Center"VerticalAlignment="Center"></ComboBox><Button Content="翻譯" Margin="10"Command="{Binding TranslateCommand}"></Button></StackPanel> <TextBox Height="300" Margin="10"Text="{Binding AskText}"TextWrapping="Wrap"AcceptsReturn="True"></TextBox></StackPanel> </Grid><Grid Grid.Column="1"><StackPanel><Button Content="AI回答" Margin="10"></Button><TextBox Height="300" Margin="10"Text="{Binding ResponseText}"TextWrapping="Wrap"></TextBox></StackPanel> </Grid>
</Grid> </StackPanel>
</Window>
界面效果如下所示:
構建ViewModel
ViewModel如下所示:
public partial class MainViewModel : ViewModelBase
{ private Kernel _kernel;[ObservableProperty]private string askText;[ObservableProperty]private string responseText;[ObservableProperty]private string selectedLanguage;public string[] Languages { get; set; }public MainViewModel(){var handler = new OpenAIHttpClientHandler();var builder = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: "Qwen/Qwen1.5-7B-Chat",apiKey: "你的apikey",httpClient: new HttpClient(handler));_kernel = builder.Build();AskText = " ";ResponseText = " ";SelectedLanguage = " ";Languages = new string[] { "中文","英文"};}[RelayCommand]private async Task Ask(){ if(ResponseText != ""){ResponseText = "";}await foreach (var update in _kernel.InvokePromptStreamingAsync(AskText)){ResponseText += update.ToString(); } }[RelayCommand]private async Task Translate(){string skPrompt = """{{$input}}將上面的輸入翻譯成{{$language}},無需任何其他內容""";if (ResponseText != ""){ResponseText = "";}await foreach (var update in _kernel.InvokePromptStreamingAsync(skPrompt, new() { ["input"] = AskText,["language"] = SelectedLanguage })){ResponseText += update.ToString();}}
}
使用流式返回
[RelayCommand]
private async Task Ask()
{ if(ResponseText != ""){ResponseText = "";}await foreach (var update in _kernel.InvokePromptStreamingAsync(AskText)){ResponseText += update.ToString(); }
}
實現效果如下:
寫提示
當我們需要翻譯功能的時候,只需要翻譯文本,其他的內容都不要,簡易的模板如下:
string skPrompt = """{{$input}}將上面的輸入翻譯成{{$language}},無需任何其他內容""";
{{$input}}
與{{$language}}
是模板里的參數,使用時會被替換,如下所示:
await foreach (var update in _kernel.InvokePromptStreamingAsync(skPrompt, new() { ["input"] = AskText,["language"] = SelectedLanguage })){ResponseText += update.ToString();}
通過以上這幾個步驟,我們就使用Avalonia制作完成一個簡易的小工具了。