通过 Microsoft.Extensions.AI 的缓存功能,智能存储和复用 AI 响应,显著降低 API 成本并将响应速度提升 10-100 倍。
在生产环境中,大语言模型调用存在三大痛点:
痛点 | 影响 | 缓存方案 |
|---|---|---|
成本高昂 | 每次 API 调用产生费用 | 重复请求直接返回缓存 |
延迟较高 | 网络+模型推理耗时 | 缓存命中毫秒级响应 |
重复请求 | 用户常问相同问题 | 智能识别并复用结果 |
典型场景:

关键组件:
组件 | 职责 |
|---|---|
CachingChatClient | 抽象基类,定义缓存逻辑 |
DistributedCachingChatClient | 基于 IDistributedCache 的实现 |
缓存键生成 | 基于消息+选项+版本的哈希计算 |
流式处理 | 自动合并/拆分流式更新 |
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.AI.OpenAI
dotnet add package Microsoft.Extensions.Caching.Memory生产环境推荐使用 Redis:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedisusing Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
// 创建缓存存储
IDistributedCache cache = new MemoryDistributedCache(/*...*/);
// 启用缓存中间件
var cachedClient = new ChatClientBuilder(baseChatClient)
.UseDistributedCache(cache)
.Build();核心要点:
ChatClientBuilder 构建管道UseDistributedCache 一行启用缓存var question = "什么是 Microsoft.Extensions.AI?";
// 第一次请求 - 调用模型
var sw1 = Stopwatch.StartNew();
var response1 = await cachedClient.GetResponseAsync(question);
sw1.Stop();
Console.WriteLine($"⏱️ 第一次: {sw1.ElapsedMilliseconds}ms");
// 第二次请求 - 从缓存返回
var sw2 = Stopwatch.StartNew();
var response2 = await cachedClient.GetResponseAsync(question);
sw2.Stop();
Console.WriteLine($"⏱️ 第二次: {sw2.ElapsedMilliseconds}ms");
Console.WriteLine($"✨ 加速比: {sw1.ElapsedMilliseconds / sw2.ElapsedMilliseconds}x");典型效果:
缓存同样支持流式模式,通过 CoalesceStreamingUpdates 控制行为:
var cachedClient = baseChatClient
.AsBuilder()
.UseDistributedCache(cache, configure: c =>
{
// true(默认):合并流式更新后缓存,读取时再拆分
c.CoalesceStreamingUpdates = true;
})
.Build();工作原理:
配置 | 存储方式 | 适用场景 |
|---|---|---|
true | 合并为完整响应 | 节省存储,推荐 |
false | 保留流式序列 | 需要精确重放流 |
using Microsoft.Extensions.Caching.StackExchangeRedis;
var redisCache = new RedisCache(Options.Create(new RedisCacheOptions
{
Configuration = "localhost:6379",
InstanceName = "MEAICache:"
}));
var cachedClient = baseChatClient
.AsBuilder()
.UseDistributedCache(redisCache)
.Build();Redis 优势:
通过 CacheKeyAdditionalValues 创建独立的缓存分区:
var productionClient = baseChatClient
.AsBuilder()
.UseDistributedCache(cache, configure: c =>
{
c.CacheKeyAdditionalValues = new[] { "prod", "v2", "zh-CN" };
})
.Build();适用场景:
场景 | 分区策略 | 示例 |
|---|---|---|
多语言 | 按语言分区 | ["zh-CN"], ["en-US"] |
版本管理 | 按版本分区 | ["v1"], ["v2"] |
环境隔离 | 按环境分区 | ["dev"], ["prod"] |
继承 CachingChatClient 实现自定义逻辑:
public class CustomCachingClient : CachingChatClient
{
protected override bool EnableCaching(
IEnumerable<ChatMessage> messages,
ChatOptions? options)
{
// 自定义规则:不缓存包含敏感词的请求
var text = string.Join(" ", messages.Select(m => m.Text));
return !text.Contains("机密") && base.EnableCaching(messages, options);
}
}默认禁用场景:
ConversationId 的请求var faqQuestions = new[]
{
"营业时间是什么?",
"如何申请退款?",
"支持哪些支付方式?",
"营业时间是什么?", // 重复问题
};
foreach (var question in faqQuestions)
{
var response = await cachedClient.GetResponseAsync(question);
// 重复问题自动从缓存返回,响应时间显著降低
}实测效果:
DistributedCachingChatClient 使用 JSON 序列化存储数据,存在以下限制:
限制项 | 说明 |
|---|---|
RawRepresentation | 不会被序列化 |
AdditionalProperties | object 值会变为 JsonElement |
自定义类型 | 可能无法完整往返 |
建议: 如果依赖这些属性,请谨慎使用或实现自定义序列化。
MEAI 会在序列化格式变更时自动更新缓存版本号(当前 v2),使旧缓存失效,避免兼容性问题。
UseDistributedCache 一行代码启用缓存适用场景:
下一步: 探索 MEAI 的 Chat Reducer(消息压缩)和自定义中间件功能,构建更强大的 AI 应用管道。