# Miloco Miot Pet Register

> 宠物成员注册主流程。**用户表达「登记/记住/让系统认识我家的猫/狗等宠物」意图就触发本 SKILL,不要求出现"注册/登记"字面词**——两条通路:①**描述它的样子**(纯文字,如"胖胖是我家橘猫,尾部有白毛、体型偏胖")→ 建花名册 + 写外观;②**发照片/视频** → 观察出多姿态候选参考图 + 共性外观 → 确认 → 落库(花名册 + 识别参照 + 外观)。也覆盖给存量宠物"补充素材"。**只用用户主动提供的信息**(文字或素材):宠物没有"陌生宠物池",不从摄像头挑、不模拟。纯改名 / 删宠物走 miloco-cli pet CRUD。

- Skill: `xiaomi/miloco-miot-pet-register` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add xiaomi/miloco-miot-pet-register`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xiaomi/miloco-miot-pet-register/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-miot-pet-register

---


# miloco-miot-pet-register

## 何时激活

| 用户意图 / 触发源 | 用户说了类似… | → 通路 |
|---|---|---|
| **文字描述登记** | "登记下胖胖,我家橘猫,尾部白毛、偏胖"(无附件,但**描述了样子**) | **B 文字通路**(第二步 2.1) |
| **附素材登记** | "这是我家猫小黑"(附图/视频)/ "记住这只狗"(附图/视频) | **A 素材通路**(第二步 2.2) |
| **给存量宠物补充素材** | "给小黑再传几张"(附图/视频) | A 素材通路 → 落库走 `append`(第五步 5.3) |
| **只说登记、无描述无素材** | "帮我登记我家猫"(既没描述样子也没附素材) | 引导(第二步 2.4):给个描述 或 发素材 |
| 纯改名 / 删宠物 | "把小黑改名" / "删掉小黑" | → miloco-cli pet update/delete(**非本 SKILL**) |

**判断规则**:用户想**让系统记住/认识某只宠物**(建身份 + 记外观) → 本 SKILL。只改花名册行(改名/删) → CRUD 命令。

## 总原则 · 只用用户主动提供的信息,不从摄像头挑

本 SKILL 靠**用户主动给的文字描述或上传的素材**建档。**宠物没有"陌生宠物池"**(系统不对宠物做 ReID/聚类,认不出的宠物只在实时描述里泛称"一只黑猫",不攒成"待认领候选")。所以:
- ❌ 不实现、也**不要用其他工具"模拟"**"从摄像头看到的宠物里挑一只建档"——这条通路不存在。
- 用户若要"从画面里挑没登记的宠物" → 一句话告知暂不支持,引导改为"描述一下它的样子,或发张清晰照片/视频"。

> 这与人注册不同:人有"陌生人池"(摄像头累积未识别人可挑出建档),宠物没有对应基建。别把人的 `pool fetch` / 从摄像头挑那套套到宠物上。

## 前置 · 功能门(关闭时整个注册不可用)

宠物识别是实验性功能,总开关 `pet_recognition` 控制。**关闭时,注册所有端点(建花名册 / 头像 / 参考图 / observe)一律返 404 → A 素材通路与 B 文字通路都走不了**:
- 用户想登记宠物却功能没开 → **引导去设置打开**:"宠物识别功能没开,现在还没法给它建档——去设置里打开「宠物识别」,打开后我就能帮它建档、在画面里认出它。"
- **别在关闭时假装建档 / 承诺"已记下"**;纯"家里有只狗"这类家庭事实由 `miloco-home-profile` skill 记录(与识别无关、不受此门控)。
- **怎么判开关**:`miloco-cli config get features.pet_recognition --value-only`(输出 `True` / `False`,与 `miloco-home-profile` 同口径)。注意 `pet list` **不受门控**(关闭时也正常返回存量花名册),**不能**拿它的成功/失败反推开关状态。

## 核心工作流

**5 步流水线**(仿人注册;两条通路 A 素材 / B 文字,无陌生池):

1. **解析触发源** — 宠物名 / 物种 / **外观描述** + 有无附件;是否"补充素材"
2. **通路判定** — B 文字通路(有描述无素材)/ A 素材通路(有素材且功能开);都无 → 引导
3. **首轮准备** — A:`pet observe --save-crops` 出候选参考图 + 共性外观;B:回显解析出的 名/物种/外观 请用户确认
4. **等待用户回复** — 本轮不发中间消息
5. **次轮落库** — 确认 → `pet add`(若新) + (A 才有)`reference-crops` + 写外观 + commit;取消 → 不落库

### 推荐路径
- **首选发素材**(推荐一段短视频,或 1~3 张、最好 3 张覆盖不同姿态/角度的照片):姿态越全,识别越准——不仅记外观,还能建**识别参照**让系统在画面里认出它。纯文字描述也能完成注册,只是没有识别参照(画面里认不出)——落库后提示用户"想让画面里认得出,再发张照片/视频"。

## 第一步 · 解析触发源

从用户话里抽:**宠物名 `name`**、**物种 `species`**(猫/狗/其它)、**外观描述**(若有);并看有无图/视频附件。
- "登记胖胖,橘猫,尾部白毛、偏胖" → name=胖胖, species=猫, 外观="橘猫,尾部有白毛,体型偏胖"(无附件 → B)
- "这是我家金毛 Max"(附视频) → name=Max, species=狗(金毛=品种,归外观), 有素材 → A
- "我家那条狗"(**无名**) → **追问真名**("这只狗叫什么名字?我用它作标识")
- 完整规则见 [references/species-name-parsing.md](./references/species-name-parsing.md)。

**🚨 重名前置查重**(拿到 `name` 后、observe / 落库**之前必做**):先 `miloco-cli pet list` 看该 `name` 是否已在花名册(后端按**精确名**判重,`pet add` 撞名直接 409)。按结果分流:
- **名不存在** → 正常往下(A observe / B 回显)。
- **名已存在 + 用户明确是"补充素材"**("给小黑再传几张") → A 素材通路 + 落库走 `append`(第五步 5.3),复用已有 pet_id,无需再问。
- **名已存在 + 用户是"注册/登记"意图(非明确补充)** → **不要 observe、不要落库**,本轮停下问用户三选一(第五步 5.5),按回复再走;**严禁**自作主张直接 append / 覆盖。

## 第二步 · 通路判定

```
收到用户消息:
  if pet_recognition 关(`config get features.pet_recognition --value-only` → `False`):
                                             → 引导去设置打开(见异常表),本轮结束;纯家庭事实交 miloco-home-profile
  elif 含图/视频附件:                         → 2.2 A 素材通路
  elif 有文字外观描述(无附件):               → 2.1 B 文字通路
  else:  # 既没描述也没素材                   → 2.4 引导:给描述 或 发素材,本轮结束等回复
