news 2026/4/15 18:32:41

.NET+AI | Agent | 自定义上下文记忆-示例(16)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET+AI | Agent | 自定义上下文记忆-示例(16)

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 共享:通过直接赋值实现记忆共享


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

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

CubeMX安装保姆级教程:涵盖IDE路径设置与驱动验证

STM32开发第一步&#xff1a;手把手教你搞定CubeMX安装、IDE配置与驱动验证 你是不是也曾在第一次打开STM32CubeMX时&#xff0c;被一堆报错搞得一头雾水&#xff1f; “Toolchain not found”、“ST-LINK未识别”、“驱动安装失败”……这些看似简单的问题&#xff0c;却常常…

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

LTspice电路仿真入门必看:基础操作完整指南

LTspice电路仿真入门&#xff1a;从零搭建你的第一个虚拟实验室你有没有过这样的经历&#xff1f;手焊了一个电源电路&#xff0c;通电瞬间冒烟&#xff1b;或者调试运放滤波器时&#xff0c;示波器上始终看不到理想的响应曲线。反复更换元件、调整布局&#xff0c;耗时几天却收…

作者头像 李华
网站建设 2026/4/11 5:49:57

Keil调试性能影响评估:合理设置断点避免延迟

Keil调试卡顿&#xff1f;别让断点拖垮你的实时系统&#xff01;你有没有遇到过这种情况&#xff1a;在Keil里调试STM32程序&#xff0c;刚点下“运行”&#xff0c;一切正常&#xff1b;可一旦加了几个断点&#xff0c;尤其是放在主循环或中断里&#xff0c;程序就开始卡顿、响…

作者头像 李华
网站建设 2026/4/15 12:37:09

7个实用的数据挖掘模型和技巧,强烈推荐!

数据分析是通过分析原始数据提取有意义见解的过程&#xff0c;这一过程包括使用分析和统计工具对数据进行检查、清洗、转换和建模&#xff0c;最终提炼出有价值的信息。这些信息用于确定业务决策——比如何时推出营销活动最合适&#xff1f;哪些客户群体最可能购买新产品&#…

作者头像 李华
网站建设 2026/4/15 12:38:17

MyBatis框架的优缺点

MyBatis框架的优缺点 一、MyBatis的核心优点 MyBatis的成功在于它在SQL控制力和开发效率之间找到了一个极佳的平衡点。 优点具体说明与价值1. SQL与代码解耦&#xff0c;灵活可控核心优势。SQL被独立写在XML文件或注解中&#xff0c;与Java代码分离。 • 利于维护&#xff1…

作者头像 李华