目录

SmartHome AI Agent:面向 OpenVela 的端侧智能家居智能体

SmartHome AI Agent 演示

SmartHome AI Agent 是一个运行于 OpenVela/NuttX 的端侧智能家居项目。它以纯 C 的 cAGENT 为推理编排内核,将自然语言输入转换为经过策略校验的本地、Node 或 MCP 工具调用,并在 QEMU Goldfish 模拟器和 ESP32-S3-BOX-3 真机上验证。

本 README 是面向评审与开发者的技术说明书;可直接下载排版版 技术文档 PDF。构建、烧录、模拟器、真机、Node、MCP 与 App 的逐步操作请见 决赛增量文档。密钥不纳入仓库,也不应写入源码或提交记录。

1. 项目目标与已实现范围

项目将“设备控制、智能体编排、远程能力接入、图形交互和移动端协同”拆分为可独立验证的层,目标是在资源受限 RTOS 上得到可解释、可裁剪、可演示的智能家居闭环。

能力 当前实现 验证目标
本地智能家居 Goldfish 为 8 个业务工具 + read_skill;BOX-3 启用 AHT30 后额外提供 get_indoor_environment 自然语言 → 工具 → 结果 → 回复
多模型 DeepSeek、MiMo、Qwen、OpenAI-compatible 与自定义预设 设置页切换内置预设、持久化当前选择、显示密钥状态
MCP 设备直连 Streamable HTTP 的 tools-only 子集,手动发现与动态导入 Caiyun 天气真实服务和主机 mock 服务
Node 协作 WebSocket Node gateway、动态工具注册、节点工具路由 多个 sensor_node 接入并调用温度/风扇能力
UI 与移动端 LVGL 面板/对话/设置页,App Bridge 的 HTTP 快照、控制、运行历史接口 模拟器与手机 App 联调
真机 ESP32-S3-BOX-3 的 LCD、触摸、Wi-Fi、LittleFS、AHT30 室内环境工具 真实 Wi-Fi、TLS、传感器与本地控制验证

平台能力边界必须明确:Goldfish 是 Node gateway 的主要验证平台;ESP32-S3-BOX-3 当前以单核稳定基线为准,重点验证 Wi-Fi、TLS、MCP/App Bridge、LVGL 和 AHT30,不将多 Node gateway 宣称为该板的已完成能力。

2. 总体架构

Console / LVGL / 手机 App
          │
          ├── App Bridge:HTTP 快照、控制命令、运行记录
          ▼
   smart_home 应用层
          │  本地设备、场景、状态、持久化、策略、UI
          ▼
       cAGENT Core
  ReAct / Session / Skill / Tool / Event / Model Provider
      │                 │                    │
      │                 │                    └─ OpenAI-compatible HTTP(S)
      │                 ├─ 本地工具(group_id=0)
      │                 ├─ Node 动态工具(group_id=10)
      │                 └─ MCP 动态工具(group_id=20)
      ▼
OpenVela runtime / cagent_addons / board adapter
      │                   │
      ├─ TCP + TLS ── LLM、标准 MCP Server
      └─ WebSocket ─ Node gateway ─ sensor_node / 风扇节点

架构的关键边界是:cAGENT 只定义运行时回调、模型和工具抽象,不依赖 LVGL、Wi-Fi 驱动、MCP SDK 或具体板级头文件;网络、板级资源与业务状态由应用或 adapter 承担。这使 Goldfish 与 BOX-3 能共享 Agent 和业务层,同时按平台选择不同的资源与传输实现。

相关代码入口:

