# Miloco Perception

> 调用摄像头看画面、听现场声音，或回顾近期事件来判断——在干嘛、有什么动静、是否有人说话/吵闹、刚才/最近发生了什么；通过画面核实设备的开关状态（如开着/关着、亮着/灭着），尤其在拿不到设备上报状态时。读不出画面看不见的具体数值（温度、湿度、音量等）。

- Skill: `xiaomi/miloco-perception` (Agent Skill)
- Install (CLI): `npx skillmds@latest add xiaomi/miloco-perception`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xiaomi/miloco-perception/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: xiaomi (https://skillmd.com/u/xiaomi)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/xiaomi/miloco-perception

---


# miloco-perception

米家多模态感知 Skill。通过摄像头视听理解（画面 + 声音）与感知日志，回答现场与近期问题。

## 核心工作流

```
解析 → 获取摄像头 → 查日志 or 实时查询 → 回复
```

### 第一步 · 解析意图

从用户自然语言中提取：

- `目标区域`：
  - 具体房间（客厅 / 卧室 / 门口…） → 该房间摄像头
  - "全屋 / 家里"或问题本就覆盖全屋 → 全部摄像头
  - 没点名房间、也非全屋意图 → 追问哪个房间（避免对所有摄像头空跑 Omni）
- `感知问题`：在做什么 / 有什么动静 / 现在什么情况
- `时间`：问的是"此刻现场"还是"近期"；若是近期，把"刚才 / 刚刚 / 最近"换算成最近一段时间窗（如 1h）

### 第二步 · 获取摄像头

**必须先 `perceive devices` 拿全量感知源，再选 source——不要直接用预注入 catalog 里的摄像头。** catalog 只是高频子集、不保证覆盖全部摄像头，也不带 `online` 状态；漏摄像头或拿离线源会导致漏查 / 空跑。

```bash
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，有成本
```

**查询感知日志**（零成本，优先使用）：

```bash
miloco-cli perceive logs --since 1h --jsonl
# 查近期事件：最近一段窗口 + 结构化逐行输出（"时间: JSON"），不读写 cursor
# --since 单位 h/m/s/d 及组合，如 1h、30m、7d；--jsonl 仅控制输出格式
```

**实时多模态感知**（调用 Omni API，1-5s，有成本）：

```bash
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` 实时查看；仅当用户明确问历史 → 才告知无记录 | "实时看了下：客厅没人" / "最近没有感知记录" |

## 关键规则

1. **近期/事件类问题 logs 优先。** 回顾类问题先查 `perceive logs`，有缓存就别调实时；"此刻在干嘛"等当下问题仍走 query，不拿过期缓存充数。
2. **查近期事件用 `perceive logs --since <窗口>`。** 取最近一段窗口、不动共享 cursor；`--jsonl` 仅是结构化输出格式。别裸调 `perceive logs`（无 `--since`）——那是游标增量模式，只返回"自上次以来的新事件"并推进共享 cursor，是给持续消费整条流的 agent（如 digest）用的。
3. **query `code=0` ≠ 成功。** `answer` 仍可能为空，按失败处理、退回 logs，别把空结果当答案回给用户。
4. **设备信息动态获取。** 从 `perceive devices` 拿摄像头，不硬编码设备清单。
5. **回复简短自然。** 按第四步组合，不堆砌术语或原始字段。
6. **隐私保护。** 摄像头感知结果不存储原始画面/录音，仅返回文本描述。不主动拍摄/录音，仅在用户明确提问时触发。
7. **声音关闭的相机听不到它的现场声音。** 声音可按相机开关（面板或 `scope camera mic-on/mic-off`，见 miloco-miot-scope；状态看 `scope camera list` 的 `voice_in_use`）——`voice_in_use=false` 时该相机音频完全不被处理，`perceive query` 也听不到它的现场声音（问"有没有人说话"只能靠画面判断）；视频感知照常。查询时如实告知「该摄像头声音已关闭」；除非用户明确要求打开，不要自行改动。

