C#集成ChatGPT API实战指南:从认证到流式响应处理

1次阅读
没有评论

共计 2899 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

背景痛点分析

直接使用原生 HttpClient 调用 ChatGPT API 时,开发者常遇到以下问题:

C# 集成 ChatGPT API 实战指南:从认证到流式响应处理

  • 令牌管理复杂:手动处理 OAuth2.0 令牌的获取与刷新,容易引入安全漏洞
  • 流式响应解析困难 :ChatGPT 的 streaming 模式返回 SSE(Server-Sent Events) 格式数据,需要特殊处理
  • 超时控制缺失 :长对话场景下未合理配置CancellationToken 可能导致线程阻塞
  • 重试机制不足:API 限流或网络抖动时缺乏自动重试策略

HTTP 库技术选型

方案 优势 劣势
原生 HttpClient 无需依赖第三方库 需要手动实现重试 / 熔断逻辑
RestSharp 简洁的链式调用语法 对 streaming 支持较弱
Refit 强类型接口定义 动态 Header 处理不够灵活

推荐使用 IHttpClientFactory 官方方案,兼具灵活性与可维护性。

核心实现步骤

1. 配置带策略的 HttpClient

// Program.cs
builder.Services.AddHttpClient("ChatGPT", client => 
{client.BaseAddress = new Uri("https://api.openai.com/v1/");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
})
.AddPolicyHandler(GetRetryPolicy());

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() =>
    HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
        .WaitAndRetryAsync(3, retryAttempt => 
            TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

⚠️ 重要提示:
– 生产环境必须配置 BaseAddress 而非硬编码 URL
– 429 状态码需特殊处理

2. 流式响应解析

public async IAsyncEnumerable<string> StreamCompletionAsync(
    ChatRequest request, 
    [EnumeratorCancellation] CancellationToken ct = default)
{
    using var response = await _httpClient.PostAsJsonAsync(
        "chat/completions", 
        request, 
        ct);

    response.EnsureSuccessStatusCode();

    await using var stream = await response.Content.ReadAsStreamAsync(ct);
    using var reader = new StreamReader(stream);

    while (!reader.EndOfStream && !ct.IsCancellationRequested)
    {var line = await reader.ReadLineAsync();
        if (string.IsNullOrEmpty(line) || !line.StartsWith("data:")) 
            continue;

        var eventData = line["data:".Length..].Trim();
        if (eventData == "[DONE]") break;

        var chunk = JsonSerializer.Deserialize<ChatChunk>(eventData);
        yield return chunk.choices[0].delta.content;
    }
}

3. OAuth2.0 认证实现

// 使用 Azure Key Vault 存储密钥
var credential = new DefaultAzureCredential();
var secret = await new SecretClient(new Uri(keyVaultUrl), 
    credential)
    .GetSecretAsync("ChatGPT-Key");

_httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", secret.Value.Value);

生产环境建议

速率限制规避

  • 实现请求队列(如通过 Channel 类)
  • 监控 x-ratelimit-remaining 响应头
  • 重要业务请求添加优先级标识

上下文管理

public class ConversationContext
{public List<ChatMessage> History { get;} = new();

    public void AddMessage(ChatRole role, string content) 
        => History.Add(new ChatMessage(role, content));

    public ChatRequest ToRequest() => new() {
        messages = History,
        max_tokens = 2000 // 动态计算剩余 token
    };
}

性能对比数据

模式 内存占用 响应延迟 适用场景
Streaming 15-20MB 1-3s 实时对话 / 长文本
非 Streaming 80-100MB 5-8s 短文本 / 批处理

扩展思考

结合 Blazor 实现实时 UI 的推荐方案:

  1. OnInitializedAsync 中启动 streaming 请求
  2. 通过 StateHasChanged() 触发局部刷新
  3. 使用 CancellationTokenSource 实现停止响应功能
@implements IAsyncDisposable
@inject ChatGPTService Service

<button @onclick="StartChat"> 开始对话 </button>
<button @onclick="cts?.Cancel()"> 停止 </button>

@foreach (var chunk in chunks)
{<p>@chunk</p>}

@code {private List<string> chunks = new();
    private CancellationTokenSource? cts;

    private async Task StartChat()
    {cts = new CancellationTokenSource();
        await foreach (var chunk in Service.StreamCompletionAsync(cts.Token))
        {chunks.Add(chunk);
            StateHasChanged();}
    }

    public async ValueTask DisposeAsync() => cts?.Cancel();
}
正文完
 0
评论(没有评论)