开启OneAPI服务

OneAPI介绍

OpenAI 接口管理 & 分发系统,支持 Azure、Anthropic Claude、Google PaLM 2 & Gemini、智谱 ChatGLM、百度文心一言、讯飞星火认知、阿里通义千问、360 智脑以及腾讯混元,可用于二次分发管理 key,仅单可执行文件,已打包好 Docker 镜像,一键部署,开箱即用. OpenAI key management & redistribution system, using a single API for all LLMs, and features an English UI.

项目地址:https://github.com/songquanpeng/one-api

使用OneAPI

基于docker部署:

# 使用 SQLite 的部署命令:
docker run --name one-api -d --restart always -p 3000:3000 -e TZ=Asia/Shanghai -v /home/ubuntu/data/one-api:/data justsong/one-api
# 使用 MySQL 的部署命令,在上面的基础上添加 `-e SQL_DSN="root:123456@tcp(localhost:3306)/oneapi"`,请自行修改数据库连接参数,不清楚如何修改请参见下面环境变量一节。
# 例如:
docker run --name one-api -d --restart always -p 3000:3000 -e SQL_DSN="root:123456@tcp(localhost:3306)/oneapi" -e TZ=Asia/Shanghai -v /home/ubuntu/data/one-api:/data justsong/one-api

部署完成后,打开本地3000端口,如下所示:

初始账户为root,密码为123456。

登录之后,会提示修改密码。

点击渠道,创建新的渠道:

填入自己的大模型密钥。

添加令牌:

测试OneAPI服务是否可用

使用Postman查看接口是否可用:

注意事项

接口地址:http://<你的IP地址>:3000/v1/chat/completions

ip地址可通过cmd输入ipconfig查到。

在请求中加入令牌

在红框位置输入OneAPI中的令牌。

测试的json

{
    "model":"SparkDesk",
    "messages":[
        {
            "role":"user",
            "content":"你是谁"
        }
    ],
      "temperature":0.7    
}

星火大模型的响应

{
    "id": "",
    "object": "chat.completion",
    "created": 1709004732,
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "您好,我是科大讯飞研发的认知智能大模型,我的名字叫讯飞星火认知大模型。我可以和人类进行自然交流,解答问题,高效完成各领域认知智能需求。"
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 2,
        "completion_tokens": 40,
        "total_tokens": 42
    }
}

创建WPF项目

SemanticKernel简介

Semantic Kernel 是一个开源 SDK,可让您轻松构建可以调用现有代码的代理。作为高度可扩展的 SDK,可以将语义内核与 OpenAI、Azure OpenAI、Hugging Face 等模型一起使用!通过将现有的 C#、Python 和 Java 代码与这些模型相结合,可以生成用于回答问题和自动执行流程的代理。

安装SemanticKernel

在SemanticKernel中使用星火大模型

创建一个OpenAIHttpClientHandler类

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)
                 {
                     // 这里是你要修改的 URL
                     Scheme = "http",
                     Host = "你的ip地址",
                     Port = 3000,
                     Path = "v1/chat/completions",
                 };
                 request.RequestUri = uriBuilder.Uri;
                 break;
         }

         // 接着,调用基类的 SendAsync 方法将你的修改后的请求发出去
         HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

         int n = 0;
         while ((int)response.StatusCode == 500 && n < 10)
         {
             response = await base.SendAsync(request, cancellationToken);
             n++;
         }

         return response;
     }
 }

使用dotenv.net存储敏感数据

在dotenv.net.dll同一路径下,创建一个.env文件:

在.env文件中存储敏感数据:

模型ID要写SparkDesk,注意不要有空格,试过了有空格会报错。

APIKey就是写之前在OneAPI中复制的令牌。

测试能不能用

测试代码如下:

 
 // 加载环境变量
 DotEnv.Load();

 // 读取环境变量
 var envVars = DotEnv.Read();

// Create kernel
 var builder = Kernel.CreateBuilder();

 var handler = new OpenAIHttpClientHandler();

 builder.AddOpenAIChatCompletion(
     modelId: envVars["ModeId"],
     apiKey: envVars["APIKey"],
     httpClient: new HttpClient(handler));

 var kernel = builder.Build();

 // Create chat history
 ChatHistory history = [];

 // Get chat completion service
 var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

 // Start the conversation                                                  
     history.AddUserMessage("你是谁?");

 // Enable auto function calling
 OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
  {
      ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
   };

     // Get the response from the AI
     var result = await chatCompletionService.GetChatMessageContentAsync(
         history,
         executionSettings: openAIPromptExecutionSettings,
         kernel: kernel);

     // Print the results
     Console.WriteLine("Assistant > " + result);

     // Add the message from the agent to the chat history
     history.AddMessage(result.Role, result.Content);
 }

查看结果:

