杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

LLM 与 AI 语音助手接入

本文档介绍 AC79NN AIoT SDK 中 LLM(大语言模型)与 AI 语音助手接入的整体架构、核心服务、各平台接入方式与典型调用流程,帮助开发者理解并基于此能力构建语音交互产品。

Purpose and Scope

本页覆盖 apps/common/LLM 目录下的完整 LLM/AI 语音助手接入能力,包括:

  • OneSDK AI Gateway(aigw):设备端 LLM 配置下发服务(get_llm_config),负责从云端获取 LLM 服务的 URL 与 APIKey;
  • OneSDK Realtime Chat Agent:实时语音对话示例(onesdk_realtime/chat_agent),展示端到端音频数据采集、Base64 编码与语音交互流程;
  • 各 AI 平台接入:讯飞 AIUI(ifly_aiui)、百度 DuerOS(duer)、AITOY 端到端(aitoye2e)等;
  • 音频输入基础设施:LLM/audio/audio_input.c 为语音助手提供麦克风数据采集接口。

以下内容属于其他页面,不在本页展开:ASR(语音识别)算法本身(见 apps/common/asr)、网络协议栈(HTTP/MQTT)的底层实现、OneSDK 设备动态注册(iot/dynreg)的完整机制。本页仅引用它们作为依赖。

Overview

在 AC79NN 平台上,AI 语音助手是一个端到端的实时语音对话链路:设备端通过麦克风采集用户语音 → 将音频数据(Base64 编码)发送到云端 LLM 服务 → 云端返回文本/音频回复 → 设备端播报。整个链路的关键前提是设备能够安全地获取 LLM 服务的接入凭证(URL + APIKey),而不是把密钥烧录在固件中。

为此,SDK 在 apps/common/LLM/onesdk/src/aigw/llm.c 中实现了 AIGW(AI Gateway)配置获取服务:设备基于已注册的 OneSDK 身份(instance_id、product_key、device_name、device_secret)向云端 GetLLMConfig 接口发起带 HMAC-SHA256 签名的 HTTP POST 请求,云端返回加密的 APIKey 与 URL,设备端用 device_secret 做 AES 解密后获得真正的 LLM 接入凭证。这样固件中只需保存设备密钥,即使固件泄露也不会直接暴露 LLM 的 APIKey。

在业务层,SDK 同时提供了多种语音助手方案的接入示例:

方案目录定位
OneSDK Realtime Chat Agentonesdk/examples/onesdk_realtime/chat_agent基于火山方舟 OneSDK 的实时语音对话(推荐)
讯飞 AIUIifly_aiui讯飞 AIUI 语音交互方案
百度 DuerOSduer/intelligent_duer百度 DuerOS 智能语音助手
AITOY 端到端aitoye2eAITOY 端到端语音模型示例

Architecture

下图展示了 LLM 与 AI 语音助手接入的整体架构与数据流:

flowchart TD
    subgraph sg_Device["设备端 (AC79NN)"]
        Mic["麦克风采集<br/>LLM/audio/audio_input.c"]
        App["应用层<br/>onesdk_realtime/chat_agent<br/>realtime_demo.c"]
        AIGW["AIGW 配置服务<br/>onesdk/src/aigw/llm.c"]
        Base64["Base64 编解码<br/>realtime_demo.c 内实现"]
        Play["音频播报"]
    end

    subgraph sg_Cloud["云端"]
        IOT["OneSDK IoT 平台<br/>GetLLMConfig"]
        LLMSvc["LLM 语音服务<br/>Realtime API"]
        Vendor["第三方平台<br/>AIUI / DuerOS"]
    end

    subgraph sg_Auth["安全基础设施"]
        HMAC["HMAC-SHA256 签名"]
        AES["AES 解密 APIKey"]
    end

    App --> AIGW
    AIGW --> HMAC
    AIGW -->|"HTTP POST<br/>签名请求"| IOT
    IOT -->|"加密 APIKey + URL"| AIGW
    AIGW --> AES
    AES -->|"明文 URL/APIKey"| App
    Mic -->|"PCM 音频"| App
    App --> Base64
    Base64 -->|"Base64 音频帧"| LLMSvc
    LLMSvc -->|"文本/音频回复"| App
    App --> Play
    App -.-> Vendor

