news 2026/4/18 2:04:46

使用 IChatReducer 进行聊天记录缩减

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 IChatReducer 进行聊天记录缩减

序言

在多轮对话场景中,随着聊天次数增加,发送给大语言模型(LLM)的上下文会持续膨胀,带来 Token 成本上升与上下文溢出风险。 Microsoft Agent Framework 将这一问题抽象为 Chat Reduction(聊天记录缩减),并通过IChatReducer策略对聊天历史进行统一治理,而不是在业务代码中零散地裁剪或拼接历史消息。

本文基于“客户端本地存储聊天记录(Client-side history)”的典型场景,演示如何使用MessageCountingChatReducer自动限制历史长度,防止上下文无限增长,并观察在“历史被遗忘”后 Agent 行为的变化。


1. 代码关键实现步骤

引入必要的依赖

  • Microsoft.Extensions.AI:提供统一的 AI 抽象(ChatMessageReducer等)

  • Azure.AI.OpenAI:用于连接 Azure OpenAI 服务

  • Microsoft.Agents.AI:Agent Framework 核心能力

配置 Agent 与缩减策略(Reducer)

AIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new AzureCliCredential()) .GetChatClient(deploymentName) .CreateAIAgent(new ChatClientAgentOptions { ChatOptions = new() { Instructions = "你是一位江湖说书人,擅长用幽默、接地气的方式讲笑话和故事。" }, Name = "Joker", // 关键点:自定义 ChatMessageStoreFactory ChatMessageStoreFactory = ctx => new InMemoryChatMessageStore( new MessageCountingChatReducer(2), // 仅保留最近 2 条 非 System 的 ChatMessage ctx.SerializedState, ctx.JsonSerializerOptions) });

组件说明

  • InMemoryChatMessageStore

    • 聊天记录保存在客户端内存中

    • 适用于 Chat Completion / 本地上下文管理场景

  • MessageCountingChatReducer(2)

    • 基于“消息数量”的缩减策略

    • 参数 2 表示仅保留最近 2 条非系统消息( 非 System 的 ChatMessage)

    • 超出部分的历史消息会被自动移除,而不是无限累积


2. 验证缩减效果

通过多轮连续对话,观察聊天记录在 Reducer 作用下的变化。在每一轮调用agent.RunAsync(...)后,读取当前线程中实际保留的聊天历史数量:

AgentThread thread = agent.GetNewThread(); Console.WriteLine(await agent.RunAsync("给我讲一个发生在茶馆里的段子,轻松一点的那种。", thread)); IList<ChatMessage>? chatHistory = thread.GetService<IList<ChatMessage>>(); Console.WriteLine($"\n 聊天有 {chatHistory?.Count} 消息.\n"); // Invoke the agent a few more times. Console.WriteLine(await agent.RunAsync("现在把这个段子加上一些表情符号,并用说书人的语气再讲一遍。", thread)); Console.WriteLine($"\n 聊天有 {chatHistory?.Count} 消息.\n"); Console.WriteLine(await agent.RunAsync("保持刚才的语气,讲一个关于健忘冒险者的轻松小故事,像是在讲笑话一样。", thread)); Console.WriteLine($"\n 聊天有 {chatHistory?.Count} 消息.\n"); // At this point, the chat history has exceeded the limit and the original message will not exist anymore, // so asking a follow up question about it will not work as expected. Console.WriteLine(await agent.RunAsync("接着刚才的氛围,讲一个发生在日常生活里的小乌龙事件,轻松随意一点。", thread)); Console.WriteLine($"\n 聊天有 {chatHistory?.Count} 消息.\n");

对话过程说明

  • 第一轮对话:「给我讲一个发生在茶馆里的段子,轻松一点的那种。」

    • 聊天历史较短,Reducer 尚未触发,历史消息正常累积

  • 第二轮对话:「现在把这个段子加上一些表情符号,并用说书人的语气再讲一遍。」

    • 新消息加入,历史仍在阈值范围内,早期消息仍可访问

  • 第三轮及之后:「保持刚才的语气,讲一个关于健忘冒险者的轻松小故事。」

    • 聊天记录达到缩减条件,MessageCountingChatReducer开始生效

    • 最早的消息被自动移除,chatHistory.Count保持在稳定范围内


3. 演示结果

结果一

结果二

结果三

结果四


4. 技术总结与适用场景

适用场景

  • Client-side history:聊天历史由客户端或应用自身维护(如 OpenAI / Azure OpenAI Chat Completion API)

不适用场景

  • Server-side history(如 Azure Foundry Agents):聊天历史由服务端统一管理,客户端无法直接干预裁剪策略

可扩展性

IChatReducer只是一个策略接口,可扩展更复杂的上下文治理逻辑:

  • TokenCountingChatReducer:按 Token 数量而非消息条数进行缩减

  • SummaryChatReducer:将旧消息压缩为摘要,而非直接删除

小结

  • 聊天历史不应无限增长

  • “遗忘”是一种主动、可控的系统设计

  • 上下文治理应以策略形式存在,而非散落在业务代码中

  • 合理使用 Chat Reduction,可在成本、稳定性与对话效果之间取得更好平衡

源代码地址

https://github.com/bingbing-gui/aspnetcore-developer/tree/master/src/09-AI-Agent/Agent-Framework/15-ChatReduction

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 2:02:38

面试 Java 基础八股文十问十答第七期

面试 Java 基础八股文十问十答第七期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;Tomcat 是什么? Tomcat 是一个开源的、轻量级的应用服务器&am…

作者头像 李华
网站建设 2026/4/16 12:32:39

017-RSA:贝壳网登录(参数password)

案例地址&#xff1a;贝壳网登录 找加密参数加密位置 这里有四个密文&#xff0c;但是不是所有密文都需要js逆向&#xff08;不是所有参数都是js代码中的&#xff09;&#xff1a; 我们可以先清空所有接口数据然后开着控制台重新刷新网页然后到我们要的接口触发&#xff0c;说…

作者头像 李华
网站建设 2026/4/17 14:40:02

快速理解USB-Blaster驱动在Quartus中的配置流程

从零搞定USB-Blaster&#xff1a;让Quartus顺利识别你的FPGA下载器你有没有遇到过这样的场景&#xff1f;辛辛苦苦写完Verilog代码&#xff0c;综合布局布线全部通过&#xff0c;时序也收敛了——终于可以烧进板子验证功能了。结果打开Quartus Programmer&#xff0c;点击“Har…

作者头像 李华
网站建设 2026/4/16 22:44:06

Gerber文件转PCB:新手必看反向流程

从Gerber到PCB&#xff1a;逆向工程实战全解析你有没有遇到过这样的情况&#xff1f;手头有一块老旧的电路板&#xff0c;设备还在用&#xff0c;但原厂早已停产&#xff0c;资料也无从查找。想修——没图纸&#xff1b;想复制——没源文件。这时候&#xff0c;如果能从这块板子…

作者头像 李华
网站建设 2026/4/18 1:33:12

洛谷 P5143 攀爬者 - 详细解题思路

题目蒟蒻的解题步骤第一步&#xff1a;理解核心需求这本质上是一个排序问题。既然要按照高度爬&#xff0c;那就必须先把所有点按z坐标排序。但有个细节要注意——如果两个点高度一样咋办&#xff1f;题目没说&#xff0c;我就自己定了规则&#xff1a;z相同看y&#xff0c;y相…

作者头像 李华
网站建设 2026/4/18 0:10:50

mptools v8.0日志导出与分析操作指南

mptools v8.0日志导出与分析实战指南&#xff1a;从采集到洞察的完整闭环你有没有遇到过这样的场景&#xff1f;系统突然告警&#xff0c;服务无响应&#xff0c;而你面对几十台设备的日志文件束手无策——不知道该看哪个、从哪查起。手动翻日志像大海捞针&#xff0c;脚本拼接…

作者头像 李华