.NET开发者的AI助手:通义千问1.8B模型C#集成教程

最近在.NET社区里,关于如何把大模型能力集成到自家应用里的讨论越来越多了。很多朋友觉得,这玩意儿听起来高大上,但真要动手做,是不是得从Python开始学起,还得搞一堆复杂的环境配置?

其实完全不用那么麻烦。如果你手头有已经部署好的模型服务,比如在星图GPU平台上跑起来的通义千问1.8B模型,那么用你最熟悉的C#和.NET技术栈,花上半小时,就能让应用拥有智能对话的能力。

今天我就带你走一遍完整的流程,从理解API怎么调用,到封装一个顺手好用的服务类,最后在ASP.NET Core Web API和WPF桌面程序里各集成一个聊天功能。整个过程,你只需要会写C#代码,会用HttpClient发请求,就能搞定。

1. 准备工作:理解我们要对接什么

在开始写代码之前,咱们先得搞清楚目标是什么。你不是在本地运行一个几十GB的模型,而是去调用一个已经部署好的服务。这个服务提供了标准的HTTP接口,你的C#程序只需要像调用普通Web API一样,给它发请求、收响应就行了。

通义千问1.8B模型的Chat API,通常提供一个/v1/chat/completions这样的端点。你发一段对话历史过去,它返回模型生成的回复。数据格式基本遵循OpenAI的Chat Completion API规范,这对我们来说是个好消息,因为社区里已经有成熟的封装模式可以参考。

