共计 2281 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
在调用 GPT- 3 等大模型 API 时,开发者常遇到以下典型问题:

- 长文本截断 :大模型的输入有 token 限制,超出部分会被截断
- token 计算误差 :不同模型的 token 计算方式不同,容易导致预算超支
- 异步上下文丢失 :在异步调用中容易丢失上下文信息
- 连接不稳定 :大模型 API 响应时间长,容易因网络波动导致失败
- 流式响应处理复杂 :需要特殊处理分块传输的响应数据
HTTP 客户端技术对比
C# 中常用的 HTTP 客户端主要有三种:
- HttpClient:.NET 官方推荐,支持 DI 注入,但需要正确管理生命周期
- RestSharp:语法简洁,但性能稍差,不适合高并发场景
- Refit:强类型接口风格,适合简单 API,但灵活性较差
对于大模型调用,推荐使用 HttpClient,因为:
- 原生支持异步流处理
- 可以配合 IHttpClientFactory 管理生命周期
- 性能最优
核心实现
1. 使用 IHttpClientFactory 实现 DI 注入
首先配置服务:
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("OpenAIClient", client =>
{client.BaseAddress = new Uri("https://api.openai.com/v1/");
client.Timeout = TimeSpan.FromSeconds(30);
});
}
然后注入使用:
public class OpenAIService
{
private readonly HttpClient _httpClient;
public OpenAIService(IHttpClientFactory httpClientFactory)
{_httpClient = httpClientFactory.CreateClient("OpenAIClient");
}
}
2. 基于 Polly 实现重试机制
安装 Polly 包后配置策略:
services.AddHttpClient("OpenAIClient")
.AddTransientHttpErrorPolicy(policy =>
policy.WaitAndRetryAsync(new[]
{TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(3),
TimeSpan.FromSeconds(5)
}));
3. 处理流式响应
public async IAsyncEnumerable<string> StreamCompletionAsync(string prompt)
{var request = new HttpRequestMessage(HttpMethod.Post, "completions");
request.Content = new StringContent(JsonSerializer.Serialize(new
{
prompt = prompt,
stream = true
}));
using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
await using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
while (!reader.EndOfStream)
{var line = await reader.ReadLineAsync();
if (!string.IsNullOrEmpty(line) && line.StartsWith("data:"))
{yield return line[5..].Trim();}
}
}
高级特性
并发控制
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5);
public async Task<string> GetCompletionWithThrottling(string prompt)
{await _semaphore.WaitAsync();
try
{return await GetCompletionAsync(prompt);
}
finally
{_semaphore.Release();
}
}
分布式追踪
using var activity = Activity.Current?.Source.StartActivity("OpenAI.Call");
activity?.SetTag("prompt", prompt);
// ... 调用代码...
避坑指南
- HttpClient 生命周期 :
- 不要 using HttpClient
-
使用 IHttpClientFactory 管理
-
敏感信息过滤 :
// 在日志中过滤 API Key .ConfigureLogging(logging => logging.AddFilter((provider, category, level) => !category.Contains("ApiKey"))) -
冷启动优化 :
- 预热连接池
- 提前实例化服务
结语
大模型调用看似简单,但要实现稳定高效的服务需要考虑很多细节。希望本文的方案能帮助你在项目中快速落地。以下是几个值得进一步思考的问题:
- 如何实现请求优先级队列?
- 如何动态调整重试策略?
- 如何设计降级方案应对 API 限流?
欢迎在评论区分享你的实践经验!
正文完
