Step 4:持久化内存
多轮对话只在当前 Session 存活期内有效。重启程序后 Session 丢失了。持久化上下文让 Agent 能在不同会话间记住用户信息。
ChatHistoryProvider
Agent 的对话历史通过 ChatHistoryProvider 管理。默认使用 InMemoryChatHistoryProvider(内存中),你可以传入自定义实现:
// 默认:InMemoryChatHistoryProvider
AIAgent agent = projectClient.AsAIAgent(
model: deploymentName,
options: new ChatClientAgentOptions
{
Instructions = "你是友好的助手。",
});
// 可以传入自定义 ChatHistoryProvider
AIAgent agent = projectClient.AsAIAgent(
model: deploymentName,
options: new ChatClientAgentOptions
{
Instructions = "你是友好的助手。",
ChatHistoryProvider = new CustomChatHistoryProvider()
});基于文件的持久化实现
public class FileChatHistoryProvider : ChatHistoryProvider
{
private readonly string _filePath;
private List<ChatMessage> _messages = new();
public FileChatHistoryProvider(string filePath)
{
_filePath = filePath;
LoadAsync().GetAwaiter().GetResult();
}
public override IReadOnlyList<ChatMessage> Messages => _messages.AsReadOnly();
public override void AddMessage(ChatMessage message)
{
_messages.Add(message);
}
public override async Task SaveAsync()
{
var json = System.Text.Json.JsonSerializer.Serialize(_messages);
await File.WriteAllTextAsync(_filePath, json);
}
private async Task LoadAsync()
{
if (File.Exists(_filePath))
{
var json = await File.ReadAllTextAsync(_filePath);
_messages = System.Text.Json.JsonSerializer
.Deserialize<List<ChatMessage>>(json) ?? new();
}
}
}基于 Session 的上下文共享
更推荐的方式是使用 AgentSession 来跨 Agent 运行共享上下文:
// 创建会话
AgentSession session = await agent.CreateSessionAsync();
// 第一轮对话告诉 Agent 个人信息
var r1 = await agent.RunAsync("记住:我叫张三,喜欢简洁的回答风格。", session);
// 模拟新的 Agent 调用(中间可能经过了其他处理)
// 同一个 Session 中 Agent 记得用户偏好
var r2 = await agent.RunAsync("你还记得我吗?", session);
// ✅ 回复:当然记得!你是张三,喜欢简洁的回答风格。
// 第三轮验证
var r3 = await agent.RunAsync("我的名字是什么?用两个字回答。", session);
// ✅ 回复:张三补充概念:Agent 的类型与执行模式
Agent 的核心类型
AIAgent 是 Agent 的抽象基类,它定义了所有 Agent 的统一接口。目前框架提供了三种主要的 Agent 类型:
ChatClientAgent 是最常用的 Agent 类型。它包装了一个 IChatClient(即底层的 AI 模型连接),提供标准的对话体验。ChatClientAgent 支持函数调用、多轮对话、流式输出和结构化输出。当你用 AIProjectClient.AsAIAgent() 创建 Agent 时,底层实际创建的就是一个 ChatClientAgent。它的运行模型是"接收用户消息 → 与 LLM 交互 → 可能需要调用工具 → 返回回复"的循环。
自定义 Agent 通过继承 AIAgent 基类来实现。如果 ChatClientAgent 的默认行为不满足你的需求——比如你想在每次 Agent 响应前都做一次安全检查——你可以继承 AIAgent 并重写它的核心方法。这种方式给了你对 Agent 行为的完全控制权。
远程 Agent 代理 是一个特殊的 Agent 类型,通过 A2A 协议连接到远端的一个 Agent 实例。当你构建多 Agent 系统时,远程 Agent 代理让你可以像调用本地 Agent 一样调用其他服务上的 Agent。
执行模式
RunAsync — 同步(阻塞式)执行。Agent 发送消息给 LLM,等待完整回复,返回 AgentResponse 对象。适合后台处理、批处理操作。
RunStreamingAsync — 异步流式执行。Agent 返回 IAsyncEnumerable<AgentResponseUpdate>,调用者通过 await foreach 遍历更新。适合聊天应用、实时仪表盘。
响应内容类型
AgentResponse 的响应内容是一个 IEnumerable<IAgentContent> 集合,每个元素可以是以下类型之一:
TextContent— 文本片段DataContent— 二进制数据(图片、文件)UriContent— 外部资源的 URI 引用FunctionCallContent— Agent 决定调用的工具函数信息FunctionResultContent— 工具函数的执行结果
AgentResponse response = await agent.RunAsync("给我画一张饼图");
// 内容集合中可能包含:
foreach (var content in response)
{
switch (content)
{
case TextContent textContent:
Console.WriteLine($"文本: {textContent.Text}");
break;
case DataContent dataContent:
Console.WriteLine($"二进制数据: {dataContent.Data.Length} bytes");
break;
case UriContent uriContent:
Console.WriteLine($"URI: {uriContent.Uri}");
break;
case FunctionCallContent fnCall:
Console.WriteLine($"函数调用: {fnCall.Name}");
break;
case FunctionResultContent fnResult:
Console.WriteLine($"函数结果: {fnResult.Result}");
break;
}
}下一步:Step 5:工作流编排 — 撰寫多步骤任务。