十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Alexa设备接入实战:从ACK协议到ACT认证全链路解析

Alexa设备接入实战:从ACK协议到ACT认证全链路解析 1. 这不是“配个网”那么简单Alexa设备接入的本质是什么很多人第一次接触Alexa设备接入以为就是下载个App、扫个码、点几下“下一步”——结果卡在“正在连接”界面半小时最后重启路由器、重装App、换手机重试三轮还是失败。我见过太多开发者拿着刚做好的温湿度传感器板子信心满满地连上Wi-Fi却在Alexa App里搜不到设备反复刷新后默默删掉整个项目文档。其实问题根本不在Wi-Fi信号强弱也不在App版本新旧而在于你没意识到Alexa设备接入不是一次性的配网动作而是一套严格分层、双向认证、状态可溯的分布式交互协议体系。它背后跑的是Amazon的Smart Home Skill API、Device SDK、以及底层基于MQTTHTTP的ACKAlexa Communication Kit通信框架。你看到的“发现设备”本质是Alexa云服务向你的设备发起了一次带签名的Discovery请求你点“打开灯”实际触发的是一个包含endpointId、directive、correlationToken的JSON payload经由AWS IoT Core路由到你的设备固件而设备返回的Response必须严格遵循Alexa Smart Home Message Schema v3规范字段名大小写、时间戳格式、status code值都不能错一位。这不是“让设备联网”而是让设备成为Alexa生态里一个可验证、可寻址、可审计的合法节点。适合谁参考硬件工程师要搞清设备端SDK如何对接全栈开发者得理清Skill后端与Lambda函数的事件路由逻辑IoT产品经理必须理解ACK中“proactive state reporting”的触发阈值设计甚至采购人员也该知道为什么同样标称“支持Alexa”的模组有的要额外买License授权有的却能免签直连——这背后是Amazon对设备安全等级如是否启用TLS 1.2、是否支持Secure Boot的硬性分级。整套流程跑通意味着你的设备真正拿到了进入全球超2亿Alexa家庭的“数字通行证”。2. 接入路径选择为什么90%的新项目都该从ACK起步2.1 三条路哪条不是坑Alexa设备接入官方提供三种技术路径Cloud-Connected Device云端直连、Local Control本地控制、Bluetooth LE蓝牙低功耗。但现实中超过八成的新项目最终都落在第一种——也就是通过ACK实现的云端直连。为什么我们来拆解每条路的真实成本Cloud-Connected DeviceACK路径设备固件集成Alexa Communication Kit SDK通过HTTPS/MQTT连接Amazon云服务。优势是开发链路最成熟Amazon提供完整的Device SDKC/C/Python、Sample Code、CI/CD模板且支持OTA升级、远程诊断、批量设备管理。劣势是必须部署自己的云后端哪怕只是个Lambda函数且所有指令流经Amazon服务器存在毫秒级延迟。Local Control局域网直控设备暴露mDNS服务Alexa Echo设备在本地网络内直接发现并通信。优势是响应快100ms、不依赖公网、隐私性好。但Amazon对设备认证极其苛刻必须通过Alexa Certification Lab的物理测试包括Wi-Fi信道抗干扰、多设备并发发现成功率等且仅支持有限品类目前仅照明、开关、插座类。我去年帮一家智能窗帘厂商做认证光是“在2.4G/5G双频Wi-Fi共存环境下连续100次mDNS广播响应时间≤800ms”这一项就返工了4次。Bluetooth LE适用于电池供电的小型设备如门锁、传感器通过Echo设备作为Bridge转发指令。但Echo必须开启BLE扫描默认关闭且设备需预配Bonding信息用户首次配网体验极差——要手动打开手机蓝牙、在Alexa App里选“Add via Bluetooth”再按住设备配对键5秒……实测用户放弃率高达67%。提示如果你的设备需要语音反馈比如“当前温度26度”、支持多房间联动“客厅灯关卧室灯开”、或要接入Routines“Good Night”自动关灯关空调Local和BLE路径根本无法满足。只有ACK路径能完整承载Alexa的语义理解与上下文管理能力。2.2 ACK不是SDK而是一套“协议栈合规包”很多开发者把ACK当成普通SDK下载集成结果在ack_device_init()调用后卡死。这里必须厘清ACK Device SDK Security Framework Certification Requirements。它不是一个函数库而是一整套强制合规体系Security Framework要求设备必须支持TLS 1.2禁用SSLv3/TLS1.0证书必须由Amazon信任的CA签发不能自签名且私钥必须存储在Secure Element或TEE可信执行环境中。我见过某国产Wi-Fi模组厂商为省0.5元BOM成本把私钥明文存Flash里结果在Alexa认证阶段被一票否决。Certification Requirements设备上线前必须通过Amazon的Automated Certification TestACT。测试项包括Discovery响应时间≤3s、Directive处理超时≤5s、State Report上报延迟≤10s、连续72小时无心跳断连等。这些不是建议值而是硬性SLA——任何一项不达标设备在用户端就会显示“设备离线”或“响应缓慢”。Device SDK分层结构真正的开发难点不在业务逻辑而在SDK的三层适配Hardware Abstraction LayerHAL需你实现Wi-Fi连接、RTC时钟、加密芯片驱动等底层接口。比如hal_wifi_connect()函数必须返回标准错误码ACK_ERR_WIFI_CONNECT_FAILED不能直接return -1。Core Service Layer处理ACK协议栈核心包括MQTT会话管理、JWT Token刷新、Message Signing。这里最容易出错的是时间同步——设备系统时间若与NTP服务器偏差30sJWT签名将被Amazon云拒绝。Application Layer才是你写业务逻辑的地方比如收到TurnOndirective后控制GPIO。但必须通过ack_state_report_send()主动上报状态不能等用户问“灯亮了吗”才响应。2.3 Smart Home AI Toolkit不是玩具是生产力加速器搜索热词里出现的“Smart Home AI Toolkit”其实是Amazon去年推出的开发者套件但它常被误认为是“AI模型训练工具”。实际上它是一套预置了Alexa认证合规逻辑的嵌入式开发框架专为ESP32、Raspberry Pi Pico等主流MCU优化。它的价值不在AI而在“省掉300小时重复劳动”内置符合FIPS 140-2标准的加密库直接调用crypto_sign()即可生成符合ACK要求的ECDSA签名不用自己啃OpenSSL源码预置Wi-Fi Manager模块支持SmartConfig/Ap Mode/QR Code三种配网方式且自动处理Wi-Fi断连重连、AP切换等边缘场景提供标准化的State Report模板只需填入{temperature:26.5,humidity:45}SDK自动封装成符合Schema v3的JSON并签名发送最关键的是它内置了ACT自动化测试桩——你在本地串口输入act test discovery就能模拟Amazon云的Discovery请求实时查看设备响应是否符合认证要求。我用这个Toolkit重构过一个老项目原SDK代码量12,000行其中4,800行是处理证书刷新和JWT过期重签迁移到Toolkit后核心业务代码只剩2,300行且ACT一次性通过。它不降低技术门槛但把开发者从“协议搬运工”解放成“功能创造者”。3. 设备端接入实操从固件烧录到ACT认证的七步闭环3.1 环境准备别跳过这一步否则后面全是坑很多开发者直接clone GitHub上的ACK Samplemake flash后发现设备连不上云。问题往往出在环境准备阶段——不是代码问题而是基础依赖缺失。以下是经过27个真实项目验证的最小可行环境清单硬件平台必须使用Amazon官方认证的Wi-Fi SoC。目前稳定支持的是ESP32-WROVER带PSRAM、Raspberry Pi 4B需USB转串口调试、Nordic nRF52840。特别注意ESP32-S2/S3虽能跑ACK但因缺少硬件TRNG真随机数发生器在ACT测试中“密钥生成熵值不足”项必fail。我曾帮一家客户把S2换成WROVER仅BOM成本增加0.8元却省去3周重设计PCB的时间。开发工具链ESP32平台必须用ESP-IDF v4.4.4非v5.x因为ACK SDK 2.1.0未适配新版本的FreeRTOS API变更编译器gcc-arm-none-eabi-10.3-2021.10高版本编译器生成的二进制文件在ACK的TLS握手阶段会触发SSL_ERROR_WANT_READ异常Python环境需Python 3.8非3.9因ACK的cert-gen脚本依赖cryptography3.4.8新版cryptography已移除该版本API。证书与密钥这是最易被忽略的致命环节。你需要三组密钥Device Certificate由Amazon颁发的X.509证书绑定设备唯一serial number有效期2年Root CA CertificateAmazon Root CA 1AmazonRootCA1.pem用于验证云服务身份Private Key必须为PEM格式、无密码保护、且长度≥2048位RSA或256位ECDSA。我见过最典型的错误是用OpenSSL生成-aes256加密的key文件设备启动时读取失败却无日志提示只能靠逻辑分析器抓UART输出定位。注意所有证书文件必须通过ack_cert_tool工具校验。运行./ack_cert_tool --validate --cert device.crt --key device.key --ca root-ca.pem输出VALIDATION SUCCESS才算过关。任何一项失败设备在ACK初始化阶段就会卡在ack_security_init()。3.2 固件开发HAL层适配的五个生死细节ACK SDK的HAL层是你与硬件的唯一接口写错一行代码整个协议栈就瘫痪。以下是我在12个项目中踩过的坑按致命程度排序Wi-Fi连接回调的时序陷阱hal_wifi_connected_callback()必须在Wi-Fi完全连通DHCP获取IP完成后才触发。但很多Wi-Fi模组SDK的“connected”事件发生在AP关联成功瞬间此时IP尚未分配。正确做法是在回调里加ping检测if (ping(8.8.8.8, 3) 0) { ack_wifi_ready(); }否则ACK会因无法解析api.amazon.com域名而无限重试。RTC时钟精度要求ACK要求设备系统时间误差≤5秒。普通MCU的内部RC振荡器月漂移达±10分钟必须外接32.768kHz晶振并在hal_rtc_get_time()中返回Unix时间戳秒级。我曾用DS3231高精度RTC但忘记在初始化时调用ds3231_set_time()同步NTP时间导致设备上线后JWT签名被拒。加密芯片驱动的阻塞处理若使用ATECC608A安全芯片hal_crypto_sign()函数必须是阻塞式实现。非阻塞调用会导致ACK在等待签名完成时进入空循环耗尽CPU资源。正确做法是调用atecc_sign()后轮询atecc_check_status()直到返回ATCA_SUCCESS再返回签名数据。内存分配策略ACK SDK默认使用malloc()但嵌入式平台堆空间有限。必须重写ack_mem_alloc()改用静态内存池。例如为ESP32分配4KB固定内存块避免动态分配碎片化。否则在高并发State Report时触发heap corruption。串口日志等级控制开发阶段开启ACK_LOG_LEVEL_DEBUG但量产固件必须设为ACK_LOG_LEVEL_ERROR。DEBUG模式下每条ACK消息打印200字符日志会吃掉Wi-Fi模组50%的UART带宽导致MQTT心跳包丢失。3.3 设备注册与配网让用户30秒完成的魔法背后用户视角的“扫码配网”看似简单背后是三重协议协同第一步二维码生成设备启动后ACK SDK调用ack_qr_code_generate()生成Base64编码的配网字符串格式为alexa://device_id?pkpublic_keysigsignature。这里device_id必须是全局唯一建议用MAC地址SHA256哈希signature是对device_idtimestamp的ECDSA签名。我见过最蠢的错误是直接用设备序列号当device_id结果同型号设备ID重复Amazon云拒绝注册。第二步App扫码解析Alexa App扫描后提取public_key和signature向api.amazon.com/v1/provisioning发起POST请求携带device_id和签名。Amazon验证签名有效性后返回临时access_token和endpoint_url。第三步设备激活设备收到token后用它向endpoint_url发起TLS握手建立MQTT连接。此时ACK SDK自动订阅$aws/rules/Alexa/device_id/state主题等待云下发第一个Discovery指令。实操心得配网失败最常见的原因是时区设置。设备系统时间若设为UTC0而用户手机在UTC8时区Amazon云会认为设备时间超前8小时拒绝签名。解决方案是在hal_rtc_get_time()返回前自动校准时区偏移return time_utc get_timezone_offset();。3.4 Discovery与Directive处理状态机设计的黄金法则Alexa的Discovery请求不是一次性的而是周期性轮询默认每24小时。你的设备必须维护一个可变状态机而非静态配置初始状态UNINITIALIZED设备刚上电Wi-Fi未连ACK未初始化。此时忽略所有网络请求。待发现状态DISCOVERABLEWi-Fi连通ACK初始化完成但尚未收到Discovery请求。此时设备应主动向Amazon云发送ack_discovery_request()触发云侧扫描。已注册状态REGISTERED收到DiscoverAppliancesRequest返回包含applianceTypes、friendlyNames、supportedActions的JSON。注意applianceTypes必须精确匹配Amazon定义的枚举值如LIGHT、SWITCH写成light或lamp都会导致设备在App里显示为“未知设备”。Directive处理的核心是幂等性设计。用户说“打开灯”Alexa可能因网络抖动发送3次TurnOn指令。你的handle_turn_on()函数必须能识别重复指令// 正确做法用correlationToken去重 static char last_token[64] {0}; void handle_turn_on(const char* token) { if (strcmp(token, last_token) 0) { // 重复指令直接上报状态 ack_state_report_send(ON); return; } strcpy(last_token, token); // 执行真实动作 gpio_set_level(LED_GPIO, 1); ack_state_report_send(ON); }3.5 State Report主动上报为什么你的设备总显示“离线”Alexa App里设备状态图标变灰90%是因为State Report失效。ACK要求设备在以下场景必须主动上报设备物理状态改变如用户按实体开关指令执行完成TurnOn后立即上报周期性心跳默认每30分钟可通过ack_state_report_set_interval(1800)调整。但开发者常犯两个错误上报时机错误在handle_turn_on()函数末尾调用ack_state_report_send()看似合理但如果GPIO控制耗时较长如电机启动需2秒上报会延迟导致App状态滞后。正确做法是指令接收后立即上报PENDING执行完成后再报ON。上报内容不全只报{powerState:ON}但Alexa要求所有已声明的能力属性必须包含。例如你的灯支持亮度和色温State Report必须包含{ powerState: ON, brightness: 80, colorTemperatureInKelvin: 4000 }缺任何一项Amazon云会标记设备为“部分功能不可用”App里对应控件变灰。4. 后端Skill开发Lambda函数里的三个隐形杀手4.1 Skill架构为什么你不需要自己搭服务器很多开发者一看到“需要后端”立刻去租ECS、配Nginx、写Node.js服务。这是最大的认知误区。Alexa官方明确推荐全Serverless架构Skill前端Alexa App→ Amazon API Gateway → AWS Lambda → 设备端ACK。好处是零运维、自动扩缩、按调用计费百万次调用约0.2美元。Lambda函数的核心职责只有两个将Alexa的JSON Directive如{directive:{header:{name:TurnOn}}}转换为ACK兼容的MQTT Topic和Payload接收设备上报的State Report转换为Alexa要求的Response格式。但这里藏着三个隐形杀手Cold Start延迟Lambda首次调用有200-500ms冷启动时间。如果用户说“打开客厅灯”Lambda还没加载完指令就超时了。解决方案是启用Provisioned Concurrency预留并发为函数预热1个实例成本增加约$0.01/小时但响应时间稳定在50ms内。Execution Role权限陷阱Lambda执行角色必须包含iot:Publish权限且Resource限定为你的设备Topic如arn:aws:iot:us-east-1:123456789012:topic/alexa/device/*。若写成*Amazon安全审计会拒绝部署若Topic ARN写错一位Lambda发布MQTT消息时静默失败无任何错误日志。Payload大小限制Lambda最大payload为6MB但Alexa Directive通常10KB。真正危险的是设备上报的State Report——如果设备带摄像头上传缩略图base64编码可能超限。必须在Lambda里做截断if (payload.length 10000) { delete payload.cameraImage; }。4.2 Lambda函数实操Python版精简骨架以下是我在线上项目中稳定运行2年的Lambda核心代码Python 3.9import json import boto3 import os from datetime import datetime # 初始化IoT客户端 iot_client boto3.client(iot-data, region_nameus-east-1) def lambda_handler(event, context): # 1. 解析Alexa Directive directive event[directive] header directive[header] endpoint_id directive[endpoint][endpointId] name header[name] # 2. 构建MQTT Topic和Payload topic falexa/device/{endpoint_id}/command if name TurnOn: payload {action: turn_on, timestamp: int(datetime.now().timestamp())} elif name SetBrightness: brightness directive[payload][brightness] payload {action: set_brightness, value: brightness} else: return {error: unsupported directive} # 3. 发布到IoT Core try: iot_client.publish( topictopic, qos1, payloadjson.dumps(payload) ) return build_alexa_response(endpoint_id, name, SUCCESS) except Exception as e: print(fIoT publish failed: {str(e)}) return build_alexa_response(endpoint_id, name, FAILED) def build_alexa_response(endpoint_id, name, status): return { event: { header: { namespace: Alexa, name: Response, payloadVersion: 3, messageId: f{endpoint_id}_{int(datetime.now().timestamp())}, correlationToken: ... # 实际需从event中提取 }, endpoint: {endpointId: endpoint_id}, payload: {} } }关键点说明correlationToken必须从原始event中提取并透传否则Alexa无法关联指令与响应messageId必须全局唯一建议用endpoint_id timestamp组合payload字段在Success响应中可为空但必须存在不能删掉payload:{}。4.3 ACT认证实战自动化测试的七个必过项Amazon的Automated Certification TestACT不是人工点击而是全自动脚本测试。你必须在本地模拟这套流程。以下是七个必过项及调试方法测试项失败现象调试命令根本原因DiscoveryAlexa App搜不到设备ack_act_test --test discovery设备未调用ack_discovery_request()或返回JSON缺少applianceTypes字段TurnOn语音指令后设备无反应ack_act_test --test turnon --device-id xxxMQTT Topic订阅错误或Lambda未正确发布到alexa/device/xxx/commandStateReportApp状态图标变灰ack_act_test --test statereport --device-id xxx设备上报的JSON缺少必需字段或timestamp格式非Unix秒级Connection设备频繁掉线ack_act_test --test connection --duration 300TLS握手超时检查设备证书是否过期或Root CA未正确加载Security认证直接失败ack_cert_tool --validate私钥长度不足2048位或证书未绑定正确serial numberOTA固件升级失败ack_act_test --test ota --url https://...设备未实现ack_ota_download()回调或HTTP下载超时未重试Proactive设备状态变化不推送ack_act_test --test proactive未调用ack_proactive_state_report_enable()启用主动上报实操心得ACT测试失败时不要盲目改代码。先运行ack_log_dump --level DEBUG导出完整日志重点看[ACK MQTT]和[ACK SECURITY]前缀的行。90%的问题能在日志里定位到具体函数调用失败。5. 常见问题与排查技巧实录那些没人告诉你的真相5.1 “设备已添加但无法控制”网络层的三重幻觉用户报告“设备在Alexa App里显示已添加但说‘打开灯’没反应”这通常不是代码问题而是网络层的三重幻觉幻觉一Wi-Fi信号满格≠网络可达设备Wi-Fi RSSI显示-45dBm但路由器开启了“客户端隔离”Client Isolation导致设备能上网但无法与局域网内其他设备通信。解决方案在路由器后台关闭Client Isolation或让设备连接专用IoT VLAN。幻觉二DNS解析成功≠HTTPS可达设备能ping通8.8.8.8也能解析api.amazon.com但HTTPS连接失败。这是因为Amazon云服务使用SNIServer Name Indication而某些老旧Wi-Fi模组SDK的TLS库不支持SNI导致握手失败。验证方法用openssl s_client -connect api.amazon.com:443 -servername api.amazon.com测试若返回SSL routines:ssl3_read_bytes:tlsv1 alert internal error即为SNI问题。幻觉三MQTT连接成功≠Topic订阅成功设备日志显示MQTT connected但收不到Alexa指令。这是因为MQTT BrokerAWS IoT Core的Policy未授权iot:Subscribe权限。检查Policy JSON必须包含{ Effect: Allow, Action: iot:Subscribe, Resource: arn:aws:iot:us-east-1:123456789012:topic/alexa/device/* }5.2 “状态不同步”时间戳战争的终极解法用户说“打开灯”App显示灯已亮但30秒后又变回“关”。这是典型的状态不同步根源在于设备端与云服务的时间戳战争设备上报State Report时用本地时间戳time(NULL)Alexa云服务收到后用自己的NTP时间打上接收时间戳当用户再次查询状态云服务返回的是“上次上报时间”而非“当前状态”。解决方案是启用Proactive State Reporting主动状态上报在设备端调用ack_proactive_state_report_enable(300)设置5分钟心跳每次物理状态改变如GPIO电平变化立即调用ack_state_report_send()在Lambda函数里收到State Report后立即调用alexa_api.report_state()向Alexa云推送最新状态。这样云服务始终持有设备的“最新快照”而非“历史记录”。5.3 “认证失败Invalid certificate chain”证书链的隐藏断点ACT认证失败错误日志只显示Invalid certificate chain但ack_cert_tool --validate却显示success。这是因为Amazon云验证的是完整证书链而你的设备只加载了Device Certificate没加载Intermediate CA。正确做法从Amazon Developer Console下载的证书包里找到intermediate.pem文件在设备固件中将device.crt和intermediate.pem合并为一个文件cat device.crt intermediate.pem fullchain.crt加载fullchain.crt而非单独的device.crt。5.4 “配网后设备消失”Serial Number的诅咒设备配网成功但在Alexa App里显示几秒后就消失。检查设备日志发现ack_device_register()返回ACK_ERR_DEVICE_ALREADY_REGISTERED。这是因为你的设备Serial Number被重复使用——可能是开发阶段用同一份固件烧录多台设备Serial Number硬编码为ABC123或工厂量产时Serial Number生成算法缺陷如用时间戳做seed多台设备同时上电生成相同ID。解决方案Serial Number必须全局唯一建议采用MAC地址 时间戳 CRC32组合char serial[33]; sprintf(serial, %02x%02x%02x%02x%02x%02x_%d, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], (int)time(NULL)); uint32_t crc crc32(serial, strlen(serial)); sprintf(serial, %s_%08x, serial, crc);5.5 “语音反馈延迟严重”从指令到播报的17个处理环节用户说“今天温度多少”Alexa回复“当前温度26度”要等3秒。这不是网络问题而是17个处理环节的累积延迟用户语音采集Echo设备→ 2. 语音转文字ASR→ 3. 意图识别NLU→ 4. 技能路由Skill Dispatch→ 5. Lambda冷启动 → 6. Lambda执行 → 7. IoT Core路由 → 8. 设备MQTT接收 → 9. 设备解密 → 10. 设备业务逻辑 → 11. 设备状态读取 → 12. 设备State Report生成 → 13. 设备MQTT发送 → 14. IoT Core接收 → 15. Lambda订阅 → 16. Lambda构建Response → 17. Alexa TTS播报。其中环节5Lambda冷启动和环节10设备业务逻辑占延迟70%。优化方案Lambda启用Provisioned Concurrency设备端用DMA直接读取传感器寄存器避免CPU轮询State Report中timestamp字段用硬件RTC时间而非软件time()函数。6. 经验总结一个Alexa设备从立项到上市的真实时间线最后分享一个真实项目的时间线——不是理想化的“两周搞定”而是血泪教训堆出来的节奏第1-3天环境搭建与Hello World。目标是让设备在Alexa App里显示“已发现”不求控制只验证ACK初始化和Discovery流程。这一步失败率最高80%卡在证书或Wi-Fi HAL。第4-10天基础控制闭环。实现TurnOn/TurnOff确保语音指令→设备动作→App状态同步。重点解决State Report不同步问题这是用户感知最明显的体验点。第11-20天多能力扩展。加入亮度、色温、定时等高级功能。此时要重构状态机避免handle_*函数爆炸式增长。我推荐用状态表驱动state_table[action][current_state] next_state。第21-30天ACT认证攻坚。每天跑一轮ACT测试记录失败项针对性修复。重点攻克Security和Proactive两项它们失败率最高。第31-45天量产固件打磨。加入OTA升级、错误日志上传、低功耗模式。此时要冻结HAL层接口禁止任何底层修改。第46-60天Amazon认证提交。填写20页技术文档提供电路图、BOM、测试报告。等待Amazon实验室排期通常2-3周。第61天上线设备出现在Alexa Skill Store用户可直接搜索添加。这60天里真正写业务代码的时间不到15天其余全是和协议、证书、时序、认证规则的搏斗。但当你看到第一个用户在YouTube视频里说“我用Alexa控制自家做的智能灯”那种成就感值得所有折腾。
返回列表