docs(readme): 同步当前实现与运行边界
SmartHome AI Agent 是一个运行于 OpenVela/NuttX 的端侧智能家居项目。它以纯 C 的 cAGENT 为推理编排内核,将自然语言输入转换为经过策略校验的本地、Node 或 MCP 工具调用,并在 QEMU Goldfish 模拟器和 ESP32-S3-BOX-3 真机上验证。
本 README 是面向评审与开发者的技术说明书;可直接下载排版版 技术文档 PDF。构建、烧录、模拟器、真机、Node、MCP 与 App 的逐步操作请见 决赛增量文档。密钥不纳入仓库,也不应写入源码或提交记录。
项目将“设备控制、智能体编排、远程能力接入、图形交互和移动端协同”拆分为可独立验证的层,目标是在资源受限 RTOS 上得到可解释、可裁剪、可演示的智能家居闭环。
read_skill
get_indoor_environment
sensor_node
平台能力边界必须明确:Goldfish 是 Node gateway 的主要验证平台;ESP32-S3-BOX-3 当前以单核稳定基线为准,重点验证 Wi-Fi、TLS、MCP/App Bridge、LVGL 和 AHT30,不将多 Node gateway 宣称为该板的已完成能力。
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 和业务层,同时按平台选择不同的资源与传输实现。
相关代码入口:
packages/cAGENT/
demos/smart_home/src/app/
src/agent/
demos/smart_home/src/device/
src/config/
demos/smart_home/src/addons/
packages/cagent_addons/
demos/smart_home/src/ui/
src/addons/smart_home_app_bridge.*
board/esp32s3-box-3/
完整调用关系见 代码架构说明。
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 但文本为空,应用层会给出“检查设置 → 工具访问”的兜底提示,避免把禁用工具误表现成成功。
agent_event
AGENT_OK
所有云模型走 OpenAI-compatible Chat Completions 适配层。当前后端清单的默认来源是编译期预设表 g_llm_presets[],而不是 UI 中散落的分支:
g_llm_presets[]
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[] 并重新构建。
settings.json
secrets.json
/data/smart_home/
backends.json
设备当前状态由 context provider 注入,以减少模型先查询再控制的无效轮次。5 个 Markdown Skill 分别承载设备控制、安全边界、场景、定时器和天气策略;较长规则可由 read_skill 按需读取,以降低常驻 prompt 体积。
工具元数据按三类正交属性表达,避免仅靠命名前缀判断:
group_id
0
10
20
category_id
flags
本地工具保持细粒度,例如 set_light、set_ac、run_scene,而不合并成一个参数庞大的“万能控制工具”。这样可提高函数调用参数正确率、保留逐工具开关与策略粒度,也便于在日志中审查控制链。
set_light
set_ac
run_scene
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> 工具。
0.0.0.0:18790
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 工具表。
route_id / source_name / public_name / connection_gen
当前 sensor_node 的 announce 以节点身份、显示信息、命令和精确 schema 为主。设备类型、能力、属性和状态构成的通用 Device Model,以及据此自动生成温度、风扇、灯光等 LVGL 卡片,属于已完成设计、待实现的下一阶段协议扩展;当前 Hub 仍将 Node 暴露为一组远程工具。协议演进与测试步骤见 Node gateway 文档。
MCP 采用标准 Streamable HTTP 的 tools-only 使用方式:设备依次发送 initialize、notifications/initialized、tools/list,将可用工具映射进 MCP catalog;手动点击 Discover MCP 或调用 probe 执行发现,避免启动阶段 DNS/TLS/HTTP 阻塞 LVGL。
initialize
notifications/initialized
tools/list
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 客户端文档。
https://mcp-weather.caiyunapp.com/mcp
X-Caiyun-API-Key
远程 I/O 必须在 addon 内自行使用 monotonic deadline;cAGENT 的 timeout_ms 对阻塞回调仅能事后统计,不能抢占 socket 读写。
timeout_ms
下表来自 AArch64、-O3、预链接对象文件的统计,用于比较 cAGENT 自身模块,不等同于最终固件 ELF 增量:
-O3
该数字不包含 mbedTLS、cJSON、NuttX socket、cagent_addons、LVGL、字体、业务工具及链接器对齐/裁剪影响。正式版本应同时保存 size、map、配置文件和运行期堆统计,不能仅用对象文件数字声称“完整系统占用”。统计方法与边界见 决赛重点文档。
cagent_addons
size
CONFIG_CAGENT_TOOL_OUTPUT_MAX_SIZE
BOX-3 将模型缓冲、App Bridge 帧和历史快照放入 PSRAM,网络与 TLS 所需的短生命周期对象保留在内部 SRAM。这样做的原因不是“PSRAM 越多越好”:Wi-Fi DMA、驱动和部分实时路径对内存属性敏感,盲目迁移 TLS/网络对象反而会增加故障面。具体放置策略见 ESP32-S3 内存分析。
端到端延迟由 DNS、TCP/TLS、云模型首包、模型推理、工具 I/O 与第二轮模型总结共同构成,不能用单一“响应毫秒数”概括。Console 的成功日志中已观测到约 2.7 秒的单轮云模型响应,但它只是某网络与模型状态下的样本,不是性能基准。
建议以如下指标形成可比较的测试记录:
MODEL_REQ/MODEL_RESP/TOOL_CALL/TOOL_RES
runtime_openvela
-6
-10
agent_stats
尚未完成“LVGL + App Bridge + MCP + 多 Node + 云模型”的长时间压力测试,因此 README 不把并发稳定性标记为已验证结论。
mcp_probe
tls_probe
SMART_HOME_NODE_GATEWAY_REQUIRED
agent_register_tool()
group_id/category_id/flags
agent_register_tool_simple()
mcp_*
node_living_*
/dev/aht0
图形效果、MCP/Node 工具导入和真机日志位于 logs;各案例的精确命令、预期输出和失败排查位于 决赛增量文档。
settings.json + secrets.json
box3_sensor_test
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/。
res/config/secrets.json
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 的期望结果。
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 指南。
box3_sensor_test --once
smart_home
SMART_HOME_APP_BRIDGE_CHAT
自研代码遵循 Apache License 2.0。第三方软件和素材许可见 NOTICE 与 THIRD-PARTY-NOTICES。
第八届CCF开源创新大赛-基于 openvela智能体 的智能家居控制系统赛题
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
SmartHome AI Agent:面向 OpenVela 的端侧智能家居智能体
SmartHome AI Agent 是一个运行于 OpenVela/NuttX 的端侧智能家居项目。它以纯 C 的 cAGENT 为推理编排内核,将自然语言输入转换为经过策略校验的本地、Node 或 MCP 工具调用,并在 QEMU Goldfish 模拟器和 ESP32-S3-BOX-3 真机上验证。
本 README 是面向评审与开发者的技术说明书;可直接下载排版版 技术文档 PDF。构建、烧录、模拟器、真机、Node、MCP 与 App 的逐步操作请见 决赛增量文档。密钥不纳入仓库,也不应写入源码或提交记录。
1. 项目目标与已实现范围
项目将“设备控制、智能体编排、远程能力接入、图形交互和移动端协同”拆分为可独立验证的层,目标是在资源受限 RTOS 上得到可解释、可裁剪、可演示的智能家居闭环。
read_skill;BOX-3 启用 AHT30 后额外提供get_indoor_environmentsensor_node接入并调用温度/风扇能力平台能力边界必须明确:Goldfish 是 Node gateway 的主要验证平台;ESP32-S3-BOX-3 当前以单核稳定基线为准,重点验证 Wi-Fi、TLS、MCP/App Bridge、LVGL 和 AHT30,不将多 Node gateway 宣称为该板的已完成能力。
2. 总体架构
架构的关键边界是:cAGENT 只定义运行时回调、模型和工具抽象,不依赖 LVGL、Wi-Fi 驱动、MCP SDK 或具体板级头文件;网络、板级资源与业务状态由应用或 adapter 承担。这使 Goldfish 与 BOX-3 能共享 Agent 和业务层,同时按平台选择不同的资源与传输实现。
相关代码入口:
packages/cAGENT/demos/smart_home/src/app/、src/agent/demos/smart_home/src/device/、src/config/demos/smart_home/src/addons/、packages/cagent_addons/demos/smart_home/src/ui/、src/addons/smart_home_app_bridge.*board/esp32s3-box-3/完整调用关系见 代码架构说明。
3. 算法与模型详细设计
3.1 ReAct 工具调用循环
cAGENT 将一次请求处理为可观察的有限轮推理循环,而不是让应用层手写特定模型的 function-call 状态机。其逻辑如下:
模型请求、响应、工具调用、工具结果、异常和完成事件会通过
agent_event回调传给 Console、LVGL 与 App Bridge 的时间线。因此演示不仅给出最终回答,也能显示“为何调用了某个工具”。若模型返回AGENT_OK但文本为空,应用层会给出“检查设置 → 工具访问”的兜底提示,避免把禁用工具误表现成成功。3.2 模型 provider 与配置选择
所有云模型走 OpenAI-compatible Chat Completions 适配层。当前后端清单的默认来源是编译期预设表
g_llm_presets[],而不是 UI 中散落的分支: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_id0、Node10、MCP20category_idflags本地工具保持细粒度,例如
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>工具。工具身份使用
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。当前真实联调目标为
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 增量:该数字不包含 mbedTLS、cJSON、NuttX socket、
cagent_addons、LVGL、字体、业务工具及链接器对齐/裁剪影响。正式版本应同时保存size、map、配置文件和运行期堆统计,不能仅用对象文件数字声称“完整系统占用”。统计方法与边界见 决赛重点文档。5.2 运行期内存与线程策略
CONFIG_CAGENT_TOOL_OUTPUT_MAX_SIZE)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 状态,定位-6timeout 和-10network;agent_stats与堆日志:arena 峰值、最大空闲块、PSRAM pool 余量;尚未完成“LVGL + App Bridge + MCP + 多 Node + 云模型”的长时间压力测试,因此 README 不把并发稳定性标记为已验证结论。
5.4 可靠性优化经验
mcp_probe,将协议排障与 LVGL 生命周期隔离。tls_probe可独立验证 DNS/TCP/TLS,不将云端失败误判为模型或 UI 故障。SMART_HOME_NODE_GATEWAY_REQUIRED以便 CI 或专用联调环境快速失败;MCP 则始终保持手动发现、失败仅禁用 MCP 的策略。6. 代码注释、接口与安全规范
6.1 注释规范
6.2 接口使用约束
agent_register_tool():动态工具需填完整元数据,包括group_id/category_id/flags;agent_register_tool_simple()不适用于需要分组的远程工具。7. 应用案例与落地验证
set_light→ 本地设备状态 → 自然语言确认run_scene→ 多设备状态更新mcp_*天气工具 → Caiyun MCP → 总结mcp_probe验证网络链node_living_*→ WebSocket gateway →sensor_nodeget_indoor_environment→/dev/aht0AHT30图形效果、MCP/Node 工具导入和真机日志位于 logs;各案例的精确命令、预期输出和失败排查位于 决赛增量文档。
8. 优化迭代过程
settings.json + secrets.jsonmcp_probebox3_sensor_test、室内环境工具9. 创新点说明
10. 快速验证
10.1 接入 OpenVela 工作区
不要把
res/config/secrets.json复制到源码或提交。应从示例生成本地文件,再通过 LittleFS 镜像或 ADB 放入/data/smart_home/。10.2 Goldfish 最小闭环
Node 双模拟器、MCP mock/真实服务、App HTTP 调试和 ADB 多设备选择,请直接按 决赛增量文档 执行;该文档还包含
mcp_probe、tls_probe和sensor_node的期望结果。10.3 ESP32-S3-BOX-3
BOX-3 使用 Make 构建与烧录流程:
在 NSH 连接 Wi-Fi 后可运行
tls_probe、mcp_probe、box3_sensor_test --once和smart_home。LittleFS 配置镜像、AHT30 接线、故障定位与完整命令见 BOX-3 指南。11. 已知限制与后续方向
SMART_HOME_APP_BRIDGE_CHAT。事件推送、设备配网、账户体系和局域网发现未作为本期交付。12. 文档、许可证与证据
自研代码遵循 Apache License 2.0。第三方软件和素材许可见 NOTICE 与 THIRD-PARTY-NOTICES。