C#实现MCP Client 与 LLM 连接,抓取网页内容功能!

该专栏优先在飞书发布,欢迎收藏关注!

https://www.feishu.cn/community/article?id=7507084665509904403

前面的课程,我们已经用C#实现了,自己的MCP Client。

下面我们一起来实现,MCP Client与LLM 对接。

一、添加依赖库

目前来说,绝大部分的大模型的API,都是遵循OpenAI的接口规范。

Microsoft.Extensions.AI 是微软官方提供的一套 统一的 AI 抽象层 ,大大简化 AI 模型在 .NET 应用中的集成。

添加依赖库:Microsoft.Extensions.AI.OpenAI,版本为:最新预发行版 9.4.4-preview.1.25259.16**,添加的时候记得勾选:包括预发行版。**

图片

添加依赖库:Microsoft.Extensions.AI,版本为:9.4.4-preview.1.25259.16。

图片

二、OpenAI 客户端实现

新增文件:ChatAIClient

图片

2.1 初始化OpenAI客户端


初始化OpenAI客户端,并使用UseFunctionInvocation 来增强客户端, 这里启用函数调用。

备注:以下代码涉及的秘钥,记得替换为自己的。

using Microsoft.Extensions.AI;
using OpenAI;
using System.ClientModel;
namespace MCPClient
{/// <summary>/// 表示一个用于与 AI 聊天模型交互的客户端封装类。/// 负责初始化聊天客户端并维护对话上下文。/// </summary>public class ChatAIClient{/// <summary>/// 封装后的 AI 聊天客户端接口,支持函数调用等功能。/// </summary>private IChatClient ChatClient;/// <summary>/// 存储当前会话中的所有聊天消息记录。/// </summary>private IList<ChatMessage> Messages;/// <summary>/// API 访问密钥,用于身份认证。【记得替换为自己的】/// </summary>private const string _apiKey = "6092598c-ce00-48fd-a5be-0d758088c888";/// <summary>/// AI 服务的基础请求地址。【记得替换为自己的】/// </summary>private const string _baseURL = "https://api-inference.modelscope.cn/v1/";/// <summary>/// 使用的 AI 模型标识符。【记得替换为自己的】/// </summary>private const string _modelID = "Qwen/Qwen2.5-72B-Instruct";/// <summary>/// 初始化一个新的 <see cref="ChatAIClient"/> 实例。/// 构造函数中自动完成聊天客户端的初始化配置。/// </summary>public ChatAIClient(){InitIChatClient();}/// <summary>/// 初始化内部使用的 AI 聊天客户端实例。/// 配置 API 凭证、服务端点,并构建具备函数调用能力的客户端。/// 同时初始化系统消息作为对话起点。/// </summary>private void InitIChatClient(){// 创建 API 密钥凭证ApiKeyCredential apiKeyCredential = new ApiKeyCredential(_apiKey);// 设置 OpenAI 客户端选项,如自定义服务端点OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();openAIClientOptions.Endpoint = new Uri(_baseURL);// 创建 OpenAI 客户端并获取指定模型的聊天接口var openaiClient = new OpenAIClient(apiKeyCredential, openAIClientOptions).GetChatClient(_modelID).AsIChatClient();// 构建增强功能的聊天客户端(例如启用函数调用)ChatClient = new ChatClientBuilder(openaiClient).UseFunctionInvocation().Build();// 初始化对话历史,包含一条系统提示信息Messages =[// 添加系统角色消息new(ChatRole.System, "您是一位乐于助人的助手,帮助我们测试MCP服务器功能,优先使用中文回答!"),];}}
}

2.2 处理用户的自然语言查询


ChatAIClient文件,添加如下代码,实现与 AI 模型交互,并传入 MCP 工具。