各组件职责:

  • AIGW 配置服务(llm.c):封装设备动态注册、签名生成、HTTP 请求、响应解析与 APIKey 解密,对外只暴露 get_llm_config() 与 aigw_llm_config_destroy() 两个接口;
  • 音频输入(audio_input.c):为语音助手提供统一的麦克风采集抽象,屏蔽不同音频硬件的差异;
  • Realtime Chat Agent(realtime_demo.c):把采集到的音频帧 Base64 编码后发送给 LLM Realtime 服务,并接收回复;
  • 安全基础设施:HMAC-SHA256 保证请求可被云端校验身份,AES 保证 APIKey 在传输与固件中不落明文。

核心实现:AIGW LLM 配置服务

数据模型与错误码

llm.h 定义了整个 LLM 接入的错误码枚举与配置结构体:

typedef enum {
    LLM_OK = 0,          // 成功
    LLM_ERR_BASE = -100, // 错误码基准值

    // 具体错误类型
    LLM_ERR_ALLOC_FAILED,    // 内存分配失败
    LLM_ERR_DEV_REG_FAILED,  // 设备注册失败
    LLM_ERR_SIGN_FAILED,     // 签名生成失败
    LLM_ERR_INVALID_CTX,     // 上下文无效
    LLM_ERR_NETWORK_FAIL,     // 网络通信失败
    LLM_ERR_PARSE_FAILED
} llm_error_t;

typedef struct {
    llm_error_t err_code;

    char *url;
    char *api_key;
} aigw_llm_config_t;

Source: llm.h

设计意图:错误码从 -100 起步,与 OneSDK 其他组件错误码错开,避免混淆;aigw_llm_config_t 中 url 与 api_key 为堆内存指针,因此配套了显式的销毁函数 aigw_llm_config_destroy(),由调用方负责生命周期管理。

get_llm_config:配置获取主流程

get_llm_config() 是整个 LLM 接入的入口,实现于 llm.c,其完整流程为:

  1. 生成随机数与时间戳:random_num() + unix_timestamp(),作为请求签名参数的一部分,防止重放攻击;
  2. 初始化 AWS 公共库:aws_common_library_init(),为后续 JSON/字节缓冲操作准备分配器;
  3. 构建动态注册参数:填充 iot_dynamic_register_basic_param(instance_id、timestamp、random_num、product_key、device_name、auth_type);
  4. 按需动态注册:若 device_secret 为空,先调用 dynamic_register() 完成设备注册,失败则返回 LLM_ERR_DEV_REG_FAILED;
  5. 强制 auth_type = 0:代码注释明确"llm api auth_type must be 0",即 LLM API 只接受一型密钥认证;
  6. HMAC-SHA256 签名:iot_hmac_sha256_encrypt() 用 device_secret 对注册参数生成签名;
  7. 组装 POST 请求体:JSON 中包含 InstanceID、product_key、device_name、random_num、timestamp、signature;
  8. 构造请求 URL:http_host + 固定路径 /2021-12-14/GetLLMConfig,查询参数 Action=GetLLMConfig&Version=2021-12-14;
  9. 发起 HTTP POST:new_http_ctx() → http_ctx_set_url() → http_ctx_set_method(HTTP_POST) → 设置 Content-Type: application/json → http_request();
  10. 解析响应:调用静态函数 parse_llm_config(),成功则填充 out_config,网络层失败返回 LLM_ERR_NETWORK_FAIL;
  11. 清理:释放 JSON、body、http_ctx 等资源。
static int parse_llm_config(struct aws_allocator *allocator, const char *device_secret,
                            const http_response_t *response, aigw_llm_config_t *out_config)
{
    if (out_config == NULL) {
        return LLM_ERR_ALLOC_FAILED;
    }

    struct aws_json_value *response_json = aws_json_value_new_from_string(allocator,
                                           aws_byte_cursor_from_c_str(response->response_body));
    if (!response_json) {
        goto error_cleanup;
    }

    struct aws_json_value *result_json = aws_json_value_get_from_object(response_json,
                                         aws_byte_cursor_from_c_str("Result"));
    if (!result_json) {
        goto error_cleanup;
    }

    char *key = aws_json_get_str(allocator, result_json, "APIKey");
    if (!key) {
        goto error_cleanup;
    }

    char *api_key = aes_decode(allocator, device_secret, key, false);
    free(key);  // 修正内存释放方式
    if (!api_key) {
        goto error_cleanup;
    }

    out_config->api_key = api_key;
    char *url = aws_json_get_str(allocator, result_json, "URL");
    if (!url) {
        goto error_cleanup;
    }
    out_config->url = strdup(url);
    free(url);

    // 修正JSON对象释放方式
    aws_json_value_destroy(response_json);
    return LLM_OK;

error_cleanup:
    if (response_json) {
        aws_json_value_destroy(response_json);
    }
    return LLM_ERR_PARSE_FAILED;
}