层 主要目录 职责
Agent Core packages/cAGENT/ ReAct、工具注册、Schema、Session、Skill、模型与 runtime 接口
应用编排 demos/smart_home/src/app/、src/agent/ 启动、工具装配、策略、事件、Console/LVGL 工作流
设备与配置 demos/smart_home/src/device/、src/config/ 本地设备状态、JSON 配置、密钥只读加载、持久化
扩展接入 demos/smart_home/src/addons/、packages/cagent_addons/ Node gateway、MCP bridge、远程工具 catalog
UI 与手机接口 demos/smart_home/src/ui/、src/addons/smart_home_app_bridge.* LVGL 页面、App Bridge HTTP API
板级实现 board/esp32s3-box-3/ LCD/触摸/Wi-Fi/LittleFS、AHT30 与资源配置

完整调用关系见 代码架构说明。

3. 算法与模型详细设计

3.1 ReAct 工具调用循环

cAGENT 将一次请求处理为可观察的有限轮推理循环,而不是让应用层手写特定模型的 function-call 状态机。其逻辑如下:

输入:用户消息、会话历史、动态设备上下文、可用工具、Skill 摘要
  │
  ├─ 组装 system prompt 与 OpenAI-compatible tools schema
  └─ iteration = 1 .. max_iterations
       │
       ├─ 调用模型 provider
       ├─ 若得到最终文本:结束并返回
       ├─ 解析 tool_call,验证名称、JSON 参数和容量限制
       ├─ tool_guard / 应用 policy 校验
       ├─ 执行本地工具,或等待 Node/MCP 的有界远程调用
       ├─ 将工具结果写入 messages
       └─ 继续下一轮,直至成功、超时、轮数或上下文预算耗尽

模型请求、响应、工具调用、工具结果、异常和完成事件会通过 agent_event 回调传给 Console、LVGL 与 App Bridge 的时间线。因此演示不仅给出最终回答,也能显示“为何调用了某个工具”。若模型返回 AGENT_OK 但文本为空,应用层会给出“检查设置 → 工具访问”的兜底提示,避免把禁用工具误表现成成功。

3.2 模型 provider 与配置选择

所有云模型走 OpenAI-compatible Chat Completions 适配层。当前后端清单的默认来源是编译期预设表 g_llm_presets[],而不是 UI 中散落的分支:

g_llm_presets[](id、端点、模型、兼容参数)
             + /data/smart_home/settings.json.active_backend_id(当前选择)
             + /data/smart_home/secrets.json.model_api_keys(仅设备数据分区)
             ↓
smart_home_model_config_load_active_backend() / secrets loader
             ↓
cAGENT OpenAI-compatible provider
             ↓
agent_runtime_t.http_post → OpenVela TCP/TLS runtime

settings.json 保存所选内置预设的 ID;secrets.json 仅从 /data/smart_home/ 读取,源码中没有默认 API Key。设置页的“可用/未配置”状态来自 secrets loader,而不是暴露密钥内容。backends.json 已作为配置存储格式与默认恢复能力提供,但尚未成为启动路径和设置页列表的动态数据源;因此当前可直接切换内置预设,新增内置预设仍需修改 g_llm_presets[] 并重新构建。

3.3 上下文、Skill 与工具元数据

设备当前状态由 context provider 注入,以减少模型先查询再控制的无效轮次。5 个 Markdown Skill 分别承载设备控制、安全边界、场景、定时器和天气策略;较长规则可由 read_skill 按需读取,以降低常驻 prompt 体积。

工具元数据按三类正交属性表达,避免仅靠命名前缀判断:

属性 语义 用途
group_id 生命周期/来源:本地 0、Node 10、MCP 20 动态注册、来源分流、UI 与审计
category_id 业务展示分类 设备面板、设置页分组
flags Core 通用风险性质 read-only、控制类等安全策略

本地工具保持细粒度,例如 set_light、set_ac、run_scene,而不合并成一个参数庞大的“万能控制工具”。这样可提高函数调用参数正确率、保留逐工具开关与策略粒度,也便于在日志中审查控制链。

4. Node 与 MCP 的远程能力设计

4.1 Node:低开销局域网协作