/// <summary>
/// 异步处理用户的自然语言查询,并与 AI 模型进行交互,支持 MCP 工具调用。
/// </summary>
/// <param name="query">用户的自然语言查询内容</param>
/// <param name="tools">可用的 MCP 工具列表,用于扩展 AI 的外部能力</param>
/// <returns>AI 返回的最终文本响应结果</returns>
public async Task<string> ProcessQueryAsync(string query, IList<McpClientTool> tools)
{// 如果消息历史为空,则初始化系统提示消息if (Messages.Count == 0){Messages = [new(ChatRole.System, "您是一位乐于助人的助手,帮助我们测试MCP服务器功能,优先使用中文回答!")];}// 添加用户输入的消息到对话历史Messages.Add(new(ChatRole.User, query));// 设置请求选项,注入可用工具var options = new ChatOptions{Tools = [.. tools]};// 调用 AI 客户端获取响应var response = await ChatClient.GetResponseAsync(Messages, options);// 将 AI 响应加入对话历史Messages.AddMessages(response);// 输出调用的工具信息OutputToolUsageInfo(response);// 返回模型生成的文本响应return response.Text;
}

2.3 MCP 工具使用情况日志


ChatAIClient文件,添加如下代码,输出 AI 调用MCP 工具的情况。

 /// <summary>/// 辅助方法:输出 AI 在响应中调用的工具信息到控制台。/// </summary>/// <param name="response">来自 AI 的完整响应对象</param>private void OutputToolUsageInfo(ChatResponse response){// 获取所有 Tool 角色的消息var toolUseMessages = response.Messages.Where(m => m.Role == ChatRole.Tool).ToList();// 判断是否调用了工具// 获取响应中所有角色为 Tool 的消息(即 AI 调用了哪些工具)var toolUseMessage = response.Messages.Where(m => m.Role == ChatRole.Tool);// 判断第一条消息的内容是否多于一个(通常第一个消息是用户问题,第二个是调用函数)if (response.Messages[0].Contents.Count > 1){// 尝试从第一条消息的第二个内容项提取出函数调用信息var functionCall = (FunctionCallContent)response.Messages[0].Contents[1];// 设置控制台输出颜色为绿色,用于突出显示工具调用信息Console.ForegroundColor = ConsoleColor.Green;string arguments = "";// 如果函数调用包含参数,则拼接参数信息if (functionCall.Arguments != null){foreach (var arg in functionCall.Arguments){arguments += $"{arg.Key}:{arg.Value};";}// 输出调用的方法名及参数信息Console.WriteLine($"调用方法名:{functionCall.Name};参数信息:{arguments}");// 遍历所有 Tool 消息,输出每个工具调用的结果foreach (var message in toolUseMessage){// 提取工具调用后的执行结果var functionResultContent = (FunctionResultContent)message.Contents[0];Console.WriteLine($"调用工具结果:{functionResultContent.Result}");}// 恢复控制台默认颜色(白色)Console.ForegroundColor = ConsoleColor.White;}else{// 如果没有参数Console.WriteLine("工具参数为空");}}else{Console.ForegroundColor = ConsoleColor.Green;Console.WriteLine("本次没有调用工具");Console.ForegroundColor = ConsoleColor.White;}}
}

三、为LLM添加工具能力

在前面课程基础之上,在Program.cs添加代码。

图片

**代码说明:**为LLM添加工具能力,并处理客户提交的内容。

