通义千问1.5-1.8B-Chat-GPTQ-Int4 .NET开发者集成教程:C#调用大模型API
本文介绍了如何在星图GPU平台上自动化部署通义千问1.5-1.8B-Chat-GPTQ-Int4镜像,并详细指导.NET开发者通过C#调用其API,实现智能对话功能。该方案可快速为各类应用集成AI助手,提升交互体验与智能化水平。
通义千问1.5-1.8B-Chat-GPTQ-Int4 .NET开发者集成教程:C#调用大模型API
最近在星图镜像广场上看到了通义千问1.5-1.8B-Chat-GPTQ-Int4这个模型,对于咱们.NET开发者来说,这绝对是个好消息。这意味着我们可以在自己的C#项目里,轻松集成一个功能强大的对话AI,给应用加点“智能”的料。
你可能已经部署好了模型,或者正准备部署。但部署只是第一步,怎么在自己的C#代码里优雅地调用它,才是咱们今天要解决的核心问题。这篇文章,我就手把手带你走一遍,从定义数据模型到封装一个健壮的调用服务,最后集成到ASP.NET Core Web API里。整个过程,我会尽量用大白话讲清楚,保证你跟着做就能跑起来。
1. 准备工作与环境确认
在开始写代码之前,咱们得先确保几件事都到位了。这就像做饭前得先备好菜和锅一样。
首先,你得有一个已经部署好的通义千问1.5-1.8B-Chat-GPTQ-Int4模型服务。我假设你已经通过星图镜像广场完成了部署,并且拿到了服务的访问地址,比如 http://你的服务器地址:端口号/v1/chat/completions。这个地址就是我们后续所有API调用的终点。
其次,准备一个.NET开发环境。我用的例子是基于.NET 6或.NET 8的,这是目前的主流选择,语法现代,性能也好。你可以用Visual Studio 2022、Rider或者VS Code,看个人习惯。
最后,我们会在项目里用到几个基本的NuGet包,主要是用来处理HTTP请求和JSON序列化的。别担心,这些都很常见。
2. 理解API:请求与响应的模样
调用任何API,第一步都是搞清楚它“吃”进去什么,“吐”出来什么。通义千问的Chat接口,遵循了比较通用的聊天补全格式。
简单来说,你需要发送一个JSON结构过去,里面包含了对话历史(messages)和一些控制生成的参数。模型处理完后,会返回另一个JSON结构,里面就有你想要的AI回复。
为了让C#能舒服地处理这些JSON,我们得先定义好对应的数据模型类。这就像给数据穿上C#的“衣服”。
2.1 定义请求数据模型
我们先在项目里创建一个叫 QwenRequest.cs 的类。这个类描述了我们要发送给模型的所有信息。
using System.Text.Json.Serialization;
namespace YourProject.Models
{
public class QwenRequest
{
// 核心:对话消息列表
[JsonPropertyName("messages")]
public List<ChatMessage> Messages { get; set; } = new List<ChatMessage>();
// 模型名称,虽然端点固定,但有时API要求指明
[JsonPropertyName("model")]
public string Model { get; set; } = "qwen1.5-1.8b-chat";
// 控制生成随机性的温度,0-2之间,越高越随机
[JsonPropertyName("temperature")]
public float Temperature { get; set; } = 0.7f;
// 每次生成的最大令牌数,控制回复长度
[JsonPropertyName("max_tokens")]
public int MaxTokens { get; set; } = 1024;
// 是否启用流式输出,我们先用简单的非流式
[JsonPropertyName("stream")]
public bool Stream { get; set; } = false;
}
// 单独定义一条消息的结构
public class ChatMessage
{
[JsonPropertyName("role")]
public string Role { get; set; } // "system", "user", "assistant"
[JsonPropertyName("content")]
public string Content { get; set; }
}
}
这里有几个关键点:
Messages是对话的核心,它是一个列表,按顺序存放了系统指令、用户问题和AI的历史回答。Role有三种:system(设定AI角色)、user(用户)、assistant(AI助手)。Temperature和MaxTokens是常用的“旋钮”,用来调整回复的创造性和长度,你可以根据场景微调。
2.2 定义响应数据模型
模型返回的数据也需要一个“家”。创建 QwenResponse.cs。
using System.Text.Json.Serialization;
namespace YourProject.Models
{
public class QwenResponse
{
[JsonPropertyName("id")]
public string Id { get; set; }
[JsonPropertyName("object")]
public string Object { get; set; }
[JsonPropertyName("created")]
public long Created { get; set; }
[JsonPropertyName("model")]
public string Model { get; set; }
// 这是最重要的部分,包含了模型的选择和回复
[JsonPropertyName("choices")]
public List<ChatChoice> Choices { get; set; }
// 使用情况统计,比如消耗了多少token
[JsonPropertyName("usage")]
public TokenUsage Usage { get; set; }
}
public class ChatChoice
{
[JsonPropertyName("index")]
public int Index { get; set; }
[JsonPropertyName("message")]
public ChatMessage Message { get; set; } // 复用请求里的ChatMessage类
[JsonPropertyName("finish_reason")]
public string FinishReason { get; set; }
}
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#就能自动把JSON字符串转换成我们熟悉的强类型对象,后续处理起来就方便多了。
3. 封装HTTP调用服务
直接在每个地方都写 HttpClient 调用代码会显得很乱,也不利于维护。最好的做法是封装一个专门的服务类。我们来创建一个 QwenAIService.cs。
这个服务要干几件事:管理HTTP客户端、构造请求、发送请求、处理响应和可能发生的错误。
using System.Net.Http.Json;
using YourProject.Models;
namespace YourProject.Services
{
public interface IQwenAIService
{
Task<string> GetChatResponseAsync(string userInput, string systemPrompt = null, CancellationToken cancellationToken = default);
}
public class QwenAIService : IQwenAIService
{
private readonly HttpClient _httpClient;
private readonly string _apiEndpoint;
private readonly ILogger<QwenAIService> _logger;
// 通过构造函数注入配置和HttpClient
public QwenAIService(HttpClient httpClient, IConfiguration configuration, ILogger<QwenAIService> logger)
{
_httpClient = httpClient;
_logger = logger;
// 从appsettings.json读取API地址
_apiEndpoint = configuration["QwenAI:ApiEndpoint"]
?? throw new ArgumentNullException("QwenAI:ApiEndpoint is not configured.");
// 可以在这里设置一些默认的HTTP头,比如认证信息
// _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
}
public async Task<string> GetChatResponseAsync(string userInput, string systemPrompt = null, CancellationToken cancellationToken = default)
{
// 1. 构造请求消息列表
var messages = new List<ChatMessage>();
if (!string.IsNullOrWhiteSpace(systemPrompt))
{
messages.Add(new ChatMessage { Role = "system", Content = systemPrompt });
}
messages.Add(new ChatMessage { Role = "user", Content = userInput });
// 2. 构造请求体
var request = new QwenRequest
{
Messages = messages,
Model = "qwen1.5-1.8b-chat",
Temperature = 0.7f,
MaxTokens = 512, // 根据需求调整
Stream = false
};
try
{
_logger.LogInformation("Sending request to Qwen AI: {UserInput}", userInput);
// 3. 发送POST请求
var response = await _httpClient.PostAsJsonAsync(_apiEndpoint, request, cancellationToken);
// 4. 确保响应成功
response.EnsureSuccessStatusCode();
// 5. 读取并解析响应
var qwenResponse = await response.Content.ReadFromJsonAsync<QwenResponse>(cancellationToken: cancellationToken);
// 6. 提取AI回复内容
var aiReply = qwenResponse?.Choices?.FirstOrDefault()?.Message?.Content?.Trim();
if (string.IsNullOrEmpty(aiReply))
{
_logger.LogWarning("Received empty or invalid response from Qwen AI.");
return "抱歉,我暂时没有理解你的问题。";
}
_logger.LogInformation("Received response from Qwen AI. Tokens used: {Total}", qwenResponse?.Usage?.TotalTokens);
return aiReply;
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "Network error when calling Qwen AI API.");
// 这里可以细化处理不同的HTTP状态码
return $"网络请求出错: {ex.StatusCode}";
}
catch (TaskCanceledException ex) when (cancellationToken.IsCancellationRequested)
{
_logger.LogWarning("The request to Qwen AI was cancelled.");
return "请求已取消。";
}
catch (Exception ex)
{
_logger.LogError(ex, "An unexpected error occurred when calling Qwen AI.");
return "处理您的请求时出现了意外错误。";
}
}
}
}
这个服务类做了很好的抽象:
- 它通过接口
IQwenAIService定义契约,方便后续测试和替换。 - 使用依赖注入,配置和
HttpClient都由外部管理,符合.NET Core的最佳实践。 - 包含了基本的日志记录,方便出问题时排查。
- 对异常进行了初步处理,返回用户友好的错误信息。
4. 添加重试与容错机制
网络请求总有可能因为各种原因失败,比如瞬间的网络抖动或者服务端压力大。对于AI对话这种体验要求较高的场景,加上简单的重试机制能提升不少稳定性。
我们不需要搞得太复杂,一个针对短暂故障的重试策略就很有用。我们可以用 Polly 这个流行的库来实现。首先,通过NuGet安装 Polly 包。
然后,修改我们的服务类,或者更好的是,在依赖注入注册时配置重试策略。这里我们在 Program.cs 中配置。
// 在Program.cs或Startup.cs中
using Polly;
using Polly.Extensions.Http;
var builder = WebApplication.CreateBuilder(args);
// ... 其他服务配置 ...
// 1. 配置一个针对HttpRequestException和5xx状态码的等待重试策略
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError() // 处理网络错误和5xx服务器错误
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(3),
TimeSpan.FromSeconds(5)
}, onRetry: (outcome, timespan, retryAttempt, context) =>
{
// 记录重试日志
var logger = context.GetLogger();
logger?.LogWarning("Retry {RetryAttempt} after {Delay}ms for {OperationKey}. Exception: {Exception}",
retryAttempt, timespan.TotalMilliseconds, context.OperationKey, outcome.Exception?.Message);
});
// 2. 为名为“QwenAI”的HttpClient配置这个策略
builder.Services.AddHttpClient<QwenAIService>("QwenAI")
.AddPolicyHandler(retryPolicy); // 应用重试策略
// 3. 注册我们的AI服务
builder.Services.AddScoped<IQwenAIService, QwenAIService>();
这样配置后,当 QwenAIService 发起的HTTP请求遇到可重试的错误时,它会自动按照1秒、3秒、5秒的间隔重试三次。很多间歇性问题通过重试就能解决,用户几乎无感知。
5. 集成到ASP.NET Core Web API
现在,我们有了一个健壮的AI服务,接下来就是把它“塞进”一个Web API项目里,暴露给前端或其他服务调用。假设我们要创建一个简单的聊天控制器。
创建一个 ChatController.cs。
using Microsoft.AspNetCore.Mvc;
using YourProject.Services;
namespace YourProject.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;
}
// 最简单的单轮对话端点
[HttpPost("simple")]
public async Task<IActionResult> SimpleChat([FromBody] SimpleChatRequest request)
{
if (string.IsNullOrWhiteSpace(request?.Message))
{
return BadRequest("Message cannot be empty.");
}
try
{
var response = await _qwenAIService.GetChatResponseAsync(request.Message);
return Ok(new { reply = response });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing chat request.");
return StatusCode(500, "An internal error occurred.");
}
}
// 支持系统指令和上下文的多轮对话端点(简化版)
[HttpPost("conversation")]
public async Task<IActionResult> ConversationalChat([FromBody] ConversationalChatRequest request)
{
// 这里可以扩展为维护一个会话ID,在服务层或缓存中保存对话历史
// 本例简化处理,每次只携带当前系统提示和用户问题
var systemPrompt = request?.SystemPrompt ?? "你是一个乐于助人的AI助手。";
var userMessage = request?.UserMessage;
if (string.IsNullOrWhiteSpace(userMessage))
{
return BadRequest("UserMessage cannot be empty.");
}
try
{
var response = await _qwenAIService.GetChatResponseAsync(userMessage, systemPrompt);
return Ok(new { reply = response });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing conversational chat request.");
return StatusCode(500, "An internal error occurred.");
}
}
}
// 请求模型
public class SimpleChatRequest
{
public string Message { get; set; }
}
public class ConversationalChatRequest
{
public string SystemPrompt { get; set; }
public string UserMessage { get; set; }
}
}
别忘了在 appsettings.json 里配置你的模型API地址:
{
"QwenAI": {
"ApiEndpoint": "http://你的服务器地址:端口号/v1/chat/completions"
},
// ... 其他配置
}
现在,运行你的Web API项目。你可以用Swagger UI、Postman或者任何HTTP客户端来测试这两个端点:
POST /api/chat/simple发送一个简单的用户消息。POST /api/chat/conversation发送一个可带系统指令的用户消息。
6. 总结与后续建议
走完这一套流程,你应该已经成功在.NET项目里接入了通义千问模型。整个过程其实并不复杂,核心就是理解API格式、封装HTTP调用、处理好错误,最后集成到你的应用框架里。
用下来感觉,这套封装方式挺实用的,特别是加了重试机制之后,稳定性好了不少。对于刚开始接触AI集成的.NET开发者来说,从这种简单的非流式调用入手,门槛比较低,也容易理解整个数据流转的过程。
当然,这只是个起点。在实际项目里,你可能还需要考虑更多东西,比如:
- 对话历史管理:现在的例子是单轮或简单的伪多轮。真正的多轮对话需要你维护一个
messages列表,每次把新的用户消息和AI回复追加进去,再发给模型。这部分状态可以保存在服务端的内存、数据库或者分布式缓存里,并关联一个会话ID。 - 流式响应:如果希望实现像ChatGPT那样一个字一个字出来的效果,就需要处理服务端返回的流式数据。这涉及到使用
HttpCompletionOption.ResponseHeadersRead并逐步读取响应流,对前端和服务端都有额外要求。 - 性能与超时:根据模型部署的硬件情况,调整
HttpClient的超时设置。对于长文本生成,MaxTokens设得太大可能导致响应时间很长,需要做好用户体验上的处理,比如前端显示“正在思考...”。 - 更细化的错误处理:根据API返回的具体错误码(比如token超限、模型忙),给用户更精准的反馈。
建议你先拿这个基础版本跑起来,看看效果。然后根据你的具体业务场景,再一步步去添加上面这些高级功能。最重要的是先让整个链路通起来,有了可工作的原型,后面的优化就都有方向了。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)