找回密码
 立即注册
首页 业界区 业界 ESP32-S3接入大模型API,对话AI

ESP32-S3接入大模型API,对话AI

跑两獗 2025-6-3 10:42:32
ESP32-S3接入大模型API,对话AI

1、先使用python验证可行性
  1. import requests
  2. url = "https://api.siliconflow.cn/v1/chat/completions"
  3. payload = {
  4.     "model": "deepseek-ai/DeepSeek-R1",
  5.     "messages": [  # 必须包含消息内容
  6.         {"role": "user", "content": "请解释量子计算的基本原理"}
  7.     ],
  8.     "stream": False,
  9.     "max_tokens": 512,
  10.     "temperature": 0.7,
  11.     "top_p": 0.7,
  12.     "top_k": 50,
  13.     "frequency_penalty": 0.5,
  14.     "n": 1
  15. }
  16. headers = {
  17.     "Authorization": "Bearer "your api_key"",
  18.     "Content-Type": "application/json"
  19. }
  20. response = requests.request("POST", url, json=payload, headers=headers)
  21. print(response.text)
复制代码
1.png
代码
2.png
3.png
秘钥获取硅基流动注册送14元免费额度,https://cloud.siliconflow.cn/i/9MqV8tO4
邀请码:9MqV8tO4
2、Postman验证POST请求结构,深化熟悉对接流程

4.png
POST请求头(Headers)设置
5.png
POST请求主体(Body)设置Authorization: your api key                                    Content-Type:application/jsonBody:
  1. {
  2.     "model": "deepseek-ai/DeepSeek-V3",
  3.     "messages": [
  4.         {"role": "user", "content": "请解释量子计算的基本原理"}//问题
  5.     ],
  6.     // "stream": False,
  7.     "max_tokens": 512,
  8.     "temperature": 0.7,
  9.     "top_p": 0.7,
  10.     "top_k": 50,
  11.     "frequency_penalty": 0.5,
  12.     "n": 1
  13. }
复制代码
实战!在esp32s3上实现ai对话:

1、使用micro python实现

因为之前验证过python的可行性,而esp32系列可以使用micro python编程,其特点是便捷高效,所以先使用mico python实现。
开发环境
编程调试下载环境:Thonny
编程语言:micro python
前置条件:烧录micro python固件(乐鑫官网中下载)
  1. import network
  2. import time
  3. import urequests
  4. import ujson
  5. from machine import reset
  6. # ====== 配置部分 ======
  7. SSID = 'jianzhiji'
  8. PASSWORD = '8765432111'
  9. API_KEY = "你的api密钥"
  10. API_URL = "https://api.siliconflow.cn/v1/chat/completions"
  11. def connect_wifi():
  12.     wlan = network.WLAN(network.STA_IF)
  13.     wlan.active(True)
  14.    
  15.     if not wlan.isconnected():
  16.         print(f"Connecting to {SSID}...")
  17.         wlan.connect(SSID, PASSWORD)
  18.         
  19.         timeout = 20
  20.         while not wlan.isconnected() and timeout > 0:
  21.             print(".", end="")
  22.             time.sleep(1)
  23.             timeout -= 1
  24.             
  25.         if not wlan.isconnected():
  26.             raise RuntimeError("WiFi连接超时")
  27.    
  28.     print("\nIP Address:", wlan.ifconfig()[0])
  29.     return wlan
  30. def api_request():
  31.     headers = {
  32.         "Authorization": f"Bearer {API_KEY}",
  33.         "Content-Type": "application/json"
  34.     }
  35.    
  36.     # 最小化请求参数
  37.     payload = {
  38.         "model": "deepseek-ai/DeepSeek-V3",
  39.         "messages": [{"role": "user", "content": "hello"}],
  40.         "max_tokens": 512,
  41.         "temperature": 0.7,
  42.         "top_p": 0.7
  43.     }
  44.    
  45.     try:
  46.         print("\n[Request]")
  47.         print("Payload:", payload)
  48.         
  49.         response = urequests.post(
  50.             API_URL,
  51.             headers=headers,
  52.             data=ujson.dumps(payload),
  53.             timeout=20
  54.         )
  55.         
  56.         print(f"\n[Response] Status: {response.status_code}")
  57.         if response.status_code == 200:
  58.             json_resp = response.json()
  59.             print("AI回复:", json_resp['choices'][0]['message']['content'])
  60.         else:
  61.             print("Error Response:", response.text)
  62.             
  63.         response.close()
  64.         
  65.     except Exception as e:
  66.         print("[Error]", str(e))
  67. try:
  68.     print("=== 启动系统 ===")
  69.     connect_wifi()
  70.     api_request()
  71.    
  72. except Exception as e:
  73.     print("\n!!! 错误:", str(e))
  74.     print("10秒后重启...")
  75.     time.sleep(10)
  76.     reset()