// 创建聊天客户端实例
ChatAIClient chatAIClient = new ChatAIClient();
// 进入主循环,持续接收用户输入直到输入 "exit"
while (true)
{try{// 设置控制台文字颜色为黄色,提示用户输入问题Console.ForegroundColor = ConsoleColor.Yellow;Console.Write("\n提问: ");// 读取用户输入并去除前后空格,若为空则赋默认空字符串string query = Console.ReadLine()?.Trim() ?? string.Empty;// 判断用户是否输入 "exit" 以退出程序if (query.ToLower() == "exit"){break;}// 调用异步方法处理用户查询,并传入预定义的工具列表(listToolsResult)string response = await chatAIClient.ProcessQueryAsync(query, listToolsResult);// 设置输出颜色为黄色,显示 AI 的响应内容Console.ForegroundColor = ConsoleColor.Yellow;Console.WriteLine($"AI:{response}");// 恢复控制台默认颜色(白色)Console.ForegroundColor = ConsoleColor.White;}catch (Exception ex){// 捕获所有异常并输出错误信息,防止程序崩溃Console.WriteLine($"\nError: {ex.Message}");}
}

四、测试效果

===

启动项目,并输入以下内容:

抓取 https://blog.csdn.net/daremeself/article/details/147166987 的内容,并markdown格式输出

调用MCP Server的工具的情况日志。

图片

AI响应的结果:

图片

好了,今天就分享到这边!

下一个课程:实现自己的MCP Server。

**文中示例代码:**https://pan.quark.cn/s/b5b8853200f9

- End -

推荐阅读

VS Code + Cline + 魔搭MCP Server 实现抓取网页内容。

C#实现自己的MCP Client

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81220.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

并发编程(6)

指令重排序 指令重排序是指在程序执行过程中&#xff0c;为了提高性能&#xff0c;编译器或处理器会对指令的执行顺序进行重新排列。 指令重排序导致可见性消失 在多线程环境下&#xff0c;每个线程都有自己的工作内存&#xff0c;线程对变量的操作是在工作内存中进行的&…

鸿蒙仓颉开发语言实战教程:页面跳转和传参

前两天分别实现了商城应用的首页和商品详情页面&#xff0c;今天要分享新的内容&#xff0c;就是这两个页面之间的相互跳转和传递参数。 首先我们需要两个页面。如果你的项目中还没有第二个页面&#xff0c;可以右键cangjie文件夹新建仓颉文件&#xff1a; 新建的文件里面没什…

Java 学习笔记:注解、泛型与 IO 流

目录 课程目标 Java 注解(Annotation) 1. 概念与作用 2. 自定义注解示例 3. JDK 内置注解 4.注释 Java 泛型(Generics) 1. 基本语法 2. 通配符与上下限 3. 常见应用场景 Java IO 流 1. 流的分类1.File文件类 2. 字节流与字符流 3. 经典示例:文件拷贝 总结与…

git仓库代码操作

1、从gitee下载代码提交到本地github仓库&#xff0c;保留提交记录 # 查看当前分支 git branch# 查看当前远程仓库 git remote -v# 确保所有更改已提交 git add . git commit -m "准备提交到GitLab"# 添加GitLab远程仓库 git remote add gitlab https://gitlab.com/…

Thinkphp6使用token+Validate验证防止表单重复提交

htm页面加 <input type"hidden" name"__token__" value"{:token()}" /> Validate 官方文档 ThinkPHP官方手册

Mcu_Bsdiff_Upgrade

系统架构 概述 MCU BSDiff 升级系统通过使用二进制差分技术&#xff0c;提供了一种在资源受限的微控制器上进行高效固件更新的机制。系统不传输和存储完整的固件映像&#xff0c;而是只处理固件版本之间的差异&#xff0c;从而显著缩小更新包并降低带宽要求。 该架构遵循一个…

Spring Boot微服务架构(四):微服务的划分原则

微服务划分原则&#xff08;CRM系统案例说明&#xff09; 一、微服务划分的核心原则 单一职责原则&#xff08;SRP&#xff09; 每个微服务只负责一个明确的业务功能服务边界清晰&#xff0c;避免功能混杂便于独立开发、测试和部署 业务领域驱动设计&#xff08;DDD&#xff0…

基于CNN卷积神经网络的带频偏QPSK调制信号检测识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2024b 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频&#xff09…

从机械应答到深度交互,移远通信如何让机器人“灵魂觉醒”?

你是否还在因机器人的“答非所问”而无奈&#xff0c;为它们的“反应慢半拍”而抓狂&#xff1f;别慌&#xff01;一场引领机器人实现“灵魂觉醒”的技术革命&#xff0c;正如同暗夜中悄然绽放的繁星&#xff0c;彻底颠覆人们对机器人的传统认知。 5月20日&#xff0c;移远通信…

软件的技术架构、应用架构、业务架构、数据架构、部署架构

一、各架构定义 1. 技术架构&#xff08;Technical Architecture&#xff09; 定义&#xff1a;技术架构关注的是支撑系统运行的底层技术基础设施和软件平台&#xff0c;包括硬件、操作系统、中间件、编程语言、框架、数据库管理系统等技术组件的选择和组合方式。它描述了系统…

HTML-前端

目录 开始学习HTML 什么是 HTML? 剖析一个 HTML 元素 嵌套元素 块级元素和内联元素 空元素 属性 为元素添加属性 布尔属性 省略包围属性值的引号 使用单引号还是双引号&#xff1f; 剖析 HTML 文档 HTML 中的空白 实体引用&#xff1a;在 HTML 中包含特殊字符 HT…

多态的总结

什么是多态&#xff1f; 答&#xff1a;多态是多种形态&#xff0c;是为了完成某种行为时&#xff0c;不同对象会产生不同的形态&#xff08;结合车票例子解释&#xff09; 2. 什么是重载、重写(覆盖)、重定义(隐藏)&#xff1f; 答&#xff1a;重载的条件是&#xff1a;在同一…

VBA 读取指定范围内的单元格数据,生成csv文件

目录 一. 需求二. 宏代码三. 添加按钮 一. 需求 ⏹有如下表格&#xff0c;现在想在Excel中添加一个按钮 点击按钮之后&#xff0c;读取该表格中的数据&#xff0c;生成csv文件将csv文件输出到和Excel同级目录 二. 宏代码 Application.PathSeparator&#xff1a;路径分隔符Cr…

【Code Agent Benchmark】论文分享No.15:TAU-Bench

论文名称&#xff1a;τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains 论文&#xff1a;https://arxiv.org/abs/2406.12045 机构&#xff1a;Sierra Github 链接&#xff1a;https://github.com/sierra-research/tau-bench# 简介 相比于Swe-ben…

Linux下 使用 SSH 完成 Git 绑定 GitHub

文章目录 1、检查 SSH2、生成 SSH key3、添加 SSH key4、验证绑定是否成功 1、检查 SSH Git Bash 中输入ssh命令&#xff0c;查看本机是否安装 SSH&#xff1a; 2、生成 SSH key &#xff08;1&#xff09;输入 ssh-keygen -t rsa 命令&#xff0c;表示我们指定 RSA 算法生…

Java 8 Stream 流操作全解析

文章目录 **一、Stream 流简介****二、Stream 流核心操作****1. 创建 Stream****2. 中间操作&#xff08;Intermediate Operations&#xff09;****filter(Predicate<T>)&#xff1a;过滤数据****1. 简单条件过滤****2. 多条件组合****3. 过滤对象集合****4. 过滤 null 值…

Java——设计模式(Design Pattern)

设计模式&#xff08;Design Pattern&#xff09;是软件开发中针对常见问题的经典解决方案&#xff0c;由 GoF&#xff08;Gang of Four&#xff09;在《设计模式&#xff1a;可复用面向对象软件的基础》一书中归纳为23 种模式&#xff0c;分为三大类&#xff1a;创建型模式、结…

python语法学习

1.python的类的定义 class Memory_Manager: 2.__init__ 方法 __init__ 是类的构造方法&#xff0c;用于初始化类的实例。 self 是类实例的引用&#xff0c;用于访问类的属性和方法。 3.方法定义 类中的方法是类的功能实现&#xff0c;通过 def 定义。 4.if __name__ __ma…

如何屏蔽mac电脑更新提醒,禁止系统更新(最新有效方法)

每次打开Mac电脑时&#xff0c;频繁的系统更新提醒可能会对我们的工作和使用体验造成干扰。为了屏蔽这些更新提醒并禁止系统自动更新&#xff0c;我们可以通过修改Hosts文件来实现。以下是详细步骤和方法&#xff0c;帮助你彻底屏蔽macOS的更新提醒。 系统关闭了自动更新也是…

windows10重装ssh无法下载

问题 windows10重装之后&#xff0c;ssh每次都是由于连接的是流量计数的网络无法下载。 解决方法 https://www.cnblogs.com/zhg1016/p/17353348.html