```

### 2.1 B 文字通路（描述建档）
把第一步解析出的 名/物种/外观**回显给用户确认**(不擅自落库,分阶段):
```
用户: 登记下胖胖,我家橘猫,尾部有白毛、体型偏胖

Agent: 好的,登记这只:
       - 名字:胖胖  · 物种:猫
       - 外观:橘猫,尾部有白毛,体型偏胖
       确认入库?（想让系统在画面里也认出它,回头发张照片或短视频,我再建识别参照）
```
发完**本轮终止等待**;用户确认 → 第五步 5.2 落库。外观描述不足(只有名/物种)也可先建档,外观可空或提示补。

### 2.2 A 素材通路（素材建识别参照）
见第三步 observe;拿候选参考图 + 共性外观发用户确认。

### 2.4 无描述无素材 → 引导（复述已知信息、只补问缺的）
先**接住第一步已解析到的信息**(物种 / 名字),**只追问缺失项**,别重复问用户已经说了的;两条方式都给出,但**素材优先**(效果最好),文字兜底。

已知物种(如已说"猫")、缺名字 + 外观:
```
用户: 我想登记下我家的猫

Agent: 好嘞,这只猫要登记(顺便告诉我它叫什么),两种方式(效果从好到省事):
       - **发一段短视频,或 1~3 张、最好 3 张照片**,尽量拍全不同姿态/角度——认得最准,还能建识别参照让画面里也认出它;
       - 或**只用文字描述它长什么样**(毛色花纹/体型/显著标记),我先建档,回头再补素材加识别参照。
