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

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

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

      Model Context Protocol(MCP)簡介以及簡單示例代碼測試(.net8)

      〇、前言

      從 2020 年到 2025 年,AI 在多個維度實(shí)現(xiàn)了跨越式發(fā)展。

      從 ChatGPT 到 DeepSeek 等大型語言模型(LLM),以及多模態(tài)融合,從一開始的文本到后續(xù)的圖片、文檔、視頻,還有輔助編程等等,都在說明 AI 不是“未來趨勢”,而是正在重塑開發(fā)方式的“當(dāng)下現(xiàn)實(shí)”。

      因此多接觸一些 AI 方面的知識,變的很有必要。

      那么本文將就 MCP 這一塊,先做下簡單介紹 MCP 是什么,然后通過簡單的示例,來看下怎么用。

      一、MCP 簡介

      1.1 什么是 MCP?

      MCP(Model Context Protocol:模型上下文協(xié)議)是由 Anthropic 于 2024 年 11 月推出的開源協(xié)議,旨在為【大型語言模型(Large Language Model:LLM)】與【外部數(shù)據(jù)源、工具和服務(wù)】提供標(biāo)準(zhǔn)化、安全的雙向通信接口

      MCP 可以將 AI 模型與外部世界的連接簡化為“即插即用”的接口,類似 USB-C 的通用性,避免為每個工具單獨(dú)定制集成方案。

      它可以通過統(tǒng)一協(xié)議,實(shí)現(xiàn) AI 模型與數(shù)據(jù)庫、API、文件系統(tǒng)等的無縫協(xié)作,解決傳統(tǒng)“碎片化集成”的痛點(diǎn)。

      image

      四大優(yōu)勢:

      • 標(biāo)準(zhǔn)化(Standardization)

      MCP 遵循統(tǒng)一的技術(shù)規(guī)范和接口定義,確保不同系統(tǒng)、組件或服務(wù)之間的兼容性。標(biāo)準(zhǔn)化可以帶來的好處:

      降低集成成本:通過定義清晰的數(shù)據(jù)格式(如JSON Schema、Protobuf)、API規(guī)范(如OpenAPI)和通信協(xié)議(如REST、gRPC),MCP使得異構(gòu)系統(tǒng)能夠快速對接。
      提升可維護(hù)性:標(biāo)準(zhǔn)化的接口和日志格式便于監(jiān)控、調(diào)試和團(tuán)隊(duì)協(xié)作。
      促進(jìn)生態(tài)發(fā)展:第三方開發(fā)者可基于標(biāo)準(zhǔn)快速開發(fā)插件或擴(kuò)展,形成豐富的工具鏈。
      類比技術(shù):類似HTTP/REST在Web服務(wù)中的角色,或Kubernetes的CRD(自定義資源定義)標(biāo)準(zhǔn)。

      • 安全性(Security)

      MCP 內(nèi)置多層次安全機(jī)制,保障數(shù)據(jù)傳輸、存儲和訪問控制的安全。好處如下:

      端到端加密:支持TLS/SSL等加密傳輸,防止數(shù)據(jù)泄露。
      身份認(rèn)證與授權(quán):集成OAuth2、JWT、RBAC(基于角色的訪問控制)等機(jī)制,確保只有合法用戶和系統(tǒng)可訪問資源。
      審計(jì)與合規(guī):記錄操作日志,滿足GDPR、等保等法規(guī)要求。
      防御常見攻擊:如防重放攻擊、DDoS緩解、輸入驗(yàn)證等。
      應(yīng)用場景:適用于金融、醫(yī)療等對數(shù)據(jù)隱私要求高的行業(yè)。

      • 靈活性(Flexibility)

      MCP 支持多種部署模式、可擴(kuò)展架構(gòu)和動態(tài)配置,適應(yīng)不同業(yè)務(wù)需求。好處如下:

      模塊化設(shè)計(jì):功能組件可插拔,用戶可根據(jù)需要啟用或替換模塊。
      支持多語言/多框架:提供 SDK 或 API 支持 Python、Java、Go 等多種語言,便于現(xiàn)有系統(tǒng)集成。
      動態(tài)配置與熱更新:無需重啟服務(wù)即可調(diào)整參數(shù)或升級功能。
      適應(yīng)不同規(guī)模:從小型應(yīng)用到大規(guī)模分布式系統(tǒng)均可部署。
      類比架構(gòu):類似于微服務(wù)網(wǎng)關(guān)(如Istio)或消息中間件(如Kafka)的靈活集成能力。

      • 跨平臺(Cross-Platform)

      MCP 可在不同操作系統(tǒng)、硬件架構(gòu)和云環(huán)境中運(yùn)行。

      操作系統(tǒng)兼容:支持 Windows、Linux、macOS、嵌入式 RTOS 等。
      云原生支持:可在 AWS、Azure、阿里云等公有云及私有云環(huán)境中部署,支持容器化(Docker)和編排(k8s)。
      邊緣計(jì)算兼容:可在邊緣設(shè)備(如 IoT 網(wǎng)關(guān))與中心云之間無縫協(xié)同。
      統(tǒng)一管理界面:無論底層平臺如何,提供一致的管理、監(jiān)控和開發(fā)體驗(yàn)。
      技術(shù)基礎(chǔ):通常基于跨平臺運(yùn)行時(如 Java JVM、.NET Core)或輕量級協(xié)議(如 MQTT、CoAP)。

      MCP 通過標(biāo)準(zhǔn)化接口客戶端-服務(wù)器架構(gòu),解決了LLM與外部工具集成的難題。它不僅讓 LLM 能夠訪問本地和遠(yuǎn)程資源,還通過動態(tài)上下文管理和安全機(jī)制,提升了AI應(yīng)用的靈活性和可靠性。

      隨著MCP 生態(tài)的擴(kuò)展,開發(fā)者可以更高效地構(gòu)建智能應(yīng)用,推動AI技術(shù)的實(shí)際落地。

      1.2 核心架構(gòu):Host-Client-Server

      MCP 采用客戶端-服務(wù)器架構(gòu)(Client-Server Architecture),由以下三類組件構(gòu)成:

      • MCP Host(主機(jī))

      它是發(fā)起請求的 AI 應(yīng)用程序,例如聊天機(jī)器人、AI 驅(qū)動的 IDE(如 Cursor)、Claude Desktop 等。

      主要職責(zé):接收用戶輸入,與 LLM 交互生成指令,并在 LLM 需要調(diào)用外部工具時觸發(fā) MCP 流程。

      • MCP Client(客戶端)

      也可以叫做“協(xié)議轉(zhuǎn)換層”,作為 MCP Host 與 MCP Server 之間的橋梁

      主要職責(zé):

      與 MCP Server 建立持久連接(如通過 JSON-RPC 2.0 協(xié)議)。
      將 LLM 的請求翻譯為 MCP 標(biāo)準(zhǔn)格式,并發(fā)送給 MCP Server。
      接收 MCP Server 的響應(yīng),返回給 MCP Host。

      • MCP Server(服務(wù)器)

      也可以叫做“功能提供層”,封裝具體的數(shù)據(jù)源或工具的訪問邏輯。

      主要職責(zé):

      提供標(biāo)準(zhǔn)化的接口,支持訪問本地資源(如文件系統(tǒng)、數(shù)據(jù)庫)或遠(yuǎn)程服務(wù)(如 API、SaaS 平臺)。
      執(zhí)行具體的工具調(diào)用(如查詢數(shù)據(jù)庫、發(fā)送郵件),并返回結(jié)果。

      關(guān)系圖如下:

      image

      1.3 MCP 是如何工作的?

      MCP 的工作流程大概可以分為如下幾個步驟。

      1)建立連接

      MCP Client 與 MCP Server 建立通信連接,通常通過以下方式:

      本地通信(STDIO):適用于同一設(shè)備內(nèi)的進(jìn)程間通信(如 AI 助手調(diào)用本地文件)。
      遠(yuǎn)程通信(HTTP+SSE):適用于跨網(wǎng)絡(luò)訪問遠(yuǎn)程服務(wù)(如調(diào)用云 API)。

      2)資源發(fā)現(xiàn)

      MCP Client 向 MCP Server 查詢可用的工具和數(shù)據(jù)源,獲取其功能描述和接口規(guī)范(如 OpenAPI 文檔)。
      示例:AI 助手需要查詢天氣時,MCP Client 會找到支持天氣查詢的 MCP Server,并獲取其 API 參數(shù)。

      3)工具調(diào)用

      MCP Host(通過 LLM)解析用戶需求,生成調(diào)用外部工具的指令。

      MCP Client 將指令轉(zhuǎn)換為 MCP 標(biāo)準(zhǔn)格式(JSON-RPC 2.0),并發(fā)送給 MCP Server。

      示例:用戶要求“查詢北京的天氣”,LLM 生成調(diào)用天氣 API 的指令,MCP Client 將其發(fā)送到天氣 MCP Server。

      4)數(shù)據(jù)交互

      MCP Server 執(zhí)行具體的工具調(diào)用(如訪問數(shù)據(jù)庫、調(diào)用 API),獲取或更新數(shù)據(jù)。

      安全機(jī)制:MCP Server 通過權(quán)限控制和沙箱機(jī)制,確保 LLM 只能訪問授權(quán)的資源。

      5)結(jié)果返回

      MCP Server 將處理結(jié)果返回給 MCP Client。

      MCP Client 將結(jié)果轉(zhuǎn)換為 LLM 可理解的格式,并傳遞給 MCP Host。

      MCP Host 將結(jié)果呈現(xiàn)給用戶或用于后續(xù)處理。

      這過程中涉及到的通信協(xié)議主要有三種:

      1)JSON-RPC 2.0 輕量級、跨語言支持,適合遠(yuǎn)程過程調(diào)用(RPC)

      {
        "jsonrpc": "2.0",
        "method": "get_weather",
        "params": {"location": "Beijing"},
        "id": 1
      }

      2)SSE(Server-Sent Events)支持服務(wù)器向客戶端的流式推送,適合實(shí)時數(shù)據(jù)交互。

      應(yīng)用場景:長輪詢天氣更新、實(shí)時日志輸出。

      3)STDIO(標(biāo)準(zhǔn)輸入輸出)適用于本地進(jìn)程間通信,延遲低。

      應(yīng)用場景:AI助手讀寫本地文件或調(diào)用本地工具。

      二、Windows 環(huán)境,基于 Ollama 和 .net 的簡單示例

      2.1 Ollama 的安裝和大模型下載

      • 簡介

      Ollama 是一個開源的本地大模型運(yùn)行框架,旨在讓開發(fā)者能夠在本地機(jī)器上輕松地運(yùn)行、管理和使用大型語言模型(LLM)。它支持多種主流模型架構(gòu)(如 Llama、Qwen、Mistral、Gemma、Phi 等),提供簡潔的命令行接口(CLI)和 REST API,便于集成到應(yīng)用中。

      其核心特點(diǎn):

      本地運(yùn)行:所有模型都在你的設(shè)備上運(yùn)行,保護(hù)數(shù)據(jù)隱私。
      輕量高效:優(yōu)化了模型加載和推理性能,支持 GPU 加速(CUDA、Metal 等)。
      簡單易用:通過簡單的 ollama run 命令即可下載并運(yùn)行模型。
      跨平臺支持:支持 macOS、Linux 和 Windows。
      可定制化:支持自定義模型參數(shù)、創(chuàng)建 Modelfile 定制提示詞、上下文長度等。

      • 下載和安裝

      官網(wǎng)下載地址https://ollama.com/download然后雙擊開始安裝即可。

      // 查看是否安裝成功
      // 命令行執(zhí)行 -v:
      C:\Windows\system32>ollama -v
      ollama version is 0.12.0
      
      // 使用 run 命令可以安裝和運(yùn)行指定模型
      // 首次運(yùn)行時會自動從 Ollama 的模型庫下載 qwen:7b 模型文件
      // 文件約 4-5 GB,具體大小取決于量化版本,需要穩(wěn)定的網(wǎng)絡(luò)連接
      C:\Windows\system32>ollama run qwen:7b
      
      // 查看已安裝模型
      C:\Windows\system32>ollama list
      NAME       ID              SIZE      MODIFIED
      qwen:7b    2091ee8c8d8f    4.5 GB    3 days ago
      
      // 運(yùn)行模型
      C:\Windows\system32>ollama run qwen:7b
      >>> 你是誰?
      我是阿里云研發(fā)的大規(guī)模語言模型,我叫通義千問。
      >>> Send a message (/? for help)
      • 可調(diào)用的 API

      Ollama 提供了一組簡潔但功能完整的 RESTful API,用于與本地運(yùn)行的大模型進(jìn)行交互。這些 API 默認(rèn)運(yùn)行在 http://localhost:11434 地址上,支持外部程序調(diào)用,實(shí)現(xiàn)模型推理、管理、生成等功能。

      以下是 Ollama 中可供外部調(diào)用的主要 API 接口及特點(diǎn):

      API 地址 方法 主要用途 是否流式 適用場景
      /api/generate POST 單輪文本生成 ? 支持 內(nèi)容生成、簡單問答
      /api/chat POST 多輪對話生成 ? 支持 聊天機(jī)器人、對話系統(tǒng)
      /api/embeddings POST 文本向量化 ? 不支持 RAG、語義搜索
      /api/tags GET 列出模型 ? 模型管理前端展示
      /api/create POST 創(chuàng)建自定義模型 ?(進(jìn)度流) 模型定制
      /api/delete POST 刪除模型 ? 清理資源
      /api/show POST 查看模型詳情 ? 調(diào)試、集成配置

      2.2 簡單調(diào)用示例(.net 8.0)【完整代碼】【使用舊版的大模型:qwen:7b】

      首先安裝包:ModelContextProtocolServer.Sse。如下包簡介:

      ??image

      2.2.1 服務(wù)端代碼

      注意:博主在嘗試通過屬性:McpServerTool,來自動獲取 tool 列表時沒有成功,因此直接從 Controller 中通過代碼獲取。

      // Program.cs
      var builder = WebApplication.CreateBuilder(args);
      // Add services to the container.
      // 添加 MCP 服務(wù)器服務(wù)
      builder.Services.AddMcpServer().WithToolsFromAssembly(); // 自動注冊當(dāng)前程序集中的工具
      builder.Services.AddMcpServer().WithHttpTransport();
      builder.Services.AddControllers();
      builder.Services.AddEndpointsApiExplorer();
      
      var app = builder.Build();
      app.UseHttpsRedirection();
      
      app.MapGet("/", () => "MCP Time Server is running!");
      app.MapMcp(); // 映射 MCP 端點(diǎn)
      
      app.UseAuthorization();
      app.MapControllers();
      app.Run();
      // TimeTool.cs
      using ModelContextProtocol.Server;
      using System.ComponentModel;
      
      namespace McpTimeServer.Tools;
      
      [McpServerToolType, Description("Time-related tools")]
      public static class TimeTool
      {
          [McpServerTool, Description("Get the current time for a city")]
          public static string GetCurrentTime([Description("The name of the city")] string city)
          {
              // 簡化邏輯,直接返回當(dāng)前時間,僅供測試用
              var now = DateTime.Now;
              return @$"{{""result"":""The current time in {city} is {now:HH:mm} on {now:yyyy-MM-dd}.""}}";
          }
      }
      // McpController.cs
      using Microsoft.AspNetCore.Mvc;
      using ModelContextProtocol.Server;
      using System.ComponentModel;
      using System.Reflection;
      using System.Text.Json;
      
      namespace McpTimeServer;
      
      [ApiController]
      [Route("[controller]")]
      public class McpController : ControllerBase
      {
          private readonly Dictionary<string, ToolInfo> _registeredTools;
          public McpController()
          {
              _registeredTools = DiscoverTools();
          }
          /// <summary>
          /// GET: /mcp/tools - 返回所有可用工具的元數(shù)據(jù)
          /// </summary>
          [HttpGet("tools")]
          public IActionResult GetTools()
          {
              var tools = _registeredTools.Values.Select(t => new
              {
                  name = t.Name,
                  description = t.Description,
                  inputSchema = t.InputSchema
              });
              return Ok(tools);
          }
          /// <summary>
          /// POST: /mcp/invoke - 調(diào)用指定工具
          /// </summary>
          [HttpPost("invoke")]
          public async Task<IActionResult> InvokeTool([FromBody] JsonElement body)
          {
              if (!body.TryGetProperty("name", out var nameElement) || nameElement.ValueKind != JsonValueKind.String)
                  return BadRequest(new { error = "Invalid or missing 'name' in request." });
              var toolName = nameElement.GetString()!;
              if (!_registeredTools.TryGetValue(toolName, out var tool))
                  return NotFound(new { error = $"Tool '{toolName}' not found." });
              JsonElement js = new JsonElement();
              // 提取 arguments
              var arguments = body.TryGetProperty("arguments", out var args) ? args : js;
              try
              {
                  JsonElement actualArguments;
                  if (arguments.ValueKind == JsonValueKind.String)
                  {
                      // 如果是字符串,嘗試解析它為 JSON
                      string jsonString = arguments.GetString();
                      using JsonDocument innerDoc = JsonDocument.Parse(jsonString);
                      actualArguments = innerDoc.RootElement.Clone(); // Clone 以脫離 document 生命周期
                  }
                  else
                  {
                      actualArguments = arguments;
                  }
                  // 綁定參數(shù)并調(diào)用
                  var methodArgs = BindArguments(tool.Method, actualArguments);
                  var result = tool.Method.Invoke(null, methodArgs); // 靜態(tài)方法,實(shí)例為 null
                  return Ok(result ?? "null");
              }
              catch (TargetInvocationException ex)
              {
                  return StatusCode(500, new { error = "Tool execution failed.", message = ex.InnerException?.Message });
              }
              catch (Exception ex)
              {
                  return StatusCode(500, new { error = "Tool binding failed.", message = ex.Message });
              }
          }
          /// <summary>
          /// 工具列表
          /// </summary>
          /// <returns></returns>
          private Dictionary<string, ToolInfo> DiscoverTools()
          {
              var tools = new Dictionary<string, ToolInfo>();
              var assemblies = AppDomain.CurrentDomain.GetAssemblies();
              foreach (var assembly in assemblies)
              {
                  try
                  {
                      var types = assembly.GetTypes()
                          .Where(t => t.IsDefined(typeof(McpServerToolTypeAttribute), false) && t.IsAbstract && t.IsSealed); // 靜態(tài)類
      
                      foreach (var type in types)
                      {
                          var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static)
                              .Where(m => m.IsDefined(typeof(McpServerToolAttribute), false));
                          foreach (var method in methods)
                          {
                              var attr = method.GetCustomAttribute<McpServerToolAttribute>()!;
                              var description = method.GetCustomAttribute<DescriptionAttribute>()?.Description ?? "No description.";
                              var name = attr.Name ?? method.Name;
      
                              var inputSchema = GenerateInputSchema(method);
      
                              tools[name] = new ToolInfo
                              {
                                  Name = name,
                                  Method = method,
                                  Description = description,
                                  InputSchema = inputSchema
                              };
                          }
                      }
                  }
                  catch(Exception ex)
                  {            }
              }
              return tools;
          }
          private object[] BindArguments(MethodInfo method, JsonElement arguments)
          {
              var parameters = method.GetParameters();
              var args = new object?[parameters.Length];
              for (int i = 0; i < parameters.Length; i++)
              {
                  try
                  {
                      var param = parameters[i];
                      string paramName = param.Name==null?"": param.Name.ToLower().ToString();
      
                      if (arguments.TryGetProperty(paramName, out var valueElement))
                      {
                          args[i] = valueElement.ValueKind switch
                          {
                              JsonValueKind.String => valueElement.GetString(),
                              JsonValueKind.Number when param.ParameterType == typeof(int) => valueElement.GetInt32(),
                              JsonValueKind.Number when param.ParameterType == typeof(double) => valueElement.GetDouble(),
                              JsonValueKind.True or JsonValueKind.False => valueElement.GetBoolean(),
                              _ => valueElement.GetRawText() // fallback
                          };
                      }
                      else if (param.HasDefaultValue)
                      {
                          args[i] = param.DefaultValue;
                      }
                      else
                      {
                          throw new ArgumentException($"Missing required parameter: {param.Name}");
                      }
                  }
                  catch(Exception ex)
                  {            }
              }
              return args;
          }
          private object GenerateInputSchema(MethodInfo method)
          {
              var properties = new Dictionary<string, object>();
              var required = new List<string>();
      
              foreach (var param in method.GetParameters())
              {
                  var paramName = param.Name!.ToLower();
                  var description = param.GetCustomAttribute<DescriptionAttribute>()?.Description ?? "";
                  properties[paramName] = new
                  {
                      type = "string", // 簡化:所有參數(shù)視為 string
                      description
                  };
                  if (!param.HasDefaultValue)
                      required.Add(paramName);
              }
              return new
              {
                  type = "object",
                  properties,
                  required = required.Count > 0 ? required : (object)Array.Empty<string>()
              };
          }
      }
      // 工具元數(shù)據(jù)
      internal class ToolInfo
      {
          public required string Name { get; init; }
          public required MethodInfo Method { get; init; }
          public required string Description { get; init; }
          public required object InputSchema { get; init; }
      }
      // 請求體
      public class InvokeToolRequest
      {
          public string? Name { get; set; }
          public JsonElement Arguments { get; set; }
      }

      2.2.2 客戶端代碼

      // Program.cs
      using McpClientApp.Models;
      using Newtonsoft.Json;
      using System;
      using System.Net.Http;
      using System.Net.Http.Json;
      using System.Text;
      using System.Text.Json;
      using System.Text.Json.Serialization;
      using System.Threading.Tasks;
      
      // .NET 8 頂級語句:無需 class/Program/main
      Console.WriteLine("MCP Client with Qwen (via Ollama) - .NET 8 - Type 'exit' to quit");
      
      // 創(chuàng)建 HttpClient (生產(chǎn)環(huán)境建議使用 IHttpClientFactory)
      using var httpClient = new HttpClient();
      
      while (true)
      {
          Console.Write("\nYou: ");
          var userQuestion = Console.ReadLine();
          if (string.IsNullOrWhiteSpace(userQuestion) || userQuestion.ToLower() == "exit")
              break;
          await ProcessQuestionAsync(userQuestion, httpClient);
      }
      
      async Task ProcessQuestionAsync(string userQuestion, HttpClient client)
      {
          const string ollamaUrl = "http://localhost:11434/api/chat";
          const string mcpServerUrl = "http://localhost:5113";
          // 1. 動態(tài)獲取工具列表并生成提示詞
          var systemPrompt = await GetAvailableToolsAsync(client, mcpServerUrl);
          // 2. 調(diào)用 Ollama (Qwen)
          object[] messages =[
              new { role = "system", content = systemPrompt },
              new { role = "user", content = userQuestion }
          ];
          var ollamaResponse = await CallOllamaAsync("qwen:7b", messages, client, ollamaUrl);
          if (string.IsNullOrEmpty(ollamaResponse))
          {
              Console.WriteLine("Error: No response from Ollama.");
              return;
          }
          Console.WriteLine($"LLM Export: {ollamaResponse}");
          // 3. 嘗試解析為工具調(diào)用
          try
          {
              ollamaResponse = ollamaResponse.Replace("}}}", "}}");
              using var jsonDoc = JsonDocument.Parse(ollamaResponse);
              var root = jsonDoc.RootElement;
              if (root.TryGetProperty("tool", out var toolElement) &&
                  root.TryGetProperty("arguments", out var argsElement))
              {
                  var toolName = toolElement.GetString();
                  var argumentsJson = argsElement.GetRawText(); // 保持原始 JSON 字符串
                  Console.WriteLine($"Calling MCP tool: {toolName} with {argumentsJson}");
                  // 4. 調(diào)用 MCP 服務(wù)端
                  var toolResult = await InvokeMcpToolAsync(toolName, argumentsJson, client, mcpServerUrl);
                  // 5. 讓 LLM 生成最終回復(fù)
                  object[] finalMessages = [
                      new { role = "system", content = "You are a helpful assistant." },
                      new { role = "user", content = userQuestion },
                      new { role = "assistant", content = ollamaResponse },
                      new { role = "tool", content = toolResult } // MCP 工具結(jié)果
                  ];
                  var finalResponse = await CallOllamaAsync("qwen:7b", finalMessages, client, ollamaUrl);
                  Console.WriteLine($"Final Answer(MCP): {finalResponse}");
                  return;
              }
          }
          catch (Exception ex)
          {
              // 不是有效的 JSON,說明是直接回答
          }
          // 直接回答
          Console.WriteLine($"Answer(No MCP): {ollamaResponse}");
      }
      
      // 【調(diào)用 Ollama API】
      async Task<string> CallOllamaAsync(string model, object[] messages, HttpClient client, string ollamaUrl)
      {
          var payload = new
          {
              model,
              messages,
              stream = false
          };
          var response = await client.PostAsJsonAsync(ollamaUrl, payload);
          response.EnsureSuccessStatusCode();
          var jsonResponse = await response.Content.ReadFromJsonAsync<JsonElement>();
          // ValueKind = Object : "{"model":"qwen:7b","created_at":"2025-09-24T11:53:43.645783Z","message":{"role":"assistant","content":"{\"tool\": \"GetCurrentTime\", \"arguments\": {\"city\": \"London\"}}}"},"done":true,"done_reason":"stop","total_duration":2392332700,"load_duration":47250000,"prompt_eval_count":112,"prompt_eval_duration":176531800,"eval_count":18,"eval_duration":2167583600}"
          return jsonResponse.GetProperty("message").GetProperty("content").ToString().Replace("\n","");
      }
      
      // 【調(diào)用 MCP 服務(wù)端工具】
      async Task<string> InvokeMcpToolAsync(string toolName, string argumentsJson, HttpClient client, string mcpServerUrl)
      {
          var payload = new { name = toolName, argumentsJson };
          var json = System.Text.Json.JsonSerializer.Serialize(payload);
          var content = new StringContent(json, Encoding.UTF8, "application/json");
          var response = await client.PostAsync($"{mcpServerUrl.TrimEnd('/')}/mcp/invoke", content);
          if (!response.IsSuccessStatusCode)
          {
              var error = await response.Content.ReadAsStringAsync();
              throw new Exception($"MCP tool call failed: {error}");
          }
          var jsonResponse = await response.Content.ReadFromJsonAsync<JsonElement>();
          return jsonResponse.TryGetProperty("result", out var result) ? result.GetString()! : "No result returned(Calling MCP).";
      }
      // 【獲取全部可用的 MCP 工具】
      async Task<string> GetAvailableToolsAsync(HttpClient client, string mcpServerUrl)
      {
          try
          {
              var response = await client.GetStringAsync($"{mcpServerUrl.TrimEnd('/')}/mcp/tools");
              var tools = System.Text.Json.JsonSerializer.Deserialize<McpTool[]>(response);
              if (tools == null || tools.Length == 0)
                  return "No tools available.";
              // 動態(tài)生成工具描述
              var toolDescriptions = string.Join("\n", tools.Select(t =>
              {
                  var paramsText = string.Join(",", t.InputSchema.Required);
                  //return $"- {t.Name}({paramsText}): {t.Description}";
                  //return $"- {t.Name}: {t.Description}";
                  return $@"- {t.Name}({paramsText}): {t.Description}
                  If you need to use a tool, respond with a JSON object in this exact format:
                  {{""tool"": ""{t.Name}"", ""arguments"": {{""{paramsText}"": ""value""}}}}";
              }));
              return @$"""
                  You can use these external tools:
                  {toolDescriptions}
                  Only output the JSON when calling a tool. Otherwise, answer normally.
                  """;
          }
          catch (Exception ex)
          {
              Console.WriteLine($"Warning: Could not fetch tools from MCP server: {ex.Message}");
              return "No external tools available."; // 降級:不啟用工具調(diào)用
          }
      }
      // Mcptool.cs
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Text.Json.Serialization;
      using System.Threading.Tasks;
      
      namespace McpClientApp.Models
      {
          // 根對象:工具列表
          public class McpTool
          {
              [JsonPropertyName("name")]
              public string Name { get; set; }
      
              [JsonPropertyName("description")]
              public string Description { get; set; }
      
              [JsonPropertyName("inputSchema")]
              public InputSchema InputSchema { get; set; }
          }
      
          // inputSchema 對象
          public class InputSchema
          {
              [JsonPropertyName("type")]
              public string Type { get; set; } // 通常是 "object"
      
              [JsonPropertyName("properties")]
              public Dictionary<string, SchemaProperty> Properties { get; set; }
      
              [JsonPropertyName("required")]
              public string[] Required { get; set; }
          }
      
          // 屬性定義(如 city)
          public class SchemaProperty
          {
              [JsonPropertyName("type")]
              public string Type { get; set; } // string, number, boolean 等
      
              [JsonPropertyName("description")]
              public string Description { get; set; }
          }
      }

      2.2.3 測試結(jié)果

      You: 你是誰?
      LLM Export: 我是阿里云研發(fā)的一款超大規(guī)模語言模型,我叫通義千問。
      Answer(No MCP): 我是阿里云研發(fā)的一款超大規(guī)模語言模型,我叫通義千問。
      
      You: 現(xiàn)在北京時間是多少?
      LLM Export: { "tool": "GetCurrentTime", "arguments": { "city": "北京" } }
      Calling MCP tool: GetCurrentTime with { "city": "北京" }
      Final Answer(MCP):  根據(jù)當(dāng)前系統(tǒng),北京時間是:2023-3-16 15:48:19 但請注意,這可能不是一個準(zhǔn)確的實(shí)時時間,因?yàn)槲以谔幚?請求時的時間可能會有些延遲。建議您通過官方時間服務(wù)或手機(jī)自帶的時間同步功能獲取最精確的時間信息。

      注意:針對本示例中使用的大模型"qwen:7b",輸出并不穩(wěn)定,存在本地時間返回異常情況,僅供理解思路吧。后續(xù)博主還會繼續(xù)測試,逐步優(yōu)化。

      2.3 使用新版的千問大模型測試:qwen3:8b【推薦使用】

      • 為什么要使用新版的大模型?

      對比舊版的大模型,新版的輸出就比較穩(wěn)定了。

      另外新版大模型在接口調(diào)用中返回了<think>標(biāo)簽內(nèi)容,標(biāo)識每次都會對指令進(jìn)行分析,所得出的結(jié)果也比較準(zhǔn)確。

      You: 現(xiàn)在北京時間是多少?
      LLM Export: <think>好的,用戶問現(xiàn)在北京時間是多少。我需要用 GetCurrentTime 工具來獲取。工具的參數(shù)是城市,所以我要指定城 市為北京。然后按照要求返回JSON對象,調(diào)用工具。確保格式正確,不添加其他內(nèi)容。檢查一下參數(shù)是否正確,城市名稱是否準(zhǔn)確。確認(rèn)無誤后生成響應(yīng)。</think>{"tool": "GetCurrentTime", "arguments": {"city": "北京"}}
      Calling MCP tool: GetCurrentTime with {"city": "北京"}
      Calling MCP toolResult: The current time in  is 13:50 on 2025-09-30.
      Final Answer(MCP): <think>好的,用戶之前問了北京時間,我調(diào)用了GetCurrentTime工具,參數(shù)是北京。現(xiàn)在工具返回了結(jié)果,顯示當(dāng)前時間是2025年9月30日13:50。需要確認(rèn)返回的格式是否正確,有沒有錯誤。用戶可能是在確認(rèn)時間,或者有安排需要知道準(zhǔn)確時間。可能用戶所在時區(qū)不同,需要明確是北京時間。另外,檢查日期和時間是否正確,確保沒有時區(qū)錯誤。然后用自然的中文回復(fù)用戶,保持簡潔。比如直接告訴用戶當(dāng)前北京時間是13:50,日期是2025年9月30日。不需要額外信息,除非用戶有進(jìn)一步問題。確保回答清晰準(zhǔn)確。</think>當(dāng)前北京時間是2025年9月30日13:50。

      其中,最終的輸出為:Final Answer(MCP):

      <think>好的,用戶之前問了北京時間,我調(diào)用了GetCurrentTime工具,參數(shù)是北京。現(xiàn)在工具返回了結(jié)果,顯示當(dāng)前時間是2025年9月30日13:50。需要確認(rèn)返回的格式是否正確,有沒有錯誤。用戶可能是在確認(rèn)時間,或者有安排需要知道準(zhǔn)確時間。可能用戶所在時區(qū)不同,需要明確是北京時間。另外,檢查日期和時間是否正確,確保沒有時區(qū)錯誤。然后用自然的中文回復(fù)用戶,保持簡潔。比如直接告訴用戶當(dāng)前北京時間是13:50,日期是2025年9月30日。不需要額外信息,除非用戶有進(jìn)一步問題。確保回答清晰準(zhǔn)確。</think>當(dāng)前北京時間是2025年9月30日13:50。

      前一段為思考過程,后邊為實(shí)際返回的結(jié)果。

      • 代碼中要調(diào)整的內(nèi)容

      具體的代碼可以查看上一章節(jié),此處不再贅述,只需調(diào)整其中的兩點(diǎn):

      1)在第三步,得到大模型第一次返回后,解析返回結(jié)果時,要先把思考內(nèi)容剔除,如下:

      // 3. 嘗試解析為工具調(diào)用
      var res_arr = ollamaResponse.Split("</think>");
      using var jsonDoc = JsonDocument.Parse(res_arr[1]);

      2)把代碼中的模型版本換成新的:qwen3:8b

      • 在 ollama 中安裝新版大模型
      // 在 ollama 中安裝
      C:\Users>ollama pull qwen3:8b
      // 查看已安裝的大模型
      C:\Users>ollama list
      NAME                    ID              SIZE      MODIFIED
      qwen3:8b                500a1f067a9f    5.2 GB    1 hours ago
      qwen:7b                 2091ee8c8d8f    4.5 GB    1 days ago
      // 運(yùn)行新版模型嘗試對話
      C:\Users>ollama run qwen3:8b
      >>> 你是誰?
      Thinking...
      嗯,用戶問我是誰,這應(yīng)該是一個常見的問題。首先,我需要確認(rèn)用戶是想了解我的基本身份,還是有更深層次的需求。可能用戶剛
      接觸這個系統(tǒng),或者對我的功能不太清楚。
      
      接下來,我應(yīng)該簡要介紹我的身份,比如我是通義千問,由通義實(shí)驗(yàn)室研發(fā),基于大規(guī)模語言模型。同時,要強(qiáng)調(diào)我的功能,比如回
      答問題、創(chuàng)作文字、編程等,這樣用戶能了解我的用途。
      
      還要注意用戶的潛在需求,比如他們可能想知道我是否可靠,或者是否有特定的功能需要使用。這時候可以提到我的訓(xùn)練數(shù)據(jù)和應(yīng)用
      場景,讓用戶更放心。
      
      另外,用戶可能沒有明確說明他們需要什么幫助,所以主動詢問是否需要進(jìn)一步協(xié)助是個好主意。這樣既能提供幫助,又能引導(dǎo)用戶
      更具體地表達(dá)需求。
      
      最后,保持回答簡潔明了,避免使用過于專業(yè)的術(shù)語,讓用戶容易理解。同時,保持友好和專業(yè)的語氣,讓用戶感到舒適和信任。
      ...done thinking.
      
      我是通義千問,由通義實(shí)驗(yàn)室研發(fā)的超大規(guī)模語言模型。我能夠回答問題、創(chuàng)作文字、編程、邏輯推理以及多語言理解等。我的訓(xùn)練
      數(shù)據(jù)來自互聯(lián)網(wǎng)上的大量文本,能夠理解和生成多種語言的內(nèi)容。如果你有任何問題或需要幫助,歡迎隨時告訴我!需要我?guī)湍阕鲂?什么嗎?
      
      >>> Send a message (/? for help)

      MCP C# 示例參考:http://www.rzrgm.cn/edisontalk/p/-/introduction-to-mcp-csharp-sdk

      posted @ 2025-09-29 20:06  橙子家  閱讀(582)  評論(2)    收藏  舉報(bào)
      主站蜘蛛池模板: 熟妇人妻激情偷爽文| 亚洲午夜成人精品电影在线观看| 久久国产成人午夜av影院| 久久人人爽爽人人爽人人片av| 国产人成777在线视频直播| 亚洲精品宾馆在线精品酒店| 人妻在线中文字幕| 久久99精品中文字幕在| 亚洲成人av免费一区| 亚洲v欧美v日韩v国产v| 国产午夜精品理论大片| 日韩精品卡一卡二卡三卡四| 爽爽精品dvd蜜桃成熟时电影院 | 国产乱子伦一区二区三区四区五区| a4yy私人毛片| 国产精品视频第一第二区| 亚洲欧美国产精品专区久久| 久久成人 久久鬼色| 欧美大bbbb流白水| 瑞安市| 亚洲热视频这里只有精品| 99精品热在线在线观看视| 黑人好猛厉害爽受不了好大撑| 性欧美欧美巨大69| 国产在线观看黄| 强奷乱码欧妇女中文字幕熟女| 无码专区 人妻系列 在线| 在线中文一区字幕对白| 成人综合人人爽一区二区| 热久久美女精品天天吊色| 日韩国产欧美精品在线| 午夜福利国产精品视频| 国产成人久久777777| 97人人添人澡人人爽超碰| 青草国产超碰人人添人人碱| 2019久久久高清日本道| 亚洲综合视频一区二区三区| 少妇人妻偷人精品视频| 欧美成人精品| 亚洲男女一区二区三区| 精品国产精品中文字幕|