| name | miloco-miot-pet-register |
| description | 宠物成员注册主流程。**用户表达「登记/记住/让系统认识我家的猫/狗等宠物」意图就触发本 SKILL,不要求出现"注册/登记"字面词**——两条通路:①**描述它的样子**(纯文字,如"胖胖是我家橘猫,尾部有白毛、体型偏胖")→ 建花名册 + 写外观;②**发照片/视频** → 观察出多姿态候选参考图 + 共性外观 → 确认 → 落库(花名册 + 识别参照 + 外观)。也覆盖给存量宠物"补充素材"。**只用用户主动提供的信息**(文字或素材):宠物没有"陌生宠物池",不从摄像头挑、不模拟。纯改名 / 删宠物走 miloco-cli pet CRUD。 |
| metadata | {"author":"miloco","version":"1.1","date":"2026-07-17","openclaw":{"requires":{"bins":["miloco-cli"]}}} |
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 文字,无陌生池):
- 解析触发源 — 宠物名 / 物种 / 外观描述 + 有无附件;是否"补充素材"
- 通路判定 — B 文字通路(有描述无素材)/ A 素材通路(有素材且功能开);都无 → 引导
- 首轮准备 — A:
pet observe --save-crops 出候选参考图 + 共性外观;B:回显解析出的 名/物种/外观 请用户确认
- 等待用户回复 — 本轮不发中间消息
- 次轮落库 — 确认 →
pet add(若新) + (A 才有)reference-crops + 写外观 + commit;取消 → 不落库
推荐路径
- 首选发素材(推荐一段短视频,或 1~3 张、最好 3 张覆盖不同姿态/角度的照片):姿态越全,识别越准——不仅记外观,还能建识别参照让系统在画面里认出它。纯文字描述也能完成注册,只是没有识别参照(画面里认不出)——落库后提示用户"想让画面里认得出,再发张照片/视频"。
第一步 · 解析触发源
从用户话里抽:宠物名 name、物种 species(猫/狗/其它)、外观描述(若有);并看有无图/视频附件。
- "登记胖胖,橘猫,尾部白毛、偏胖" → name=胖胖, species=猫, 外观="橘猫,尾部有白毛,体型偏胖"(无附件 → B)
- "这是我家金毛 Max"(附视频) → name=Max, species=狗(金毛=品种,归外观), 有素材 → A
- "我家那条狗"(无名) → 追问真名("这只狗叫什么名字?我用它作标识")
- 完整规则见 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,单次批量)/ 视频(原文件,禁抽帧):
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)
第五步 · 次轮落库 / 取消
通用:新宠物先建壳(名不存在时——已按第一步"重名前置查重"确认):
miloco-cli pet add --name <name> --species <猫/狗/其它> --pretty
若 pet add 返回 409(名已存在):说明前置查重漏了 → 停下走 5.5 问用户(补充 / 覆盖 / 另一只),别自动改名硬塞、别静默 append / replace。
写外观(两通路都做,用户已确认才写,member_persona,subject_id=pet_id)。含中文用 --ops-file:
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 + 绝对分):
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 注册省的是"用户手动裁剪调整头像"这步,不是不要头像):
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:
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:文字描述注册(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 文字通路无素材 → 占位