<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Microsoft Agent Framework 接入DeepSeek的優雅姿勢

      一、前言

      ? Microsoft Agent Framework 框架發布也有一陣子了,在觀望(摸魚)過后,也是果斷(在老板的威脅下)將幾個AI應用微服務完成了從Semantic Kernel 框架到Microsoft Agent Framework 框架中的遷移工作。

      所以這篇文章,我想記錄一下在開發過程中的我總結的一下工程化用法

      二、Agent Framework是什么

      簡單來講,Microsoft Agent Framework 是微軟在 Semantic Kernel 之后推出的一個 新一代智能體(Agent)開發框架。它其實就是 SK 的“進化版”——思路差不多,但更直接、更好用,也更符合現在大家在做 多智能體(Multi-Agent)系統 的趨勢。

      如果你用過 Semantic Kernel,大概還記得那種層層嵌套的概念:KernelSkillFunctionContext…… 用起來就像在拼一堆樂高磚塊。

      三、對比Semantic Kernel

      1. 結構更加直觀和優雅

        以前 SK 的 “Function” / “Skill” 概念太抽象。
        在 Agent Framework 里,你可以直接定義一個 Agent 類,然后給它掛上工具(Tool)、記憶(Memory)。

      2. Prompt 與邏輯分離更自然

        在 SK 里常常要寫一堆 Template Function,還要用 YAML 或 JSON 去配置。
        在 Agent Framework 中,你直接在創建 Agent 時傳入 instructions(提示詞),框架會自動封裝上下文調用,大幅減少模板樣板代碼。

      3. 內置的多 Agent 協作更順手
        它原生支持多個 Agent 之間的消息傳遞,你可以像寫微服務一樣寫“智能體服務”。

      四、使用姿勢

      在使用SK框架的時候我就很討厭構建一個“kernel”,什么都找他實現,那種方法一開始很方便和簡潔,但是復用和調試就是災難。所以我的做法是:每個任務一個 Agent,職責單一、結構清晰、方便測試。然后再把這些 Agent 都注冊進 IOC 容器里,像注入普通服務一樣調用。

      4.1 Agent任務分配

      以一個從文檔上解析公司名做示例:

      namespace STD.AI.Implementations
      {
          public class CompanyExtractionAgent : BaseAgentFunction, ICompanyExtractionAgent
          {
              private readonly AIAgent _agent;
              public CompanyExtractionAgent(IOptions<LLMConfiguration> config)
              {
                  var openAIClient = new OpenAIClient(new ApiKeyCredential(config.Value.ApiKey), new 	                         OpenAIClientOptions
                  {
                      Endpoint = new Uri(config.Value.Endpoint),
                  });
                  var responseClient = openAIClient.GetChatClient(config.Value.Model);
                  _agent = responseClient.CreateAIAgent(instructions:
                      "你是一個信息抽取助手,請從文本中提取所有公司名稱,必須返回合法 JSON 數組,如 [\"公司A\", \"公司B\"]。不要輸出解釋或額外內容。");
              }
      
              public async Task<List<string>> ExtractCompanyNamesAsync(string filePath)
              {
                  if (!File.Exists(filePath))
                      throw new FileNotFoundException("找不到指定文件", filePath);
      
                  string content = DocumentReader.ExtractText(filePath);
                  if (string.IsNullOrWhiteSpace(content))
                      return new List<string>();
      
      
                  var thread = _agent.GetNewThread();
                  var chunks = SplitDocumentIntoChunks(content);
                  var allCompanies = new HashSet<string>();
                  foreach (var chunk in chunks)
                  {
                      string prompt = @$"
                      請從以下文本片段中中提取所有公司名稱,并嚴格以 JSON 數組形式輸出:
                      示例輸出:
                       [""阿里巴巴集團"", ""騰訊科技有限公司"", ""百度公司""]
                      以下是正文:{chunk}";
                      try
                      {
                          var response = await _agent.RunAsync(prompt, thread);
                          string raw = response.Text ?? string.Empty;
                          string cleaned = CleanJsonResponseList(raw);
                          var companies = JsonSerializer.Deserialize<List<string>>(cleaned) ?? new List<string>();
                          LogProvider.Info(raw);
                          foreach (var c in companies) allCompanies.Add(c);
                      }
                      catch (JsonException ex)
                      {
                          LogProvider.Warning($"解析失敗: {ex.Message}");
                      }
                  }
                  return allCompanies.ToList();
              }
          }
      }
      

      4.2 給Agent 裝上手和眼

      4.2.1 添加MCP服務

      namespace STD.AI
      {
          public static class MCPConfigExtension
          {
              public static string _pluginPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
              public static string _userDataDir = Path.Combine(_pluginPath, "browser-data");
              public static async Task AddMcpClientAsync(this IServiceCollection services, bool Headless)
              {
                  try
                  {
                      var config = new List<string>
                      {
                           "@playwright/mcp",
                           "--caps", "pdf",
                           "--output-dir",Path.GetTempPath(),
                           "--user-data-dir", _userDataDir,
                      };
                      if (Headless)
                      {
                          config.Add("--headless");
                      }
                      var transport = new StdioClientTransport(new StdioClientTransportOptions
                      {
                          Name = "PlaywrightMCP",
                          Command = "npx",
                          Arguments = config
                      });
                      var mcpClient = await McpClient.CreateAsync(transport);
                      services.AddSingleton(mcpClient);
                  }
                  catch (Exception ex)
                  {
                      LogProvider.Error($"AddMcpClientfail:{ex.ToString()}");
                  }
      
              }
          }
      }
      

      4.2.2 注冊MCP工具

      namespace STD.AI.Implementations
      {
          /// <summary>
          /// 公司信息查詢 Agent,使用 MCP 瀏覽器工具自動查詢公司信息
          /// </summary>
          public class CompanyInfoQueryAgent : BaseAgentFunction, ICompanyInfoQueryAgent
          {
              private readonly AIAgent _agent;
              private readonly McpClient _mcpClient;
      
              public CompanyInfoQueryAgent(IOptions<LLMConfiguration> config, McpClient mcpClient)
              {
                  _mcpClient = mcpClient ?? throw new ArgumentNullException(nameof(mcpClient));
      
                  var openAIClient = new OpenAIClient(new ApiKeyCredential(config.Value.ApiKey), new OpenAIClientOptions
                  {
                      Endpoint = new Uri(config.Value.Endpoint)
                  });
      
                  var responseClient = openAIClient.GetChatClient(config.Value.Model);
      
                  // 獲取 MCP 工具并注冊到 Agent
                  var tools = _mcpClient.ListToolsAsync().GetAwaiter().GetResult();
      
                  _agent = responseClient.CreateAIAgent(
                      instructions: @"
                      你是一個專業的商業信息采集 AI 助手,擁有網絡訪問能力 (MCP 瀏覽器工具)。
                      你的任務是:自動訪問多個公開來源(如企業官網、天眼查、企查查、維基百科、新聞報道等),
                      提取公司相關信息,并輸出為嚴格 JSON 格式,映射到以下 CompanyInfo 結構。
                      
                      請嚴格返回合法 JSON(不包含解釋性文字或 Markdown)。
                      
                      ### CompanyInfo 字段定義與說明:
                      {
                        ""companyName"": ""公司中文名稱(必須字段)"",
                        ""englishName"": ""英文名稱,如有"",
                        ""officialWebsite"": ""公司官網 URL,如未知可留空"",
                        ""contactPhone"": ""公司主要聯系電話"",
                        ""email"": ""公司官方郵箱"",
                        ""address"": ""公司總部地址"",
                        ""businessScope"": ""經營范圍,描述主營業務及服務"",
                        ""registrationNumber"": ""工商注冊號(如可獲得)"",
                        ""unifiedSocialCreditCode"": ""統一社會信用代碼(如可獲得)"",
                        ""companyType"": ""公司類型(如有限責任公司、股份有限公司等)"",
                        ""legalRepresentative"": ""法定代表人姓名"",
                        ""registeredCapital"": ""注冊資本(含幣種)"",
                        ""establishedDate"": ""公司成立日期(ISO格式,如 2020-05-12)"",
                        ""industry"": ""所屬行業(如互聯網、制造業等)"",
                        ""mainBusiness"": ""主營產品或服務"",
                        ""employeeCount"": ""員工數量(大約范圍,如 '100-500人')"",
                        ""stockCode"": ""股票代碼(如上市公司)"",
                        ""stockExchange"": ""交易所(如上交所、納斯達克)"",
                        ""lastUpdated"": ""數據最后處理時間(ISO 8601 格式)""
                      }
                      
                      返回的 JSON 必須能直接被 C# System.Text.Json 反序列化為 CompanyInfo 對象。
                      ",
                      name: "mcpAgent",
                      description: "調用 MCP 工具實現公司數據查詢",
                      tools: tools.Cast<AITool>().ToList()
                  );
              }
      
              public async Task<CompanyInfo?> QueryCompanyInfoAsync(string companyName)
              {
                  if (string.IsNullOrWhiteSpace(companyName))
                      throw new ArgumentException("公司名稱不能為空", nameof(companyName));
      
                  var thread = _agent.GetNewThread();
      
                  string userPrompt = $@"
                  請使用 MCP 瀏覽器工具搜索并訪問多個網頁,
                  綜合提取公司 “{companyName}” 的完整工商及公開資料。
                  請整合不同來源的數據,確保字段盡量完整,并返回合法 JSON。
                  ";
                  var response = await _agent.RunAsync(userPrompt, thread);
                  string raw = response.Text ?? string.Empty;
                  raw = CleanJsonResponse(raw);
                  return JsonSerializer.Deserialize<CompanyInfo>(raw);
              }
          }
      }
      
      

      4.3 注冊函數工具

      4.3.1 編寫函數工具

      using Microsoft.Extensions.AI;
      
      namespace STD.AI.Tools
      {
          public class CompanyInfoTool : AITool
          {
              private readonly HttpClient _httpClient;
      
              public CompanyInfoTool(HttpClient httpClient)
              {
                  _httpClient = httpClient;
              }
      
              public async Task<string> QueryCompanyInfoAsync(string companyName)
              {
                  var response = await _httpClient.GetAsync($"https://api.example.com/company/{companyName}");
                  return await response.Content.ReadAsStringAsync();
              }
          }
      
      }
      

      4.3.2 注冊函數工具

      namespace STD.AI.Implementations
      {
          public class CompanyInfoAgent : BaseAgentFunction, ICompanyInfoAgent
          {
              private readonly AIAgent _agent;
              private readonly CompanyInfoTool _companyInfoTool;
      
              public CompanyInfoAgent(IOptions<LLMConfiguration> config, CompanyInfoTool companyInfoTool)
              {
                  _companyInfoTool = companyInfoTool ?? throw new ArgumentNullException(nameof(companyInfoTool));
      
                  var openAIClient = new OpenAIClient(new ApiKeyCredential(config.Value.ApiKey), new OpenAIClientOptions
                  {
                      Endpoint = new Uri(config.Value.Endpoint)
                  });
      
                  var responseClient = openAIClient.GetChatClient(config.Value.Model);
      
                  // 創建 Agent,并注冊工具
                  _agent = responseClient.CreateAIAgent(
                      instructions: "你是一個公司信息查詢助手,請使用工具查詢公司相關信息。",
                      name: "companyInfoAgent",
                      description: "使用公司信息查詢工具來獲取公司資料",
                      tools: new List<AITool> { _companyInfoTool }
                  );
              }
      
              public async Task<string> GetCompanyInfoAsync(string companyName)
              {
                  var thread = _agent.GetNewThread();
      
                  // AI 通過工具查詢公司信息
                  var response = await _agent.RunAsync($"請查詢公司 {companyName} 的詳細信息", thread);
                  return response.Text;
              }
          }
      }
      

      4.4 記憶功能

      namespace STD.AI.Implementations
      {
      
          public class CompanyInfoAgentWithMemory : BaseAgentFunction
          {
              private readonly AIAgent _agent;
              private readonly CompanyInfoTool _companyInfoTool;
              public CompanyInfoAgentWithMemory(IOptions<LLMConfiguration> config, CompanyInfoTool companyInfoTool)
              {
                  _companyInfoTool = companyInfoTool ?? throw new ArgumentNullException(nameof(companyInfoTool));
      
                  var openAIClient = new OpenAIClient(new ApiKeyCredential(config.Value.ApiKey), new OpenAIClientOptions
                  {
                      Endpoint = new Uri(config.Value.Endpoint)
                  });
      
                  var responseClient = openAIClient.GetChatClient(config.Value.Model);
      
                  // 創建代理
                  _agent = responseClient.CreateAIAgent(
                      instructions: "你是一個公司信息查詢助手,請使用工具查詢公司相關信息。",
                      name: "companyInfoAgentWithMemory",
                      description: "使用公司信息查詢工具,并且記住用戶的歷史對話。",
                      tools: new List<AITool> { _companyInfoTool }
                  );
              }
      
              // 查詢公司信息并使用記憶存儲對話內容
              public async Task<string> GetCompanyInfoAsync(string companyName)
              {
                  var thread = _agent.GetNewThread();
      
                  // AI 通過工具查詢公司信息
                  var response = await _agent.RunAsync($"請查詢公司 {companyName} 的詳細信息", thread);
      
                  // 序列化并保存當前對話狀態到持久存儲(例如文件、數據庫等)
                  var serializedThread = thread.Serialize(JsonSerializerOptions.Web).GetRawText();
                  await SaveThreadStateAsync(serializedThread);
      
                  return response.Text;
              }
      
              // 恢復之前的對話上下文并繼續對話
              public async Task<string> ResumePreviousConversationAsync(string companyName)
              {
                  var thread = _agent.GetNewThread();
      
                  // 從存儲中加載之前的對話狀態
                  var previousThread = await LoadThreadStateAsync();
      
                  // 反序列化并恢復對話
                  var reloadedThread = _agent.DeserializeThread(JsonSerializer.Deserialize<JsonElement>(previousThread));
      
                  // 使用恢復的上下文繼續對話
                  var response = await _agent.RunAsync($"繼續查詢公司 {companyName} 的信息", reloadedThread);
      
                  return response.Text;
              }
      
              // 模擬保存線程狀態到持久存儲
              private async Task SaveThreadStateAsync(string serializedThread)
              {
                  // 示例:保存到文件(可以替換為數據庫或其他存儲介質)
                  var filePath = Path.Combine(Path.GetTempPath(), "agent_thread.json");
                  await File.WriteAllTextAsync(filePath, serializedThread);
              }
      
              // 模擬加載存儲的線程狀態
              private async Task<string> LoadThreadStateAsync()
              {
                  // 示例:從文件加載(可以替換為數據庫或其他存儲介質)
                  var filePath = Path.Combine(Path.GetTempPath(), "agent_thread.json");
                  return await File.ReadAllTextAsync(filePath);
              }
          }
      }
      

      內存上下文實現

      [將內存添加到代理 | Microsoft Learn]

      五、一些小坑

      5.1 API地址配置

      namespace STD.Model
      {
          public class LLMConfiguration
          {
              public string Model { get; set; }
              public string Endpoint { get; set; }
              public string ApiKey { get; set; }
              public bool IsValid()
              {
                  return !string.IsNullOrWhiteSpace(Model) &&
                         !string.IsNullOrWhiteSpace(Endpoint) &&
                         Uri.IsWellFormedUriString(Endpoint, UriKind.Absolute) &&
                         !string.IsNullOrWhiteSpace(ApiKey);
              }
          }
      }
      

      填寫Endpoint(OpenAI規范):

      SK框架:https://api.deepseek.com/v1
      AgentFramework框架:https://api.deepseek.com
      

      5.2 結構化輸出

      namespace STD.AI.Implementations
      {
          public class CompanyInfoQueryAgent : BaseAgentFunction, ICompanyInfoQueryAgent
          {
              private readonly AIAgent _agent;
              private readonly McpClient _mcpClient;
      
              public CompanyInfoQueryAgent(IOptions<LLMConfiguration> config, McpClient mcpClient)
              {
                  _mcpClient = mcpClient ?? throw new ArgumentNullException(nameof(mcpClient));
      
                  var openAIClient = new OpenAIClient(
                      new ApiKeyCredential(config.Value.ApiKey),
                      new OpenAIClientOptions { Endpoint = new Uri(config.Value.Endpoint ?? "https://api.deepseek.com") }
                  );
      
                  // 獲取 chat client(DeepSeek/Azure/OpenAI 的封裝)
                  var chatClient = openAIClient.GetChatClient(config.Value.Model);
      
                  // 從你的 MCP client 獲取工具列表(假設返回 IList<AITool> 或 可轉換的集合)
                  var tools = _mcpClient.ListToolsAsync().GetAwaiter().GetResult()
                                .Cast<AITool>()
                                .ToList();
      
                  JsonElement companySchema = AIJsonUtilities.CreateJsonSchema(typeof(CompanyInfo));
      			//定義規范輸出
                  ChatOptions chatOptions = new()
                  {
                      ResponseFormat = ChatResponseFormat.ForJsonSchema(
                          schema: companySchema,
                          schemaName: nameof(CompanyInfo),
                          schemaDescription: "Structured CompanyInfo output"),
                  };
      
                  chatOptions.Tools = tools;
      
                  var agentOptions = new ChatClientAgentOptions
                  {
                      Name = "CompanyInfoAgent",
                      Instructions = @"你是商業信息采集助手。請使用已注冊的瀏覽器/網頁工具搜索并整合公司信息,嚴格返回符合 CompanyInfo JSON schema 的對象。",
                      Description = "使用 MCP 工具檢索公司公開信息,返回結構化 CompanyInfo。",
                      ChatOptions = chatOptions
                  };
      
                  // 創建 Agent(使用 chatClient 的 CreateAIAgent 重載)
                  _agent = chatClient.CreateAIAgent(agentOptions);
              }
      
              public async Task<CompanyInfo?> QueryCompanyInfoAsync(string companyName)
              {
                  if (string.IsNullOrWhiteSpace(companyName))
                      throw new ArgumentException("公司名稱不能為空", nameof(companyName));
      
                  var thread = _agent.GetNewThread();
      
                  string prompt = $@"
      請使用已注冊的網頁/瀏覽器工具(MCP 工具集合),訪問多個來源(官網、企查查/天眼查、維基/百科、相關新聞等),
      綜合提取公司 ""{companyName}"" 的信息并嚴格返回符合 CompanyInfo 模型的 JSON 對象。";
      
                  var response = await _agent.RunAsync(prompt, thread);
      
                  // 框架內置反序列化(結構化輸出),使用 System.Text.Json Web 選項
                  var company = response.Deserialize<CompanyInfo>(JsonSerializerOptions.Web);
                  return company;
              }
          }
      }
      
      

      RunAsync報錯,經排查DeepseekAPI不支持,但官方文檔是支持JsonFormat type:jsonobject 的
      如有大佬,望告知解惑

      posted @ 2025-11-05 11:55  daibitx  閱讀(526)  評論(4)    收藏  舉報
      主站蜘蛛池模板: 在线无码免费看黄网站| 深夜av在线免费观看| 婷婷六月天在线| 日本亚洲一级中文字幕| 免费吃奶摸下激烈视频| 国产精品自拍视频免费看| 真实国产乱啪福利露脸| 欧美性猛交xxxx乱大交丰满| 国产综合视频精品一区二区| 国产在线精品成人一区二区| 久久综合九色综合久桃花| 欧美日韩国产亚洲沙发| 好吊妞| 亚洲av产在线精品亚洲第一站| 亚洲乱色熟女一区二区蜜臀| 国产欧美日韩va另类在线播放| 麻豆蜜桃av蜜臀av色欲av| 国产av午夜精品福利| 亚洲第一综合天堂另类专| 亚洲国产高清av网站| 久久国产精品老人性| 青青草一区二区免费精品| 极品无码国模国产在线观看| 強壮公弄得我次次高潮A片| 最新亚洲春色av无码专区| 午夜视频免费试看| 免费无码VA一区二区三区| 福利一区二区视频在线| 精品粉嫩国产一区二区三区| 欧美成人www免费全部网站| 免费无遮挡无码视频网站| 国产精品久久久久久久网| 国产片AV国语在线观看手机版| 亚洲av永久无码精品天堂久久| 国产高潮刺激叫喊视频| 无码熟妇人妻av影音先锋| 国产91久久精品成人看| 在线看av一区二区三区| 国产精品 亚洲一区二区三区| 欧美成人一区二区三区不卡| 日韩有码av中文字幕|