AI创客项目开发教程 – AID101-1-2-04 – Assistant Role详解

导航栏:首页 / AI教程目录 / AI创客项目开发教程目录 / 第1篇 基础知识篇 / AID101-1-2-04–Assistant Role详解

本节内容简介

本节将详细讲解 Assistant Role(助手角色)在 ESP32 开发板上调用 AI 平台 API 实现具有上下文的交互。通过本节课程,您将理解 如何利用Assistant Role 来存储 AI 的回答,如何通过携带与AI模型的对话历史实现上下文感知的连续对话,以及如何在实际应用中动态管理多轮对话。

Assistant Role(助手角色)详解

什么是 Assistant Role?

Assistant Role(助手角色)是 AI 大语言模型 API 调用中用于存储 AI 回答的角色。在多轮对话中,每一轮 AI 的回答都会被记录为 Assistant Role,并携带在下一轮请求的 messages 数组中,从而使 AI 能够理解对话的上下文,实现连贯的交互体验。

核心作用:

  • 💬 回答存储:记录 AI 在每一轮对话中的回答内容
  • 🔄 上下文传递:将历史对话信息传递给 AI,使其理解对话脉络
  • 🧠 连续对话:支持多轮问答,让对话更加自然连贯
  • 📝 对话管理:帮助程序跟踪和管理对话历史

为什么需要 Assistant Role?

与人类对话一样,与 AI 的连续对话也需要”记忆”。当用户与AI交流时,如果没有上下文,AI 无法理解用户在之前的对话中的交流内容,通过 Assistant Role,我们将 AI 每一轮的回答都记录下来,并在下一轮请求时一同发送,这样 AI 就能理解完整的对话上下文。

Assistant Role 与 System Role、User Role 的关系

三种角色的协作分工

角色作用内容来源变化频率
System Role设定 AI 的行为规则和身份开发者预设通常固定
User Role用户的提问和指令用户输入每次对话都可能变化
Assistant RoleAI 的回答记录AI 自动生成每轮对话都会新增

messages 数组中三种消息的顺序

messages 数组中的消息顺序非常重要,AI 模型按照消息出现的顺序来理解对话上下文。因此,必须严格按照时间顺序排列消息:

正确顺序:
1. system (最先)
2. user (第一轮用户问题)
3. assistant (第一轮AI回答)
4. user (第二轮用户问题)
5. assistant (第二轮AI回答)
6. user (第三轮用户问题)
...以此类推

示例程序:带有上下文的单轮对话

注意

本程序需要配合my_info.h代码使用,否则程序将无法正常编译。
请点击以下链接前往该代码页面,复制下载该代码:

http://ai.taichi-maker.com/index.php/homepage/ai-tutorial-index/ai-maker-project-tutorial-index/my_info_h-code-description/

/* 
 * ESP32 AI平台调用 Assistant角色示例
 * 
 * 功能描述:
 * 本程序演示如何在 ESP32(特别是 ESP32-S3)开发板上,通过 HTTPS 协议向 AI 平台
 * 发送带有上下文的对话请求,展示如何使用 assistant role 实现多轮对话功能。
 * 
 * 本程序仅执行一次对话请求,但这次请求中包含了完整的对话历史,
 * 模拟了多轮对话中的"第二轮"场景,演示 assistant role 如何传递上下文。
 * 
 * 对话场景:
 * - User(第一轮): 帮我计算2的2次方
 * - AI(第一轮回答): 2的2次方等于4。计算方法是:2 × 2 = 4。
 * - User(第二轮/本程序请求点): 那3呢
 * 
 * 通过本程序,初学者可以清晰理解:当 AI 需要理解上下文时,
 * 需要在请求中携带之前的对话历史(通过 assistant role)。
 * 
 * 作者:Taichi-Maker
 * 作者官网:http://ai.taichi-maker.com
 * 创建日期:2026年03月27日
 * 版本:1.0.1
 * 
 * 硬件要求:
 * - 支持 Wi-Fi 的 ESP32 开发板(推荐使用 ESP32-S3-DevKitC-1,因其性能更好、内存更大)
 * 
 * 所需软件库:
 * - ArduinoJson 库(版本 7.0.0 或更高)——用于处理 JSON 数据(虽然本例中请求体为硬编码,但响应解析通常需要它)
 *   官网:https://arduinojson.org/
 * 
 * 配置说明:
 * 
 * 1. 在 my_info.h 文件中填写您的 Wi-Fi 名称(ssid)和密码(password)。
 * 2. 在 my_info.h 文件中将 ai_api_key 替换为您从 AI 平台获取的有效 API 密钥(切勿泄露!)。
 * 3. 确保开发板已正确连接到电脑,并选择正确的开发板型号与端口。
 * 
 * 使用方法:
 * 将本程序上传至 ESP32 后,打开串口监视器(波特率设置为 115200),
 * 程序会自动连接 Wi-Fi 并向 AI 平台发送两次请求,每次请求都会包含之前的对话历史,
 * 从而实现上下文感知的多轮对话。
 * 
 * 注意事项:
 * - 本例使用 client.setInsecure() 跳过了 SSL 证书验证,仅适用于测试环境;
 *   在生产环境中应使用有效证书以确保通信安全。
 * - 请求仅在 setup() 中执行两次,loop() 为空,不会重复发送。
 * 
 * 兼容性说明:
 * 本程序已在 ESP32-S3-DevKitC-1 开发板上测试通过。
 * 
 * 许可证:MIT License
 * 
 * 程序源:
 * 本程序源自太极创客团队精心开发的《AI创客项目开发教程》。该教程专为热爱科技创新、热衷于动手实践 * 创客爱好者与初学者量身打造,是一套完全免费、开源且注重实战的AIoT(人工智能物联网)入门学习资源。
 * 
 * 通过本教程,您可以系统地掌握从项目构思、方案设计、软硬件选型,到实际搭建、系统集成与调试优化的 * 整开发流程。
 * 您可以通过以下链接获得更多关于本教程的详细信息:
 * http://ai.taichi-maker.com/index.php/homepage/ai-tutorial/
 */

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include "my_info.h"

