当前位置: 首页 > news >正文

网站建设后续需要维护住房和城乡建设部贰级建造师网站

网站建设后续需要维护,住房和城乡建设部贰级建造师网站,页面模版 公众号,软件开发专业好吗理论 1、什么是MCP MCP(Model Context Protocol,模型上下文协议)是一种开放式协议,它实现了LLM与各种工具的调用。使LLM从对话、生成式AI变成了拥有调用三方工具的AI。用官方的比喻,MCP就是USB-C接口,只要实现了这个接口&#x…

理论

1、什么是MCP

MCP(Model Context Protocol,模型上下文协议)是一种开放式协议,它实现了LLM与各种工具的调用。使LLM从对话、生成式AI变成了拥有调用三方工具的AI。用官方的比喻,MCP就是USB-C接口,只要实现了这个接口,就可以接入AI,对AI进行赋能。
MCP
其本质是统一了AI调用三方功能的接口,借助AI Agent,使得LLM可以使用三方提供的服务来处理用户提出的问题。

从上图可以看到一些MCP的相关概念
MCP server:提供服务的三方,需要实现MCP server的功能,即将提供的功能接口按照MCP协议规定的格式,告知MCP client。
MCP client:连接MCP server与LLM的桥梁,负责管理与MCP server一对一的连接。
MCP hosts:一般指AI应用,通常由AI Agent实现MCP client的功能,再由AI Agent作为MCP hosts。
除此之外,还需要知道MCP tools的概念,第三方提供的功能接口一般称为一个tool,在后面的代码中会展示这一点。

这里引用up隔壁的程序员老王的一张视频截图,很清晰的展示了从用户提问,到AI返回结果这一过程中,是如何调用三方MCP服务的。原视频:10分钟讲清楚 Prompt, Agent, MCP 是什么
在这里插入图片描述

2、小智AI MCP server

下面回到小智AI中,在虾哥提供的源码中,实现了MCP server,目前该功能还在内测中(2025年7月20日),可以去小智官网看看使用教程。

关于MCP协议的格式这里也不再复述,菜鸟教程和xiaozhi-esp32源码的/docs/mcp-protocol.md中有非常详细的介绍。这里只关注MCP的核心逻辑。

我们来看看MCP server的源码。最关键的类就是McpServer,这个类实现了注册工具、解析响应、调用工具等功能。

class McpServer {
public:static McpServer& GetInstance() {static McpServer instance;return instance;}void AddCommonTools();void AddTool(McpTool* tool);void AddTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback);void ParseMessage(const cJSON* json);void ParseMessage(const std::string& message);private:McpServer();~McpServer();void ParseCapabilities(const cJSON* capabilities);void ReplyResult(int id, const std::string& result);void ReplyError(int id, const std::string& message);void GetToolsList(int id, const std::string& cursor);void DoToolCall(int id, const std::string& tool_name, const cJSON* tool_arguments, int stack_size);std::vector<McpTool*> tools_;std::thread tool_call_thread_;
};

AddCommonTools()
这个方法实现了注册工具的功能,在Application::Start()中调用。

    // Add MCP common tools before initializing the protocol
#if CONFIG_IOT_PROTOCOL_MCPMcpServer::GetInstance().AddCommonTools();
#endif

其具体实现没什么神秘的,就是调用AddTool将功能接口的信息、参数和接口push进tools队列。
比如设置音量的接口:

    AddTool("self.audio_speaker.set_volume", "Set the volume of the audio speaker. If the current volume is unknown, you must call `self.get_device_status` tool first and then call this tool.",PropertyList({Property("volume", kPropertyTypeInteger, 0, 100)}), [&board](const PropertyList& properties) -> ReturnValue {auto codec = board.GetAudioCodec();codec->SetOutputVolume(properties["volume"].value<int>());return true;});
void McpServer::AddTool(McpTool* tool) {// Prevent adding duplicate toolsif (std::find_if(tools_.begin(), tools_.end(), [tool](const McpTool* t) { return t->name() == tool->name(); }) != tools_.end()) {ESP_LOGW(TAG, "Tool %s already added", tool->name().c_str());return;}ESP_LOGI(TAG, "Add tool: %s", tool->name().c_str());tools_.push_back(tool);
}void McpServer::AddTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback) {AddTool(new McpTool(name, description, properties, callback));
}

ParseMessage()
解析收到的JSON,对JSON格式校验,如果是调用tool就调用DoToolCall去执行对应的tool。

void McpServer::ParseMessage(const cJSON* json) {// Check JSONRPC versionauto version = cJSON_GetObjectItem(json, "jsonrpc");if (version == nullptr || !cJSON_IsString(version) || strcmp(version->valuestring, "2.0") != 0) {ESP_LOGE(TAG, "Invalid JSONRPC version: %s", version ? version->valuestring : "null");return;}// Check methodauto method = cJSON_GetObjectItem(json, "method");if (method == nullptr || !cJSON_IsString(method)) {ESP_LOGE(TAG, "Missing method");return;}...if (method_str == "tools/call") {...DoToolCall(id_int, std::string(tool_name->valuestring), tool_arguments, stack_size ? stack_size->valueint : DEFAULT_TOOLCALL_STACK_SIZE);} else {ESP_LOGE(TAG, "Method not implemented: %s", method_str.c_str());ReplyError(id_int, "Method not implemented: " + method_str);}
}

DoToolCall()
查找tool,创建新的线程,在新线程中调用tool中的回调函数,即三方实现的功能接口。

