Step 3:多轮对话
单轮对话中,Agent 每次调用都是独立的——第二次问"那物流到哪了?"时,Agent 已经忘了刚才说的是哪个订单。多轮对话通过 AgentSession 解决这个问题。
什么是 AgentSession?
AgentSession 是跨 Agent 运行的会话状态容器。它在多次 RunAsync 调用之间保存上下文:
csharp
// 创建会话
AgentSession session = await agent.CreateSessionAsync();
// 第一轮
var r1 = await agent.RunAsync("我叫张三,是一名 .NET 开发者。", session);
// 第二轮——Agent 记得用户叫张三
var r2 = await agent.RunAsync("我的职业是什么?", session);
// ✅ 回复:你是 .NET 开发者
// 第三轮——继续深入
var r3 = await agent.RunAsync("帮我推荐几本 C# 进阶的书。", session);每一轮调用后,Agent 框架自动把本轮的用户消息和 AI 回复追加到 session 中。后续调用带着完整历史上下文,所以 Agent 知道"职业"指的是"刚说的 .NET 开发者"。
Session 的序列化与恢复
AgentSession 可以序列化保存,也可以从序列化数据恢复——这在 Web 应用中至关重要:
csharp
// 序列化会话(存到文件/数据库/Redis)
var serialized = agent.SerializeSession(session);
await File.WriteAllTextAsync($"session_{userId}.json", serialized);
// 从序列化恢复会话
var savedSessionData = await File.ReadAllTextAsync($"session_{userId}.json");
AgentSession restoredSession = await agent.DeserializeSessionAsync(savedSessionData);
// 用恢复的会话继续对话
var reply = await agent.RunAsync("我们刚才说到哪了?", restoredSession);完整的对话管理
csharp
public class ConversationManager
{
private readonly AIAgent _agent;
private readonly string _storagePath;
public ConversationManager(AIAgent agent, string storagePath)
{
_agent = agent;
_storagePath = storagePath;
}
public async Task<AgentSession> GetOrCreateSessionAsync(string userId)
{
var sessionFile = Path.Combine(_storagePath, $"session_{userId}.json");
if (File.Exists(sessionFile))
{
var data = await File.ReadAllTextAsync(sessionFile);
return await _agent.DeserializeSessionAsync(data);
}
return await _agent.CreateSessionAsync();
}
public async Task SaveSessionAsync(string userId, AgentSession session)
{
var serialized = _agent.SerializeSession(session);
var sessionFile = Path.Combine(_storagePath, $"session_{userId}.json");
Directory.CreateDirectory(_storagePath);
await File.WriteAllTextAsync(sessionFile, serialized);
}
public async Task<string> ChatAsync(string userId, string message)
{
var session = await GetOrCreateSessionAsync(userId);
var response = await _agent.RunAsync(message, session);
await SaveSessionAsync(userId, session);
return response.ToString();
}
}生产环境注意事项
并发安全
多个请求同时操作同一个 Session 可能导致消息乱序。解决方案是为每个用户会话使用独占的 Session 实例,或者实现 Session 的锁机制。
存储持久化
AgentSession 默认存在于内存中,服务器重启后丢失。生产环境需要实现 Session 的序列化存储。上面的 ConversationManager 类展示了基于文件的持久化方案。分布式部署建议使用 Redis 或 Cosmos DB。
上下文窗口管理
LLM 的上下文窗口是有限的(GPT-4o-mini 支持 128K tokens)。随着对话轮次增加,历史消息越来越多。解决办法是定期检查 Session 中的 Token 总数,在接近上限时把早期对话压缩为一段摘要。SerializeSession 和 DeserializeSessionAsync 方法让这种操作成为可能。
Session 的实现原理
AgentSession 内部维护了一个消息列表。每次 RunAsync 调用时,Agent 框架会:
- 从 Session 中读取历史消息
- 拼接新的用户消息
- 发送给 LLM
- 把 LLM 的回复追加到 Session 中
下一步:Step 4:持久化内存 — 通过 Context Provider 实现跨会话记忆。