```
啥都没说(如"帮我登记个宠物"):把物种也一起问("是猫、狗还是别的宠物,叫什么,什么样")。
发完**本轮终止等待**,用户补描述/素材后重进第一步。

## 第三步 · A 素材通路首轮（observe）

对上传的素材调 **一次** `pet observe`,拿候选参考 crop + 共性外观描述。

🚨 **`<MediaPath>` 用消息给的真实路径**:即用户消息里 `[media attached: <绝对路径>]` / `MediaPath(s)` 提供的那个(通常形如 `~/.openclaw/workspace/media/inbound/openclaw-staged-…/….mp4`)。**绝不**拿 `message_id`(如 `om_x100…`)拼文件名、**绝不**猜 `/tmp/openclaw/media/inbound/…` 之类路径。

单图 / 多图(≤3,单次批量)/ 视频(原文件,禁抽帧):
```bash
miloco-cli pet observe --image <MediaPath> --save-crops /tmp/<uuid>_pet --pretty
miloco-cli pet observe --images <p1> --images <p2> --images <p3> --save-crops /tmp/<uuid>_pet --pretty
miloco-cli pet observe --video <MediaPath.mp4> --save-crops /tmp/<uuid>_pet --pretty
```

返回字段:
- `detected` — 是否检出猫/狗
- `description` — 共性外观描述(物种 / 体型 / 毛色花纹 / 显著标记 / summary),即**待落库的外观**
- `crops_saved` — `[{index, path, score, species_guess}]`:每张候选参考 crop 的本地路径 + 绝对质量分(第五步喂 `reference-crops --scores`)。**注意:这些是发给系统落库用的单张,不逐张发用户**
- `montage_saved_to` — **多姿态参考图横向拼成的一张图**(后端统一高 384 等比缩放拼接);**发用户看候选就发这一张**,别把 `crops_saved` 逐张刷屏
- `avatar_saved_to` — 默认头像本地路径(observe 已按头部框裁好;第五步喂 `pet avatar` 作注册默认头像)
- `candidates` — 候选元数据(已清 base64)
- `warnings` — **数组** `[{type, level, message}]`(type 见下表,level 多为 `warn`,message 是人话);逐条转述给用户
- `refs_inconsistent` — **顶层布尔字段**:多图时 omni 疑似"不是同一只";**同一件事也会在 `warnings` 里出现一条 `type = refs_inconsistent`——两处是同一个信号,跟住户只说一遍**

**本步硬约束**:
- ❌ 每轮 `pet observe` **恰调一次**,不"再试 / 刷新一下"。结果不理想(检不到 / 大众脸)直接按结果发话让用户决定。
- ❌ 视频**禁客户端抽帧**再 `--image`(丢多帧姿态,识别参照差);原文件交 `--video`,后端选帧。
- ❌ 不给 CLI 加 `| jq` / `| grep` 管道(丢字段)。
- 🚨 **拼图用 `message` 工具发、只发图**:候选图必须用 `message(action=send, media=montage_saved_to)` 显式上传(飞书 DM `MEDIA:` 内联标记不渲染);发 **`montage_saved_to` 这一张**(多姿态已横向拼好),不逐张发 `crops_saved`(刷屏),无 montage 才退单张。**这条 `message` 的 `text` 留空、不写话术**——话术改用普通文字回复(见下条)。
- 🚨 **发完拼图后,必须再用一句普通文字回复(assistant `content`)把确认话术说出来**——像平时聊天直接回文字、**不经任何工具**,内容用下方"首轮文字模板"。**别只调 `message` 发张图就收尾**。(即:图走 `message` 工具、话术走你的文字回复,两者分开。)
- 🚨 **发完(拼图 + 文字确认),本轮到此为止**:进第四步**纯等待**——**严禁本轮落库**(`pet add` / `reference-crops`)。observe 与落库是两轮,落库须等用户下轮回"确认"。
- 🚨 **别把用户的"注册/登记"当成对 observe 结果的认可**:那是**意图**;而这次具体**记成什么样**(外观、选哪几张图)得用户看过、回"确认"才算数。所以本轮只把结果给他看,落库是他点头后**下一轮**的事。

**处理提示**(发用户时用自然语言转述;前五条是 `warnings[].type` 的取值;末条的顶层 `refs_inconsistent` 与 `warnings` 里的同名条目是**同一件事**,合并成一句说、别转述两遍):

| 信号 | 含义 | 首轮话术处理 |
|---|---|---|
| `warnings[].type = species_mismatch` | 检出物种与用户说的不符 | "我看着更像{检出物种},你确认是{用户物种}吗?" |
| `warnings[].type = generic_look` | 大众花色/脸,难独一区分 | 照常注册,但提示"这只花色比较常见,后续多补不同姿态识别更稳" |
| `warnings[].type = multiple_pets` | 画面里不止一只 | "画面里不止一只,本次先注册主体那只;其它的分别再各传一次" |
| `warnings[].type = partial_decode_failed` | 有图没解出来(截断/损坏/不是图片),已跳过 | "其中有张我没打开(文件像是损坏了),这次用剩下的看的;想把那张也算上就重新发一次" |
| `warnings[].type = low_sharpness` | 素材偏糊(不硬拒,只是参照会打折) | 照常注册,但提示"这几张有点糊,识别参照效果会差些;有更清晰的可以再补" |
| 顶层 `refs_inconsistent = true` | 多图疑似不是同一只 | "这几张看着可能不是同一只?确认都是{name}我再入库,或只留同一只的" |

首轮文字模板(作为你这轮的**普通文字回复(assistant `content`)** 直接说出来,不放进 `message`):
> 观察好了:{summary}。我挑了 N 张不同姿态作识别参照(图),确认给「{name}」入库?回"确认"。

（`{summary}` 是 observe 出的完整外观描述、已含物种,**外观只说这一次**,别再在句首另起"这是一只…"重复一遍。）

无名时句尾追问:"这只{物种}叫什么名字?"

## 第四步 · 等待用户回复

发完(候选图 / 回显)后**纯等待**:不发中间消息、不主动重跑 observe,直到用户下一轮回复。
- "确认"/"好"/"对" → 第五步落库
- "取消"/"不对" → 第五步 5.4
- 改名字/物种/外观/删某张候选 → 按回复调整后落库(如用户说"第 2 张不要",落库时 `--crops` 去掉该张;改外观则用新外观写 member_persona)

## 第五步 · 次轮落库 / 取消

**通用**:新宠物先建壳(名不存在时——已按第一步"重名前置查重"确认):
```bash
miloco-cli pet add --name <name> --species <猫/狗/其它> --pretty   # → 记下返回 id (pet_id)
```
**若 `pet add` 返回 409(名已存在)**:说明前置查重漏了 → **停下走 5.5 问用户**(补充 / 覆盖 / 另一只),**别**自动改名硬塞、**别**静默 append / replace。
**写外观**(两通路都做,**用户已确认才写**,member_persona,subject_id=pet_id)。含中文用 `--ops-file`:
```bash
# /tmp/<uuid>_persona.json（op=add；entry 必填 type/subject_id/subject_name/content，
#  date 省略即可——后端自动填当日；--user-edit 会把 source/confidence 置 user_told/1.0）:
# [{"op":"add","entry":{"type":"member_persona","subject_id":"<pet_id>",
#    "subject_name":"<name>","content":"<外观：A 用 observe 的 summary / B 用用户描述>"}}]
miloco-cli home-profile profile-write --ops-file /tmp/<uuid>_persona.json --user-edit --pretty
miloco-cli home-profile commit --pretty
```

### 5.1 A 素材通路 · 存识别参照 + 默认头像
在通用建壳 + 写外观之外,存参考图(注册整组替换,用 observe 存下的 crop + 绝对分):
```bash
miloco-cli pet reference-crops <pet_id> \
    --crops /tmp/<uuid>_pet_0.jpg --crops /tmp/<uuid>_pet_1.jpg \
    --scores <crops_saved 各 score 逗号拼接> --mode replace --pretty