Node gateway 监听 0.0.0.0:18790,使用与 OpenClaw 兼容的 WebSocket over TCP:HTTP Upgrade、masked client frame、ping/pong 与 token 校验均保留,但实现收敛为嵌入式所需的有限缓冲和 Kconfig 上限。节点上线后上报 ID、命令及 schema,Hub 将其导入为 node_<node_id>_<command> 工具。

sensor_node ─ WebSocket Upgrade + token ─► smart_home gateway
sensor_node ─ announce(command/schema) ──► remote catalog
catalog mutation ─────────────────────────► cAGENT 动态工具列表
LLM ─ tool_call(node_xxx) ───────────────► gateway invoke
gateway ─ invoke/result ─────────────────► sensor_node

工具身份使用 route_id / source_name / public_name / connection_gen,防止清洗重名和旧连接迟到事件误删新工具。网络线程只维护 catalog;真正的注册、注销和 UI 可见列表更新由串行 mutation 路径执行,避免并发修改 cAGENT 工具表。

当前 sensor_node 的 announce 以节点身份、显示信息、命令和精确 schema 为主。设备类型、能力、属性和状态构成的通用 Device Model,以及据此自动生成温度、风扇、灯光等 LVGL 卡片,属于已完成设计、待实现的下一阶段协议扩展;当前 Hub 仍将 Node 暴露为一组远程工具。协议演进与测试步骤见 Node gateway 文档。

4.2 MCP:端侧直连的受控子集

MCP 采用标准 Streamable HTTP 的 tools-only 使用方式:设备依次发送 initialize、notifications/initialized、tools/list,将可用工具映射进 MCP catalog;手动点击 Discover MCP 或调用 probe 执行发现,避免启动阶段 DNS/TLS/HTTP 阻塞 LVGL。

Discover MCP
  └─ MCP worker(独立栈、总 deadline)
       ├─ POST initialize
       ├─ POST notifications/initialized
       ├─ POST tools/list
       └─ mutation drain → mcp_<route_id> 工具注册

LLM tool_call → tools/call → HTTP(S) response → Agent 下一轮

当前真实联调目标为 https://mcp-weather.caiyunapp.com/mcp,密钥以 X-Caiyun-API-Key 从设备 secrets 注入;也提供主机 mock server,验证协议和 catalog 而不依赖公网。实现不承担 SSE、OAuth、完整资源/提示词能力;这些是本项目明确的 MVP 边界,而非“完整 MCP 客户端”的宣称。详见 MCP 客户端文档。

远程 I/O 必须在 addon 内自行使用 monotonic deadline;cAGENT 的 timeout_ms 对阻塞回调仅能事后统计,不能抢占 socket 读写。

5. 性能、资源与可靠性分析

5.1 代码体积:可复核的静态快照

下表来自 AArch64、-O3、预链接对象文件的统计,用于比较 cAGENT 自身模块,不等同于最终固件 ELF 增量:

组件 Flash 类代码/只读数据 静态 RAM 说明
Core(ReAct、session、skill、tool、runtime) 36.3 KiB 0 B 可移植核心
模型抽象与 JSON 1.6 KiB 640 B provider 公共层
OpenAI-compatible provider 9.9 KiB 0 B Chat Completions/工具调用适配
OpenVela HTTP/TLS wrapper 13.3 KiB 48 B 网络 runtime 封装
上述完整对象集合 62.7 KiB 688 B 预链接静态快照

该数字不包含 mbedTLS、cJSON、NuttX socket、cagent_addons、LVGL、字体、业务工具及链接器对齐/裁剪影响。正式版本应同时保存 size、map、配置文件和运行期堆统计,不能仅用对象文件数字声称“完整系统占用”。统计方法与边界见 决赛重点文档。

5.2 运行期内存与线程策略

