Bootstrap

c#通过网上AI大模型实现对话功能

基础使用

https://siliconflow.cn/网站有些免费的大模型可以使用,去注册个账户,拿到apikey
引用 nuget

Microsoft.Extensions.AI.OpenAI

using Microsoft.Extensions.AI;
using OpenAI;
using System.ClientModel;

namespace ConsoleApp2
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
            openAIClientOptions.Endpoint = new Uri("https://api.siliconflow.cn/v1");

            // SiliconCloud API Key
            string mySiliconCloudAPIKey = "你的api key";


            OpenAIClient client = new OpenAIClient(new ApiKeyCredential(mySiliconCloudAPIKey), openAIClientOptions);
            IChatClient chatClient = client.AsChatClient("Qwen/Qwen2.5-7B-Instruct");
            while (true)
            {
                var response = chatClient.CompleteStreamingAsync(Console.ReadLine());//手动输入问题

                await foreach (var item in response)
                {
                    Console.Write(item.Text);
                }
                Console.Write("\r\n\r\n");
            }
        }
    }
}

给大模型额外提供函数能力


using OpenAI;
using OpenAI.Chat;
using System.ClientModel;

namespace ConsoleApp2
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
            openAIClientOptions.Endpoint = new Uri("https://api.siliconflow.cn/v1");

            // SiliconCloud API Key
            string mySiliconCloudAPIKey = "你的api key";


            OpenAIClient client = new OpenAIClient(new ApiKeyCredential(mySiliconCloudAPIKey), openAIClientOptions);
            var assistantClient = client.GetChatClient("Qwen/Qwen2.5-7B-Instruct");


            await FunctionCallPlayground(assistantClient, "how is the weather today in beijing?");

            Console.ReadKey();
        }

        private static async Task FunctionCallPlayground(ChatClient chatClient, string prompt)
        {
            Console.WriteLine(prompt);

            var messages = new[]
            {
            new UserChatMessage(  prompt)
        };

            BinaryData functionParameters = BinaryData.FromBytes("""
                 {
                 "type": "object",
                 "properties": {
                 "city": {
                 "type": "string",
                 "description": "The name of the city to query weather for."
                 }
                 },
                 "required": ["city"],
                 "additionalProperties": false
                 }
                 """u8.ToArray());
 

            var chatTool = ChatTool.CreateFunctionTool("get_weather", "Get the current weather for a given city.", functionParameters);
            var options = new ChatCompletionOptions
            {
                Temperature = 0.01f,
                TopP = 0.95f,

            };
            options.Tools.Add(chatTool);
            var response = chatClient.CompleteChat(messages, options);



            // 假设我们只处理第一个工具调用请求
            var func1Name = response.Value.ToolCalls[0].FunctionName;
            var func1Args = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string,string>>( response.Value.ToolCalls[0].FunctionArguments.ToString());
            var func1Out = await GetWeather(func1Args["city"] );


            options = new ChatCompletionOptions
            {
                Temperature = 0.01f,
                TopP = 0.95f,

            };
            response = chatClient.CompleteChat(new ChatMessage[] { messages[0] , new ToolChatMessage(response.Value.ToolCalls[0].Id, func1Out) }, options);

            Console.WriteLine(response.Value.Content.FirstOrDefault()?.Text);
        }

        private static async Task<string> GetWeather(string city)
        {
            return $"23摄氏度";

        }
    }


}

用Microsoft.Extensions.AI库实现


using Microsoft.Extensions.AI;
using OpenAI;
using OpenAI.Chat;
using System.ClientModel;

