.NET+AI | Agent | 自定义上下文记忆-示例(16)
2026/4/1 12:16:56 网站建设 项目流程

AIContextProvider 实战:用户信息记忆组件

一句话简介

从零实现完整的 UserInfoMemory 类,支持自动提取用户信息、序列化持久化和跨 Thread 共享。


🎯 核心功能

  • 自动提取:从对话中提取用户姓名和年龄

  • 智能询问:未知信息时主动询问,已知时直接使用

  • 状态持久化:支持序列化和反序列化

  • 跨 Thread 共享:在不同对话线程间共享记忆


💻 完整实现

步骤 1:定义数据模型

public class UserInfo { public string? UserName { get; set; } public int? UserAge { get; set; } }

步骤 2:实现 UserInfoMemory

public sealedclassUserInfoMemory : AIContextProvider { privatereadonly IChatClient _chatClient; public UserInfo UserInfo { get; set; } // 构造函数1:首次创建 public UserInfoMemory(IChatClient chatClient, UserInfo? userInfo = null) { _chatClient = chatClient; UserInfo = userInfo ?? new UserInfo(); } // 构造函数2:反序列化恢复 public UserInfoMemory(IChatClient chatClient, JsonElement serializedState, ...) { _chatClient = chatClient; UserInfo = serializedState.Deserialize<UserInfo>() ?? new UserInfo(); } // 调用前:注入用户信息到上下文 public override ValueTask<AIContext> InvokingAsync( InvokingContext context, CancellationToken ct = default) { var instructions = new StringBuilder(); instructions.AppendLine(UserInfo.UserName isnull ? "Ask the user for their name." : $"The user's name is {UserInfo.UserName}."); instructions.AppendLine(UserInfo.UserAge isnull ? "Ask the user for their age." : $"The user's age is {UserInfo.UserAge}."); returnnew ValueTask<AIContext>(new AIContext { Instructions = instructions.ToString() }); } // 调用后:从对话中提取用户信息 public override async ValueTask InvokedAsync( InvokedContext context, CancellationToken ct = default) { if ((UserInfo.UserName isnull || UserInfo.UserAge isnull) && context.RequestMessages.Any(x => x.Role == ChatRole.User)) { try { var result = await _chatClient.GetResponseAsync<UserInfo>( context.RequestMessages, new ChatOptions { Instructions = "Extract user's name and age if present." }, ct); // 仅更新未知信息 UserInfo.UserName ??= result.Result.UserName; UserInfo.UserAge ??= result.Result.UserAge; } catch { /* 提取失败不影响主流程 */ } } } // 序列化:只保存数据状态 public override JsonElement Serialize(JsonSerializerOptions? options = null) { return JsonSerializer.SerializeToElement(UserInfo, options); } }

💻 注册到 Agent

var chatClient = AIClientHelper.GetDefaultChatClient(); var options = new ChatClientAgentOptions { Instructions = "You are a friendly assistant.", AIContextProviderFactory = ctx => new UserInfoMemory( chatClient, ctx.SerializedState, ctx.JsonSerializerOptions) }; var agent = chatClient.CreateAIAgent(options);

🧪 测试效果

4 轮对话流程

第 1 轮:用户说"你好" → Agent 询问姓名和年龄 第 2 轮:用户说"我叫张三" → Agent 确认姓名,继续询问年龄 第 3 轮:用户说"25岁" → Agent 确认年龄,信息收集完成 第 4 轮:用户说"天气怎么样?" → Agent 记住用户是张三(记忆生效)

序列化与恢复

// 序列化当前状态 var serialized = thread.Serialize(); // 恢复对话 var restored = agent.DeserializeThread(serialized); var memory = restored.GetService<UserInfoMemory>(); Console.WriteLine(memory.UserInfo.UserName); // "张三"

跨 Thread 共享

// 从原 Thread 提取用户信息 var userInfo = oldThread.GetService<UserInfoMemory>()?.UserInfo; // 注入到新 Thread var newMemory = newThread.GetService<UserInfoMemory>(); newMemory.UserInfo = userInfo; // 新 Thread 直接拥有用户信息(无需重新询问)

🏢 最佳实践

技术要点

说明

两个构造函数

首次创建 + 反序列化恢复

使用 ??= 运算符

仅更新未知信息,不覆盖已知

异常处理

InvokedAsync 中的异常不影响主流程

只序列化数据

不序列化服务依赖(如 IChatClient)

验证记忆恢复

反序列化后通过对话测试验证


🎯 总结

  • 完整实现:InvokingAsync(注入)+ InvokedAsync(提取)+ Serialize(持久化)

  • 智能询问:根据记忆状态动态生成 Instructions

  • 序列化支持:保存和恢复对话状态

  • 跨 Thread 共享:通过直接赋值实现记忆共享


如需获取文章配套完整代码,可扫码咨询领取。👇

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询