复制代码
6.png

2、使用C语言实现

开发环境
编程调试下载环境:VSCOde+espidf插件
编程语言:C
  1. #include <string.h>
  2. #include "esp_log.h"
  3. #include "nvs_flash.h"
  4. #include "esp_event.h"
  5. #include "esp_netif.h"
  6. #include "protocol_examples_common.h"
  7. #include "esp_http_client.h"
  8. #include "esp_sntp.h"
  9. // 在文件开头添加
  10. #include "lwip/apps/sntp.h"
  11. #define MAX_HTTP_OUTPUT_BUFFER 2048
  12. static const char *TAG = "HTTP_AI_CLIENT";
  13. #define API_ENDPOINT "http://api.siliconflow.cn/v1/chat/completions"
  14. // 添加事件处理函数
  15. static esp_err_t http_event_handler(esp_http_client_event_t *evt)
  16. {
  17.     switch (evt->event_id) {
  18.         case HTTP_EVENT_ERROR:
  19.             ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
  20.             break;
  21.         case HTTP_EVENT_ON_CONNECTED:
  22.             ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
  23.             break;
  24.         case HTTP_EVENT_HEADERS_SENT:
  25.             ESP_LOGI(TAG, "HTTP_EVENT_HEADERS_SENT");
  26.             break;
  27.         case HTTP_EVENT_ON_HEADER:
  28.             ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
  29.             break;
  30.         case HTTP_EVENT_ON_DATA:
  31.             ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
  32.             break;
  33.         case HTTP_EVENT_ON_FINISH:
  34.             ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
  35.             break;
  36.         case HTTP_EVENT_DISCONNECTED:
  37.             ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
  38.             break;
  39.         default:
  40.             break;
  41.     }
  42.     return ESP_OK;
  43. }
  44. static void http_post_request(void)
  45. {
  46.     char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
  47.     esp_http_client_config_t config = {
  48.         .url = API_ENDPOINT,
  49.         .event_handler = http_event_handler, // 添加事件处理
  50.         .timeout_ms = 30000,                // 增加超时到30秒
  51.         .skip_cert_common_name_check = true, // 跳过证书CN检查
  52.         .cert_pem = NULL,                   // 不指定证书
  53.     };
  54.     esp_http_client_handle_t client = esp_http_client_init(&config);
  55.     const char *json_data =
  56.     "{"
  57.         ""model": "deepseek-ai/DeepSeek-V3","//选择模型
  58.         ""messages": ["
  59.             "{"
  60.                 ""role": "user","
  61.                 ""content": "你好""//填入问题内容
  62.             "}"
  63.         "],"
  64.         ""max_tokens": 512,"
  65.         ""temperature": 0.7,"
  66.         ""top_p": 0.7,"
  67.         ""top_k": 50,"
  68.         ""frequency_penalty": 0.5,"
  69.         ""n": 1"
  70.     "}";
  71.     esp_http_client_set_method(client, HTTP_METHOD_POST);
  72.     esp_http_client_set_header(client, "Content-Type", "application/json");
  73.     esp_http_client_set_header(client, "Authorization", "your api key");//key_API
  74.     esp_err_t err = esp_http_client_open(client, strlen(json_data));
  75.     if (err != ESP_OK) {
  76.         ESP_LOGE(TAG, "连接失败: %s", esp_err_to_name(err));
  77.         goto cleanup;
  78.     }
  79.     int wlen = esp_http_client_write(client, json_data, strlen(json_data));
  80.     if (wlen < 0) {
  81.         ESP_LOGE(TAG, "数据写入失败");
  82.         goto cleanup;
  83.     }
  84.     int content_length = esp_http_client_fetch_headers(client);
  85.     if (content_length < 0) {
  86.         ESP_LOGE(TAG, "获取头部信息失败");
  87.         goto cleanup;
  88.     }
  89.     int data_read = esp_http_client_read_response(client, output_buffer, MAX_HTTP_OUTPUT_BUFFER);
  90.     if (data_read >= 0) {
  91.         ESP_LOGI(TAG, "HTTP状态码 = %d, 内容长度 = %"PRIu64,
  92.                 esp_http_client_get_status_code(client),
  93.                 esp_http_client_get_content_length(client));
  94.         ESP_LOGI(TAG, "响应内容: %s", output_buffer);
  95.     } else {
  96.         ESP_LOGE(TAG, "读取响应失败");
  97.     }
  98. cleanup:
  99.     esp_http_client_cleanup(client);
  100. }
  101. static void http_task(void *pvParameters)
  102. {
  103.     http_post_request();
  104.     ESP_LOGI(TAG, "HTTP示例完成");
  105.     vTaskDelete(NULL);
  106. }
  107. void app_main(void)
  108. {
  109.     ESP_ERROR_CHECK(nvs_flash_init());
  110.     ESP_ERROR_CHECK(esp_netif_init());
  111.     ESP_ERROR_CHECK(esp_event_loop_create_default());
  112.     ESP_ERROR_CHECK(example_connect());
  113.     sntp_setoperatingmode(SNTP_OPMODE_POLL);
  114.     sntp_setservername(0, "pool.ntp.org");  // 第1个NTP服务器
  115.     sntp_setservername(1, "time.nist.gov"); // 第2个NTP服务器(可选)
  116.     sntp_init();
  117.     // 在 sntp_init() 后添加时间同步等待
  118.     int retry = 0;
  119.     const int retry_count = 10;
  120.     while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
  121.         printf("Waiting for system time to sync... (%d/%d)\n", retry, retry_count);
  122.         vTaskDelay(2000 / portTICK_PERIOD_MS);
  123.     }
  124.     xTaskCreate(&http_task, "http_task", 8192, NULL, 5, NULL);
  125. }
