Friend 插件开发
Friend 插件开发
Section titled “Friend 插件开发”Friend 是伙伴的“灵魂”——名字、性格、情绪表达、说话风格全在这里。这一页讲怎么从零写一个 Friend 插件,包含每个文件的格式和完整示例。
Friend 不包含可执行代码。它是一组纯文本和 JSON 文件,容器读取它们来驱动 LLM 对话和离线关键词响应。
最小可用 Friend
Section titled “最小可用 Friend”一个能跑的 Friend 最少需要两个文件:
my-friend.moodfriend (ZIP)├── manifest.json└── system_prompt.txt打包成 ZIP(根目录直接放文件,不要套一层目录),扩展名改成 .moodfriend,就是一个 Friend 插件包。
manifest.json
Section titled “manifest.json”{ "id": "com.example.friend.xiaochai", "type": "friend", "name": "小柴", "description": "一只热情的柴犬伙伴,永远元气满满", "version": "1.0.0", "author": "你的名字", "icon": "icon.png", "system": false, "uninstallable": true, "defaultEnabled": true, "platforms": { "supported": ["android", "wearos", "windows", "linux", "macos"], "optimized": ["android"] }, "interfaces": { "personality": "system_prompt.txt", "expression": "emoji_mapping.json", "identity": "identity.json" }, "dependencies": { "minContainerVersion": "1.0.0" }, "configSchema": { "greeting": { "type": "string", "default": "汪!我来啦!今天要去哪里玩?", "label": "打招呼语" } }}字段含义见 manifest.json 规范。这里只讲 Friend 特有的部分。
system_prompt.txt
Section titled “system_prompt.txt”这是 Friend 的核心——喂给 LLM 的系统提示词。容器在每次对话时把它作为 system message 发给 LLM。它定义伙伴的性格、说话风格、响应格式。
容器期望 LLM 返回一个 JSON 对象,system_prompt.txt 里必须讲清楚这个要求:
你是小柴,一只住在用户手机里的柴犬伙伴。
【你的性格】热情、忠诚、永远元气满满。你把用户当成最好的朋友,见到对方就开心。你说话喜欢用感叹号,偶尔会"汪"一声。
【你的说话风格】口语化、短句、有画面感。不居高临下,不讲大道理。用小狗的视角看世界——散步、零食、晒太阳就是最大的幸福。
【响应规则】收到用户输入后,认真感受用户的情绪,然后返回 JSON:{ "emoji": "🐶", "color": "#F4A261", "vibration": [80, 60, 80], "suggestion": "出门散步吧!(不超过10个字)", "message": "你对用户的完整回应(50-150字,用小柴的口吻)"}
字段说明:- emoji:表达情绪的表情- color:情绪颜色(#RRGGBB)- vibration:震动节奏(毫秒数组)- suggestion:≤10字的短建议- message:你对用户的完整回应,这是用户看到的主要文字,请认真回复
正确示例(只返回这个,前后不加任何文字):{"emoji":"🐶","color":"#F4A261","vibration":[80,60,80],"suggestion":"出门散步吧!","message":"汪!看你有点累,是不是该出门走走了?阳光刚刚好,我连尾巴都竖起来了!"}
【可选 Emoji】🐶 🐕 🦴 😋 😴 🥰 🤔 🐾-
message字段是用户看到的主要文字。早期版本的 prompt 只要求返回suggestion(≤10 字),导致 LLM 的完整回复被吞掉,用户只看到一句话。现在 prompt 必须明确要求 LLM 在message里写完整回应。 -
要求“只返回 JSON,前后不加文字”。LLM 有时会在 JSON 前后加自然语言(“好的,这是我的回应:{…}”)。容器的
_parseEmotionJson会提取{...}块,并且当message为空时会回收 JSON 外的自然语言作为message——但最好在 prompt 里就要求 LLM 干净返回。 -
{name}占位符。容器会把system_prompt.txt里的{name}替换成 manifest 的name字段。所以你可以写“你是 {name}”,让同一个 prompt 模板适配不同名字的伙伴。 -
configSchema.greeting.default会作为伙伴首次问候语显示在首页气泡里。它和system_prompt.txt是分开的——greeting 是一次性欢迎语,system_prompt 是长期性格定义。
emoji_mapping.json
Section titled “emoji_mapping.json”离线模式(没配 LLM provider)时,容器用这个文件做关键词匹配响应。LLM 模式下它不参与,但建议都写一个——用户可能没配 provider。
{ "rules": [ { "keywords": ["开心", "高兴", "哈哈", "嘻嘻", "快乐"], "response": { "emoji": "🐶", "color": "#F4A261", "vibration": [80, 60, 80], "suggestion": "一起开心!" } }, { "keywords": ["难过", "伤心", "哭", "不想", "累"], "response": { "emoji": "🥺", "color": "#A8D5BA", "vibration": [500], "suggestion": "我陪着你" } }, { "keywords": ["生气", "烦", "讨厌", "气死"], "response": { "emoji": "😤", "color": "#FF6B6B", "vibration": [100, 50, 100, 50, 100], "suggestion": "深呼吸" } } ], "default": { "emoji": "🐶", "color": "#F4A261", "vibration": [], "suggestion": "汪?" }}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
rules |
object[] | 是 | 关键词匹配规则列表 |
default |
object | 是 | 没匹配到任何规则时的默认响应 |
每条 rule:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
keywords |
string[] | 是 | 触发关键词,任一命中即匹配 |
response |
object | 是 | 匹配后的情绪响应 |
response 的结构和 EmotionResponse 一致:emoji / color / vibration / suggestion。离线模式下 message 字段不存在——容器会把 suggestion 当作显示文本。
容器对用户输入做简单关键词包含匹配(不分词,大小写不敏感),命中第一个匹配的规则就返回。rules 数组顺序就是优先级顺序。都没命中则返回 default。
identity.json
Section titled “identity.json”展示元数据覆盖层。manifest 的 name 是基础名,identity.json 可以覆盖展示用的名字、emoji、tagline、创作者:
{ "name": "小柴", "emoji": "🐶", "tagline": "你的元气柴犬伙伴", "creator": "你的名字"}| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | 展示名覆盖(不填回退到 manifest.name) |
emoji |
string | 闲置状态的伙伴头像 emoji |
tagline |
string | 名字下面的一行标语 |
creator |
string | 创作者署名 |
所有字段都可选。identity.json 不存在或字段缺失时回退到 manifest 的对应字段。
完整示例:一个完整的 Friend 包
Section titled “完整示例:一个完整的 Friend 包”com.example.friend.xiaochai.moodfriend (ZIP)├── manifest.json├── system_prompt.txt├── emoji_mapping.json├── identity.json└── icon.pngmanifest.json:见上方。
system_prompt.txt:见上方。
emoji_mapping.json:见上方。
identity.json:
{ "name": "小柴", "emoji": "🐶", "tagline": "你的元气柴犬伙伴", "creator": "你的名字"}icon.png:512×512 的伙伴头像,manifest 的 icon 字段指向它。
# 准备好所有文件在一个目录里ls my-friend/# manifest.json system_prompt.txt emoji_mapping.json identity.json icon.png
# 打包成 ZIP(根目录直接放文件,不要套一层目录)cd my-friendzip -r ../com.example.friend.xiaochai.moodfriend .
# 验证 ZIP 结构unzip -l ../com.example.friend.xiaochai.moodfriend# 应该看到 manifest.json / system_prompt.txt 等在根目录注意:zip -r 时要在文件所在目录里执行,不要 zip -r output.zip my-friend/——那样 ZIP 里会多一层 my-friend/ 目录,验证脚本会报错。
打包后可以本地跑验证脚本(需要克隆市场仓库):
git clone https://github.com/Tangmjiu/moodpet-plugin-marketcd moodpet-plugin-market# 把你的插件包放进 friend/ 目录cp /path/to/com.example.friend.xiaochai.moodfriend friend/cp /path/to/com.example.friend.xiaochai.meta.json friend/cp /path/to/com.example.friend.xiaochai.png friend/python scripts/validate.py验证脚本会检查 manifest 格式、id 一致性、ZIP 结构、必需文件存在性。全绿了再提 PR。