Source: llm.c

关键安全设计:云端返回的 APIKey 是密文,设备端必须用 device_secret 通过 aes_decode() 解密才能获得真正的 Key;URL 字段则明文下发。这样固件中只有设备密钥,LLM 服务密钥的泄露面被压缩到"已注册设备"本身。解析使用 goto error_cleanup 统一错误出口,所有失败路径都返回 LLM_ERR_PARSE_FAILED 并释放 JSON 对象。

配置销毁

void aigw_llm_config_destroy(aigw_llm_config_t *config)
{
    if (!config) {
        return;
    }
    if (config->api_key) {
        free(config->api_key);
        config->api_key = NULL;
    }
    if (config->url) {
        free(config->url);
        config->url = NULL;
    }
    free(config);
    config = NULL;
}

Source: llm.c

设计意图:api_key 是敏感凭证,使用 free() 释放而非延迟回收;局部置 NULL 防止悬垂指针。该函数必须是调用方在使用完配置后显式调用,属于典型的"谁申请谁释放"所有权模型。

核心实现:OneSDK Realtime Chat Agent

apps/common/LLM/onesdk/examples/onesdk_realtime/chat_agent/realtime_demo.c 是实时语音对话的完整示例,包含:

  • 实例配置宏:SAMPLE_HTTP_HOST(线上实例 iot-cn-shanghai.iot.volces.com)、SAMPLE_INSTANCE_ID、SAMPLE_MQTT_HOST、SAMPLE_DEVICE_NAME、SAMPLE_DEVICE_SECRET、SAMPLE_PRODUCT_KEY、SAMPLE_PRODUCT_SECRET,接入时替换为真实产品参数;
  • GlobalSign Root CA 证书:内置 global_sign_root_ca[],用于 TLS 校验证书链;
  • Base64 编解码工具:基于 mbedtls 实现两遍式(先查询长度再实际编码)的 base64_encode() / base64_decode();
  • 音频测试数据:data[] / data2[] 数组存放 PCM 音频的 Base64 字符串,用于离线验证语音链路。
int base64_encode(const unsigned char *input, size_t input_len, char **output, size_t *output_len)
{
    // 参数校验
    if (!input || input_len == 0 || !output || !output_len) {
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
    }

    // 第一次调用:获取所需缓冲区大小
    size_t olen;
    int ret = mbedtls_base64_encode(NULL, 0, &olen, input, input_len);
    if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
        return ret;
    }

    // 分配内存(包括终止符)
    *output = (char *)malloc(olen + 1);
    if (!*output) {
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
    }

    // 第二次调用:实际编码
    if ((ret = mbedtls_base64_encode((unsigned char *)*output, olen,
                                     output_len, input, input_len)) != 0) {
        free(*output);
        *output = NULL;
        return ret;
    }

    // 添加终止符
    (*output)[*output_len] = '\0';
    return 0;
}

Source: realtime_demo.c

设计意图:两遍式编码避免调用方预先知道输出长度;malloc(olen + 1) 多分配一个字节存放 '\0' 终止符,使输出可直接当作 C 字符串使用。base64_decode() 则对称地先去除末尾终止符再解码。语音数据走 Base64 是为了让二进制 PCM 音频能够嵌入 JSON/文本协议中传输。

第三方 AI 平台接入

SDK 在 apps/common/LLM 下按平台分目录组织接入代码:

