老胡
发布于 2026-09-24 / 2 阅读
0
0

MAF 快速上手(3)让 Agent 记住上下文:多轮对话multi_turn

前两集我们让 Agent 讲了笑话、还给它装上了函数工具。但那些例子里,每次调用都是"一问一答、互不相关"。你问第二句时,Agent 早把第一句忘了。

这一集要解决的就是多轮对话:让 Agent 记住你们前面聊过什么,第二句话能接着第一句话的意思往下走。比如先让它讲个海盗笑话,再补一句"给这笑话加表情、用海盗鹦鹉的口吻再讲一遍",它得知道"这笑话"指的是哪一个,对吧?

示例源码位于:dotnet/samples/01-get-started/03_multi_turn/


一、这一集比前两集多了什么

前两集的调用都是单轮:RunAsync("一句话") 进去,结果出来,结束。第三集只多了一个东西,就是会话对象 AgentSession

  1. 调用前先用 agent.CreateSessionAsync() 开一个会话;
  2. 之后每一次 RunAsync(...) / RunStreamingAsync(...) 都把这个 session 一起传进去;
  3. 框架自动把每轮问答存进会话,下一轮调用时连同历史一起发给模型。

环境、建客户端、造 Agent 的写法跟第一集完全一样,这里不再重复,没配好密钥的回第一集看环境变量那一节即可。


二、先搞懂:多轮对话靠什么"记性"

大模型本身没有记忆:你每发一次请求,对它来说都是全新的对话,除非你把历史消息一条条附上。

两种做法:

  • 手工拼历史:自己维护一个消息列表,每轮把旧消息和新问题一起发。能行,但麻烦,还得管 token 长度。
  • 交给 AgentSession(本集做法):MAF 把"历史消息的管理"封装进了会话对象。你只管反复调用同一个 session,框架在背后替你拼接上下文。这才是 Agent 框架存在的意义之一。

这个"记忆"存在你本地程序的会话对象里,不在 DeepSeek 服务端。关掉程序,会话就没了;重开一个 CreateSessionAsync() 得到的也是全新空白会话。所以"让 Agent 记住"指的是"在当前运行周期内连续对话",不是跨进程持久化。


三、核心代码逐行讲

// Copyright (c) Microsoft. All rights reserved.

// 本示例演示如何用 OpenAI 兼容接口(这里用 DeepSeek)创建一个 Agent,
// 并通过会话(AgentSession)实现多轮对话:上下文由会话对象自动保留。

using System.ClientModel;
using Microsoft.Agents.AI;
using OpenAI;
using OpenAI.Chat;

// DeepSeek 提供 OpenAI 兼容的接口。密钥通过环境变量提供;
// 默认模型为 "deepseek-flash"(官方当前推荐)。其他可选模型包括 "deepseek-v4-pro"。
// 注意:旧模型名如 "deepseek-chat" / "deepseek-reasoner" 已不在官方文档中,应避免使用。
var apiKey = Environment.GetEnvironmentVariable("DEEPSEEK_API_KEY") ?? throw new InvalidOperationException("未设置环境变量 DEEPSEEK_API_KEY。");
var model = Environment.GetEnvironmentVariable("DEEPSEEK_MODEL") ?? "deepseek-flash";

// 将 OpenAI 客户端指向 DeepSeek 的接口地址,而不是 api.openai.com。
OpenAIClient openAIClient = new(
    new ApiKeyCredential(apiKey),
    new OpenAIClientOptions { Endpoint = new Uri("https://api.deepseek.com") });

// 获取选定模型的聊天客户端,并将其包装为 MAF 的 Agent,设定人设与名字。
ChatClient chatClient = openAIClient.GetChatClient(model);
AIAgent agent = chatClient.AsAIAgent(instructions: "你是一个擅长讲笑话的助手。", name: "笑话大王");

