找回密码
 立即注册
首页 业界区 安全 Microsoft Agent Framework 取出 DeepSeek 思考内容 ...

Microsoft Agent Framework 取出 DeepSeek 思考内容

奄蜊 前天 10:15
本文提供的方法适用于 DeepSeek 和豆包等模型
前置博客:

  • Microsoft Agent Framework 与 DeepSeek 对接


  • C# Microsoft Agent Framework 与 豆包 对接
核心原理是从 AgentResponseUpdate 里面的 RawRepresentation 获取 reasoning_content 字段
核心代码如下
  1. AIAgent agent = ...;
  2. IEnumerable<ChatMessage> messages = ...;
  3. AgentSession? session = ...;
  4. AgentRunOptions? options = ...;
  5.         await foreach (AgentResponseUpdate agentRunResponseUpdate in agent.RunStreamingAsync(messages, session, options, cancellationToken))
  6.         {
  7.             var contentIsEmpty = string.IsNullOrEmpty(agentRunResponseUpdate.Text);
  8.             if (contentIsEmpty && agentRunResponseUpdate.RawRepresentation is Microsoft.Extensions.AI.ChatResponseUpdate streamingChatCompletionUpdate)
  9.             {
  10.                 if (streamingChatCompletionUpdate.RawRepresentation is StreamingChatCompletionUpdate chatCompletionUpdate)
  11.                 {
  12. #pragma warning disable SCME0001 // Patch 属性是实验性内容
  13.                     ref JsonPatch patch = ref chatCompletionUpdate.Patch;
  14.                     if (patch.TryGetJson("$.choices[0].delta"u8, out var data))
  15.                     {
  16.                         var jsonElement = JsonElement.Parse(data.Span);
  17.                         if (jsonElement.TryGetProperty("reasoning_content", out var reasoningContent))
  18.                         {
  19.                             // 拿到的 reasoningContent 就是思考内容
  20.                         }
  21.                     }
  22. #pragma warning restore SCME0001
  23.                 }
  24.             }
复制代码
我将这段代码封装为扩展方法,方便上层业务使用,代码如下
  1. using System.ClientModel.Primitives;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. using System.Text.Json;
  5. using OpenAI.Chat;
  6. using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
  7. namespace Microsoft.Agents.AI.Reasoning;
  8. public static class ReasoningAIAgentExtension
  9. {
  10.     public static IAsyncEnumerable<ReasoningAgentRunResponseUpdate> RunReasoningStreamingAsync(this AIAgent agent, ChatMessage message,
  11.         AgentSession? session = null,
  12.         AgentRunOptions? options = null,
  13.         CancellationToken cancellationToken = default)
  14.     {
  15.         return RunReasoningStreamingAsync(agent, [message], session, options, cancellationToken);
  16.     }
  17.     public static async IAsyncEnumerable<ReasoningAgentRunResponseUpdate> RunReasoningStreamingAsync(this AIAgent agent, IEnumerable<ChatMessage> messages,
  18.         AgentSession? session = null,
  19.         AgentRunOptions? options = null,
  20.         [EnumeratorCancellation]
  21.         CancellationToken cancellationToken = default)
  22.     {
  23.         bool? isThinking = null;
  24.         bool isFirstOutputContent = true;
  25.         await foreach (AgentResponseUpdate agentRunResponseUpdate in agent.RunStreamingAsync(messages, session, options, cancellationToken))
  26.         {
  27.             var contentIsEmpty = string.IsNullOrEmpty(agentRunResponseUpdate.Text);
  28.             if (contentIsEmpty && agentRunResponseUpdate.RawRepresentation is Microsoft.Extensions.AI.ChatResponseUpdate streamingChatCompletionUpdate)
  29.             {
  30.                 if (streamingChatCompletionUpdate.RawRepresentation is StreamingChatCompletionUpdate chatCompletionUpdate)
  31.                 {
  32. #pragma warning disable SCME0001 // Patch 属性是实验性内容
  33.                     ref JsonPatch patch = ref chatCompletionUpdate.Patch;
  34.                     if (patch.TryGetJson("$.choices[0].delta"u8, out var data))
  35.                     {
  36.                         var jsonElement = JsonElement.Parse(data.Span);
  37.                         if (jsonElement.TryGetProperty("reasoning_content", out var reasoningContent))
  38.                         {
  39.                             // 拿到的 reasoningContent 就是思考内容
  40.                         }
  41.                     }
  42. #pragma warning restore SCME0001
  43.                 }
  44.             }
  45.             if (!contentIsEmpty)
  46.             {
  47.                 var responseUpdate = new ReasoningAgentRunResponseUpdate(agentRunResponseUpdate);
  48.                 if (isFirstOutputContent)
  49.                 {
  50.                     responseUpdate.IsFirstOutputContent = true;
  51.                 }
  52.                 if (isThinking is true && isFirstOutputContent)
  53.                 {
  54.                     responseUpdate.IsThinkingEnd = true;
  55.                 }
  56.                 isFirstOutputContent = false;
  57.                 isThinking = false;
  58.                 yield return responseUpdate;
  59.             }
  60.         }
  61.     }
  62. }
复制代码
用到的辅助类 ReasoningAgentRunResponseUpdate 代码如下
  1. namespace Microsoft.Agents.AI.Reasoning;
  2. public class ReasoningAgentRunResponseUpdate : AgentResponseUpdate
  3. {
  4.     public ReasoningAgentRunResponseUpdate(AgentResponseUpdate origin) : base(origin.Role, origin.Contents)
  5.     {
  6.         Origin = origin;
  7.         AdditionalProperties = origin.AdditionalProperties;
  8.         AuthorName = origin.AuthorName;
  9.         CreatedAt = origin.CreatedAt;
  10.         MessageId = origin.MessageId;
  11.         RawRepresentation = origin.RawRepresentation;
  12.         ResponseId = origin.ResponseId;
  13.         ContinuationToken = origin.ContinuationToken;
  14.         AgentId = origin.AgentId;
  15.     }
  16.     public AgentResponseUpdate Origin { get; }
  17.     public string? Reasoning { get; set; }
  18.     /// <summary>
  19.     /// 是否首次输出内容,前面输出的都是内容
  20.     /// </summary>
  21.     /// 仅内容输出,无思考的首次内容输出:
  22.     /// - IsFirstOutputContent = true
  23.     /// - IsFirstThinking = false
  24.     /// - IsThinkingEnd = false
  25.     /// 有思考,完成思考后的首次内容输出:
  26.     /// - IsFirstOutputContent = true
  27.     /// - IsFirstThinking = false
  28.     /// - IsThinkingEnd = true
  29.     public bool IsFirstOutputContent { get; set; }
  30.     /// <summary>
  31.     /// 思考的首次输出
  32.     /// </summary>
  33.     public bool IsFirstThinking { get; set; }
  34.     /// <summary>
  35.     /// 是否思考结束
  36.     /// </summary>
  37.     public bool IsThinkingEnd { get; set; }
  38. }
复制代码
业务层使用示例:
  1. ChatClientAgent aiAgent = ...;
  2. ChatMessage message = new ChatMessage(ChatRole.User, "请讲一个笑话");
  3. await foreach (var agentRunResponseUpdate in aiAgent.RunReasoningStreamingAsync(message))
  4. {
  5.     if (agentRunResponseUpdate.IsFirstThinking)
  6.     {
  7.         Console.WriteLine("思考:");
  8.     }
  9.     if (agentRunResponseUpdate.Reasoning is not null)
  10.     {
  11.         Console.Write(agentRunResponseUpdate.Reasoning);
  12.     }
  13.     if (agentRunResponseUpdate.IsThinkingEnd)
  14.     {
  15.         Console.WriteLine();
  16.         Console.WriteLine("--------");
  17.     }
  18.     var text = agentRunResponseUpdate.Text;
  19.     if (!string.IsNullOrEmpty(text))
  20.     {
  21.         Console.Write(text);
  22.     }
  23. }
复制代码
输出效果如下:
  1. 思考:
  2. 用户让我讲一个笑话,那得选个轻松有趣、贴近生活的,别太复杂。首先,得考虑不同年龄段都能听懂,最好有点小反转,这样笑点更足。
  3. 比如可以从日常场景入手,像去超市、和朋友互动,或者宠物相关的?宠物的笑话通常很受欢迎,因为可爱又有反差感。
  4. 哦,想到一个关于猫和主人的:
  5. 主人发现猫最近总偷喝鱼缸里的水,于是教训它:“你再偷喝,我就把你和鱼一起炖了!”
  6. 第二天,主人发现鱼缸里的鱼全没了,猫蹲在旁边舔爪子,抬头一脸无辜:“主人,我帮你提前处理了食材~”
  7. 这个有小反转,猫的逻辑很可爱,应该挺逗的。或者换个更接地气的,比如关于吃饭的:
  8. 昨天去吃火锅,服务员问我要辣的还是不辣的,我说:“微辣就行,别太辣。”
  9. 服务员:“好的,我们这边微辣是‘外地人眼中的特辣’,特辣是‘本地人眼中的微辣’,您要哪个?”
  10. 我:“……给我来个‘外地人眼中的微辣’的微辣吧。”
  11. 服务员愣了一下:“好的,清水锅加一片辣椒!”
  12. 这个也很真实,很多地方的微辣都很辣,有共鸣感。不过还是宠物的那个更可爱,可能用户会更喜欢。再调整一下,让语言更自然:
  13. 有只猫特别爱偷喝鱼缸里的水,主人每次看见都批评它:“再偷喝,我就把你和鱼一起炖了!”
  14. 结果第二天起床,主人发现鱼缸里的鱼全不见了,猫正蹲在旁边舔嘴巴,看见主人过来,还一脸邀功地说:“主人你看!我提前把配菜都处理好了??”
  15. 对,这样更生动,有表情符号也更活泼。或者再短一点的?比如冷笑话?不过可能用户想要正常的笑话,不是冷的。那就选这个猫的吧,应该不错。
  16. --------
  17. 有只猫特别爱偷喝鱼缸里的水,主人每次看见都批评它:“再偷喝,我就把你和鱼一起炖了!”
  18. 结果第二天起床,主人发现鱼缸里的鱼全不见了,猫正蹲在旁边舔嘴巴,看见主人过来,还一脸邀功地说:“主人你看!我提前把配菜都处理好了”
复制代码
本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin fc4cf4f485ea3e2268a67c0c6900827d9803d9b3
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin fc4cf4f485ea3e2268a67c0c6900827d9803d9b3
复制代码
获取代码之后,进入 SemanticKernelSamples/LadelallkeacheWhikurwearqobakaju 文件夹,即可获取到源代码
更多技术博客,请参阅 博客导航

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册