// 创建一个安全的 Wi-Fi 客户端(用于 HTTPS 连接)
WiFiClientSecure client;

// 创建一个 HTTP 客户端对象,用于发送请求
HTTPClient https;

/* 
 * -------------- 带有上下文的对话请求体 --------------
 * 
 * 此处使用 C++11 的原始字符串字面量(Raw String Literal)语法 R"rawliteral(...)rawliteral"
 * 来定义一个多行 JSON 字符串,避免手动转义双引号和换行符。
 * 
 * 该 JSON 符合 OpenAI API 兼容格式,包含以下关键字段:
 * - model: 指定要调用的 AI 模型名称
 * - messages: 对话历史,包含 system、user、assistant、user 四条消息
 * 
 * 本请求体模拟了多轮对话中的"第二轮"场景:
 * - system: 设定 AI 的身份
 * - user(第一轮): 帮我计算2的2次方
 * - assistant(第一轮回答): 2的2次方等于4。计算方法是:2 × 2 = 4。
 * - user(第二轮): 那3呢
 * 
 * 通过携带前面对话历史,AI 能够理解"那3呢"是指"3的2次方等于几"。
 */
const char* request_payload = R"rawliteral({
  "model": "qwen-flash",
  "messages": [
    {
      "role": "system",
      "content": "你是一个智能助理"
    },
    {
      "role": "user",
      "content": "帮我计算2的2次方"
    },
    {
      "role": "assistant",
      "content": "2的2次方等于4。计算方法是:2 × 2 = 4。"
    },
    {
      "role": "user",
      "content": "那3呢"
    }
  ]
})rawliteral";

void setup() {
  // 初始化串口通信,波特率为 115200
  Serial.begin(115200);
  delay(1000); // 短暂等待串口稳定

  Serial.println();
  Serial.println("---------- AI Platform Config ----------");
  Serial.print("AI Platform API Endpoint: ");
  Serial.print(ai_host);
  Serial.println(ai_endpoint);
  Serial.println();

  Serial.println("---------- Procedures ----------");
  Serial.println("Step 1: Connecting WiFi...");
  
  // 开始连接 Wi-Fi
  WiFi.begin(ssid, password);

  // 循环等待直到成功连接
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("Step 2: WiFi Connected!");
  Serial.println("Step 3: Initialize HTTPS Connection...");

  // 【重要】跳过 SSL 证书验证(仅用于开发测试!)
  // 在真实产品中应加载有效证书以防止中间人攻击
  client.setInsecure();

  // 设置SSL连接超时时间
  client.setTimeout(15); // 15秒超时
  
  Serial.println("Step 4: Send Request to AI Platform...");
  Serial.println();
  
  // 发送带有上下文的请求
  sendAIRequest(request_payload, "带有上下文的对话请求");

  Serial.println();
  Serial.println("Step 5: Task Completed!");
}

// 主循环留空,因为本例只需发送一次请求
void loop() {
  // 空
}