void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* tool_arguments, int stack_size) {// 在tools中按tool_name查找toolauto tool_iter = std::find_if(tools_.begin(), tools_.end(), [&tool_name](const McpTool* tool) { return tool->name() == tool_name; });// 解析回调函数的参数PropertyList arguments = (*tool_iter)->properties();try {for (auto& argument : arguments) {...}}// Start a task to receive data with stack sizeesp_pthread_cfg_t cfg = esp_pthread_get_default_config();cfg.thread_name = "tool_call";cfg.stack_size = stack_size;cfg.prio = 1;esp_pthread_set_cfg(&cfg);// Use a thread to call the tool to avoid blocking the main threadtool_call_thread_ = std::thread([this, id, tool_iter, arguments = std::move(arguments)]() {try {ReplyResult(id, (*tool_iter)->Call(arguments));} catch (const std::exception& e) {ESP_LOGE(TAG, "tools/call: %s", e.what());ReplyError(id, e.what());}});tool_call_thread_.detach();
}

ReplyResult()ReplyError() 就是将结果转为JSON,并通过protocol(mqtt或websocket)发送出去。

void McpServer::ReplyResult(int id, const std::string& result) {std::string payload = "{\"jsonrpc\":\"2.0\",\"id\":";payload += std::to_string(id) + ",\"result\":";payload += result;payload += "}";Application::GetInstance().SendMcpMessage(payload);
}void Application::SendMcpMessage(const std::string& payload) {Schedule([this, payload]() {if (protocol_) {protocol_->SendMcpMessage(payload);}});
}

通过对源码的分析,我们知道了MCP server的核心逻辑,简单来说就是在server中将接口放入tools,之后由MCP client发起调用,server解析JSON后去调用对应的接口。至于client是如何知道有哪些tool的,可以在ParseMessage()中发现端倪:

if (method_str == "tools/list") {std::string cursor_str = "";if (params != nullptr) {auto cursor = cJSON_GetObjectItem(params, "cursor");if (cJSON_IsString(cursor)) {cursor_str = std::string(cursor->valuestring);}}GetToolsList(id_int, cursor_str);

具体的client代码实现还没有看,但不难猜测,client会发起一次获取tools的请求,这样就知道了有哪些tool。

下面我们就可以注册一个自己的tool,来实现对外设的控制。

实践

实现功能:语音控制灯光亮度
首先初始化RGB灯

// 配置定时器
ledc_timer_config_t ledc_timer = {.speed_mode = LEDC_LOW_SPEED_MODE,.duty_resolution = LEDC_TIMER_8_BIT,.timer_num = LEDC_TIMER_0,.freq_hz = 5000,
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));// 配置通道
ledc_channel_config_t ledc_channel={.gpio_num = GPIO_NUM_1,.speed_mode = LEDC_LOW_SPEED_MODE,.channel = LEDC_CHANNEL_0,.timer_sel = LEDC_TIMER_0,.duty = 0,
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));

然后添加tool

AddTool("self.my_led.set_brightness","Set the brightness of the blue LED. The brightness is a percentage value from 0 to 100.",PropertyList({Property("brightness", kPropertyTypeInteger, 0, 100)}),[](const PropertyList& properties) -> ReturnValue {uint32_t brightness = static_cast<uint32_t>(properties["brightness"].value<int>());ESP_LOGI(TAG, "my led set brightness %lu", brightness);if (brightness > 100) {brightness = 100;}uint32_t duty = (brightness * 255) / 100; // Convert to 8-bit duty cycleESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty));ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));return true;});

效果如下:

小智AI使用MCP控制RGB灯光亮度

http://www.dtcms.com/a/593701.html

相关文章:

  • 交友视频网站建设广告策划书范本
  • spring boot集成 RustFS服务
  • 谷歌攻克AI“灾难性遗忘“难题!最新范式突破AI持续学习内存瓶颈
  • SuperMap GIS基础产品FAQ集锦(20251110)
  • Kimi K2 Thinking 量化之后再量化,模型文件缩水60%,准确率85%,部署教程来了
  • 【图像处理基石】边缘检测技术:从经典算法到实战应用
  • DevEco Studio 鸿蒙HarmonyOS 引入本地har
  • 【路径算法】IDA*与D*和Lite D* 的比较及IDA*算法详解
  • 做网站运营这工作怎么样wordpress 星 评分
  • 单一职责原则(SRP)深度解析
  • 网站建设福州公司南县网站设计
  • ESD防护设计宝典(二十八):半导体的ESD失效模式与机理
  • 关于止盈和止损的问题(一)
  • LeetCode 分类刷题:141. 环形链表
  • 在哪个网站做视频赚钱的亚马逊计划裁员1万人
  • 建材建设行业网站做网站从何开始
  • leetcode 3542
  • 【Python Maze Diary 1.1】迷宫算法术语
  • 大学计算机基础(Windows 7+Office 2010)第一章课后练习
  • PyTorch中int32和int64在性能上有什么差异
  • 机器学习入门:从零开始理解AI的核心引擎(附Python实战)
  • 【AI学习-comfyUI学习-简易加载器工作流(文生图)-各个部分学习-第七节-2】
  • 西安建设高端网站外星人建设的网站
  • Bugku-Web题目-文件包含
  • 给自己做的网站换首页北京大良网站建设
  • 网站的内容规划怎么写nodejs做网站还是app
  • 从“识图”到“购得”:图片搜索商品如何重构消费与供应链逻辑?
  • 通过OCR实现验证码识别
  • 33.Transformer架构
  • 环形链表快慢指针全解析:相遇必然性与多步速追击证明