惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
腾讯CDC
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
量子位
博客园 - 聂微东
Jina AI
Jina AI
小众软件
小众软件
The Cloudflare Blog
有赞技术团队
有赞技术团队
V
V2EX
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志
B
Blog
MongoDB | Blog
MongoDB | Blog
L
LangChain Blog
宝玉的分享
宝玉的分享
C
Check Point Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
IT之家
IT之家
N
Netflix TechBlog - Medium
I
InfoQ
J
Java Code Geeks
S
SegmentFault 最新的问题
V
Visual Studio Blog
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
D
DataBreaches.Net
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
B
Blog RSS Feed
S
Schneier on Security
Webroot Blog
Webroot Blog
P
Proofpoint News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
Project Zero
Project Zero
Scott Helme
Scott Helme
C
CERT Recently Published Vulnerability Notes
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security

博客园 - Artech

[MAF预定义的AIContextProvider-04]Mem0Provider——长期记忆基于的云端解决方案 [MAF预定义的AIContextProvider-03]ChatHistoryMemoryProvider——赋予Agent从经验中学习的能力 [MAF预定义的AIContextProvider-02]AgentSkillsProvider——将Agent Skills引入MAF [MAF预定义的AIContextProvider-01]TextSearchProvider——RAG在MAF中的实现 [MAF预定义ChatClient中间件-09]MessageInjectingChatClient-赋予工具消息注入的能力 [MAF预定义ChatClient中间件-08]OpenTelemetryChatClient-实现链路跟踪和性能监控 [MAF预定义ChatClient中间件-07]PerServiceCallChatHistoryPersistingChatClient——基于ReAct循环的一步一存档 [MAF预定义ChatClient中间件-06]利用ImageGeneratingChatClient开发专业图片生成Agent [MAF预定义ChatClient中间件-05]动态修改ChatOptions和请求消息 [MAF预定义ChatClient中间件-04]ReducingChatClient——精减对话历史又不丢失基本语义 [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间 [MAF预定义ChatClient中间件-02]FunctionInvokingChatClient——实现ReAct循环和人机交互的大功臣 [MAF预定义ChatClient中间件-01]LoggingChatClient——在调用LLM前后输出日志 [MAF的Agent管道详解-07]利用AIAgent中间件构建Agent管道 [MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合 [MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合 - Artech [MAF的Agent管道详解-05]对话历史的持久化和输入输出的增强 [MAF的Agent管道详解-04]如何让LLM按照要求的结构输出数据? [MAF的Agent管道详解-03]连接LLM的IChatClient对象 [MAF的Agent管道详解-02]IChatClient管道如何完美连接大模型? [MAF的Agent管道详解-01]塑智能体边界,从AIAgent抽象类开始 [对比学习LangChain和MAF-04]针对消息的设计 [对比学习LangChain和MAF-03]完全不同的Agent设计哲学 [对比学习LangChain和MAF-02]基本编程模式的差异(下篇) [对比学习LangChain和MAF-01]基本编程模式的差异(上篇) 这是一篇测试文章 我所理解的Python元模型 除了按值和引用,方法参数的第三种传递方式 方法的三种调用形式 可以调用Null的实例方法吗? 自定义Key类型的字典无法序列化的N种解决方案 为什么ASP.NET Core的路由处理器可以使用一个任意类型的Delegate 深入解析ASP.NET Core MVC的模块化设计[下篇] 深入解析ASP.NET Core MVC的模块化设计[上篇] ASP.NET Core MVC应用模型的构建[4]: Action的选择 ASP.NET Core MVC应用模型的构建[3]: Controller的收集 ASP.NET Core MVC应用模型的构建[2]: 定制应用模型 ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图 基于HTTP2/3的流模式消息交换如何实现? 编写高效的代码,你应该了解Array、Memory、ReadOnlySequence . . . WebAssembly核心编程[4]: Memory WebAssembly核心编程[3]: Module 与 Instance WebAssembly核心编程[2]:类型系统 WebAssembly核心编程[1]:wasm模块实例化的N种方式 WebAssembly入门笔记[4]:利用Global传递全局变量 WebAssembly入门笔记[3]:利用Table传递引用
[MAF预定义的AIContextProvider-05]CompactionProvider——采用多种策略压缩对话历史
Artech · 2026-07-13 · via 博客园 - Artech

为解决LLM调用无状态的问题,我们不得不将消息历史作为上下文的一部分发送给LLM。但随着对话的进行,消息历史会不断增长,最终可能会超出LLM的上下文窗口限制。随着LLM的上下文窗口的不断扩大,可以有朝一日上下文窗口不再成为问题,但也并不意味着将整个对话历史原封不动地发送给LLM就是最优的选择。LLM拥有上下文的丰富程度与推理的质量并不是完全正相关的,当对话历史的长度超过一定程度后,过长的上下文反而会干扰LLM对当前对话的理解和推理,导致LLM生成的响应质量下降。所以对话历史的压缩需求可能永远都不会消失。针对消息的压缩,MAF提供了不止一种解决方案,一种是使用ReducingChatClient这个IChatClient中间件,另一种就是使用本篇文章着重介绍的CompactionProvider这个AIContextProvider

1. 利用CompactionProvider摘要对话历史

CompactionProvider支持不同的消息压缩策略,比如摘要、折叠、删除和替换等。由于CompactionProvider对压缩策略进行了抽象,原则上我们可以自行提供任一的策略来压缩对话历史。下面的例子演示了针对摘要的压缩策略,它可以在不丢失语义的前提下将多条消息压缩成一条。下面的实例演示了如何利用CompactionProvider,结合代表摘要压缩策略的SummarizationCompactionStrategy来对对话历史进行摘要压缩。

using Azure;
using dotenv.net;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Compaction;
using Microsoft.Extensions.AI;
using OpenAI;

DotEnv.Load();

var apiKey = Environment.GetEnvironmentVariable("API_KEY")!;
var endpoint = Environment.GetEnvironmentVariable("OPENAI_URL")!;

var summaryClient = new OpenAIClient(
    credential: new AzureKeyCredential(apiKey),
    options: new OpenAIClientOptions { Endpoint = new Uri(endpoint) })
    .GetChatClient(model: "gpt-5.2-chat")
    .AsIChatClient();

var compactionStrategy = new SummarizationCompactionStrategy(
    chatClient: summaryClient,
    trigger:  messageIndex => messageIndex.TotalMessageCount > 6, 
    minimumPreservedGroups: 1);
var compactionProvider = new CompactionProvider(compactionStrategy);

var agent = new OpenAIClient(
    credential: new AzureKeyCredential(apiKey),
    options: new OpenAIClientOptions { Endpoint = new Uri(endpoint) })
    .GetChatClient(model: "gpt-5.2-chat")
    .AsIChatClient()
    .AsBuilder()
    .Use((messages, options, next, cancelToken) => {
        Console.WriteLine($"请求消息共计{messages.Count()}条");
        var index = 1;
        foreach (var message in messages)
        {
            Console.WriteLine($"{index++}. {message}");
        }
        return next(messages, options, cancelToken);
    })
    .Build()
    .AsAIAgent(options: new ChatClientAgentOptions {  AIContextProviders = [compactionProvider] });

ChatMessage[] messages = [
    new ChatMessage(ChatRole.User, "今天苏州的天气怎么样?"),
    new ChatMessage(ChatRole.Assistant, "苏州今天是晴天。"),
    new ChatMessage(ChatRole.User, "气温多少?。"),
    new ChatMessage(ChatRole.Assistant, "室外温度25度。"),
    new ChatMessage(ChatRole.User, "有风吗?"),
    new ChatMessage(ChatRole.Assistant, "西北风4级。"),
    new ChatMessage(ChatRole.User, "根据天气,给我一些着装建议。")
];

var response = await agent.RunAsync(messages);
Console.WriteLine($"\n\n{response}");

如代码所示,我们创建了一个SummarizationCompactionStrategy对象来指定我们想要使用的摘要压缩策略,它的三个参数分别是:

  • summaryClient:摘要需要借助LLM的语言处理能力,所以需要这个参数提供的IChatClient来调用LLM生成摘要内容;
  • trigger:是一个CompactionTrigger类型的委托用于定义触发压缩的条件。上面的例子中,我们指定的触发条件是当消息总数超过6条时就触发压缩;
  • minimumPreservedGroups:是一个整数值,用于指定在触发压缩时至少要保留多少消息组。消息组在基于CompactionProvider的压缩策略中是一个重要的概念,我们将在后续部分对其进行详细介绍,这里我么姑且理解只需要保留最近的一条消息就可以了,需要对前面的消息进行压缩;

在基于这个SummarizationCompactionStrategy对象创建了一个CompactionProvider对象之后,我们将它注册到后面构建的AIAgent对象上。为了查看摘要压缩后的消息,我们调用ChatClientBuilderUse方法注册了一个IChatClient中间件输出所有的请求消息。程序的输出如下所示:

请求消息共计2条
1. [Summary]
**对话摘要:**

- 用户询问苏州今天天气情况。
- 提供信息:
  - 天气:晴天
  - 气温:25°C
  - 风力:西北风 4 级

无使用工具调用。对话围绕苏州当日天气展开。
2. 根据天气,给我一些着装建议。


根据目前 **25°C、晴天、西北风4级** 的天气情况,给你一些穿搭建议:

### 🌤️ 上衣
- ✅ **短袖T恤、衬衫、薄款POLO** 都很合适
- 如果怕风,可以带一件 **薄款防风外套或开衫**

### 👖 下装
- ✅ **薄款长裤、牛仔裤、休闲裤**
- ✅ 女生也可以穿 **半裙或连衣裙**
- 不建议太厚的裤子(会有点热)

### 👟 鞋子
- ✅ 运动鞋、休闲鞋、乐福鞋都合适
- 晴天路干,也可以穿透气一点的鞋

### 🌞 其他建议
- 有太阳,**可以带太阳镜或遮阳帽**
- 紫外线可能较强,建议涂防晒
- 风力4级稍有风感,头发容易被吹乱 😄

总体来说是一个**舒适偏暖、略有风的好天气**,穿得清爽一点最合适。

如果你是上班、约会还是户外活动,我也可以帮你具体搭配一下 😊

可以看到,原本的7条消息被压缩成了2条,其中第一条是压缩后的摘要消息,第二条是用户的最新消息。摘要消息中不仅保留了对话的核心信息,还对对话内容进行了适当的扩展和润色,使得它更像是人类总结出来的内容而不是简单地罗列式的摘要。虽然消息数量减少了,但是语义信息并没有丢失,所以LLM同样能够给出我们希望的响应内容。

2. 消息组

消息组对于CompactionProvider的压缩策略来说是一个非常重要的概念。我们上面多次提及的针对消息的压缩,其实应该改为针对消息组的压缩。消息组是压缩系统的原子单位,它把一条或多条逻辑相关的ChatMessage组合成一个可被压缩策略整体处理的结构。所有压缩策略都不是直接操作ChatMessage,而是操作消息组。消息组是MAF在构建可压缩对话历史时引入的结构化分组层。它的设计目标是:

  • 让压缩策略能够基于结构化的消息单元进行处理,而不是逐条操作零散的消息;
  • 让工具调用、多条针对同一角色的消息,以及折叠或摘要后的内容,都能够作为一个整体被压缩、替换或保留;
  • 让token/byte统计、turnIndex、排除标记等元数据绑定在消息组级别,从而实现更精确、更高效的压缩控制;

可以把它理解为:消息组 = ChatMessage的逻辑分组 + 压缩元数据 + 语义标签

上面提到的TurnIndex被称为轮次索引。Turn表示由一次User消息开启的交互轮次,包含该User消息之后直到下一条User消息之前的所有消息。对话历史的每一条消息都具有一个确定的TurnIndex,一如下这个对话历史为例:

User 发言 → 开启新Turn
Assistant回复 → 属于当前Turn
Tool调用/ToolResult → 属于当前Turn
Assistant主动发言(无User输入)→ 仍属于当前Turn
User再次发言 → 开启新Turn

目前没有看到由官方的文档对消息组的划分规则提供明确的说明,下面所述的划分规则来源于对源代码的分析。为么方面说明,我们定义如下几种消息类型:

  • Reasoning-Only:指的是那些只包含TextReasoningContent内容的Assistant消息。这些消息通常用于表达LLM的推理过程、思考路径或者一些辅助性的解释说明,它们不包含任何工具调用的内容;
  • Function-Call:指的是那些包含FunctionCallContent内容的Assistant消息;
  • Function-Result:指的是那些包含FunctionResultContent内容的Tool消息;

如果一个消息组包含多条消息,有且只有如下这一种排序,我们需要这种组合来保证工具调用的完整性:包含一条Function-Call消息和紧随其后的一条Function-Result消息,以及在这前后或者其间Assistant针对工具调用和结果的推理。

  • Reasoning-Only(0条或者多条)
  • Function-Call(1条)
  • Reasoning-Only/Function-Result(1条或者多条)
  • Reasoning-Only(0条或者多条)

上述的划分规则决定了通过如下这个CompactionGroupKind枚举表示的消息组类型:

public enum CompactionGroupKind
{
	System,
	User,
	AssistantText,
	ToolCall,
	Summary
}

具体类型说明如下:

  • System:系统消息组,包含所有角色为System的消息;
  • User:用户消息组,包含所有连续的角色为User的消息;
  • AssistantText:Assistant文本消息组,包含所有连续的角色为Assistant且不包含工具调用内容的消息;
  • ToolCall:工具调用消息组,按照我们前面的说法,一个包含多条消息的消息组必然属于这种类型;
  • Summary:摘要消息组,包含经过摘要压缩后的消息;

2.2 CompactionMessageGroup

消息组MAF中通过如下这个CompactionMessageGroup类来表示:

public sealed class CompactionMessageGroup
{
	public static readonly string SummaryPropertyKey = "_is_summary";
	public CompactionGroupKind Kind { get; }
	public IReadOnlyList<ChatMessage> Messages { get; }
	public int MessageCount { get; }
	public int ByteCount { get; }
	public int TokenCount { get; }
	public int? TurnIndex { get; }
	public bool IsExcluded { get; set; }
	public string? ExcludeReason { get; set; }
}

属性说明如下:

  • Kind:表示消息组的类型;
  • Messages:组成这个消息组的ChatMessage列表;
  • MessageCount、ByteCount、TokenCount:这个消息组中包含的消息数量、总字节数和总token数;
  • TurnIndex:这个消息组所属的Turn索引;
  • IsExcluded和ExcludeReason:用于标记这个消息组是否被排除在压缩之外,以及排除的原因;

为了避免语义丢失,对于摘要生成的ChatMessage,一般不允许对它进行二次摘要,所以CompactionProvider必需能够识别什么是摘要消息。具体做法很简单,这样的ChatMessageAdditionalProperties中会有一个键为专门的键来标记它是一个摘要消息,这个键就是CompactionMessageGroup类中的SummaryPropertyKey静态字段,值为布尔值。

3. 消息索引

作为对话历史的ChatMessage列表划分为一个个CompactionMessageGroup后,为了方便后续压缩,MAF还需要为这些消息组创建对应的消息索引。消息索引可以看作为消息组构建的、可以在上边应用相应的策略对其实施压缩的Workspace。消息索引通过如下这个CompactionMessageIndex类型表示。

public sealed class CompactionMessageIndex
{
    public IList<CompactionMessageGroup> Groups { get; }
    public Tokenizer? Tokenizer { get; }

    public CompactionMessageIndex(
        IList<CompactionMessageGroup> groups, 
        Tokenizer? tokenizer = null);

    public CompactionMessageGroup InsertGroup(
        int index, 
        CompactionGroupKind kind, 
        IReadOnlyList<ChatMessage> messages, 
        int? turnIndex = null);
	public CompactionMessageGroup AddGroup(
        CompactionGroupKind kind, 
        IReadOnlyList<ChatMessage> messages, 
        int? turnIndex = null);
}

一个CompactionMessageIndex对象通过指定的一组CompactionMessageGroup对象来构建而成。由于需要利用分词器计算Token数量,所以在构建CompactionMessageIndex对象的时候可以选择性地传入一个Tokenizer对象。消息索引提供了InsertGroupAddGroup两个方法来向索引中插入新的消息组或者添加新的消息组,并利用GroupsTokenizer属性来访问当前的消息组和分词器。如果没有显式提供分词器,默认会按照每4个字节算作一个Token的方式来估算Token数量。

我们可以调用GetAllMessages方法获取整个消息列表。CompactionMessageGroup利用IsExcluded属性来标记消息组是否被排除在压缩之外,GetIncludedMessages方法返回未被排除在外的消息组提供的消息。如果知道TurnIndex,我们还可以调用GetTurnGroups方法来获取隶属于指定轮次的所有消息组。

public sealed class CompactionMessageIndex
{
	public IEnumerable<ChatMessage> GetIncludedMessages();
	public IEnumerable<ChatMessage> GetAllMessages();
	public IEnumerable<CompactionMessageGroup> GetTurnGroups(int turnIndex);
}

CompactionMessageIndex还定义如下这些返回各种汇总统计的属性,这些统计信息对于压缩策略的决策非常重要。

public sealed class CompactionMessageIndex
{
	public int TotalGroupCount { get; }
	public int TotalMessageCount { get; }
	public int TotalByteCount { get; }
	public int TotalTokenCount { get; }
	public int IncludedGroupCount { get; }
	public int IncludedMessageCount { get; }
	public int IncludedByteCount { get; }
	public int IncludedTokenCount { get; }
	public int TotalTurnCount { get; }
	public int IncludedTurnCount { get; }
	public int IncludedNonSystemGroupCount { get; }
	public int RawMessageCount { get; }

    internal static CompactionMessageIndex Create(IList<ChatMessage> messages, Tokenizer? tokenizer = null);
}

具体汇总统计包括:

  • TotalGroupCount、TotalMessageCount、TotalByteCount、TotalTokenCount:整个消息索引中包含的消息组数量、消息数量、字节数和token数;
  • IncludedGroupCount、IncludedMessageCount、IncludedByteCount、IncludedTokenCount:未被排除在压缩之外的消息组数量、消息数量、字节数和token数;
  • TotalTurnCount、IncludedTurnCount:整个消息索引中包含的Turn数量和未被排除在压缩之外的Turn数量;
  • IncludedNonSystemGroupCount:未被排除在压缩之外的、且类型不为System的消息组数量;
  • RawMessageCount:原始的消息数量,也就是未经过任何分组或者压缩之前的消息数量;

4. 压缩策略

如下所示的CompactionStrategy抽象了所谓的压缩策略,它旨在从三个维度描述压缩对话历史的策略:何时触发压缩压缩后的目标状态以及具体的压缩执行逻辑

public abstract class CompactionStrategy
{
	protected CompactionTrigger Trigger { get; }
	protected CompactionTrigger Target { get; }

	protected CompactionStrategy(CompactionTrigger trigger, CompactionTrigger? target = null);

	protected abstract ValueTask<bool> CompactCoreAsync(
        CompactionMessageIndex index, 
        ILogger logger, 
        CancellationToken cancellationToken);
	public async ValueTask<bool> CompactAsync(
        CompactionMessageIndex index, 
        ILogger? logger = null, 
        CancellationToken cancellationToken = default);
}

CompactionStrategy中表示触发压缩的Trigger和表示压缩目标状态的Target都是如下这个CompactionTrigger类型的委托。这是一个输入参数为CompactionMessageIndex对象,返回值为布尔值的委托。实现具体压缩策略的子类必需重写的CompactCoreAsync方法也将压缩直接应用到作为参数的CompactionMessageIndex对象上。压缩完成之后,CompactionMessageIndexGetIncludedMessages方法返回的消息列表就是经过压缩后的消息列表了。

public delegate bool CompactionTrigger(CompactionMessageIndex index);

5. CompactionProvider

由于压缩操作最终落在注册的CompactionStrategy对象上,所以Compaction自身的实现其实很简单。前面已经说过了,压缩针对的原子单元是CompactionMessageGroup,而不是单个的ChatMessage,所以中间涉及一个从ChatMessage列表到CompactionMessageGroup列表的构建过程。为了避免这个过程重写执行,CompactionProvider会将针对当前消息列表构建好的CompactionMessageGroup列表存储在Session状态中。对于每次Agent调用,它只需要针对新产生的消息以增量的方式构建CompactionMessageGroup列表,并将其追加到现有的列表之中。

CompactionMessageGroup列表被封装在内嵌的State类中。当ProviderSessionState初始化的时候,可以执行存储此State对象对应Session状态的键,如果没有显式指定,会默认使用CompationProvider的类型名称作为键。CompationProvider会创建一个ProviderSessionState<State>对象来管理这个状态,

public sealed class CompactionProvider : AIContextProvider
{
    private readonly CompactionStrategy _compactionStrategy;
    private readonly ProviderSessionState<State> _sessionState;
    public CompactionProvider(CompactionStrategy compactionStrategy, string? stateKey = null, ILoggerFactory? loggerFactory = null)
    {
        _compactionStrategy = compactionStrategy;
        stateKey ??= _compactionStrategy.GetType().Name;
        StateKeys = [stateKey];
        _sessionState = new ProviderSessionState<State>(
            _ => new State(),
            stateKey,
            AgentJsonUtilities.DefaultOptions);
        ...
    }
    public override IReadOnlyList<string> StateKeys { get; }

    internal sealed class State
    {
        public List<CompactionMessageGroup> MessageGroups { get; set; } = [];
    }
}

CompactionProvider利用重写的InvokingCoreAsync方法来实现对话历史的压缩,针对指定CompactionStrategy压缩对话历史最终实现在静态方法CompactAsync中。这个方法接受一个CompactionStrategy对象和一个ChatMessage列表作为输入,首先将ChatMessage列表转换成CompactionMessageGroup列表并构建成一个CompactionMessageIndex对象,然后调用CompactionStrategyCompactAsync方法来执行压缩,最后调用GetIncludedMessages方法返回压缩后的消息列表。

public sealed class CompactionProvider : AIContextProvider
{
    public static async Task<IEnumerable<ChatMessage>> CompactAsync(
        CompactionStrategy compactionStrategy, 
        IEnumerable<ChatMessage> messages, 
        ILogger? logger = null, 
        CancellationToken cancellationToken = default)
    {
        List<ChatMessage> messageList = messages as List<ChatMessage> ?? [.. messages];
        CompactionMessageIndex messageIndex = CompactionMessageIndex.Create(messageList);
        await compactionStrategy.CompactAsync(messageIndex, logger, cancellationToken)
            .ConfigureAwait(false);
        return messageIndex.GetIncludedMessages();
    }

    protected override async ValueTask<AIContext> InvokingCoreAsync(
        InvokingContext context, 
        CancellationToken cancellationToken = default)
}

InvokingCoreAsync方法的具体实现逻辑如下:

  • 确认Session存在,消息列表不为空,否则直接返回InvokingContext携带的AIContext
  • 将消息列表转换成CompactionMessageGroup列表,如果Session状态中已经存在CompactionMessageGroup列表,则只针对新消息构建CompactionMessageGroup列表并追加到现有列表之中;
  • 利用CompactionMessageGroup列表创建CompactionMessageIndex对象,并将其传入CompactionStrategyCompactAsync方法来执行压缩,得到压缩后的消息列表;
  • 使用最新的CompactionMessageGroup列表更新Session状态;
  • 提取InvokingContext中原有的AIContext,并用压缩后的消息列表替换原有AIContext中的消息列表,构建一个新的AIContext对象返回;