/* 
 * -------------- 向 AI 平台发送 HTTPS 请求的核心函数 --------------
 * 
 * 该函数完成以下步骤:
 * 1. 构造完整的 HTTPS 请求 URL(基于 my_info.h 中定义的主机、端口和路径)
 * 2. 设置请求头:Content-Type 为 application/json,Authorization 为 Bearer + API 密钥
 * 3. 发送 POST 请求,携带上述 JSON 请求体
 * 4. 接收并打印 HTTP 响应状态码和响应内容
 * 
 * 参数:
 * - payload: 要发送的 JSON 请求体
 * - description: 请求的描述名称,用于输出显示
 */
void sendAIRequest(const char* payload, const char* description) {
  // 构造 Authorization 请求头:格式为 "Bearer <your-api-key>"
  String auth = "Bearer ";
  auth += ai_api_key;

  // 初始化 HTTPS 连接(使用 client、主机名、端口、API 路径)
  if (https.begin(client, ai_host, ai_port, ai_endpoint)) {

    // 设置超时时间(毫秒)- 增加超时时间以处理更复杂的请求
    https.setTimeout(20000); // 20秒超时
    https.setConnectTimeout(10000); // 10秒连接超时

    // 添加必要的 HTTP 请求头
    https.addHeader("Content-Type", "application/json");
    https.addHeader("Authorization", auth);

    // 发送 POST 请求,并获取 HTTP 状态码
    int httpCode = https.POST(payload);

    Serial.println("---------- " + String(description) + " Response ----------");
    if (httpCode > 0) {
      // 打印 HTTP 响应状态码(如 200 表示成功)
      Serial.print("HTTP Response Code: ");
      Serial.println(httpCode);

      // 如果响应成功(HTTP 200 OK)
      if (httpCode == HTTP_CODE_OK) {
        // 获取完整的响应字符串
        String resp = https.getString();
        Serial.println("AI Response : ");
        Serial.println(resp);  // 打印 AI 返回的完整 JSON(含模型生成的回答)
      }
    } else {
      // 打印 HTTP 错误信息(如连接失败、超时等)
      Serial.print("HTTP error: ");
      Serial.println(https.errorToString(httpCode).c_str());
      Serial.print("Error code: ");
      Serial.println(httpCode);
    }
    Serial.println("========================================");

    // 结束本次 HTTP 会话,释放资源
    https.end();
  } else {
    // 如果无法建立 HTTPS 连接,打印错误提示
    Serial.println("Unable to connect to server");
  }
}

/*
 * ========================================================================
 * 【附录】本程序实际发送的 HTTP 请求内容(供参考)
 * ========================================================================
 * 
 * 请求内容:
 * POST /api/v3/chat/completions HTTP/1.1
 * Host: ark.cn-beijing.volces.com
 * Content-Type: application/json
 * Authorization: Bearer [你的API密钥]
 * 
 * {
 *   "model": "qwen-flash",
 *   "messages": [
 *     {
 *       "role": "system",
 *       "content": "你是一个智能助理"
 *     },
 *     {
 *       "role": "user",
 *       "content": "帮我计算2的2次方"
 *     },
 *     {
 *       "role": "assistant",
 *       "content": "2的2次方等于4。计算方法是:2 × 2 = 4。"
 *     },
 *     {
 *       "role": "user",
 *       "content": "那3呢"
 *     }
 *   ]
 * }
 * 
 * 说明:
 * - 本程序请求包含完整的对话历史,模拟多轮对话中的"第二轮"场景
 * - messages 数组中包含:
 *   1. system: 设定 AI 身份
 *   2. user(第一轮): 第一轮用户提问
 *   3. assistant(第一轮回答): 第一轮 AI 回答
 *   4. user(第二轮): 第二轮用户提问"那3呢"
 * - AI 通过理解完整上下文,能够正确理解"那3呢"是指"3的2次方"
 * - 通过这种方式,可以实现具有上下文感知能力的多轮对话
 * ========================================================================
 */

程序说明:

本程序演示了如何通过 assistant role 实现带有上下文的对话。

本程序仅执行一次请求,这次请求模拟了多轮对话中的”第二轮”场景,包含完整的对话历史:

  • User: 帮我计算2的2次方
  • AI: 2的2次方等于4。计算方法是:2 × 2 = 4。
  • User: 那3呢

关键特点:

  • 程序只发送一次请求,但请求中包含了完整的对话历史
  • 通过 assistant role 携带 AI 的历史回答
  • AI 能够理解上下文,正确理解”那3呢”是指”3的2次方等于几”

关键代码:带有上下文的请求体定义

const char* request_payload = R"rawliteral({
  "model": "qwen-flash",
  "messages": [
    {
      "role": "system",
      "content": "你是一个智能助理"
    },
    {
      "role": "user",
      "content": "帮我计算2的2次方"
    },
    {
      "role": "assistant",
      "content": "2的2次方等于4。计算方法是:2 × 2 = 4。"
    },
    {
      "role": "user",
      "content": "那3呢"
    }
  ]
})rawliteral";