```
再设**默认头像**(observe 已按头部框自动裁好、存为 `<prefix>_avatar.jpg`;Agent 注册省的是"用户手动裁剪调整头像"这步,**不是不要头像**):
```bash
miloco-cli pet avatar <pet_id> --image /tmp/<uuid>_pet_avatar.jpg --pretty
```
回复:"已给「{name}」建好档案:记了 N 张识别参照 + 外观 + 头像。"

### 5.2 B 文字通路 · 只建壳 + 外观(无识别参照)
只做通用的 `pet add` + 写外观,**不调 reference-crops**。回复:
> 已给「{name}」建好档案(记了外观)。想让系统在画面里认得出它,发张照片或短视频,我再帮它建识别参照。

### 5.3 补充素材(append,存量宠物 + 素材)
跳过 `pet add`,直接对已有 pet_id:
```bash
miloco-cli pet reference-crops <pet_id> --crops /tmp/<uuid>_pet_0.jpg --scores <score> --mode append --pretty
```
(append 把新旧参考图按绝对分留 top-3。)外观如有更新同通用第 3 步。回复:"已给「{name}」补充素材,识别参照已更新。"

### 5.4 用户取消
**不调任何落库命令**,回复:"好的,没有入库。要重新描述或发素材再看吗?"observe 无副作用,不需清理。

### 5.5 重名(注册意图撞已有名)· 停下问 + 三分支
第一步"重名前置查重"发现名已存在且是注册意图(或落库时 `pet add` 撞 409)→ **本轮只发一句问话、不 observe、不落库**:
> 「{name}」已经在花名册里了。你是想:① 给它**补充**这次的素材,② **覆盖重登**(用这次的重新记),还是 ③ 这其实是**另一只**(那换个名)?回 1 / 2 / 3。

发完**本轮终止等待**。用户回复后分支:
- **① 补充**(复用已有 pet_id,**两轮**):本轮 `pet observe` 出新候选 → 发拼图(`message` 只发图) + 必须再用普通文字回复(content)一句"这次挑了 N 张,确认加进「{name}」的识别参照?回确认" → **停下等确认**(不落库);下一轮确认后走 5.3(`reference-crops … --mode append`),**不重发拼图**,回一句"已给「{name}」补充素材,识别参照已更新"。
- **② 覆盖重登**(复用已有 pet_id,**两轮**):本轮 `pet observe` 出新候选 → 发拼图(`message` 只发图) + 必须再用普通文字回复(content)一句"这次挑了 N 张,确认用它们**覆盖**「{name}」旧档案?回确认" → **停下等确认**(不落库);下一轮确认后 `reference-crops <pet_id> … --mode replace`(整组替换旧参考图)+ 重写 member_persona + 重设默认头像(同 5.1),**不重发拼图**,回一句"已用新素材覆盖「{name}」的档案"。
- **③ 另一只** → 请用户给**新名字**,拿到后按新宠物从第一步重走(`pet add` 新名)。

> 头像:**A 素材通路已自动落默认头像**(observe 的头部裁剪,见 5.1);用户想换/精调去 **web 宠物页**(Agent 不做手动裁剪)。**B 文字通路**无素材 → 暂无头像(占位),可后续发张照片/去 web 设。

## 用户可见输出(硬约束)

### 术语黑名单
**只约束 agent 实际发给用户的 reply 文本**;本 SKILL 里的流程/命令描述、agent 自己的推理与日志继续用这些术语没问题。

| ❌ 用户话术禁用 | ✅ 改用 |
|---|---|
| observe / track / crop / candidate / grounding / tier | "观察" / "识别参照(图)" / "候选" |
| reference-crops / member_persona / commit / profile-write | "识别参照" / "外观" / "存档" |
| 任何内部 id(pet_id 内部形态) | 用宠物名指代,不必展示 |

### 多图/视频仍是同一只
A 素材通路多图/视频入库前若 `refs_inconsistent`,**必须**先跟用户确认是不是同一只,不擅自把疑似不同只的混入同一档案。

## 关键约束

### 约束 1 · 候选/回显与落库分阶段,中间必须用户确认
A 通路 `pet observe`(出候选)、B 通路(回显解析)→ **等待用户明确回复** → 才 `pet add`+(A)`reference-crops`+写外观。observe 无副作用、不落库;绝不在同一轮直接落库。理由:让用户看一眼"准备记成什么样"再入库,避免记错宠物 / 记进大众脸 / 记错外观。

### 约束 2 · 视频原文件提交,禁抽帧（A 通路）
视频必须 `--video <原文件>`,不 ffmpeg 抽帧后 `--image`(丢多帧姿态、识别参照差)。后端 `--video` 已含选帧。

### 约束 3 · 同条消息 ≥2 张图单次批量（A 通路）
一条消息多张图是"同一只的多份参照",一次 `--images a --images b ...`(≤3),不拆 N 次 `--image`。

### 约束 4 · 功能门 + 无池不模拟
`pet_recognition` 关 → **整个注册(A 素材 + B 文字通路)均返 404、不可用**,引导去设置打开、不建档不假装;宠物无陌生池 → 不实现/不假装"从摄像头挑"。

## 异常处理

| 异常 | 处理 | 话术 |
|---|---|---|
| `pet_recognition` 关(注册端点返 404) | 引导去设置打开、不建档 | "宠物识别功能没开,现在还没法给它建档——去设置里打开「宠物识别」,打开后我就能帮它建档、在画面里认出它。" |
| `detected=false`(没检出猫/狗) | 不入库;**先看 `warnings`**——含 `partial_decode_failed` / `low_sharpness` 就按第三步表里那条说(是"图没打开 / 偏糊",不是"没看清是猫是狗"),别把住户推去反复换图;都没有才用右侧话术 | "这张/这段里没看清是猫还是狗,换一张更清楚的,或直接描述它的样子?" |
| `species_mismatch` / `refs_inconsistent` / `multiple_pets` | 见第三步处理表 | 同上表 |
| 用户没给宠物名 | 追问 | "这只{物种}叫什么名字?我用它作标识。" |
| 上传非图非视频 | 引导改发或改描述 | "只能用图片或视频建识别参照;要么重发一张照片/视频,要么直接描述它的样子。" |
| pet 名已存在(且非补充素材意图) | **停下走 5.5** | 按 5.5 问三选一(①补充/②覆盖/③另一只),别用旧的两选一 |
| CLI 非零 exit / 服务不可用 | 不抛 stack,人话告知 | "刚才没登记成功,稍后再试。" |
| 用户要"从摄像头挑没登记的宠物" | 按总原则引导 | "宠物暂时只能靠你描述或发照片/视频登记,来一段吧。" |

## 示例与反例
端到端场景 + 反例见 [references/examples.md](./references/examples.md):文字描述注册(B)/ 单只多图注册(A)/ 单只视频注册(A)/ 补充素材(append)/ 无描述无素材引导 + 反例(抽帧、拆调、跳过确认、模拟从摄像头挑、功能关仍强行 observe)。

## 边界
- ❌ 不做花名册纯行 CRUD 的改名/删(→ miloco-cli pet update/delete)
- ❌ 无"陌生宠物池",不从摄像头挑、不模拟
- ❌ 不接 IdentityEngine/ReID/person 表(红线:宠物走花名册 + 参考图 + member_persona)
- ✅ 泛档案里顺带提到的宠物事实(作息/习惯/健康)由 miloco-home-profile 处理;本 SKILL 专管"专门登记这只宠物"(建身份 + 外观 ± 识别参照)
- ✅ `pet_recognition` 关 → 整个注册(A 素材 + B 文字通路)均不可用 → 话术引导去设置打开、不建档
- ✅ 补充素材走 `reference-crops --mode append`(绝对分留 top-3)
- ✅ A 素材通路自动落**默认头像**(observe 头部裁剪 → `pet avatar`);精调/更换走 web。B 文字通路无素材 → 占位

