共计 3580 个字符,预计需要花费 9 分钟才能阅读完成。
背景痛点
作为一名 C# 开发者,当我们需要将 AI 能力集成到应用中时,往往会遇到以下几个典型问题:

- 协议转换复杂 :AI 服务通常提供 REST API,需要手动处理 HTTP 请求和 JSON 序列化
- 异步处理困难 :AI 推理通常是耗时操作,需要良好的异步编程模型避免阻塞 UI
- 模型版本控制 :线上模型更新后,如何确保客户端兼容性是个挑战
- 性能瓶颈 :高并发场景下,未经优化的 AI 调用可能导致系统资源耗尽
技术选型对比
C# 生态中有几种主流的 AI 集成方式,各有优缺点:
- Azure Cognitive Services
- 优点:开箱即用,服务稳定,支持多种 AI 能力
- 缺点:需要网络连接,有调用费用
-
适用场景:快速集成标准 AI 功能(如 OCR、语音识别)
-
ML.NET
- 优点:纯.NET 实现,可离线使用
- 缺点:模型训练能力有限
-
适用场景:需要本地执行的简单机器学习任务
-
TensorFlow.NET
- 优点:可直接使用 TensorFlow 模型,功能强大
- 缺点:学习曲线较陡
- 适用场景:需要复杂深度学习模型的场景
核心实现
HTTP API 封装
对于调用云端 AI 服务,我们需要一个健壮的 HTTP 客户端封装:
public class AIClient : IDisposable
{
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
public AIClient(string baseUrl, string apiKey, ILogger logger)
{
_httpClient = new HttpClient
{BaseAddress = new Uri(baseUrl)
};
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
_logger = logger;
}
public async Task<TResponse> PostAsync<TRequest, TResponse>(string endpoint, TRequest request)
{
try
{var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(endpoint, content);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<TResponse>(responseJson);
}
catch (Exception ex)
{_logger.LogError(ex, "AI API 调用失败");
throw;
}
}
public void Dispose() => _httpClient?.Dispose();
}
TensorFlow 模型加载
对于本地 TensorFlow 模型,我们可以这样加载和推理:
public class TensorFlowModel : IDisposable
{
private readonly Graph _graph;
private readonly Session _session;
public TensorFlowModel(string modelPath)
{_graph = new Graph();
var modelBytes = File.ReadAllBytes(modelPath);
_graph.Import(modelBytes);
_session = new Session(_graph);
}
public float[] Predict(float[] input)
{// 创建输入张量 (Tensor)
var tensor = new Tensor(input);
// 运行推理
var runner = _session.GetRunner();
runner.AddInput(_graph["input"][0], tensor);
runner.Fetch(_graph["output"][0]);
var output = runner.Run()[0];
return (float[])output.GetValue();}
public void Dispose()
{_session?.Dispose();
_graph?.Dispose();}
}
性能优化
批处理测试
使用 BenchmarkDotNet 测试不同批处理大小对吞吐量的影响:
[MemoryDiagnoser]
public class AIPerformanceBenchmark
{
private AIClient _client;
private List<Request> _batchRequests;
[Params(1, 10, 100)]
public int BatchSize {get; set;}
[GlobalSetup]
public void Setup()
{_client = new AIClient("https://api.example.com", "key", NullLogger.Instance);
_batchRequests = Enumerable.Range(0, 1000)
.Select(i => new Request { Data = $"sample_{i}" })
.ToList();}
[Benchmark]
public async Task ProcessBatch()
{var tasks = _batchRequests.Take(BatchSize)
.Select(r => _client.PostAsync<Request, Response>("/predict", r));
await Task.WhenAll(tasks);
}
}
内存优化
对于高频调用场景,可以使用对象池减少 GC 压力:
public class TensorPool : IDisposable
{private readonly ConcurrentBag<Tensor> _pool = new();
private readonly int _maxSize;
public TensorPool(int maxSize = 100) => _maxSize = maxSize;
public Tensor Rent(int size)
{if (_pool.TryTake(out var tensor) && tensor.TensorByteSize >= size)
return tensor;
return new Tensor(new float[size]);
}
public void Return(Tensor tensor)
{if (_pool.Count < _maxSize)
_pool.Add(tensor);
else
tensor.Dispose();}
public void Dispose()
{foreach (var tensor in _pool)
tensor.Dispose();
_pool.Clear();}
}
避坑指南
- 文化差异问题
-
在序列化 JSON 时,明确指定文化信息:
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, NumberHandling = JsonNumberHandling.AllowReadingFromString }; -
模型热更新
-
使用文件监视器实现热重载:
var watcher = new FileSystemWatcher(modelDir); watcher.NotifyFilter = NotifyFilters.LastWrite; watcher.Changed += (s, e) => ReloadModel(); watcher.EnableRaisingEvents = true; -
日志规范
- 记录完整的请求上下文:
_logger.LogInformation("AI 调用 - 模型:{Model} 版本:{Version} 耗时:{Elapsed}ms", modelName, modelVersion, stopwatch.ElapsedMilliseconds);
延伸思考
当 AI 服务响应超时时,可以考虑以下降级策略:
- 本地缓存 :对历史查询结果建立缓存
- 简化模型 :准备一个轻量级的本地备用模型
- 业务降级 :返回有意义的默认值或部分功能
- 队列重试 :将请求放入队列异步处理
实现这些策略需要根据业务场景权衡,没有放之四海而皆准的方案。在实际项目中,建议通过 A / B 测试评估不同降级策略对用户体验的影响。
正文完