项目 Goldfish ESP32-S3-BOX-3 设计含义
LLM request/response 应用分配并可观测 优先置于 PSRAM bulk pool 避免 TLS 与 UI 争用内部 SRAM
最小模型缓冲 请求 12 KiB、响应 8 KiB 相同接口,按 PSRAM 策略分配 覆盖常规 OpenAI-compatible payload
工具输出上限 3 KiB(CONFIG_CAGENT_TOOL_OUTPUT_MAX_SIZE) 相同 允许 Skill/远程工具返回可用结果,仍有上限
App/历史帧 常规堆 PSRAM 保护 Wi-Fi、TLS、驱动的内部 SRAM
远程工作线程 Node/MCP 独立工作线程 以单核稳定基线按需启用 DNS/TLS 不占用 LVGL 主循环

BOX-3 将模型缓冲、App Bridge 帧和历史快照放入 PSRAM,网络与 TLS 所需的短生命周期对象保留在内部 SRAM。这样做的原因不是“PSRAM 越多越好”:Wi-Fi DMA、驱动和部分实时路径对内存属性敏感,盲目迁移 TLS/网络对象反而会增加故障面。具体放置策略见 ESP32-S3 内存分析。

5.3 延迟、容量和观察方法

端到端延迟由 DNS、TCP/TLS、云模型首包、模型推理、工具 I/O 与第二轮模型总结共同构成,不能用单一“响应毫秒数”概括。Console 的成功日志中已观测到约 2.7 秒的单轮云模型响应,但它只是某网络与模型状态下的样本,不是性能基准。

建议以如下指标形成可比较的测试记录:

  • agent_event:每轮 MODEL_REQ/MODEL_RESP/TOOL_CALL/TOOL_RES 的时间线;
  • runtime_openvela 阶段日志:DNS、TCP、TLS、HTTP 状态,定位 -6 timeout 和 -10 network;
  • agent_stats 与堆日志:arena 峰值、最大空闲块、PSRAM pool 余量;
  • Node/MCP:工具数、catalog mutation 数、连接代数、远程 deadline 命中率;
  • 真机:连续对话、MCP 发现、App 请求并发时的内存峰值与失败恢复。

尚未完成“LVGL + App Bridge + MCP + 多 Node + 云模型”的长时间压力测试,因此 README 不把并发稳定性标记为已验证结论。

5.4 可靠性优化经验

  • MCP discovery 改为手动触发,并提供 mcp_probe,将协议排障与 LVGL 生命周期隔离。
  • tls_probe 可独立验证 DNS/TCP/TLS,不将云端失败误判为模型或 UI 故障。
  • Wi-Fi 初始化先检测已有 IP 和 DNS;已在线时不重复关联/DHCP,减少 Console 与 LVGL 两种入口的网络扰动。
  • Node/MCP 的动态工具更新以 catalog + mutation queue 串行化;UI 查询读取应用侧 catalog,避免直接遍历正在变更的核心表。
  • 工具禁用由应用 policy 处理,保留工具 schema 的稳定性,并在对话无文本时提供可操作的提示。
  • Node gateway、MCP bridge 与云模型凭据均采用可选能力的降级策略:默认配置下,某项启动或配置失败只更新其状态并保留本地控制、UI 和其他已就绪能力。Node gateway 可显式启用 SMART_HOME_NODE_GATEWAY_REQUIRED 以便 CI 或专用联调环境快速失败;MCP 则始终保持手动发现、失败仅禁用 MCP 的策略。

6. 代码注释、接口与安全规范

6.1 注释规范

  1. 公共头文件必须说明所有权、线程归属、缓冲区容量、单位、返回值和错误码;例如 transport 的 payload 仅在回调期间有效,跨线程必须复制。
  2. 并发代码必须在锁、worker、catalog mutation、connection generation 旁解释“谁写、谁读、何时释放”,而不是只描述语句本身。
  3. 网络、TLS、MCP 与 Node 的超时应注明使用 monotonic deadline 的位置与剩余时间传递方式。
  4. 驱动、协议和可上游代码遵循 NuttX/OpenVela 周边英文注释风格;应用业务层可使用简洁中文注释,但函数名、错误码与结构字段保持英文一致性。
  5. 不为显而易见的赋值写注释;优先解释边界、原因、硬件约束、失败恢复和兼容性取舍。
  6. 文档与注释不得记录真实 API Key、Wi-Fi 密码、App Token、设备序列号或内部地址。

