目录

在构建复杂的对话式 AI 应用时,如何有效管理和利用对话过程中的上下文信息至关重要。这不仅关系到 AI Agent 是否能“记住”之前的交流内容,更决定了它能否提供连贯、智能且个性化的交互体验。在 Microsoft Agent Framework 中,AIContextProvider 扮演了这一核心角色。本文将通过一个具体的代码示例,带您深入了解 AIContextProvider 的强大功能。
什么是 AIContextProvider?
AIContextProvider 是一个抽象类,它允许开发者在 AI Agent 的调用生命周期中注入、修改和持久化上下文信息。您可以把它想象成 AI Agent 的“记忆模块”。通过实现这个类,我们可以在 Agent 处理用户请求之前(InvokingAsync)向其提供必要的背景知识,并在处理之后(InvokedAsync)根据最新的对话更新这些知识。
框架会自动处理 AIContextProvider 状态的序列化和反序列化,确保在多轮对话中上下文信息能够被可靠地传递。
核心方法解析
AIContextProvider 主要通过重写以下三个核心方法来管理上下文:
-
InvokingAsync: 此方法在 Agent 调用大语言模型(LLM)之前执行。它接收当前的调用上下文InvokingContext,并返回一个AIContext对象。您可以在这里动态修改 Agent 的Instructions(系统提示),从而影响它本次对话的行为。 -
InvokedAsync: 此方法在 Agent 调用 LLM 之后执行。它允许您访问到 Agent 的完整请求消息(RequestMessages)和最终的响应。这是一个绝佳的时机,可以用来从用户的最新回复中提取信息并更新我们的上下文状态。 -
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 应用开发带来无限可能。

1010

被折叠的 条评论
为什么被折叠?