你需要准备的东西很简单:

  • 一个已经部署好的通义千问1.8B模型服务地址(比如 http://your-server-ip:port
  • 一个能跑.NET 6/7/8的开发环境(Visual Studio 2022 或 VS Code都行)
  • 基础的C#异步编程知识(会用async/await

模型服务那边怎么部署的,我们今天不展开,假设你已经通过星图镜像广场或者其他方式,让服务在某个地方跑起来了。我们的任务,就是让C#程序能和这个服务“对话”。

2. 核心步骤:封装模型服务客户端

直接裸用HttpClient发请求也能工作,但代码会显得很零散,不好维护。咱们先花点时间,封装一个专门用于调用通义千问模型的客户端类。这样,在主程序里用起来就干净多了。

2.1 定义数据模型

首先,定义API请求和响应对应的C#类。这能让序列化和反序列化变得非常直观。

using System.Text.Json.Serialization;

namespace QwenClient.Models
{
    // 单条消息的格式
    public class ChatMessage
    {
        [JsonPropertyName("role")]
        public string Role { get; set; } = "user"; // "system", "user", "assistant"

        [JsonPropertyName("content")]
        public string Content { get; set; } = string.Empty;
    }

    // 发送给API的请求体
    public class ChatCompletionRequest
    {
        [JsonPropertyName("model")]
        public string Model { get; set; } = "qwen1.8b-chat"; // 模型名称,按实际部署的填

        [JsonPropertyName("messages")]
        public List<ChatMessage> Messages { get; set; } = new();

        [JsonPropertyName("temperature")]
        public float Temperature { get; set; } = 0.7f; // 控制随机性,0-2之间

        [JsonPropertyName("max_tokens")]
        public int MaxTokens { get; set; } = 1024; // 生成的最大长度

        [JsonPropertyName("stream")]
        public bool Stream { get; set; } = false; // 是否流式输出,我们先做非流式
    }

    // API返回的响应体(非流式)
    public class ChatCompletionResponse
    {
        [JsonPropertyName("id")]
        public string Id { get; set; } = string.Empty;

        [JsonPropertyName("choices")]
        public List<ChatChoice> Choices { get; set; } = new();

        [JsonPropertyName("usage")]
        public TokenUsage Usage { get; set; } = new();
    }

    public class ChatChoice
    {
        [JsonPropertyName("index")]
        public int Index { get; set; }

        [JsonPropertyName("message")]
        public ChatMessage Message { get; set; } = new();

        [JsonPropertyName("finish_reason")]
        public string FinishReason { get; set; } = string.Empty;
    }

    public class TokenUsage
    {
        [JsonPropertyName("prompt_tokens")]
        public int PromptTokens { get; set; }

        [JsonPropertyName("completion_tokens")]
        public int CompletionTokens { get; set; }

        [JsonPropertyName("total_tokens")]
        public int TotalTokens { get; set; }
    }
}

这几个类定义了数据在C#世界里的形状。注意我们用JsonPropertyName特性来匹配JSON里的字段名,这样System.Text.Json序列化的时候就不会出错。

2.2 实现服务客户端

接下来是重头戏,实现一个QwenAIClient类,它负责所有和模型API的通信细节。

using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

namespace QwenClient.Services
{
    public interface IQwenAIService
    {
        Task<string> GetChatResponseAsync(List<ChatMessage> messages, CancellationToken cancellationToken = default);
    }

    public class QwenAIClient : IQwenAIService
    {
        private readonly HttpClient _httpClient;
        private readonly string _apiKey; // 如果API需要密钥
        private readonly JsonSerializerOptions _jsonOptions;

        public QwenAIClient(string baseAddress, string apiKey = "")
        {
            _httpClient = new HttpClient
            {
                BaseAddress = new Uri(baseAddress.TrimEnd('/') + "/") // 确保地址以/结尾
            };
            _apiKey = apiKey;

            // 配置JSON序列化选项
            _jsonOptions = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
            };

            // 设置默认请求头
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            if (!string.IsNullOrEmpty(_apiKey))
            {
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _apiKey);
            }
        }

        public async Task<string> GetChatResponseAsync(List<ChatMessage> messages, CancellationToken cancellationToken = default)
        {
            var request = new ChatCompletionRequest
            {
                Messages = messages,
                Model = "qwen1.8b-chat",
                Temperature = 0.7f,
                MaxTokens = 1024
            };

            var jsonContent = JsonSerializer.Serialize(request, _jsonOptions);
            var httpContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");

            try
            {
                var response = await _httpClient.PostAsync("v1/chat/completions", httpContent, cancellationToken);
                response.EnsureSuccessStatusCode(); // 如果状态码不是2xx,会抛出异常

                var responseJson = await response.Content.ReadAsStringAsync(cancellationToken);
                var completionResponse = JsonSerializer.Deserialize<ChatCompletionResponse>(responseJson, _jsonOptions);

                // 返回模型生成的回复内容
                return completionResponse?.Choices?.FirstOrDefault()?.Message?.Content?.Trim() 
                    ?? "抱歉,我没有收到有效的回复。";
            }
            catch (HttpRequestException ex)
            {
                // 处理网络或HTTP错误
                return $"请求API时出错: {ex.Message}";
            }
            catch (JsonException ex)
            {
                // 处理JSON解析错误
                return $"解析响应时出错: {ex.Message}";
            }
            catch (TaskCanceledException) when (cancellationToken.IsCancellationRequested)
            {
                // 用户取消了请求
                return "请求已取消。";
            }
        }

        // 一个更方便的方法,直接发送用户消息并获取回复
        public async Task<string> SendMessageAsync(string userMessage, CancellationToken cancellationToken = default)
        {
            var messages = new List<ChatMessage>
            {
                new ChatMessage { Role = "user", Content = userMessage }
            };
            return await GetChatResponseAsync(messages, cancellationToken);
        }

        // 带对话历史的方法
        public async Task<string> SendMessageWithHistoryAsync(string userMessage, List<ChatMessage> history, CancellationToken cancellationToken = default)
        {
            var messages = new List<ChatMessage>();
            messages.AddRange(history);
            messages.Add(new ChatMessage { Role = "user", Content = userMessage });
            
            var response = await GetChatResponseAsync(messages, cancellationToken);
            
            // 把本次交互加入历史(可选)
            history.Add(new ChatMessage { Role = "user", Content = userMessage });
            history.Add(new ChatMessage { Role = "assistant", Content = response });
            
            return response;
        }
    }
}

这个客户端类做了几件关键事情:

  1. 封装了HttpClient,管理连接和请求头。
  2. 处理了JSON的序列化(请求)和反序列化(响应)。
  3. 实现了基本的错误处理,避免程序因为网络问题直接崩溃。
  4. 提供了两个便捷方法,一个用于单次对话,一个用于维护对话历史的多轮聊天。

有了这个客户端,在业务代码里调用模型就变得非常简单,一两行代码就能搞定。

3. 实战集成:在ASP.NET Core Web API中使用

现在,我们把这个客户端用到一个实际的ASP.NET Core Web API项目中。假设你想提供一个聊天接口给前端调用。

3.1 配置依赖注入

首先,在Program.cs里注册我们的服务。

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// 从配置中读取模型API地址
var qwenApiBaseUrl = builder.Configuration["QwenAI:BaseUrl"] 
    ?? "http://localhost:8000"; // 默认地址
var qwenApiKey = builder.Configuration["QwenAI:ApiKey"] ?? string.Empty;