第一次请求失败,为了解决这个问题,我们加了下面这段代码:

  int n = 0;
  while ((int)response.StatusCode == 500 && n < 10)
  {
      response = await base.SendAsync(request, cancellationToken);
      n++;
  }

再请求一遍就成功了。

收到了星火认知大模型的回答。

使用HandyControl构建页面

xaml如下:

<Window x:Class="SK_Wpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
        xmlns:hc="https://handyorg.github.io/handycontrol"
        xmlns:local="clr-namespace:SK_Wpf"    
        mc:Ignorable="d"
        Title="SK_WPF" Height="450" Width="800"
        Loaded="Window_Loaded">
    <StackPanel Margin="32">
        <hc:Row Margin="0,20,0,0">
            <hc:Col Span="11">
                <StackPanel>
                    <Button Style="{StaticResource ButtonPrimary}" Content="问AI" Width="80"
                            Click="Button_Click_1"/>
                    <hc:TextBox x:Name="textBox1"
                                Margin="0,20,0,0"
                                Width="300" Height="200"
                                AcceptsReturn="True"/>

                </StackPanel>
            </hc:Col>
            <hc:Col Span="2">
                <Grid >
                    <hc:LoadingCircle x:Name="loading1" 
                                      HorizontalAlignment="Center" 
                                      VerticalAlignment="Center"
                                      Visibility="Hidden"/>
                </Grid>
            </hc:Col>
            <hc:Col Span="11">
                <StackPanel>
                    <hc:Tag ShowCloseButton="False" Content="AI回答"/>
                    <RichTextBox x:Name="richTextBox2"  
                                 VerticalAlignment="Center" 
                                 HorizontalAlignment="Center" 
                                 Margin="0,20,0,0"
                                 Width="300" Height="200">
                    </RichTextBox>
                </StackPanel>
            </hc:Col>
        </hc:Row>
    </StackPanel>
</Window>

实现效果如下:

在WPF中集成SK+OneAPI+星火认知大模型

cs如下:

using dotenv.net;
using HandyControl.Controls;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using SK_Wpf.Plugins;
using System.Net.Http;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SK_Wpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : System.Windows.Window
    {
        IDictionary<string, string>? envVars;      
        Kernel? kernel;
        ChatHistory history = [];
        IChatCompletionService chatCompletionService;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 加载环境变量
            DotEnv.Load();

            // 读取环境变量
            envVars = DotEnv.Read();



            // Create kernel
            var builder = Kernel.CreateBuilder();

            var handler = new OpenAIHttpClientHandler();

            builder.AddOpenAIChatCompletion(
                modelId: envVars["ModeId"],
                apiKey: envVars["APIKey"],
                httpClient: new HttpClient(handler));
            builder.Plugins.AddFromType<HelloPlugin>("helloPlugin");

            var kernel = builder.Build();

            // Get chat completion service
            chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();


        }
      
        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            loading1.Visibility = Visibility.Visible;

            string question = textBox1.Text;
          
            // Get user input
            history.AddUserMessage(question);

            // Enable auto function calling
            OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
            {
                ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
            };

            // Get the response from the AI
            var result = await chatCompletionService.GetChatMessageContentAsync(
                history,
                executionSettings: openAIPromptExecutionSettings,
                kernel: kernel);

            // Print the results           
            richTextBox2.AppendText(result.ToString());

            // Add the message from the agent to the chat history
            history.AddMessage(result.Role, result.Content);

            loading1.Visibility = Visibility.Hidden;
         
        }
    }     
    }

实现效果如下所示:

总结

本文是一次在WPF使用SemanticKernel基于OneAPI集成讯飞星火认知大模型的实践,没有申请OpenAIAPIKey的可以使用讯飞星火认知大模型,现在个人身份认证有送200万token,个人使用可以用很久了。但是效果上肯定和OpenAI还有差别,经过测试,自动本地函数调用,用OpenAI可以用星火认知大模型不行。下期可以写一下两个模型回答的对比。

最后感谢大佬们的分享,见参考。

参考

1、想学Semantic Kernel,没有OpenAI接口该怎么办? (qq.com)

2、实战教学:用Semantic Kernel框架集成腾讯混元大模型应用 (qq.com)

3、Create AI agents with Semantic Kernel | Microsoft Learn

4、songquanpeng/one-api: OpenAI 接口管理 & 分发系统,支持 Azure、Anthropic Claude、Google PaLM 2 & Gemini、智谱 ChatGLM、百度文心一言、讯飞星火认知、阿里通义千问、360 智脑以及腾讯混元,可用于二次分发管理 key,仅单可执行文件,已打包好 Docker 镜像,一键部署,开箱即用. OpenAI key management & redistribution system, using a single API for all LLMs, and features an English UI. (github.com)

5、microsoft/semantic-kernel: Integrate cutting-edge LLM technology quickly and easily into your apps (github.com)