namespace ConsoleApp2
{
    internal class Program
    {
        const string APIKEY = "你的apikey";
        static async Task Main(string[] args)
        {
            OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
            openAIClientOptions.Endpoint = new Uri("https://api.siliconflow.cn/v1");

            // SiliconCloud API Key
            string mySiliconCloudAPIKey = APIKEY;

            var weathfunc = new GetWeatherFunction();
            var humidtyfunc = new GetHumidityFunction();
            ChatOptions chatOptions = new ChatOptions()
            {
                Temperature = 0.01f,
                TopP = 0.95f,
                Tools = new AIFunction[] { weathfunc, humidtyfunc }
            };

            OpenAIClient client = new OpenAIClient(new ApiKeyCredential(mySiliconCloudAPIKey), openAIClientOptions);
            IChatClient chatClient = client.AsChatClient("Qwen/Qwen2.5-7B-Instruct");
            while (true)
            {

                var question = Console.ReadLine();//手动输入问题
                var response = await chatClient.CompleteAsync(question, chatOptions);
                _check:
                if(response.FinishReason == Microsoft.Extensions.AI.ChatFinishReason.ToolCalls)
                {
                    List<AIContent> callRets = new List<AIContent>();
                   foreach( var aiContent in response.Choices[0].Contents)
                    {
                        if(aiContent is FunctionCallContent callContent)
                        {
                            var callid = callContent.CallId;
                            var func = (AIFunction)chatOptions.Tools.FirstOrDefault(m=>((AIFunction)m).Metadata.Name == callContent.Name);
                            var ret  =await func!.InvokeAsync(callContent.Arguments);
                            callRets.Add(new FunctionResultContent(callid , callContent.Name , ret));
                        }
                    }
                    List<Microsoft.Extensions.AI.ChatMessage> list = new List<Microsoft.Extensions.AI.ChatMessage>();
                    list.Add(new Microsoft.Extensions.AI.ChatMessage(Microsoft.Extensions.AI.ChatRole.User, question));
                    list.Add(new Microsoft.Extensions.AI.ChatMessage(Microsoft.Extensions.AI.ChatRole.Tool, callRets));
                    response = await chatClient.CompleteAsync(list, chatOptions);
                    goto _check;
                }
                else
                {
                    Console.WriteLine(response.Choices[0].Contents.FirstOrDefault()?.ToString());
                }
                
                Console.Write("\r\n");
            }
        }

    }


    public class GetWeatherFunction : AIFunction
    {
        Microsoft.Extensions.AI.AIFunctionMetadata _Metadata;
        public override AIFunctionMetadata Metadata => _Metadata;

        public GetWeatherFunction() {
            _Metadata = new Microsoft.Extensions.AI.AIFunctionMetadata("get_weather")
            {
                Description = "Get the current weather for a given city.",
                Parameters = new[] { new AIFunctionParameterMetadata("city") { 
                    ParameterType = typeof(string),
                    Description = "The name of the city to query weather for.",
                    IsRequired = true,
                } },  
            };
            
        }

        protected override async Task<object?> InvokeCoreAsync(IEnumerable<KeyValuePair<string, object?>> arguments, CancellationToken cancellationToken)
        {
            return $"23摄氏度";
        }
    }

    public class GetHumidityFunction : AIFunction
    {
        Microsoft.Extensions.AI.AIFunctionMetadata _Metadata;
        public override AIFunctionMetadata Metadata => _Metadata;

        public GetHumidityFunction()
        {
            _Metadata = new Microsoft.Extensions.AI.AIFunctionMetadata("get_humidity")
            {
                Description = "获取指定城市的湿度",
                Parameters = new[] { new AIFunctionParameterMetadata("city") {
                    ParameterType = typeof(string),
                    Description = "要获取湿度的城市名称",
                    IsRequired = true,
                } },
            };

        }

        protected override async Task<object?> InvokeCoreAsync(IEnumerable<KeyValuePair<string, object?>> arguments, CancellationToken cancellationToken)
        {
            return $"70%";
        }
    }

}


用json格式回答

通过设置ResponseFormat 为json,可以让大模型以json格式输出

上面代码修改为:

                    List<Microsoft.Extensions.AI.ChatMessage> list = new List<Microsoft.Extensions.AI.ChatMessage>();
                    list.Add(new Microsoft.Extensions.AI.ChatMessage(Microsoft.Extensions.AI.ChatRole.User, question));
                    list.Add(new Microsoft.Extensions.AI.ChatMessage(Microsoft.Extensions.AI.ChatRole.Tool, callRets));
                    ChatOptions chatOptions2 = new ChatOptions()
                    {
                        Temperature = 0.01f,
                        TopP = 0.95f,
                        MaxOutputTokens = int.MaxValue,
                        ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.Json,
                    };
                    response = await chatClient.CompleteAsync(list, chatOptions2);

注意:如果你的提问需要调用你自己定义的函数去计算,那么,提问时不要设置ResponseFormat ,否则回答类型不会是FinishReason == Microsoft.Extensions.AI.ChatFinishReason.ToolCalls,也就无法触发你的程序去调用函数了,只有计算完结果后,回传结果给大模型时才设置 ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.Json

提问需要这么提问:
北京现在的温度和湿度是多少?请用这种格式回答:[“温度值”,“湿度值”]

;