"我回来了。"晚上七点四十,我推开门,对着空气说了这么一句。三秒之内,门廊感应灯亮起,客厅主灯自动调到 40% 的暖光,空调从 28 度节能模式切到 26 度舒适风,加湿器开了低频,音响播起我昨晚没听完的那期播客。这一连串动作,不是我在 Home Assistant 里写死的自动化规则——因为规则根本写不出这种"通人情"的响应。Home Assistant 负责连接设备,OpenClaw 负责理解人话、拆解意图、调度服务。两者一组合,才真正构成一套"AI 原生"的全屋智能控制范式。
这篇文章想讲清楚三件事:为什么 OpenClaw 能补齐 Home Assistant 的自动化短板;把两者打通需要经过哪些关键步骤,包括部署、通道集成和 Skill 开发;以及我在真实环境里跑了几个月之后踩过的坑和沉淀下来的经验。适合正在玩 Home Assistant、对千篇一律的规则自动化不满意的人,也适合刚接触 OpenClaw、想给它找一个高价值落地场景的朋友。
1. 从"规则自动化"到"意图驱动":这套组合到底解决了什么
1.1 Home Assistant 的自动化天花板:规则无法穷举生活
Home Assistant(以下简称 HA)本身是一个极其优秀的设备集成层。它通过 REST API、MQTT、Zigbee、Z-Wave 等协议,把不同品牌的灯、空调、传感器、摄像头统一抽象成 entity 和 service,这层抽象极其重要,它让上层控制逻辑不再关心设备品牌差异。但它的自动化引擎本质上是"状态机 + 规则":
yaml复制alias: "回家开灯"
trigger:
- platform: state
entity_id: binary_sensor.front_door
to: "on"
condition:
- condition: state
entity_id: sun.sun
state: "below_horizon"
action:
- service: light.turn_on
target:
entity_id: light.living_room
这段 YAML 表达的是"门开了,且太阳落山了,就开客厅灯"。问题在于:规则必须被提前想清楚。如果我想表达"我回来了,你觉得怎么安排比较合适",规则引擎完全无能为力。它不知道今天是什么日子、外面温度多少、我睡眠质量如何、昨晚到底几点睡的。规则是静态的,人的需求是动态的。
我在家里接了 60 多个实体、十几个传感器之后,对传统自动化的三个短板体会特别深:
- 组合穷举不完。实体之间的相关性是指数级的,手写规则只能覆盖最常用的几条,更多潜在需求被白白浪费。
- 上下文完全缺失。"开灯"这个动作,深夜加班回家和周末白天回家,含义天差地别,但规则里的条件就那几行。
- 冲突没有仲裁机制。多个自动化同时触发、条件互相矛盾时,HA 只会按触发顺序执行,不会思考"哪个才是用户真正想要的"。
1.2 OpenClaw 补上的 Agent 层:理解、规划、执行、记忆
OpenClaw 是一个开源的个人 AI Agent 框架,核心设计是让大语言模型不再只停留在聊天框里,而是能真正调用外部工具、访问数据、执行动作。它在架构上承担了智能家居"大脑"的角色:向下通过 API 驱动 HA,向上接收用户的自然语言请求。
它有几个特性,恰好击中智能家居的痛点:
- Skill 机制:把"控制灯光""查询天气""读取日历"封装成可被模型调用的工具,相当于给 Agent 装上了手。没有 Skill 的模型只能聊天,有了 Skill 的模型才能干活。
- Active Memory:能跨会话记住用户的长期偏好和上下文,这是最近社区里讨论很多的一个方向。对家居场景特别关键,因为"家"本身就是最需要上下文的地方。
- 多模型路由:按任务类型把请求分发给不同模型,复杂规划用大模型,简单指令用本地小模型,兼顾成本与响应速度。
- 多入口接入:微信、飞书、钉钉、网页 UI、CLI 都能接,意味着你不用专门掏出手机 App,日常聊天入口喊一声就行。
1.3 边界划清:Agent 是大脑,Home Assistant 是神经和肌肉
这里必须说清楚一个边界:OpenClaw 不是要取代 HA。HA 在设备接入、状态上报、本地自治方面做得非常成熟,如果 Agent 网络断了、模型挂了,HA 自己的自动化仍然能兜底。我把这套架构理解成三层:
- 设备层:灯、传感器、空调等物理设备。
- 集成层:HA,负责抽象设备、执行指令、维护状态。
- 智能层:OpenClaw,负责理解意图、规划任务、编排动作、积累记忆。
这个分层有一个额外的好处:换 Agent 框架不影响设备层,换设备也不影响 Agent 层。我后来把一部分自动化从 HA 挪到 OpenClaw 上,又把另一部分从 OpenClaw 挪回 HA,整个过程完全没有动过设备配置。这就是分层解耦带来的底气。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 部署前的顶层设计:网络拓扑、模型选型与安全边界
2.1 先画拓扑:谁在哪个网段,数据往哪走
在动手安装之前,建议先花十分钟想清楚拓扑。我的方案是:
- 家庭路由器负责基础网络;
- 一台 NUC 小主机跑 HA,用 Docker 部署;
- 同一台 NUC 上再跑 OpenClaw,让 Agent 和 HA 之间走内网,延迟极低;
- 模型层放在云端 API,或者本机 Ollama 跑小模型,按需路由。
拓扑上有一个容易忽略的坑:OpenClaw 所在的容器最好使用 host 网络模式,或者与 HA 容器放在同一个自定义 bridge 网络里。否则你从容器里访问 http://homeassistant.local:8123 可能会解析不到,因为容器内 DNS 和 mDNS 的处理方式跟宿主机不一样。我一开始用默认 bridge 网络,发现 Agent 调用 HA 时经常超时,后来把两个容器放进同一个自定义网络,问题立刻消失。这种内网互通问题,越早想清楚越省事。
2.2 模型选型:云端 API、本地模型、还是混合路由
智能家居场景对模型的要求和通用聊天不一样,延迟敏感、指令重复度高、涉及家庭隐私。三种路线各有利弊:
| 路线 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| 云端 API(如 DeepSeek) | 理解能力强,无需本地算力 | 有网络延迟,调用成本随次数增长 | 复杂意图解析、长对话规划 |
| 本地模型(Ollama 部署) | 无外部依赖,隐私好,响应快 | 小模型理解能力有限 | 固定指令、设备开关、状态查询 |
| 混合路由 | 兼顾质量与成本 | 需要额外配置路由策略 | 生产化使用,我最终选它 |
我最终采用的混合策略是:所有"开关灯、查温度、执行场景"这类高频低复杂度指令走本地小模型(Ollama 里的 7B 级别模型),响应能压到一秒左右;而"帮我规划一个周末节能方案"这类需要推理的请求,路由到云端大模型。OpenClaw 的配置里可以按 Skill 或按关键词设置模型路由规则,这一步在初期可以不配,但设备一多、请求一密,混合路由几乎是必须的。
2.3 安全边界:给一个能控制全屋设备的 Agent 上三道锁
让 Agent 控制全屋设备,等于把家的控制权交了出去。我的原则是三道锁:
- 最小权限:给 OpenClaw 单独建一个 HA 用户,只授予控制设备和读取状态的权限,不要用管理员账户。多花三十秒建账户,换来的是长期的心理安全。
- 网络隔离:Agent 调用 HA 的 API 只允许在内网发生,HA 不要直接暴露到公网。远程访问走带有身份验证的入口,而不是裸开端口。
- 指令白名单:在 Skill 层做参数校验,比如"温度"字段只接受 16 到 30 的整数,"灯"只接受已知 entity_id 列表。这一点非常关键,因为大模型生成参数时偶尔会幻觉出不存在的设备名,校验层能兜住。
关于第三点我多说一句:不要相信模型永远不犯错。我给 Skill 加了参数校验之后,再也没有出现过把卧室温度调到 80 度这种事。模型负责"想",校验层负责"把关",两者配合才是健康的架构。
3. 落地部署:Home Assistant 与 OpenClaw 的完整环境搭建
3.1 Home Assistant 端:生成长期访问令牌并验证 API
HA 端只需要两步。第一步是准备控制凭证:在 HA 界面左下角点击用户名,进入个人资料页面,下滑找到"长期访问令牌",创建一个并保存好。这个 Token 就是 OpenClaw 访问 HA 的钥匙,建议单独为 Agent 创建,不要用默认的管理员令牌。
第二步是确认 API 可用:
bash复制curl -X GET "http://homeassistant.local:8123/api/states/light.living_room" \
-H "Authorization: Bearer YOUR_LONG_LIVED_TOKEN" \
-H "Content-Type: application/json"
如果返回了带 entity_id、state、attributes 的 JSON,就说明 API 通了。这一步建议单独做一次,因为后面 Agent 配置出问题的时候,你需要能快速确认"到底是 API 的问题还是 Agent 的问题"——没有这个基准线,排查会非常痛苦。
3.2 OpenClaw 的三种部署路径
OpenClaw 的部署方式比较灵活,我实际试过三种:
- Windows 本机部署:用 PowerShell 安装脚本,适合只想在桌面环境快速体验的人。但要注意运行时会占用相当大的系统资源,而且文件锁问题在 Windows 上尤其多(后面踩坑部分会展开)。
- Docker 部署:最推荐的方式,一条命令就能拉起,日志、配置文件、数据卷都隔离得干干净净。我自己的生产环境就是宿主机加 Docker 容器。
- 云服务器或小主机部署:适合家里有 NAS、NUC、树莓派的朋友,部署在局域网内,天然和内网设备靠近。
以 Docker 为例,核心命令类似这样:
bash复制docker run -d \
--name openclaw \
--network host \
-v ~/.openclaw:/root/.openclaw \
-e OPENCLAW_MODEL=deepseek-chat \
-e OPENCLAW_API_KEY=your_api_key \
openclaw/openclaw:latest
第一次启动之后,OpenClaw 会在 ~/.openclaw 目录下生成配置文件和密钥文件,Windows 上对应的是 %USERPROFILE%\.openclaw。这个目录很重要,后续改模型、加 Skill、调记忆参数都靠它。建议一开始就把它纳入备份范围,丢了配置的代价远大于备份的成本。
3.3 首次配置:onboarding 引导与模型参数确认
新版本 OpenClaw 启动后会进入 onboarding 流程,引导你配置模型提供商、确认密钥、测试对话。如果你跳过了 onboarding,也可以在配置文件中手动指定模型。这里有一个经常翻车的地方:模型名必须和提供商文档里写的一模一样。
举个例子,如果你用 DeepSeek 的 API,配置里写 deepseek-chat 是正确的;但如果你写成 deepseek-v3 或者简写成 ds,Agent 启动后就会直接报错 unknown model。我在切换模型时踩过这个坑,日志里只有一行 the agent run failed before producing a reply,排查了半天才发现是模型名写错了。所以首次配置完一定要跑一句最简单的测试指令,比如"你好,请回复 OK",确认链路通了再做集成。这一步花一分钟,能省掉后面一整晚的排查时间。
4. 打通控制通道:REST、MQTT、WebSocket 三条路径怎么选
4.1 REST API:最小成本的控制通路
OpenClaw 要控制 HA,最直接的方式就是调 REST API。HA 提供了两套和 Agent 关系最大的 API:
GET /api/states:拉取所有实体状态,用于让 Agent"感知"当前家里发生了什么。POST /api/services/{domain}/{service}:执行服务调用,比如light/turn_on、climate/set_temperature、scene/turn_on。
在 Skill 里用 Python 封装一个通用调用函数,几十行就能覆盖绝大多数场景:
python复制import os
import requests
HA_URL = os.getenv("HA_URL", "http://homeassistant.local:8123")
HA_TOKEN = os.getenv("HA_TOKEN")
def call_service(domain, service, entity_id=None, **kwargs):
url = f"{HA_URL}/api/services/{domain}/{service}"
headers = {
"Authorization": f"Bearer {HA_TOKEN}",
"Content-Type": "application/json",
}
payload = {"entity_id": entity_id} if entity_id else {}
payload.update(kwargs)
resp = requests.post(url, headers=headers, json=payload, timeout=5)
resp.raise_for_status()
return resp.json()
def get_state(entity_id):
url = f"{HA_URL}/api/states/{entity_id}"
headers = {"Authorization": f"Bearer {HA_TOKEN}"}
resp = requests.get(url, headers=headers, timeout=5)
resp.raise_for_status()
return resp.json()["state"]
这套方案的优点是实现简单、依赖少、排查方便。缺点是每次都要发请求,状态是"拉取"而非"推送"的,在需要实时感知大量状态变化时不够优雅。但作为第一步,它足够支撑大多数场景。
4.2 MQTT:事件驱动架构的基石
如果家里设备量大、联动频繁,我建议把 MQTT 也接进来。HA 本身内置了 MQTT 集成,再配一个 Mosquitto broker,OpenClaw 就可以订阅设备事件,实时感知"门开了""有人移动""温度超阈值"等变化,不需要主动轮询。
我设计的主题结构是这样的:
text复制home/events/ # 设备事件,如 presence/客厅有人
home/commands/ # 控制指令,如 light/living_room
home/states/ # 状态快照,如 sensor/temperature
OpenClaw 侧写一个订阅脚本,收到事件后先做一次意图判断:这个事件是否值得触发主动行动?比如"客厅有人移动"在凌晨两点就会触发安防逻辑——Agent 主动调摄像头快照、向手机推送告警、甚至根据预设策略做出响应。这种"事件驱动 + Agent 决策"的组合,是传统自动化很难做到的。
不过 MQTT 方案的复杂度明显高于 REST:broker 维护、主题规划、QoS 级别选择都需要经验。我的建议是:前期先用 REST 跑通,等场景确实需要实时响应时再引入 MQTT,不要一开始就双线作战。
4.3 WebSocket:实时状态同步与长连接会话
HA 还有一个 WebSocket API,支持长连接、服务调用、状态订阅。相比 REST 的短请求,WebSocket 更适合做"持续在线"的 Agent 大脑,因为它能订阅状态变化事件,一旦某个实体状态变化,服务端会主动推送过来。
python复制import asyncio
import json
import websockets
async def subscribe_states():
uri = f"ws://{HA_HOST}:8123/api/websocket"
async with websockets.connect(uri) as ws:
auth_required = json.loads(await ws.recv())
await ws.send(json.dumps({"type": "auth", "access_token": HA_TOKEN}))
await ws.recv() # auth_ok
await ws.send(json.dumps({
"id": 1,
"type": "subscribe_events",
"event_type": "state_changed",
}))
while True:
event = json.loads(await ws.recv())
entity = event.get("event", {}).get("data", {}).get("entity_id")
new_state = event.get("event", {}).get("data", {}).get("new_state")
if entity and new_state:
print(f"{entity} -> {new_state.get('state')}")
这段代码可以作为 OpenClaw 某个 Skill 的底层模块。我个人使用最多的是 REST 加 WebSocket 的组合:REST 负责执行控制,WebSocket 负责监听关键状态变化。三条通道各有定位,不是选择题,而是组合拳。
5. Skill 编写实战:让 Agent 学会操作你的每一件设备
5.1 Skill 的基本结构与注册流程
OpenClaw 的 Skill 概念,可以理解成给 Agent 的一本"操作手册"。Agent 遇到用户请求时,会先判断该调用哪个 Skill,然后把用户意图翻译成 Skill 的参数,最后执行并返回结果。一个 Skill 通常包含两个部分:描述文件(告诉模型这个 Skill 是干什么的、有哪些参数)和实现逻辑(实际执行的代码)。
以我自己的一个 Skill 为例,目录结构大概是:
text复制~/.openclaw/skills/
└── ha_control/
├── skill.yaml # 元数据和参数描述
└── main.py # 执行逻辑
skill.yaml 里要写清楚名称、描述、参数列表。描述写得越准确,模型就越不容易误调用。我见过很多人写描述特别随意,比如"控制家居",结果模型根本不知道这个 Skill 能控制哪些设备、支持什么操作,自然就调不准了。描述文件就是给模型看的文档,写文档的功夫省不得。
5.2 一个可用的 Home Assistant Skill 示例
yaml复制# skill.yaml
name: ha_control
description: 控制 Home Assistant 中的智能设备。
支持开关灯、调节空调温度、查询传感器状态、执行场景。
参数 entity 必须是合法的 entity_id,例如 light.living_room。
version: 1.0.0
entry: main.py
parameters:
- name: action
type: string
required: true
enum: [turn_on, turn_off, set_temperature, query, run_scene]
- name: entity
type: string
required: false
- name: value
type: number
required: false
python复制# main.py
import sys
import json
import requests
def main():
args = json.loads(sys.argv[1])
action = args["action"]
entity = args.get("entity")
value = args.get("value")
if action == "turn_on":
result = call_service("light", "turn_on", entity)
elif action == "turn_off":
result = call_service("light", "turn_off", entity)
elif action == "set_temperature":
result = call_service("climate", "set_temperature", entity, temperature=value)
elif action == "query":
result = get_state(entity)
elif action == "run_scene":
result = call_service("scene", "turn_on", entity)
else:
result = {"error": "unknown action"}
print(json.dumps(result, ensure_ascii=False))
if __name__ == "__main__":
main()
这个示例比较简单,但已经能覆盖大部分控制需求。实际使用中,我会在 main.py 里加一层参数校验:entity 必须以 light.、climate.、sensor.、scene. 等合法前缀开头,value 必须在合理范围内。这样可以