6.2 接口使用约束

  • agent_register_tool():动态工具需填完整元数据,包括 group_id/category_id/flags;agent_register_tool_simple() 不适用于需要分组的远程工具。
  • 只读自省接口用于 UI/策略读取工具名称、schema 和元数据;不允许 UI 直接修改 core 内部工具表。
  • 应用 policy callback 是最终执行闸门。设置页对本地工具使用 policy deny,而不是在模型请求过程中临时删除 Schema;Node/MCP 工具的可见性和生命周期由各自 catalog 管理。
  • 任何外部 JSON 均需限制长度、验证 UTF-8/JSON 与参数范围;远程 public name 超长或清洗冲突时拒绝,不截断成潜在同名工具。

7. 应用案例与落地验证

场景 用户操作 调用链 已验证环境
本地灯光控制 “打开客厅灯,亮度 35%” LLM → set_light → 本地设备状态 → 自然语言确认 Goldfish、BOX-3 Console
场景控制 “我要睡觉了” LLM → run_scene → 多设备状态更新 Goldfish
MCP 天气 “今天会下雨吗?” LLM → mcp_* 天气工具 → Caiyun MCP → 总结 Goldfish;BOX-3 可用 mcp_probe 验证网络链
多节点协作 查询温度或调节远程风扇 LLM → node_living_* → WebSocket gateway → sensor_node 双 Goldfish 模拟器
移动端面板 查看状态、手动控制、查看时间线 Flutter App → App Bridge HTTP → snapshot/command/history Goldfish App Bridge
真机环境感知 “查看室内温湿度” LLM → get_indoor_environment → /dev/aht0 AHT30 ESP32-S3-BOX-3 + SENSOR-01

图形效果、MCP/Node 工具导入和真机日志位于 logs;各案例的精确命令、预期输出和失败排查位于 决赛增量文档。

8. 优化迭代过程

阶段 发现的问题 优化措施 结果与取舍
本地 Agent 业务层承担模型协议和循环,难以复用 提取 cAGENT 的 provider/runtime/tool/skill/ReAct 层 应用只管理设备与 UI
工具设计 聚合型工具参数复杂、难以禁用和审计 保留细粒度本地工具,增加 group/category/flags 调用与安全粒度更清晰,消耗有限工具槽位
模型配置 切换模型需要改源码,Key 有泄露风险 内置预设表 + settings.json + secrets.json 运行时切换内置预设并持久化;密钥仅在设备数据区;动态后端清单留作后续扩展
MCP 启动 DNS/TLS/tools/list 影响 UI 启动 手动 discovery、独立 worker、mcp_probe 启动可预测;发现需用户触发
远程工具并发 网络线程直接改注册表存在竞态 catalog/mutation queue/connection generation 动态上下线可追踪,代码复杂度上升
BOX-3 资源 UI、TLS、模型缓冲竞争内存 PSRAM bulk pool、独立 probe、阶段日志 定位性提升;仍需长期并发压测
真机能力 仅有虚拟设备不足以展示落地 AHT30 板级驱动、box3_sensor_test、室内环境工具 获得可测硬件闭环