// 注册QwenAIClient为单例服务
builder.Services.AddSingleton<IQwenAIService>(sp => 
    new QwenAIClient(qwenApiBaseUrl, qwenApiKey));

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

appsettings.json里配置你的模型服务地址:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "QwenAI": {
    "BaseUrl": "http://your-model-server:port",
    "ApiKey": "your-api-key-if-required"
  },
  "AllowedHosts": "*"
}

3.2 创建聊天控制器

然后,创建一个API控制器来处理聊天请求。

using Microsoft.AspNetCore.Mvc;
using QwenClient.Services;

namespace QwenApiDemo.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ChatController : ControllerBase
    {
        private readonly IQwenAIService _qwenAIService;
        private readonly ILogger<ChatController> _logger;

        public ChatController(IQwenAIService qwenAIService, ILogger<ChatController> logger)
        {
            _qwenAIService = qwenAIService;
            _logger = logger;
        }

        // POST api/chat/single
        [HttpPost("single")]
        public async Task<IActionResult> SendSingleMessage([FromBody] SingleChatRequest request)
        {
            if (string.IsNullOrWhiteSpace(request?.Message))
            {
                return BadRequest("消息内容不能为空。");
            }

            try
            {
                _logger.LogInformation("收到聊天请求: {Message}", request.Message);
                
                var response = await _qwenAIService.SendMessageAsync(request.Message);
                
                _logger.LogInformation("AI回复: {Response}", response);
                return Ok(new { success = true, response });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理聊天请求时出错");
                return StatusCode(500, new { success = false, error = "处理请求时发生错误。" });
            }
        }

        // POST api/chat/conversation
        [HttpPost("conversation")]
        public async Task<IActionResult> SendMessageWithHistory([FromBody] ConversationRequest request)
        {
            if (string.IsNullOrWhiteSpace(request?.UserMessage))
            {
                return BadRequest("用户消息不能为空。");
            }

            try
            {
                // 在实际项目中,对话历史应该从数据库或缓存中获取
                // 这里为了演示,我们使用请求中传递的历史,或者新建一个
                var history = request.History ?? new List<ChatMessage>();
                
                var response = await _qwenAIService.SendMessageWithHistoryAsync(
                    request.UserMessage, 
                    history
                );
                
                return Ok(new { 
                    success = true, 
                    response,
                    // 返回更新后的历史,前端可以保存起来用于下次请求
                    updatedHistory = history 
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理对话请求时出错");
                return StatusCode(500, new { success = false, error = "处理请求时发生错误。" });
            }
        }
    }

    // 请求模型类
    public class SingleChatRequest
    {
        public string Message { get; set; } = string.Empty;
    }

    public class ConversationRequest
    {
        public string UserMessage { get; set; } = string.Empty;
        public List<ChatMessage> History { get; set; } = new();
    }
}

这个控制器提供了两个端点:

  • /api/chat/single:处理单次对话,不维护历史上下文。
  • /api/chat/conversation:处理多轮对话,需要传递历史消息记录。

现在,你的前端应用就可以通过调用这些API接口,实现聊天功能了。启动项目,用Swagger或者Postman测试一下,应该能看到模型返回的回复。

4. 另一种场景:在WPF桌面应用中集成

除了Web API,在桌面应用里集成AI能力也很有用。比如,做一个智能助手工具,或者给现有桌面软件增加一个智能问答侧边栏。我们用WPF来演示一下。

4.1 创建WPF项目并安装必要的包

创建一个新的WPF项目,然后通过NuGet安装必要的包:

  • Microsoft.Extensions.Hosting (用于依赖注入)
  • CommunityToolkit.Mvvm (可选,用于MVVM模式)

4.2 实现ViewModel和界面

我们先创建一个简单的ViewModel来管理聊天逻辑。

// ChatViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using QwenClient.Services;
using System.Collections.ObjectModel;
using System.Threading;

namespace QwenWpfDemo.ViewModels
{
    public partial class ChatViewModel : ObservableObject
    {
        private readonly IQwenAIService _qwenAIService;
        private CancellationTokenSource _cancellationTokenSource;

        public ChatViewModel(IQwenAIService qwenAIService)
        {
            _qwenAIService = qwenAIService;
            Messages = new ObservableCollection<ChatMessage>();
            _cancellationTokenSource = new CancellationTokenSource();
        }

        [ObservableProperty]
        private ObservableCollection<ChatMessage> _messages;

        [ObservableProperty]
        private string _userInput = string.Empty;

        [ObservableProperty]
        private bool _isLoading;

        [ObservableProperty]
        private string _statusMessage = "就绪";

        [RelayCommand]
        private async Task SendMessageAsync()
        {
            if (string.IsNullOrWhiteSpace(UserInput))
                return;

            var userMessage = UserInput.Trim();
            UserInput = string.Empty; // 清空输入框
            
            // 添加用户消息到界面
            Messages.Add(new ChatMessage { Role = "user", Content = userMessage });
            
            // 显示AI正在思考
            Messages.Add(new ChatMessage { Role = "assistant", Content = "正在思考..." });
            IsLoading = true;
            StatusMessage = "AI正在思考...";
            
            try
            {
                // 准备对话历史(排除最后一条"正在思考..."的消息)
                var history = Messages.Take(Messages.Count - 1).ToList();
                
                // 调用AI服务
                var response = await _qwenAIService.GetChatResponseAsync(
                    history, 
                    _cancellationTokenSource.Token
                );
                
                // 替换"正在思考..."为实际回复
                Messages.RemoveAt(Messages.Count - 1);
                Messages.Add(new ChatMessage { Role = "assistant", Content = response });
                
                StatusMessage = "就绪";
            }
            catch (TaskCanceledException)
            {
                // 用户取消了请求
                Messages.RemoveAt(Messages.Count - 1);
                StatusMessage = "请求已取消";
            }
            catch (Exception ex)
            {
                // 处理其他错误
                Messages.RemoveAt(Messages.Count - 1);
                Messages.Add(new ChatMessage { 
                    Role = "assistant", 
                    Content = $"出错了: {ex.Message}" 
                });
                StatusMessage = "发生错误";
            }
            finally
            {
                IsLoading = false;
            }
        }

        [RelayCommand]
        private void CancelRequest()
        {
            _cancellationTokenSource.Cancel();
            _cancellationTokenSource = new CancellationTokenSource(); // 重置
            StatusMessage = "已取消";
        }

        [RelayCommand]
        private void ClearChat()
        {
            Messages.Clear();
            StatusMessage = "对话已清空";
        }
    }
}

4.3 创建简单的聊天界面

XAML界面可以设计得很简洁:

<!-- MainWindow.xaml -->
<Window x:Class="QwenWpfDemo.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:local="clr-namespace:QwenWpfDemo"
        mc:Ignorable="d"
        Title="通义千问桌面助手" Height="600" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 消息列表 -->
        <ListView Grid.Row="0" ItemsSource="{Binding Messages}" 
                  Background="#1E1E1E" Foreground="White"
                  ScrollViewer.HorizontalScrollBarVisibility="Disabled">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Border Margin="5" Padding="10" CornerRadius="8"
                            Background="{Binding Role, Converter={StaticResource RoleToColorConverter}}">
                        <StackPanel>
                            <TextBlock Text="{Binding Role}" FontWeight="Bold" 
                                       Foreground="LightGray" Margin="0,0,0,5"/>
                            <TextBlock Text="{Binding Content}" TextWrapping="Wrap" 
                                       FontSize="14"/>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

        <!-- 输入区域 -->
        <Grid Grid.Row="1" Margin="10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            
            <TextBox Grid.Column="0" Text="{Binding UserInput, UpdateSourceTrigger=PropertyChanged}"
                     Height="60" VerticalContentAlignment="Top" 
                     AcceptsReturn="True" VerticalScrollBarVisibility="Auto"
                     Padding="10" FontSize="14">
                <TextBox.InputBindings>
                    <KeyBinding Key="Enter" Command="{Binding SendMessageCommand}"/>
                </TextBox.InputBindings>
            </TextBox>
            
            <Button Grid.Column="1" Command="{Binding SendMessageCommand}" 
                    Content="发送" Margin="10,0,5,0" Width="60" Height="30"
                    IsEnabled="{Binding IsLoading, Converter={StaticResource InverseBooleanConverter}}"/>
            
            <Button Grid.Column="2" Command="{Binding CancelRequestCommand}" 
                    Content="取消" Width="60" Height="30"
                    IsEnabled="{Binding IsLoading}"/>
        </Grid>

        <!-- 状态栏 -->
        <StatusBar Grid.Row="2" Background="#252526">
            <StatusBarItem>
                <TextBlock Text="{Binding StatusMessage}" Foreground="White" Margin="5"/>
            </StatusBarItem>
            <Separator/>
            <StatusBarItem>
                <Button Command="{Binding ClearChatCommand}" Content="清空对话" 
                        Margin="5,0" Padding="10,2"/>
            </StatusBarItem>
            <StatusBarItem HorizontalAlignment="Right">
                <ProgressBar Width="100" Height="10" IsIndeterminate="True" 
                             Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}"/>
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