目录说明关键文件
ifly_aiui讯飞 AIUI:ifly_aiui_demo.c(示例)、ifly_aiui_user.c(用户配置)、ifly_model_parse.c(模型解析)ifly_aiui_demo.c
duer百度 DuerOS:intelligent_duer(认证算法 duer_auth_algorithm.c、HTTP 请求 duer_http_req.c、JSON 解析 duer_json_parse.c、录音 duer_record.c、Socket duer_socket.c);my_platform(自有平台 HTTP API 封装)duer_http_req.c、duer_auth_algorithm.c
aitoye2eAITOY 端到端语音模型示例e2e_demo.c
extra附加工具(如 G.711 编解码 g711.c,用于音频编码转换)g711.c
audio音频输入抽象,供各语音方案复用audio_input.c

各平台接入共享同一套基础能力:设备身份注册(OneSDK iot_basic)、HTTP/TLS 传输(protocols/http)、音频采集(LLM/audio)。差异主要体现在认证方式(讯飞 AppID/APIKey、DuerOS OAuth 算法、OneSDK HMAC 签名)与协议格式(JSON 请求、WebSocket 长连接等)上。

核心流程

LLM 配置获取时序

sequenceDiagram
    participant App as 应用层 (chat_agent)
    participant AIGW as aigw/llm.c
    participant Reg as iot/dynreg
    participant HTTP as protocols/http
    participant Cloud as OneSDK 云端 GetLLMConfig

    App->>AIGW: get_llm_config(iot_basic_ctx, &out_config)
    activate AIGW
    AIGW->>AIGW: 生成 random_num / timestamp
    alt device_secret 为空
        AIGW->>Reg: dynamic_register(iot_basic_ctx)
        Reg-->>AIGW: 设备注册结果
    end
    AIGW->>AIGW: HMAC-SHA256 签名 (auth_type=0)
    AIGW->>HTTP: POST /2021-12-14/GetLLMConfig<br/>body: InstanceID/product_key/device_name/random/timestamp/signature
    activate HTTP
    HTTP->>Cloud: HTTPS 请求
    Cloud-->>HTTP: Result{APIKey(密文), URL}
    deactivate HTTP
    AIGW->>AIGW: aes_decode(device_secret, APIKey)
    AIGW-->>App: LLM_OK + out_config{url, api_key}
    deactivate AIGW
    App->>App: aigw_llm_config_destroy(&config)

实时语音对话数据流

flowchart LR
    Mic["麦克风 PCM 采集"] --> Enc["base64_encode<br/>(mbedtls 两遍式)"]
    Enc --> Send["发送音频帧到 LLM Realtime"]
    Send --> Resp["接收文本/音频回复"]
    Resp --> Dec["base64_decode"]
    Dec --> Play["音频播报"]
    Resp --> Text["文本展示/意图执行"]

实时对话链路的特点:音频帧是分块连续发送的(流式),每帧独立 Base64 编码后随请求体上行;回复同样以流式分块到达。这与配置获取的一次性 HTTP 请求(上节)在时序上有本质区别——配置获取是"先认证、再使用"的前置步骤,语音对话则是长连接上的持续交互。

使用示例

获取 LLM 接入配置

#include "llm.h"
#include "iot_basic.h"

// iot_basic_ctx 由 OneSDK 初始化(包含 instance_id/product_key/device_name/device_secret 等)
aigw_llm_config_t *llm_cfg = malloc(sizeof(aigw_llm_config_t));
int ret = get_llm_config(iot_basic_ctx, llm_cfg);
if (ret == LLM_OK) {
    printf("LLM url=%s, api_key=%s\n", llm_cfg->url, llm_cfg->api_key);
    // 使用 url/api_key 建立 LLM Realtime 连接...
} else {
    printf("get_llm_config failed: %d\n", ret);
}
aigw_llm_config_destroy(llm_cfg);

Source: llm.h 、 llm.c

音频帧 Base64 编码(语音上行)

// input: 麦克风采集的 PCM 数据; input_len: 帧长度
char *b64 = NULL;
size_t b64_len = 0;
if (base64_encode((const unsigned char *)pcm_frame, frame_len, &b64, &b64_len) == 0) {
    // b64 可直接嵌入 JSON 请求体发送给 LLM Realtime 服务
    send_audio_frame(b64, b64_len);
    free(b64);
}

Source: realtime_demo.c

示例接入参数配置