复制代码
终端输出结果
7.png

由于该版本等待时间过短,提问复杂问题时常常等不到回答就提示连接失败。
以下优化版本增加
1、超时策略
2、动态缓冲区扩容
3、分段传输机制
  1. #include <string.h>
  2. #include "esp_log.h"
  3. #include "nvs_flash.h"
  4. #include "esp_event.h"
  5. #include "esp_netif.h"
  6. #include "protocol_examples_common.h"
  7. #include "esp_http_client.h"
  8. #include "esp_sntp.h"
  9. // 在文件开头添加
  10. #include "lwip/apps/sntp.h"
  11. #define MAX_HTTP_OUTPUT_BUFFER 2048
  12. static const char *TAG = "HTTP_AI_CLIENT";
  13. #define API_ENDPOINT "http://api.siliconflow.cn/v1/chat/completions"
  14. // 添加事件处理函数
  15. static esp_err_t http_event_handler(esp_http_client_event_t *evt)
  16. {
  17.     switch (evt->event_id) {
  18.         case HTTP_EVENT_ERROR:
  19.             ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
  20.             break;
  21.         case HTTP_EVENT_ON_CONNECTED:
  22.             ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
  23.             break;
  24.         case HTTP_EVENT_HEADERS_SENT:
  25.             ESP_LOGI(TAG, "HTTP_EVENT_HEADERS_SENT");
  26.             break;
  27.         case HTTP_EVENT_ON_HEADER:
  28.             ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
  29.             break;
  30.         case HTTP_EVENT_ON_DATA:
  31.             ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
  32.             break;
  33.         case HTTP_EVENT_ON_FINISH:
  34.             ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
  35.             break;
  36.         case HTTP_EVENT_DISCONNECTED:
  37.             ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
  38.             break;
  39.         default:
  40.             break;
  41.     }
  42.     return ESP_OK;
  43. }
  44. static void http_post_request(void)
  45. {
  46.     // char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
  47.        // 增大缓冲区防止数据截断
  48.     char *output_buffer = calloc(1, MAX_HTTP_OUTPUT_BUFFER * 2); // 扩容至4096
  49.     if (!output_buffer) {
  50.         ESP_LOGE(TAG, "内存分配失败");
  51.         return;
  52.     }
  53.     esp_http_client_config_t config = {
  54.         .url = API_ENDPOINT,
  55.         .event_handler = http_event_handler,
  56.         .timeout_ms = 120000,                // 超时延长至120秒
  57.         .disable_auto_redirect = false,      // 允许重定向
  58.         .keep_alive_enable = true,           // 启用长连接
  59.         .skip_cert_common_name_check = true,
  60.         .cert_pem = NULL
  61.     };
  62.     esp_http_client_handle_t client = esp_http_client_init(&config);
  63.     const char *json_data =
  64.     "{"
  65.         ""model": "deepseek-ai/DeepSeek-R1","//选择模型
  66.         ""messages": ["
  67.             "{"
  68.                 ""role": "user","
  69.                 ""content": "写一篇散文""//填入问题内容
  70.             "}"
  71.         "],"
  72.         ""max_tokens": 512,"
  73.         ""temperature": 0.7,"
  74.         ""top_p": 0.7,"
  75.         ""top_k": 50,"
  76.         ""frequency_penalty": 0.5,"
  77.         ""n": 1"
  78.     "}";
  79.     esp_http_client_set_method(client, HTTP_METHOD_POST);
  80.     esp_http_client_set_header(client, "Content-Type", "application/json");
  81.     esp_http_client_set_header(client, "Authorization", "  ");//key_API
  82.      // 新增分段接收逻辑
  83.     int total_read = 0;
  84.     esp_err_t err = esp_http_client_open(client, strlen(json_data));
  85.     if (err == ESP_OK) {
  86.         // 分段写入数据(应对大请求体)
  87.         const char *ptr = json_data;
  88.         int remaining = strlen(json_data);
  89.         while (remaining > 0) {
  90.             int written = esp_http_client_write(client, ptr, remaining);
  91.             if (written <= 0) break;
  92.             ptr += written;
  93.             remaining -= written;
  94.         }
  95.     }
  96.     int wlen = esp_http_client_write(client, json_data, strlen(json_data));
  97.     if (wlen < 0) {
  98.         ESP_LOGE(TAG, "数据写入失败");
  99.         goto cleanup;
  100.     }
  101. // 新增分段读取逻辑
  102.     if (esp_http_client_fetch_headers(client) >= 0) {
  103.         int read_len;
  104.         do {
  105.             read_len = esp_http_client_read(client,
  106.                 output_buffer + total_read,
  107.                 MAX_HTTP_OUTPUT_BUFFER * 2 - total_read - 1
  108.             );
  109.             if (read_len > 0) {
  110.                 total_read += read_len;
  111.             }
  112.         } while (read_len > 0);
  113.         
  114.         output_buffer[total_read] = '\0'; // 确保字符串终止
  115.     }
  116.     int data_read = esp_http_client_read_response(client, output_buffer, MAX_HTTP_OUTPUT_BUFFER);
  117.     if (data_read >= 0) {
  118.         ESP_LOGI(TAG, "HTTP状态码 = %d, 内容长度 = %"PRIu64,
  119.                 esp_http_client_get_status_code(client),
  120.                 esp_http_client_get_content_length(client));
  121.         ESP_LOGI(TAG, "响应内容: %s", output_buffer);
  122.     } else {
  123.         ESP_LOGE(TAG, "读取响应失败");
  124.     }
  125. cleanup:
  126.     esp_http_client_cleanup(client);
  127. }
  128. static void http_task(void *pvParameters)
  129. {
  130.     http_post_request();
  131.     ESP_LOGI(TAG, "HTTP示例完成");
  132.     vTaskDelete(NULL);
  133. }
  134. void app_main(void)
  135. {
  136.     ESP_ERROR_CHECK(nvs_flash_init());
  137.     ESP_ERROR_CHECK(esp_netif_init());
  138.     ESP_ERROR_CHECK(esp_event_loop_create_default());
  139.     ESP_ERROR_CHECK(example_connect());
  140.     sntp_setoperatingmode(SNTP_OPMODE_POLL);
  141.     sntp_setservername(0, "pool.ntp.org");  // 第1个NTP服务器
  142.     sntp_setservername(1, "time.nist.gov"); // 第2个NTP服务器(可选)
  143.     sntp_init();
  144.     // 在 sntp_init() 后添加时间同步等待
  145.     int retry = 0;
  146.     const int retry_count = 10;
  147.     while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
  148.         printf("Waiting for system time to sync... (%d/%d)\n", retry, retry_count);
  149.         vTaskDelay(2000 / portTICK_PERIOD_MS);
  150.     }
  151.     xTaskCreate(&http_task, "http_task", 18192, NULL, 5, NULL);
  152. }