4.4 配置依赖注入和启动

App.xaml.cs中配置依赖注入:

// App.xaml.cs
public partial class App : Application
{
    private readonly IHost _host;

    public App()
    {
        _host = Host.CreateDefaultBuilder()
            .ConfigureServices((context, services) =>
            {
                // 从appsettings.json读取配置
                var configuration = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", optional: false)
                    .Build();

                // 注册Qwen AI服务
                var baseUrl = configuration["QwenAI:BaseUrl"] ?? "http://localhost:8000";
                var apiKey = configuration["QwenAI:ApiKey"] ?? "";
                
                services.AddSingleton<IQwenAIService>(sp => 
                    new QwenAIClient(baseUrl, apiKey));
                
                // 注册ViewModels和Views
                services.AddSingleton<ChatViewModel>();
                services.AddSingleton<MainWindow>();
            })
            .Build();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await _host.StartAsync();
        
        var mainWindow = _host.Services.GetRequiredService<MainWindow>();
        mainWindow.DataContext = _host.Services.GetRequiredService<ChatViewModel>();
        mainWindow.Show();
        
        base.OnStartup(e);
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        await _host.StopAsync();
        _host.Dispose();
        
        base.OnExit(e);
    }
}

这样,一个简单的WPF聊天应用就完成了。运行起来,输入文字,点击发送,就能看到AI的回复了。