// 线上实例
#define SAMPLE_HTTP_HOST "iot-cn-shanghai.iot.volces.com"
#define SAMPLE_INSTANCE_ID "***"
#define SAMPLE_MQTT_HOST "***"
#define SAMPLE_DEVICE_NAME "***"
#define SAMPLE_DEVICE_SECRET "***"
#define SAMPLE_PRODUCT_KEY "***"
#define SAMPLE_PRODUCT_SECRET "***"

Source: realtime_demo.c

配置选项

配置项来源类型说明
SAMPLE_HTTP_HOSTrealtime_demo.c字符串宏云端 IoT 平台主机名,用于拼接 GetLLMConfig 请求 URL
SAMPLE_INSTANCE_IDrealtime_demo.c字符串宏OneSDK 实例 ID,设备注册与请求签名的必填参数
SAMPLE_DEVICE_NAMErealtime_demo.c字符串宏设备名称
SAMPLE_DEVICE_SECRETrealtime_demo.c字符串宏设备密钥,用于 HMAC 签名与 APIKey AES 解密;为空时触发 dynamic_register()
SAMPLE_PRODUCT_KEYrealtime_demo.c字符串宏产品 Key
SAMPLE_PRODUCT_SECRETrealtime_demo.c字符串宏产品密钥(动态注册用)
iot_basic_ctx->config->auth_typeiot_basic 配置整数认证类型;LLM API 强制要求为 0
GET_LLM_CONFIG_PATHllm.c常量字符串/2021-12-14/GetLLMConfig,云端接口路径,随 API 版本演进
API_VERSION_QUERY_PARAMllm.c常量字符串Version=2021-12-14,API 版本查询参数

API 参考

int get_llm_config(iot_basic_ctx_t *iot_basic_ctx, aigw_llm_config_t *out_config)

从云端获取 LLM 服务配置(URL 与解密后的 APIKey)。

参数:

  • iot_basic_ctx(iot_basic_ctx_t *):OneSDK 基础上下文,必须已初始化,包含 config->instance_id、product_key、device_name、device_secret、auth_type、http_host 等字段;
  • out_config(aigw_llm_config_t *):输出参数,成功时填充 url 与 api_key(均为堆内存,需调用 aigw_llm_config_destroy 释放)。

返回:

  • LLM_OK(0):成功;
  • LLM_ERR_DEV_REG_FAILED:device_secret 为空且动态注册失败;
  • LLM_ERR_NETWORK_FAIL:HTTP 请求无响应;
  • LLM_ERR_PARSE_FAILED:响应 JSON 缺失 Result/APIKey/URL 或 AES 解密失败;
  • LLM_ERR_ALLOC_FAILED:out_config 为 NULL 或内存分配失败。

实现要点: 见 llm.c。

void aigw_llm_config_destroy(aigw_llm_config_t *config)

释放 aigw_llm_config_t 及其内部 url、api_key 内存,并将指针置 NULL。见 llm.c。

int base64_encode(const unsigned char *input, size_t input_len, char **output, size_t *output_len)

将二进制音频数据编码为 Base64 字符串(输出带 '\0' 终止符)。返回 0 成功;参数非法或 mbedtls 失败时返回 MBEDTLS 错误码。见 realtime_demo.c。

int base64_decode(const char *input, size_t input_len, unsigned char **output, size_t *output_len)

将 Base64 字符串解码为二进制 PCM 数据;自动剔除末尾 '\0'。返回 0 成功。见 realtime_demo.c。

失败模式与边界情况

设备未注册

当 iot_basic_ctx->config->device_secret == NULL 时,get_llm_config() 会先调用 dynamic_register() 完成设备注册。若注册失败(如网络不通、产品密钥错误),直接返回 LLM_ERR_DEV_REG_FAILED,调用方应重试或上报错误。注意:注册成功后 device_secret 会被写入上下文,后续调用不会再重复注册。

APIKey 解密失败

parse_llm_config() 中对 APIKey 的解析使用 aes_decode(allocator, device_secret, key, false)。如果云端返回的密文与设备密钥不匹配(例如设备在云端被重置、密钥轮换),解密返回 NULL,函数走 error_cleanup 返回 LLM_ERR_PARSE_FAILED。此时固件中不会残留任何部分解析的配置。

HTTP 层失败