这段代码定义了带有上下文的请求体,包含完整的对话历史,模拟多轮对话中的”第二轮”场景。

关键结构解析:

  • role: "system" – 设定 AI 的身份
  • role: "user" (第一轮) – 第一轮用户提问
  • role: "assistant" – 第一轮 AI 的回答
  • role: "user" (第二轮) – 第二轮用户提问”那3呢”

为什么这样做?

  • 通过携带历史对话,AI 才能理解”那3呢”是追问”3的2次方”
  • 这种方式实现了上下文感知的连续对话

对话流程

以下展示的是示例程序请求和AI平台响应流程,请留意:请求中携带了之前的对话历史,使 AI 能够理解上下文

┌─────────────────────────────────────────────────────────────────┐
│                     带有上下文的对话请求                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ESP32 ──────► messages:                                       │
│                 [                                               │
│                   {role: "system", content: "你是一个智能助理"},  │
│                   {role: "user", content: "帮我计算2的2次方"},    │
│                   {role: "assistant", content: "2的2次方等于4。"},│
│                   {role: "user", content: "那3呢"}               │
│                 ]                                               │
│                              ▼                                  │
│             AI 平台理解上下文以及用户提问然后推理回应                │
│                              ▼                                  │
│   ESP32 ◄────── AI 回答:                                        │
│                 {                                               │
│                   role: "assistant",                            │
│                   content: "3的2次方等于9。"                      │
│                 }                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

带有上下文的AI交流关键机制解析

1. 历史记录累积

每完成一轮对话,新的 assistant role 就会被添加到 messages 数组中。随着对话轮次的增加,messages 数组会不断增长,包含越来越多的历史对话。

2. 上下文理解

AI 模型通过读取完整的 messages 数组,理解对话的完整脉络。如,在本示例中,当用户提到”那3呢”时,AI 会结合第一轮的”2的2次方”,理解用户是想问”3的2次方”。

3. 动态消息构建

在实际应用中,每一轮请求都需要重新构建 messages 数组,包含:

  • System Role(固定不变)
  • 所有的历史对话(User + Assistant)
  • 当前的新问题(User)

思考题:

如果我们想要继续以上示例程序中的对话,实现新的一轮与AI交流,在这一轮里,我们需要问AI的问题是“那5呢”,也就是问AI“5的2次方等于几”。为了实现这一请求,我们该如何编写新一轮交流的请求体?

请先不要看以下答案,试着自己思考一下,并且尝试改写以上示例程序,验证你的请求体内容是否正确。

思考题答案:

const char* request_payload = R"rawliteral({
  "model": "qwen-flash",
  "messages": [
    {
      "role": "system",
      "content": "你是一个智能助理"
    },
    {
      "role": "user",
      "content": "帮我计算2的2次方"
    },
    {
      "role": "assistant",
      "content": "2的2次方等于4。计算方法是:2 × 2 = 4。"
    },
    {
      "role": "user",
      "content": "那3呢"
    },
    {
      "role": "assistant",
      "content": "3的2次方等于9。计算方法是:3 × 3 = 9。"
    },
    {
      "role": "user",
      "content": "那5呢"
    }
  ]
})rawliteral";

思考题请求体说明:

本请求体内容在两轮对话的基础上增加了一轮,演示更复杂的多轮对话场景:

  1. 第一轮对话:用户询问”2的2次方是多少”,AI 回答”2的2次方等于4。”
  2. 第二轮对话:用户追问”那3呢”,AI 回答”3的2次方等于9。计算方法是:3 × 3 = 9。”
  3. 第三轮对话:用户再追问”那5呢”,AI 回答”5的2次方等于25。计算方法是:5 × 5 = 25。”

关键特点:

  • 三轮对话形成完整的上下文链
  • 每轮请求都携带之前所有的对话历史
  • AI 能够追踪多轮对话的脉络


总结

Assistant Role 的核心价值

  1. 实现上下文理解:通过携带对话历史,AI 能够理解多轮对话的完整脉络
  2. 支持连续对话:用户无需重复说明背景信息,对话更加自然流畅
  3. 构建智能应用:为客服、调试、控制等场景提供连贯的交互体验

Assistant Role 的使用要点

  1. 历史累积:每轮对话后,将 assistant 的回答添加到 messages 数组
  2. 顺序重要:严格按照时间顺序排列消息
  3. 成本控制:注意 token 消耗,避免对话过长
  4. 动态管理:在实际应用中,需要动态构建请求体