5. 一些实用技巧和注意事项

在实际使用中,你可能会遇到一些具体问题。这里分享几个小技巧,能帮你少走弯路。

连接和超时设置:如果模型服务响应比较慢,或者网络不太稳定,可以调整HttpClient的超时设置。在创建QwenAIClient时,可以这样配置:

_httpClient.Timeout = TimeSpan.FromSeconds(60); // 设置60秒超时

处理流式响应:上面的例子用的是非流式接口,一次返回完整回复。如果模型支持流式输出(像ChatGPT那样一个字一个字往外蹦),你可以用HttpCompletionOption.ResponseHeadersRead模式来逐步读取响应。不过处理起来会复杂一些,需要解析SSE(Server-Sent Events)格式。

管理对话历史:在多轮对话中,历史消息会越来越长。模型通常有上下文长度限制(比如4096个token),超出限制的旧消息会被截断。你可以在客户端里加个逻辑,当历史消息总长度接近限制时,自动移除最早的一些消息,或者进行总结压缩。

错误处理和重试:网络请求总有可能失败。对于非关键操作,可以实现简单的重试机制。可以用Polly这样的库,轻松添加重试策略:

// 安装Polly包后
var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .Or<TaskCanceledException>()
    .WaitAndRetryAsync(3, retryAttempt => 
        TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

var response = await retryPolicy.ExecuteAsync(async () => 
    await _qwenAIService.GetChatResponseAsync(messages));

性能考虑:如果你的应用并发量比较大,要注意HttpClient的最佳实践。.NET Core推荐使用IHttpClientFactory来管理HttpClient实例的生命周期,避免Socket耗尽问题。可以把QwenAIClient改造成使用IHttpClientFactory。

6. 总结

走完这一趟,你会发现用C#集成大模型API,其实和调用其他任何RESTful服务没有本质区别。核心就是三个步骤:定义好数据模型、封装好HTTP客户端、在业务逻辑里调用。

封装好的QwenAIClient类是个很好的起点,你可以根据实际需求扩展它,比如添加流式响应支持、实现更复杂的对话历史管理、或者加入更多的模型参数控制。在ASP.NET Core里,通过依赖注入来使用这个服务,能让代码保持整洁和可测试。在WPF里,结合MVVM模式,可以快速构建出响应式的用户界面。

实际用下来,这种集成方式对.NET开发者来说非常友好,不需要离开熟悉的技术栈,就能给应用加上AI能力。无论是做个内部工具,还是给产品增加智能特性,这条路都走得通。当然,实际项目中还会遇到更多细节问题,比如身份认证、限流、监控等等,但有了这个基础,那些都是可以逐步完善的。

如果你之前没接触过大模型集成,建议先从简单的单次对话功能开始,跑通整个流程。等熟悉了,再慢慢加入更复杂的功能,比如多轮对话、流式输出、或者同时支持多个不同的模型。最重要的是动手试起来,遇到问题就查查文档,或者看看社区里有没有类似的解决方案。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