目录
一句话简介
🎯 核心价值
💡 问题场景
🚀 解决方案:三步实现记忆对话
核心机制
实现代码
🌊 流式多轮对话
🔒 多用户场景:线程隔离
实现代码
📜 访问对话历史
📊 API 速查表
核心 API
调用模式对比
🏢 企业级最佳实践
✅ 推荐做法
❌ 常见错误
🎯 总结
上一篇
一句话简介
AgentThread 是 Microsoft Agent Framework 提供的对话线程管理机制,通过显式创建并复用线程对象,让 AI Agent 在多轮对话中拥有完整的上下文记忆能力。
🎯 核心价值
✅多轮记忆:Agent 自动记住所有对话历史
✅线程隔离:多用户场景下对话互不干扰
✅简单易用:三行代码实现带记忆的对话
✅流式支持:同时支持同步和流式多轮对话
💡 问题场景
很多开发者在使用 Agent 时会遇到"失忆"问题:
// ❌ 问题演示 await agent.RunAsync("我叫张三"); await agent.RunAsync("你知道我叫什么吗?"); // Agent: "抱歉,我不知道您的名字"原因:每次调用RunAsync()不传thread参数时,MAF 会临时创建新线程并在调用结束后丢弃,导致历史消息丢失。
🚀 解决方案:三步实现记忆对话
核心机制
实现代码
// 步骤1: 创建 Agent var chatClient = AIClientHelper.GetDefaultChatClient(); AIAgent agent = chatClient.CreateAIAgent( instructions: "你是专业助理,记住用户所有信息并提供个性化服务", name: "PersonalAssistant" ); // 步骤2: 创建 Thread(关键!) AgentThread thread = agent.GetNewThread(); // 步骤3: 多轮对话(复用同一个 thread) await agent.RunAsync("我叫李明,是软件工程师,喜欢咖啡", thread); await agent.RunAsync("你记得我叫什么吗?", thread); // ✅ 能准确回答 await agent.RunAsync("我喜欢什么饮料?", thread); // ✅ 能准确回答核心要点:
🔧 使用
GetNewThread()创建线程🔧 所有调用都传入同一个
thread对象🔧 Thread 自动管理所有历史消息
🌊 流式多轮对话
AgentThread 同样支持流式调用,适合长文本生成场景。
// 创建故事创作 Agent AIAgent storyWriter = chatClient.CreateAIAgent( instructions: "你是创意写作助手,记住所有故事元素保持一致性", name: "StoryWriter" ); // 创建线程 AgentThread storyThread = storyWriter.GetNewThread(); // 第一轮:设定背景 awaitforeach (var chunk in storyWriter.RunStreamingAsync( "科幻故事,2150年火星殖民地,主角阿尔法是工程师", storyThread)) { Console.Write(chunk); } // 第二轮:引入冲突(Agent 记得前面设定) awaitforeach (var chunk in storyWriter.RunStreamingAsync( "生命支持系统故障,阿尔法需24小时内修复", storyThread)) { Console.Write(chunk); } // 第三轮:添加转折(Agent 记得所有情节) awaitforeach (var chunk in storyWriter.RunStreamingAsync( "阿尔法发现故障是人为破坏", storyThread)) { Console.Write(chunk); }🔒 多用户场景:线程隔离
AgentThread 的重要特性是线程隔离,每个用户应有独立线程。
实现代码
// 创建客服 Agent AIAgent customerService = chatClient.CreateAIAgent( instructions: "电商客服,记住每位客户信息提供个性化服务", name: "CustomerService" ); // 为两个用户创建独立线程 AgentThread threadZhangSan = customerService.GetNewThread(); AgentThread threadLiSi = customerService.GetNewThread(); // 张三的对话 await customerService.RunAsync("我叫张三,想买笔记本电脑,预算8000元", threadZhangSan); await customerService.RunAsync("主要用来做软件开发", threadZhangSan); // 李四的对话(完全隔离) await customerService.RunAsync("我是李四,想买游戏鼠标", threadLiSi); await customerService.RunAsync("价格300元以内", threadLiSi); // 验证隔离:两个用户各自记得自己的信息 await customerService.RunAsync("你记得我的预算和用途吗?", threadZhangSan); await customerService.RunAsync("我刚才想买什么?", threadLiSi);📜 访问对话历史
Thread 内部维护历史消息列表,可用于统计、调试、导出等场景。
// 获取历史消息 IList<ChatMessage>? chatHistory = thread.GetService<IList<ChatMessage>>(); if (chatHistory != null) { Console.WriteLine($"总消息数: {chatHistory.Count}"); // 统计不同角色的消息 var userMessages = chatHistory.Where(m => m.Role == ChatRole.User).Count(); var assistantMessages = chatHistory.Where(m => m.Role == ChatRole.Assistant).Count(); // 遍历显示 foreach (var message in chatHistory) { Console.WriteLine($"[{message.Role}]: {message.Text}"); } }使用场景:
📊 统计对话轮数
🔍 调试和日志记录
📝 导出对话历史
⚠️ 监控 Token 使用量
注意事项:
⚠️ 历史消息只读访问,不建议直接修改
⚠️ 长对话需注意 Token 限制,可用 ChatReducer 自动裁剪
⚠️ 多用户场景务必线程隔离
📊 API 速查表
核心 API
API | 功能 | 场景 |
|---|---|---|
agent.GetNewThread() | 创建新线程 | 用户会话开始 |
RunAsync(msg, thread) | 同步多轮对话 | 记忆上下文 |
RunStreamingAsync(msg, thread) | 流式多轮对话 | 长文本生成 |
thread.ThreadId | 获取线程ID | 日志、调试 |
thread.GetService<IList<ChatMessage>>() | 获取历史消息 | 统计、导出 |
调用模式对比
调用方式 | Thread 参数 | 是否记忆 | 使用场景 |
|---|---|---|---|
RunAsync("消息") | ❌ 不传 | ❌ 不记忆 | 单次查询 |
RunAsync("消息", thread) | ✅ 传入 | ✅ 记忆 | 多轮对话 |
RunStreamingAsync("消息") | ❌ 不传 | ❌ 不记忆 | 单次流式 |
RunStreamingAsync("消息", thread) | ✅ 传入 | ✅ 记忆 | 多轮流式 |
🏢 企业级最佳实践
✅ 推荐做法
1. 为每个用户会话创建独立 Thread
// 用户登录时 var userThread = agent.GetNewThread(); _userThreads[userId] = userThread;2. 整个对话过程复用同一个 Thread
var thread = _userThreads[userId]; await agent.RunAsync(message, thread);3. 添加元数据便于管理
thread.Metadata["UserId"] = userId; thread.Metadata["SessionStartTime"] = DateTime.UtcNow;❌ 常见错误
1. 忘记传入 Thread 参数
// ❌ 错误:每次都创建新线程 await agent.RunAsync("第一句话"); await agent.RunAsync("第二句话"); // 忘记了第一句话2. 每次调用都创建新 Thread
// ❌ 错误:不复用线程 var thread1 = agent.GetNewThread(); await agent.RunAsync("第一句话", thread1); var thread2 = agent.GetNewThread(); // ❌ 不应该创建新的! await agent.RunAsync("第二句话", thread2);3. 多用户共用一个 Thread
// ❌ 错误:会导致对话混乱 var sharedThread = agent.GetNewThread(); await agent.RunAsync("用户A的消息", sharedThread); await agent.RunAsync("用户B的消息", sharedThread); // B能看到A的历史!🎯 总结
✅AgentThread 核心作用:管理对话历史,实现多轮对话记忆
✅使用方法:创建 Thread → 复用 Thread → 自动记忆
✅线程隔离:每个用户独立 Thread,多用户场景安全
✅流式支持:同步和流式调用都支持 Thread
✅历史访问:可获取历史消息用于统计、调试、导出
核心原则:一个用户会话 = 一个 Thread,始终复用!
下一篇
引入地址