// 多轮对话(非流式):创建一个会话对象,后面每次调用都把同一个 session 传进去,
// Agent 就会记住之前说过的话,无需我们手动拼接历史。
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("给我讲一个关于海盗的笑话。", session));
Console.WriteLine(await agent.RunAsync("给这个笑话加上一些表情符号,并用海盗鹦鹉的口吻再讲一遍。", session));

// 多轮对话(流式):同样创建一个新会话,逐句把更新打印出来,
// 上下文依旧由 session 自动保留。
session = await agent.CreateSessionAsync();
await foreach (var update in agent.RunStreamingAsync("给我讲一个关于海盗的笑话。", session))
{
    Console.WriteLine(update);
}
await foreach (var update in agent.RunStreamingAsync("给这个笑话加上一些表情符号,并用海盗鹦鹉的口吻再讲一遍。", session))
{
    Console.WriteLine(update);
}

几个值得停下来看的地方:

  • CreateSessionAsync() 是关键:它返回一个空的 AgentSession。多轮对话的"连续性"全靠反复传同一个 session 实例。如果你每次都新建一个会话,那就又退回单轮了。
  • RunAsync(提示词, session) 多了一个参数:前两集我们只传提示词;这一集把会话作为第二个参数带上,框架就会自动把这次问答并入会话历史。流式版 RunStreamingAsync(提示词, session) 同理。
  • 非流式和流式用的是同一套会话机制:上面两段代码各开了一个新会话(CreateSessionAsync() 得到的是全新空白会话),互不干扰;想让流式接着非流式的话题聊,就得共用同一个 session 变量。
  • name: "笑话大王"instructions 跟第一集一样,没变。多轮对话改变的只是"调用时多了会话参数",Agent 本身的定义不变。

四、运行时到底发生了什么

把非流式那两段拆开看,幕后其实是:

  1. CreateSessionAsync() 在本地建好一个空会话;
  2. 第一轮 RunAsync("讲个海盗笑话", session):框架把"空历史 + 这句话"发给 DeepSeek,拿到笑话,并把这次问答写回 session
  3. 第二轮 RunAsync("加表情、用鹦鹉口吻再讲", session):框架把"上一轮的问答 + 这句新指令"一起发给 DeepSeek;
  4. 模型因为看到了前面的笑话,才知道"这笑话"指什么,于是产出带表情、鹦鹉口吻的版本。

所以"记住上下文"靠的不是模型,而是框架在每次请求时帮你把历史带上。


五、动手改造

跑通之后,试试这几件事,把多轮对话吃透:

  • 加第三轮:在同一个 session 里再问"把它翻译成英文",验证它仍记得前面那只鹦鹉讲的笑话。
  • 验证"失忆":把第二次 RunAsync 改用 await agent.CreateSessionAsync() 新建会话再问,你会发现它答不上来"这笑话"指什么,直观感受会话的作用。
  • 串起第二集的工具:把 03session 机制套到 02_add_tools 的 Agent 上,让带工具的 Agent 也能多轮连续对话(提示词换成"阿姆斯特丹天气怎样?那北京呢?")。

六、小结

这一集你学会了用 AgentSession 做多轮对话:用 CreateSessionAsync() 开会话,每次调用把同一个 session 传给 RunAsync / RunStreamingAsync,框架自动保留上下文。记住三点:记忆在本地会话里、不在服务端;连续性靠复用同一 session;每次新建会话等于开新话题。

下一篇我们讲"记忆"(04_memory),看看如何让 Agent 跨运行、跨会话地长期记住信息。

示例源码

  • 本示例:dotnet/samples/01-get-started/03_multi_turn/Program.cs
  • 上一篇:dotnet/samples/01-get-started/02_add_tools/使用说明书.md
  • 系列参考:同目录 01_hello_agent02_add_tools04_memory

参考资料

  • Microsoft Agent Framework 的 OpenAI 扩展(Microsoft.Agents.AI.OpenAI
  • DeepSeek 官方 API 文档(中文):https://api-docs.deepseek.com/zh-cn/
  • 参考博文:《MAF快速入门(1)化繁为简的AGENT创建范式》,作者 EdisonZhou(cnblogs)

评论