Microsoft Agent Framework - AIContextProvider 上下文管理

目录

什么是 AIContextProvider?

核心方法解析

实战演练:打造一个能记住用户偏好的健身教练

1. 定义上下文状态和提供者

2. 在调用前注入上下文 (InvokingAsync)

3. 在调用后更新上下文 (InvokedAsync)

4. 状态序列化 (Serialize)

如何使用 AIContextProvider

结论


上一篇

图片

在构建复杂的对话式 AI 应用时,如何有效管理和利用对话过程中的上下文信息至关重要。这不仅关系到 AI Agent 是否能“记住”之前的交流内容,更决定了它能否提供连贯、智能且个性化的交互体验。在 Microsoft Agent Framework 中,AIContextProvider 扮演了这一核心角色。本文将通过一个具体的代码示例,带您深入了解 AIContextProvider 的强大功能。

什么是 AIContextProvider

AIContextProvider 是一个抽象类,它允许开发者在 AI Agent 的调用生命周期中注入、修改和持久化上下文信息。您可以把它想象成 AI Agent 的“记忆模块”。通过实现这个类,我们可以在 Agent 处理用户请求之前(InvokingAsync)向其提供必要的背景知识,并在处理之后(InvokedAsync)根据最新的对话更新这些知识。

框架会自动处理 AIContextProvider 状态的序列化和反序列化,确保在多轮对话中上下文信息能够被可靠地传递。

核心方法解析

AIContextProvider 主要通过重写以下三个核心方法来管理上下文:

  1. InvokingAsync: 此方法在 Agent 调用大语言模型(LLM)之前执行。它接收当前的调用上下文 InvokingContext,并返回一个 AIContext 对象。您可以在这里动态修改 Agent 的 Instructions(系统提示),从而影响它本次对话的行为。

  2. InvokedAsync: 此方法在 Agent 调用 LLM 之后执行。它允许您访问到 Agent 的完整请求消息(RequestMessages)和最终的响应。这是一个绝佳的时机,可以用来从用户的最新回复中提取信息并更新我们的上下文状态。

  3. Serialize: 此方法负责将当前的上下文状态序列化为 JsonElement。框架会在适当的时候调用它,以持久化 Agent 的“记忆”。

实战演练:打造一个能记住用户偏好的健身教练

让我们通过您提供的 UserInfoMemory 示例来具体分析。这个例子实现了一个能够记住用户“最喜欢的运动”的 AI 健身教练。

1. 定义上下文状态和提供者

首先,我们定义一个简单的数据类 UserInfo 来存储状态,然后创建 UserInfoMemory 类并继承自 AIContextProvider

// 用于存储上下文信息的简单数据模型
internalsealedclassUserInfo
{
    publicstring? FavSport { get; set; }
}

// 自定义的上下文提供者
internalsealedclassUserInfoMemory : AIContextProvider
{
    privatereadonly IChatClient _chatClient;
    public UserInfo UserInfo { get; set; }

    // 构造函数,用于初始化或从序列化状态恢复
    public UserInfoMemory(IChatClient chatClient, UserInfo? userInfo = null)
    {
        this._chatClient = chatClient;
        this.UserInfo = userInfo ?? new UserInfo();
    }

    public UserInfoMemory(IChatClient chatClient, JsonElement serializedState, JsonSerializerOptions? jsonSerializerOptions = null)
    {
        this._chatClient = chatClient;
        this.UserInfo = serializedState.ValueKind == JsonValueKind.Object ?
            serializedState.Deserialize<UserInfo>(jsonSerializerOptions)! :
            new UserInfo();
    }
    
    // ... 核心方法实现
}

注意这里的两个构造函数:一个用于首次创建,另一个用于从 JsonElement(即持久化的状态)恢复,这对于框架的自动状态管理至关重要。

2. 在调用前注入上下文 (InvokingAsync)

在 Agent 与 LLM 交互之前,我们通过 InvokingAsync 动态调整它的系统提示。

public override ValueTask<AIContext> InvokingAsync(
    InvokingContext context,
    CancellationToken cancellationToken = default)
{
    StringBuilder instructions = new();
    instructions
        .AppendLine(
            this.UserInfo.FavSport is null ? "询问用户最喜欢的运动,一直到他回答为止" : $"用户最喜欢的运动是: {this.UserInfo.FavSport}.");
      
    return new ValueTask<AIContext>(new AIContext
    {
        Instructions = instructions.ToString()
    });
}
  • 如果 UserInfo.FavSport 为空,我们指示 Agent 主动询问用户的偏好。

  • 如果 UserInfo.FavSport 已有值,我们直接将这个信息(例如:“用户最喜欢的运动是:足球”)注入到提示中,让 Agent 在后续的对话里始终知晓这个关键信息。

3. 在调用后更新上下文 (InvokedAsync)

当 Agent 完成一次交互后,我们需要从用户的回复中捕捉信息来更新我们的“记忆”。InvokedAsync 是执行此操作的理想位置。

public override async ValueTask InvokedAsync(
    InvokedContext context,
    CancellationToken cancellationToken = default)
{
    if (string.IsNullOrEmpty(this.UserInfo.FavSport) && context.RequestMessages.Any(x => x.Role == ChatRole.User))
    {
        var result = await this._chatClient.GetResponseAsync<UserInfo>(
            context.RequestMessages,
            new ChatOptions()
            {
                Instructions = "从用户的消息里提取体育运动,如果提取失败返回空."
            },
            cancellationToken: cancellationToken);
        this.UserInfo.FavSport = result.Result.FavSport;
    }
}

这段代码非常巧妙:

  • 它首先检查 FavSport 是否仍为空,以及本次交互是否包含用户消息。

  • 如果条件满足,它会发起一次独立的 LLM 调用,其唯一目的是从用户的消息中提取运动名称并结构化为 UserInfo 对象。

  • 提取成功后,更新 this.UserInfo.FavSport 的值。在下一次对话中,InvokingAsync 就会使用这个新值。

4. 状态序列化 (Serialize)

最后,我们需要告诉框架如何保存 UserInfoMemory 的状态。

public override JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null)
{
    return JsonSerializer.SerializeToElement(this.UserInfo, jsonSerializerOptions);
}

我们只需将 UserInfo 对象序列化为 JsonElement 即可。框架将负责在不同对话轮次之间传递这个 JsonElement,并通过接受 JsonElement 的构造函数来重建 UserInfoMemory 的状态。

如何使用 AIContextProvider

在创建 AIAgent 时,通过 AIContextProviderFactory 将我们的 UserInfoMemory 注册进去。

AIAgent agent = chatClient.CreateAIAgent(new ChatClientAgentOptions()
{
    Instructions = "你是一个AI运动健身教练,你需要掌握用户喜欢的体育运动.",
    AIContextProviderFactory = ctx => new UserInfoMemory(
        chatClient.AsIChatClient(),
        ctx.SerializedState,
        ctx.JsonSerializerOptions)
});

框架会为每个 AgentThread(即每个独立的对话)创建一个 UserInfoMemory 实例,确保不同对话之间的上下文是隔离的。

结论

AIContextProvider 是 Microsoft Agent Framework 中实现有状态、个性化对话的核心机制。通过优雅地分离上下文管理逻辑,它允许开发者构建出能够学习和适应用户需求的智能 Agent。正如我们的示例所示,无论是动态调整 Agent 的行为,还是从对话中提取和记忆信息,AIContextProvider 都提供了强大而灵活的解决方案。掌握它,将为您的 AI 应用开发带来无限可能。

引入地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值