Microsoft.Extensions.AI 上下文压缩功能详解

概述

Microsoft.Extensions.AI 提供了两种上下文压缩策略,用于解决长对话场景中的token限制问题,通过智能缩减历史消息来保持对话连贯性。

两种压缩策略对比

特性

MessageCountingChatReducer

SummarizingChatReducer

压缩方式

简单计数,保留最近N条消息

AI生成摘要,保留关键信息

触发条件

每次对话轮次

超过阈值时自动触发

信息保留

完整保留最近消息

压缩为摘要,可能丢失细节

适用场景

简单对话,需要完整上下文

复杂对话,需要长期记忆

计算开销

较高(需调用AI模型)

一、MessageCountingChatReducer(直接计数压缩)

基本配置

csharp

var countingReducer = new MessageCountingChatReducer(targetCount: 3);
var reducingClient = chatClient.AsBuilder()
    .UseChatReducer(reducer: countingReducer)
    .Build();

工作流程

  1. 初始化: 设置目标消息数(如保留最近3条非系统消息)

  2. 对话模拟: 进行多轮对话,消息列表不断增长

  3. 压缩效果:

    • 始终保留系统消息

    • 仅保留最近N条用户/助手消息

    • 删除早期的对话内容

示例输出

text

📤 用户: 我的订单号是多少?
📥 助手: 您的订单号是...
📊 当前消息总数: 3 条

📤 用户: 订单什么时候发货?
📥 助手: 通常在下单后...
📊 当前消息总数: 5 条

...

✅ 压缩前: 13 条消息
✅ 压缩后: 7 条消息(系统+最近3轮对话)

二、SummarizingChatReducer(智能摘要压缩)

基本配置

csharp

var summarizingReducer = new SummarizingChatReducer(
    chatClient: chatClient,    // 需要AI客户端生成摘要
    targetCount: 2,           // 保留最近消息数
    threshold: 1              // 触发阈值
);

工作机制

1. 触发条件

text

触发摘要 = (总消息数 - 系统消息) > (targetCount + threshold)
  • 示例:targetCount=2, threshold=1

  • 当非系统消息超过 3 条时触发摘要生成

  • 保留:系统消息 + 最近2条消息 + 历史摘要

2. 摘要生成过程

  1. 收集旧消息: 获取超过保留数量的历史消息

  2. 调用AI总结: 使用聊天客户端生成简洁摘要

  3. 重构消息列表:

    text

    压缩前: [系统消息, 历史1, 历史2, 历史3, 历史4, 最近1, 最近2]
    压缩后: [系统消息, 摘要, 最近1, 最近2]

医疗对话示例

原始对话流程

  1. 系统提示: "你是一位专业的医疗咨询助手。"

  2. 用户: "我最近经常头痛,是什么原因?"

  3. 助手: 给出头痛可能原因和建议

  4. 用户: "我每天睡眠时间大概5小时..."

  5. 助手: 建议保证睡眠

  6. 用户: "除了头痛,我还感觉眼睛很干涩。"

  7. 助手: 解释干眼原因并建议(触发摘要)

压缩效果

text

📊 初始消息数: 6 条(未触发摘要)
📊 当前消息数: 7 条(已超过阈值 3 条)

✅ 压缩后消息数: 5 条
[系统消息, 摘要消息, 最近2条对话]

高级功能:自定义摘要提示词

医疗专用提示词配置

csharp

customReducer.SummarizationPrompt = """
请为以下医疗咨询对话生成简洁的临床摘要(不超过 3 句话):

要求:
- 提取患者主诉症状和时长
- 记录已提供的初步建议
- 保留关键医学信息(用药史、过敏史等,如有)
- 使用专业医学术语
- 不要添加推测性诊断或建议

格式:【患者主诉】症状描述 | 【已知信息】关键背景 | 【初步建议】已给出的建议
""";

自定义摘要输出示例

text

📋 压缩后的消息结构:
[系统消息]
[自定义摘要] 【患者主诉】持续低烧3天,体温37.8℃ | 【已知信息】青霉素过敏史 | 【初步建议】多休息、多喝水,监测体温,超过38.5℃需就医
[最近对话1]
[最近对话2]

三、技术实现要点

集成方式

csharp

// 方式1:通过Builder集成
var client = chatClient.AsBuilder()
    .UseChatReducer(reducer)
    .Build();

// 方式2:直接使用Reducer
var reducedMessages = await reducer.ReduceAsync(messages, cancellationToken);

压缩时机控制

  1. 手动触发: 在合适时机调用ReduceAsync

  2. 自动触发: 集成到聊天客户端中,每次对话自动检查

  3. 阈值调整: 根据应用场景调整targetCountthreshold

四、应用场景推荐

适合MessageCountingChatReducer

  • ✅ 短期对话(如订单查询)

  • ✅ 需要完整上下文理解的场景

  • ✅ 资源受限环境

  • ❌ 长期记忆要求高的对话

适合SummarizingChatReducer

  • ✅ 医疗咨询(需要长期病史)

  • ✅ 技术支持(多步骤问题解决)

  • ✅ 教育辅导(渐进式学习)

  • ✅ 任何需要"记住"早期对话的场景

五、性能考虑

因素

CountingReducer

SummarizingReducer

延迟

几乎为0

需要AI生成摘要时间

Token成本

0

需要消耗额外Token

内存占用

固定大小

取决于摘要长度

六、最佳实践

  1. 混合策略: 短期用计数,长期转摘要

  2. 阈值调优:

    • 高频交互:设置较高阈值

    • 重要信息:设置较低阈值及早摘要

  3. 领域优化: 为不同场景编写专用摘要提示词

  4. 监控: 记录压缩率、摘要质量指标

七、注意事项

  1. 信息丢失: 摘要可能遗漏重要细节

  2. 成本控制: 摘要生成需要额外API调用

  3. 一致性: 确保摘要准确反映历史对话

  4. 调试: 保留原始对话日志以便问题排查

通过合理使用这两种压缩策略,可以在有限的token预算下,实现更长的、有记忆的智能对话体验。

不会做游戏