使用C#接入DeepSeek API实现自己的AI助手

过年期间DeepSeek非常火爆,这段时间用着官方的客户端访问,总是会提示“服务器繁忙,请稍后再试。”,本文介绍怎么通过接入DeepSeek的API实现自己的客户端。

DeepSeek开放平台获取 API Key

首先我们需要登录DeepSeek的开放平台,在开放平台上进行API Key的申请。

在浏览器中访问 https://platform.deepseek.com,即可进入开放平台,首页为”用量信息“,展示我们的用量和余额,并且以图表形式展示每天的使用情况。

https://static.scung.cn/a4850502-dc2b-47bf-9706-076307e77a47.png

点击菜单项”API Keys“,可以查看我们所有创建的API Key,点击页面上的“创建 API Key”按钮,在弹出的窗口中输入一个方便记忆的名称,点击“创建”即可。

https://static.scung.cn/2a1b2ca5-7be5-4529-bb5a-5a8ba11b415c.png

需要注意的是,当我们创建好 API Key 之后,需要复制一下,之后则无法重新查看,如果忘记的话只能删除重新创建。

接入

使用任意IDE创建一个新的 .Net 项目,根据文档我们先构建几个模型类,用来存储数据

// 消息类,用来承载发送和收到消息
class Message
{
    [JsonPropertyName("role")]
    public string Role { get; set; }
    [JsonPropertyName("content")]
    public string Content { get; set; }

}

// 请求类,用来发送请求
class ChatRequest
{
    [JsonPropertyName("model")]
    public string Model { get; }
    [JsonPropertyName("messages")]
    public List<Message> Messages { get; }
    [JsonPropertyName("plugins")]
    public string[] Plugins { get; }
    [JsonPropertyName("stream")]
    public bool Stream { get; }
    [JsonPropertyName("temperature")]
    public double Temperature { get; }

    public ChatRequest(string model, List<Message> messages, string[] plugins, bool stream, double temperature)
    {
        Model = model;
        Messages = messages;
        Plugins = plugins;
        Stream = stream;
        Temperature = temperature;
    }
}

响应类型比较复杂,先不使用模型类,到时候直接通过解析 json 数据获取。

接下来开始发送请求。使用 HttpClient 来操作。DeepSeek可以启用流式输出,如果不启用流式输出,在发送请求之后,DeepSeek会把回答的所有内容都生成完毕之后才会返回,需要很长时间的等待,效果不太友好,启用流式输出之后,DeepSeek会在生成token之后立即返回,呈现的效果就是逐字回答。

下面的代码中启用了流式输出,对于流式输出,需要多加几个判断,比如在返回有效 token 时,DeepSeek会加上 data; 前缀,当生成停止时,DeepSeek会发送 [DONE],在生成卡顿时则会发送 keep-alive 来告诉客户端继续等待。

string apiKey = "sk-********************"; // 替换为你的 API 密钥
string apiUrl = "https://api.deepseek.com/v1/chat/completions";

using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");

var messages = new List<Message>() {
  new Message{ Role = "system", Content = "你是一个编程助手。" }
};

while (true)
{
    Console.ForegroundColor = ConsoleColor.Green;
    var input = Console.ReadLine();

    messages.Add(new Message { Role = "user", Content = input });
    // 构造请求体
    var requestBody = new ChatRequest("deepseek-chat", messages, ["web_search"], true, 0.7);

    // 发送请求
    var content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json");
    var request = new HttpRequestMessage(HttpMethod.Post, apiUrl) { Content = content };
    using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

    // 确保请求成功
    response.EnsureSuccessStatusCode();

    // 读取流式响应
    using var stream = await response.Content.ReadAsStreamAsync();
    using var reader = new System.IO.StreamReader(stream);

    var msg = new Message { Role = "assistant", Content = "" };

    while (!reader.EndOfStream)
    {
        var line = await reader.ReadLineAsync();
        if (!string.IsNullOrEmpty(line))
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            if (line.Contains("DONE"))
            {
                Console.WriteLine();
                break;
            }
            if (line.StartsWith("data:"))
            {
                Console.ForegroundColor = ConsoleColor.White;
                line = line.Substring(5);

                // 解析 JSON 数据
                var jsonDocument = JsonDocument.Parse(line);
                var choices = jsonDocument.RootElement.GetProperty("choices");

                foreach (var choice in choices.EnumerateArray())
                {
                    var delta = choice.GetProperty("delta");
                    if (delta.TryGetProperty("content", out var contentElement))
                    {
                        var ac = contentElement.GetString();
                        msg.Content += ac;
                        Console.Write(ac); // 输出增量内容
                    }
                }
                continue;
            }
            Console.WriteLine(line);
        }
    }

    // 收到的消息继续添加进消息列表,实现上下文联系
    messages.Add(msg);
}

这样我们就有了一个AI助手,下面体验一下效果,👍针不戳

https://static.scung.cn/c7878759-0be1-414d-b6a3-de3cd9f0ded0.png

发布时间:2025-02-16
其他阅读

解决sqlite依赖无法打包单文件的问题

在一次WPF开发中,选用了sqlite作为内嵌数据库,使用 ystem.Data.SQLite 库来调用,在使用 Fody 进行单文件打包时,发现打包文成后会出现 x86 和 x64 两个特定的文件夹,分别对应着32位和64位的 SQLite.Interop.dll,本文介绍修改项目文件来实现将 sqlite 通信库一起打包成单文件的方法。

查看原文

管道技术——中间件的灵魂

在现代Web开发中,中间件技术使用越来越广泛,本文带大家了解中间件的基础,同时也是中间件的灵魂所在,管道技术。在C#中,依赖于委托,我们可以很容易就实现一个中间件管道。所以在阅读本文前,请确保你已经学会了什么是委托,包括但不限于Delegate,Action,Func。除此之外,本文还会使用到反射相关知识,请确保你已经学会了什么是反射。

查看原文

IIS 设置跨域问题

之前说过nginx设置跨域,今天记录以下IIS设置跨域

查看原文

TypeScript中的数组操作

我们在编码时,总会用到数组/列表这种类型,用于在单个对象中存储多个内容。在 TypeScript 中,也已经内置了该类型,方便我们来使用。

查看原文

Entity Framework Core链接Oracle的问题

最近使用 Entity Framework Core 来链接 Oracle 11g 数据库,发现很多 LINQ 语句使用起来都会有问题,查看日志输出发现是生成SQL语句无法被 11g 版本执行,好在Oracle官方已经给我们提供了解决方案。

查看原文