miloco-perception
米家多模态感知 Skill。通过摄像头视听理解(画面 + 声音)与感知日志,回答现场与近期问题。
核心工作流
解析 → 获取摄像头 → 查日志 or 实时查询 → 回复
第一步 · 解析意图
从用户自然语言中提取:
目标区域:- 具体房间(客厅 / 卧室 / 门口…) → 该房间摄像头
- "全屋 / 家里"或问题本就覆盖全屋 → 全部摄像头
- 没点名房间、也非全屋意图 → 追问哪个房间(避免对所有摄像头空跑 Omni)
感知问题:在做什么 / 有什么动静 / 现在什么情况时间:问的是"此刻现场"还是"近期";若是近期,把"刚才 / 刚刚 / 最近"换算成最近一段时间窗(如 1h)
第二步 · 获取摄像头
必须先 perceive devices 拿全量感知源,再选 source——不要直接用预注入 catalog 里的摄像头。 catalog 只是高频子集、不保证覆盖全部摄像头,也不带 online 状态;漏摄像头或拿离线源会导致漏查 / 空跑。
miloco-cli perceive devices # 返回 device_type=camera 的感知源(含 did/room/online)
按 room 选出目标区域的在线摄像头 did,作为后续 --source。
第三步 · 查日志 / 实时查询
核心原则:能用日志答的,不调实时。
感知问题
│
├─ 近期/事件类("刚才发生了什么" "最近怎么样")
│ → miloco-cli perceive logs --since <时长> --jsonl
│ 已有感知结果缓存,零大模型成本
│
└─ 此刻细节类("现在在做什么" "猫在干嘛" "看看客厅")
→ miloco-cli perceive query --source <did> [--source <did>] --query "<问题>"
调用摄像头 + Omni API,1-5s,有成本
查询感知日志(零成本,优先使用):
miloco-cli perceive logs --since 1h --jsonl
# 查近期事件:最近一段窗口 + 结构化逐行输出("时间: JSON"),不读写 cursor
# --since 单位 h/m/s/d 及组合,如 1h、30m、7d;--jsonl 仅控制输出格式
实时多模态感知(调用 Omni API,1-5s,有成本):
miloco-cli perceive query --source <did> [--source <did>] --query "<用户问题>"
# 每个摄像头用独立的 --source 重复传,可多次;是 --source 不是 --sources
# 调用摄像头 + Omni API 进行多模态理解,返回自然语言描述
第四步 · 组合回复
- 单一结果 → 直接转述:实时为 Omni API 返回的描述,单条日志直接复述事件本身
- 多个结果 → 按事件和区域归纳,别逐条复述、不必报每条时间点
示例
此刻·全屋 — "猫在干嘛"
解析:区域=全屋,此刻 → 实时
设备:perceive devices → cam_001(客厅摄像头)、cam_002(卧室摄像头)
执行:$ miloco-cli perceive query --source cam_001 --source cam_002 --query "猫在干嘛"
→ "猫在客厅沙发上睡觉"
回复:"猫在客厅沙发上睡觉"
此刻·指定房间 — "客厅是不是有人在说话"
解析:区域="客厅",此刻 → 实时
设备:perceive devices → cam_001(客厅摄像头)、cam_002(卧室摄像头)→ 按 room 选客厅,取 cam_001
执行:$ miloco-cli perceive query --source cam_001 --query "有没有人在说话,在聊什么"
→ "有两个人在聊天,像是在商量晚饭吃什么"
回复:"客厅有两个人在聊天,好像在商量晚饭"
近期回顾 — "门口刚才有什么动静"
解析:区域="门口",近期 → 日志
执行:$ miloco-cli perceive logs --since 1h --jsonl # 最近一段窗口 + 结构化输出,不碰 cursor
→ 2026-06-11T20:35:00+08:00: {"门口": "有人在门口停留"}
2026-06-11T20:52:00+08:00: {"客厅": "客厅有人走动"}
2026-06-11T21:08:00+08:00: {"门口": "快递员放下包裹后离开"}
筛门口记录,归纳为一件事
回复:"门口刚才有人停留过,后来快递放下包裹就走了"
异常处理
| 异常 | 处理方式 | 回复 |
|---|---|---|
| 摄像头不可用(区域无摄像头 / 离线) | 有近期感知日志则读取日志,否则如实告知原因 | "客厅没有摄像头" / "摄像头离线,仅能看最近记录" |
| perceive query 超时或返回空 | 退回最近感知日志 | "实时感知失败,最近一次:…" |
| 近期无感知日志 | 能现场判断的问题 → 转 perceive query 实时查看;仅当用户明确问历史 → 才告知无记录 |
"实时看了下:客厅没人" / "最近没有感知记录" |
关键规则
- 近期/事件类问题 logs 优先。 回顾类问题先查
perceive logs,有缓存就别调实时;"此刻在干嘛"等当下问题仍走 query,不拿过期缓存充数。 - 查近期事件用
perceive logs --since <窗口>。 取最近一段窗口、不动共享 cursor;--jsonl仅是结构化输出格式。别裸调perceive logs(无--since)——那是游标增量模式,只返回"自上次以来的新事件"并推进共享 cursor,是给持续消费整条流的 agent(如 digest)用的。 - query
code=0≠ 成功。answer仍可能为空,按失败处理、退回 logs,别把空结果当答案回给用户。 - 设备信息动态获取。 从
perceive devices拿摄像头,不硬编码设备清单。 - 回复简短自然。 按第四步组合,不堆砌术语或原始字段。
- 隐私保护。 摄像头感知结果不存储原始画面/录音,仅返回文本描述。不主动拍摄/录音,仅在用户明确提问时触发。
- 声音关闭的相机听不到它的现场声音。 声音可按相机开关(面板或
scope camera mic-on/mic-off,见 miloco-miot-scope;状态看scope camera list的voice_in_use)——voice_in_use=false时该相机音频完全不被处理,perceive query也听不到它的现场声音(问"有没有人说话"只能靠画面判断);视频感知照常。查询时如实告知「该摄像头声音已关闭」;除非用户明确要求打开,不要自行改动。