小智AI完整的MCP交互流程
發(fā)布日期:2025/11/5 14:21:31 瀏覽量:
1. 初始化階段 - 設(shè)備與AI服務(wù)器建立連接
// ESP32設(shè)備啟動時 void Application::Initialize() { // ...其他初始化 #if CONFIG_IOT_PROTOCOL_MCP McpServer::GetInstance().AddCommonTools(); // 注冊MCP工具 #endif // 建立與小智AI的連接 protocol_->Connect(); // WebSocket連接到小智AI }
連接建立過程:
ESP32設(shè)備 → 小智AI服務(wù)器
WebSocket連接: wss://api.xiaozhi.me/mcp/device/{device_id}
2. 工具注冊階段 - AI獲取設(shè)備能力
當(dāng)連接建立后,小智AI會查詢設(shè)備的MCP工具列表:
AI服務(wù)器發(fā)送工具列表請求:
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }
ESP32設(shè)備響應(yīng)(基于mcp_server.cc):
// 在McpServer::HandleRequest中處理 void McpServer::HandleRequest(const std::string& request) {
cJSON* json = cJSON_Parse(request.c_str()); auto method = cJSON_GetObjectItem(json, "method"); if (strcmp(method->valuestring, "tools/list") == 0) { // 返回工具列表 cJSON* response = cJSON_CreateObject();
cJSON* result = cJSON_CreateObject();
cJSON* tools = cJSON_CreateArray(); // 添加音量控制工具 cJSON* volume_tool = cJSON_CreateObject(); cJSON_AddStringToObject(volume_tool, "name", "self.audio_speaker.set_volume"); cJSON_AddStringToObject(volume_tool, "description", "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."); // 添加工具參數(shù)schema cJSON* input_schema = cJSON_CreateObject(); cJSON_AddStringToObject(input_schema, "type", "object");
cJSON* properties = cJSON_CreateObject();
cJSON* volume_prop = cJSON_CreateObject(); cJSON_AddStringToObject(volume_prop, "type", "integer"); cJSON_AddNumberToObject(volume_prop, "minimum", 0); cJSON_AddNumberToObject(volume_prop, "maximum", 100); cJSON_AddItemToObject(properties, "volume", volume_prop); cJSON_AddItemToObject(input_schema, "properties", properties); cJSON_AddItemToObject(volume_tool, "inputSchema", input_schema); cJSON_AddItemToArray(tools, volume_tool); // 添加更多工具... cJSON_AddItemToObject(result, "tools", tools); cJSON_AddItemToObject(response, "result", result); // 發(fā)送響應(yīng) char* response_str = cJSON_Print(response);
protocol_->SendMCPResponse(response_str); free(response_str); cJSON_Delete(response);
} cJSON_Delete(json);
}
設(shè)備返回的工具列表:
{ "jsonrpc": "2.0", "id": 1, "result": { "tools": [
{ "name": "self.get_device_status", "description": "Provides the real-time information of the device...", "inputSchema": {"type": "object", "properties": {}}
},
{ "name": "self.audio_speaker.set_volume", "description": "Set the volume of the audio speaker...", "inputSchema": { "type": "object", "properties": { "volume": {"type": "integer", "minimum": 0, "maximum": 100}
}, "required": ["volume"]
}
}
]
}
}
3. 用戶語音輸入階段
用戶說話: “把音量調(diào)到80”
↓
ESP32麥克風(fēng)采集 → 音頻處理 → Opus編碼 → 發(fā)送到小智AI
↓
小智AI: 語音識別(ASR) → “把音量調(diào)到80”
4. AI理解和工具調(diào)用決策
小智AI模型分析用戶意圖:
輸入: "把音量調(diào)到80" AI分析: - 意圖: 音量控制 - 參數(shù): 音量值=80 - 選擇工具: self.audio_speaker.set_volume - 生成參數(shù): {"volume": 80}
5. AI發(fā)送工具調(diào)用請求
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "self.audio_speaker.set_volume", "arguments": { "volume": 80 } }
6. ESP32設(shè)備執(zhí)行工具調(diào)用
// 在McpServer::HandleRequest中處理工具調(diào)用 void McpServer::HandleRequest(const std::string& request) {
cJSON* json = cJSON_Parse(request.c_str()); auto method = cJSON_GetObjectItem(json, "method"); if (strcmp(method->valuestring, "tools/call") == 0) { auto params = cJSON_GetObjectItem(json, "params"); auto tool_name = cJSON_GetObjectItem(params, "name"); auto arguments = cJSON_GetObjectItem(params, "arguments"); if (strcmp(tool_name->valuestring, "self.audio_speaker.set_volume") == 0) { // 執(zhí)行音量設(shè)置 auto volume = cJSON_GetObjectItem(arguments, "volume"); int volume_value = volume->valueint; // 調(diào)用實際的音量控制 auto& board = Board::GetInstance(); auto codec = board.GetAudioCodec();
codec->SetOutputVolume(volume_value); // 顯示通知(如果有顯示屏) auto display = board.GetDisplay(); if (display) {
display->ShowNotification("音量: " + std::to_string(volume_value));
} // 構(gòu)造成功響應(yīng) cJSON* response = cJSON_CreateObject();
cJSON* result = cJSON_CreateObject(); cJSON_AddBoolToObject(result, "success", true); cJSON_AddNumberToObject(result, "volume", volume_value); cJSON_AddStringToObject(result, "message", "音量設(shè)置成功"); cJSON_AddItemToObject(response, "result", result); // 發(fā)送響應(yīng) char* response_str = cJSON_Print(response);
protocol_->SendMCPResponse(response_str); free(response_str); cJSON_Delete(response);
}
} cJSON_Delete(json);
}
7. 設(shè)備返回執(zhí)行結(jié)果
{ "jsonrpc": "2.0", "id": 2, "result": { "success": true, "volume": 80, "message": "音量設(shè)置成功" } }
8. AI生成語音回復(fù)
小智AI根據(jù)執(zhí)行結(jié)果生成回復(fù):
工具執(zhí)行結(jié)果: {“success”: true, “volume”: 80, “message”: “音量設(shè)置成功”}
AI生成回復(fù): “好的,已將音量調(diào)整到80”
TTS合成: 文字 → 語音
發(fā)送音頻: 語音數(shù)據(jù) → ESP32設(shè)備
9. 設(shè)備播放AI回復(fù)
// ESP32接收并播放AI回復(fù) void Application::OnIncomingAudio(AudioStreamPacket&& packet) { std::lock_guard<std::mutex> lock(mutex_); if (device_state_ == kDeviceStateSpeaking &&
audio_decode_queue_.size() < MAX_AUDIO_PACKETS_IN_QUEUE) {
audio_decode_queue_.emplace_back(std::move(packet));
}
} // 音頻解碼和播放 void Application::OnAudioOutput() { if (!audio_decode_queue_.empty()) { auto packet = std::move(audio_decode_queue_.front());
audio_decode_queue_.pop_front(); // Opus解碼 std::vector<int16_t> pcm_data;
opus_decoder_->Decode(packet.payload, pcm_data); // 播放音頻 auto codec = Board::GetInstance().GetAudioCodec();
codec->WriteOutput(pcm_data);
}
}
完整時序圖
關(guān)鍵實現(xiàn)細(xì)節(jié)
A. 協(xié)議層實現(xiàn)
// 在protocol實現(xiàn)中處理MCP消息 class Protocol { public: void SendMCPResponse(const std::string& response) { // 通過WebSocket發(fā)送MCP響應(yīng) websocket_->send(response);
} void OnMCPRequest(const std::string& request) { // 將MCP請求轉(zhuǎn)發(fā)給McpServer處理 McpServer::GetInstance().HandleRequest(request);
}
};
B. 異步處理
// MCP請求的異步處理 void McpServer::HandleRequest(const std::string& request) { // 在后臺任務(wù)中處理,避免阻塞主線程 background_task_->Schedule([this, request]() { ProcessMCPRequest(request);
});
}
C. 錯誤處理
// 工具調(diào)用錯誤處理 if (tool_execution_failed) {
cJSON* error_response = cJSON_CreateObject();
cJSON* error = cJSON_CreateObject();
cJSON_AddNumberToObject(error, "code", -1);
cJSON_AddStringToObject(error, "message", "Tool execution failed");
cJSON_AddItemToObject(error_response, "error", error); char* response_str = cJSON_Print(error_response);
protocol_->SendMCPResponse(response_str);
free(response_str);
cJSON_Delete(error_response);
}
性能特點
延遲分析:
- 語音識別: ~200-500ms
- AI理解決策: ~100-300ms
- MCP工具調(diào)用: ~10-50ms (本地執(zhí)行)
- TTS合成: ~200-400ms
- 總延遲: ~500-1250ms
對比外部MCP服務(wù)器方案:
- 額外網(wǎng)絡(luò)往返: +100-200ms
- 服務(wù)器處理: +50-100ms
- 本地MCP優(yōu)勢: 節(jié)省150-300ms延遲
這就是ESP32本地MCP實現(xiàn)的完整流程
馬上咨詢: 如果您有業(yè)務(wù)方面的問題或者需求,歡迎您咨詢!我們帶來的不僅僅是技術(shù),還有行業(yè)經(jīng)驗積累。
QQ: 39764417/308460098 Phone: 13 9800 1 9844 / 135 6887 9550 聯(lián)系人:石先生/雷先生