9. 创新点说明

  1. 面向 RTOS 的可裁剪 Agent 内核:以 runtime 回调隔离模型、TLS、板级与 UI,使同一 ReAct/工具核心可在模拟器和真机复用。
  2. 远程能力作为动态工具导入:Node 与 MCP 不是业务代码分支,而是共享 catalog、身份和 policy 的工具来源,LLM 可在同一 schema 中选择本地或远程能力。
  3. 资源感知的协议分层:Node 保持 WebSocket 兼容而轻实现;MCP 直连聚焦最小可用 tools 子集,将完整协议复杂度与固件资源约束显式区分。
  4. 可观察、可恢复的端侧链路:Agent 事件时间线、DNS/TCP/TLS 阶段日志、独立 TLS/MCP probe 与 mutation 统计形成从云端到工具的定位链。
  5. 从虚拟到真实设备的连续验证:Goldfish 承担多节点和 App 快速迭代,BOX-3 承担 Wi-Fi、触屏、LittleFS 与 AHT30 硬件闭环,避免以模拟结果替代真机结论。

10. 快速验证

10.1 接入 OpenVela 工作区

cd <openvela-root>
mkdir -p packages/demos
ln -sfnT ../../openvela_smarthome/demos/smart_home packages/demos/smart_home
ln -sfnT ../openvela_smarthome/packages/cAGENT packages/cAGENT
ln -sfnT ../openvela_smarthome/packages/cagent_addons packages/cagent_addons

不要把 res/config/secrets.json 复制到源码或提交。应从示例生成本地文件,再通过 LittleFS 镜像或 ADB 放入 /data/smart_home/。

10.2 Goldfish 最小闭环

source build/envsetup.sh
./build.sh vendor/openvela/boards/vela/configs/goldfish-smart_home --cmake -j"$(nproc)"
# 启动模拟器后,在 NSH 中
ifup eth0
renew eth0
smart_home "打开客厅灯,亮度35%"

Node 双模拟器、MCP mock/真实服务、App HTTP 调试和 ADB 多设备选择,请直接按 决赛增量文档 执行;该文档还包含 mcp_probe、tls_probe 和 sensor_node 的期望结果。

10.3 ESP32-S3-BOX-3

BOX-3 使用 Make 构建与烧录流程:

./build.sh vendor/espressif/boards/esp32s3/esp32s3-box-3/configs/smart_home/ -j"$(nproc)"
make -C nuttx flash ESPTOOL_PORT=/dev/ttyACM0 ESPTOOL_BAUD=921600

在 NSH 连接 Wi-Fi 后可运行 tls_probe、mcp_probe、box3_sensor_test --once 和 smart_home。LittleFS 配置镜像、AHT30 接线、故障定位与完整命令见 BOX-3 指南。

11. 已知限制与后续方向

  • MCP 尚未覆盖 SSE、OAuth、资源和 prompts;复杂、有状态的 MCP Server 需要 sidecar 或后续 transport 扩展。
  • Node 设备描述协议已具备演进方向,但通用 Device Model 到动态 LVGL 卡片的完整映射仍在设计中。
  • 手机 App 当前以 App Bridge 的 HTTP 快照、命令与运行历史为主;聊天路由须额外开启 SMART_HOME_APP_BRIDGE_CHAT。事件推送、设备配网、账户体系和局域网发现未作为本期交付。
  • BOX-3 的多核 SMP 启动尚未成为稳定基线;项目以单核配置保证可复现的 UI/网络/传感器验证。
  • 语音识别、离线唤醒、完整真机多节点协同与长时并发压测是后续迭代项。

12. 文档、许可证与证据

主题 文档
复现总入口 决赛增量文档
cAGENT、工具和资源设计 决赛重点文档
应用调用关系 代码架构说明
MCP/Node mcp-client.md、node-gateway.md
BOX-3 esp32s3-box.md、内存放置分析
App Bridge box3-gateway-integration.md
答辩材料 官方 ai_agent 与 cAGENT 对比、答辩问答手册、答辩演讲稿
测试截图、视频与真机日志 logs/

自研代码遵循 Apache License 2.0。第三方软件和素材许可见 NOTICE 与 THIRD-PARTY-NOTICES。

关于

第八届CCF开源创新大赛-基于 openvela智能体 的智能家居控制系统赛题

90.8 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号