http_request() 返回 NULL(超时、DNS 失败、TLS 握手失败等)时返回 LLM_ERR_NETWORK_FAIL。源码未对 HTTP 做重试,重试策略由上层应用决定——典型的做法是短退避重试 2-3 次后提示用户"网络不可用"。

JSON 解析边界

  • 响应体不是合法 JSON → aws_json_value_new_from_string 失败 → LLM_ERR_PARSE_FAILED;
  • 缺少 Result 节点、APIKey 或 URL 字段 → 各自 goto error_cleanup;
  • 所有失败路径统一销毁 response_json,避免内存泄漏;
  • out_config == NULL 时返回 LLM_ERR_ALLOC_FAILED(语义上为参数错误,但复用该错误码)。

Base64 编解码边界

  • input == NULL || input_len == 0 直接返回错误,防止空指针解引用;
  • 解码时若输入恰好以 '\0' 结尾则自动减长,兼容"带终止符的字符串"与"原始长度"两种调用习惯;
  • 编码输出的 '\0' 终止符不计入 output_len,调用方拼接 JSON 时需自行处理。

并发与资源管理

  • 单线程模型:get_llm_config() 内部全程使用调用方线程栈上或显式分配的资源,无全局可变状态,天然可重入;但 random_num() 与 unix_timestamp() 依赖系统时钟与随机源,在同一时刻并发调用会生成相同时间戳——不支持并发调用同一上下文,调用方应串行化配置获取流程;
  • 内存所有权:url/api_key 由 malloc/strdup 分配,必须配对 free(通过 aigw_llm_config_destroy);示例中 base64_encode 的输出 *output 同样要求调用方 free;
  • 安全擦除:签名串与 body_str 使用 aws_string_destroy_secure() 销毁(清零后释放),降低敏感信息残留在堆中的风险;api_key 释放使用普通 free(),如需更高安全等级可替换为安全清零版本。

性能与运维注意

  • 请求开销:GetLLMConfig 每次调用包含 1 次 HTTPS 往返 + HMAC 签名 + AES 解密,建议只在首次启动或配置失效时调用一次并缓存结果,避免频繁请求;
  • TLS 校验:realtime_demo.c 内置 GlobalSign Root CA,生产环境应使用与实例匹配的根证书;llm.c 中 URL 协议部分被注释掉,默认直接使用 http_host 拼接,若需要 HTTPS 需启用对应配置;
  • 音频链路:Base64 编码会使数据膨胀约 33%,在低带宽网络下需评估上行带宽;建议按帧编码、流式发送,避免一次性缓存整段音频;
  • 调试手段:llm.c 中保留了 printf("llm request body: %s\n", content) 与响应体打印,可临时开启定位签名/解析问题,量产固件应关闭。

扩展点

  1. 新增云端 API 版本:修改 GET_LLM_CONFIG_PATH 与 API_VERSION_QUERY_PARAM 宏即可适配新的接口版本,无需改动调用方;
  2. 接入新 LLM 平台:参照 ifly_aiui、duer、aitoye2e 的目录结构,在 apps/common/LLM/ 下新增平台目录,复用 LLM/audio/audio_input.c 的采集抽象与 OneSDK 的注册/HTTP 能力;
  3. 替换认证方式:get_llm_config() 内的 HMAC 签名与 AES 解密是内聚的两步,可抽成独立的"凭证提供器"接口,便于对接私有化部署或自建网关;
  4. 音频格式扩展:extra/g711.c 提供 G.711 编解码,可在此扩展更多编码(如 Opus、AAC)以适配不同云端的音频格式要求;
  5. 重试与缓存:建议在应用层包一层"配置缓存 + 退避重试",这是当前源码刻意留给上层的策略空间。

相关链接

  • AIGW LLM 配置服务实现
  • LLM 配置头文件与错误码
  • OneSDK Realtime Chat Agent 示例
  • 讯飞 AIUI 接入
  • 百度 DuerOS 接入
  • AITOY 端到端示例
  • 音频输入抽象

相关页面:ASR 语音识别细节见"语音识别"目录;OneSDK 设备注册与 MQTT 链路见"设备接入"目录;HTTP/TLS 协议栈见"网络协议"目录。

Prev
语音识别 ASR 引擎
Next
摄像头传感器驱动