复制代码
终端打印接收结果,可以成功等待接受长文本
8.png

NTP服务器

NTP服务器(Network Time Protocol Server)的作用是提供精确、统一的时间同步服务,它是互联网中时间同步的核心基础设施。以下是其核心作用:
1. 时间同步


  • 核心功能:NTP服务器通过协议将设备(如计算机、手机、物联网设备)的本地时间与全球标准时间(如UTC)同步。
  • 解决设备时钟漂移:硬件时钟可能因温度、电池等原因产生误差,NTP定期校准时间,确保设备间时间一致。
2. 安全协议的基础


  • SSL/TLS证书验证:HTTPS通信依赖证书的有效期验证。若设备时间错误:

    • 证书可能被误判为“未生效”或“已过期”,导致连接失败。

  • 示例场景:你之前的ESP32代码中,若系统时间未同步,访问HTTPS API时可能因证书时间校验失败而超时。
3. 日志与调试


  • 统一时间戳:设备生成的日志若时间不一致,将难以追踪问题(如分布式系统故障)。
  • 示例:ESP32的日志若时间错误,无法与服务器日志对照,增加调试难度。
4. 协调分布式系统


  • 跨设备协同:物联网、金融交易等场景依赖毫秒级时间同步,避免数据冲突。
  • 示例:多个ESP32设备协同工作时,需严格按时间顺序执行操作。
5. NTP与SNTP的区别


  • NTP:高精度(毫秒/微秒级),适用于服务器、基站等。
  • SNTP(简单NTP):精简版,精度稍低(秒级),适合资源受限设备(如ESP32)。
  • 你的代码:使用esp_sntp_init()即是为ESP32提供轻量级时间同步。
为什么你的ESP32项目需要NTP服务器?

在之前的代码中,你遇到HTTP连接超时问题,可能原因之一是:

  • ESP32系统时间未同步 → SSL证书验证失败 → 服务器拒绝连接。
  • 初始化SNTP后,设备获取正确时间 → 证书验证通过 → 正常通信。
总结

NTP服务器像互联网的“原子钟”,确保设备时间精准统一。对物联网设备而言,它是安全通信、协同工作的基石。
如果文章对你有所帮助,可以帮我点一下左下角推荐该文,万分感谢
博主目前在广州,深圳找实习。
如有大佬(HR,BOSS)能推荐实习,恳请私信小弟,给个机会,帮帮小弟,万分感谢!!!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册