Skip to content

Broker 开发教程

Broker = 可分享的应用包(manifest + UI + 插件),可在市场安装、跨用户复用。本文覆盖完整开发流程、签名机制、从简单到复杂的实例。


Broker 长什么样

📦 Broker 包结构 · 创意工坊
my_broker/
├── manifest.json        # 核心配置(id/name/version/author_pubkey)
├── ui/                  # 前端 iframe 资源
│   ├── index.html       # 入口
│   ├── app.js           # 前端逻辑
│   └── style.css
├── plugins/             # Python 插件(可选)
│   └── my_plugin.py
├── recipes/             # 可选自带 recipes
│   └── my_recipe.json
├── triggers.json        # 触发声明(定时/信号)
└── cover.png            # 市场封面

📄 src/broker/workshop/__init__.py — Broker 加载器 📄 src/broker/hub.py — BrokerHub 核心 📄 src/bridge/routes/broker_workshop.py — REST API


manifest.json 结构

json
{
  "id": "my_awesome_broker",
  "name": "我的应用",
  "version": "1.0.0",
  "description": "一句话描述",
  "author_name": "Your Name",
  "author_pubkey": "base64-encoded-public-key",
  
  "ui": {
    "entry": "ui/index.html",
    "width": 800,
    "height": 600
  },
  
  "capabilities_required": [
    "network.http",
    "storage.kv"
  ],
  
  "role_defs": {
    "assistant": {
      "description": "提供 XXX 能力",
      "tools": ["my_tool"]
    }
  },
  
  "triggers": [
    {"type": "schedule", "cron": "0 9 * * *", "action": "morning_greeting"},
    {"type": "event", "event": "user.login", "action": "welcome"}
  ],
  
  "recipes": ["recipes/my_recipe.json"]
}

字段说明

字段必填说明
idbroker_id,必须唯一,与目录名一致
name显示名
versionsemver 格式
author_pubkey作者公钥(Ed25519)
ui.entryiframe 入口 HTML
capabilities_required需要的能力(网络/存储等)
role_defs定义 agent 角色
triggers触发条件(定时/事件)

开发流程

1. 从模板起步

bash
# 拷贝 starter 模板
cp -r workspace/manager/brokers/starter_broker/ workspace/manager/brokers/my_broker/

# 或直接从仓库
git clone <repo> && cd familiars/workspace/manager/brokers/starter_broker/

2. 本地开发

bash
# 安装到本地
python main.py broker install workspace/manager/brokers/my_broker/

# 在交换所工坊中查看
# Desktop → 应用 → 交换所工坊 → 已安装

3. 发布

bash
# 生成作者密钥(首次)
python main.py broker keygen --name "my-name"
# → ~/.familiars/authors/my-name.key

# 打包
python main.py broker pack workspace/manager/brokers/my_broker/
# → my_broker.broker.zip

# 签名
python main.py broker sign my_broker.broker.zip --author my-name
# → 写入 SIGNATURE 文件到 zip 内

# 发布到 relay
python main.py broker publish my_broker.broker.zip
# → 上传到 FAMILIARS_MARKETPLACE_URL

签名与安全

🔐 安装校验链 · 创意工坊
安装时依次校验三条,不过全拒:

┌──────────────────────────────────────────────────────────────────────┐
│  Step 1 · sha256 校验                                                │
│    download_hash == index.sha256                                     │
│    → 防止传输篡改                                                     │
│              │                                                       │
│              ▼                                                       │
│  Step 2 · Ed25519 签名校验                                           │
│    verify(pubkey, sha256(manifest.json), signature)                 │
│    → 防止内容篡改                                                     │
│              │                                                       │
│              ▼                                                       │
│  Step 3 · 作者身份校验                                                │
│    signature_pubkey == index.author_pubkey                           │
│    → 防止冒充                                                        │
└──────────────────────────────────────────────────────────────────────┘

📄 src/broker/workshop/install.py:verify_signature()


实例一:简单 Broker —— 天气助手

目标:每天早上 9 点推送天气预报到聊天。

📦 weather_assistant · 创意工坊
┌──────────────────────────────────────────────────────────────────────┐
│  manifest.json                                                       │
│  id: weather_assistant    capabilities: [network.http]               │
│  triggers: [{type: schedule, cron: "0 9 * * *"}]                    │
└───────────────────────────────┬──────────────────────────────────────┘

          ┌─────────────────────┼─────────────────────┐
          ▼                     ▼                     ▼
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ plugins/weather.py │ │ ui/index.html      │ │ cover.png          │
│                    │ │                    │ │                    │
│ class WeatherPlugin│ │ ☀️ 今日天气:22°C   │ │ 🌤️               │
│ def fetch_and_push │ │ [测试推送]          │ │                    │
│   → httpx.get()    │ │                    │ │                    │
│   → emit_event()   │ │                    │ │                    │
└────────────────────┘ └────────────────────┘ └────────────────────┘

manifest.json

json
{
  "id": "weather_assistant",
  "name": "天气助手",
  "version": "1.0.0",
  "description": "每天早上推送天气预报",
  "author_name": "Demo Author",
  "author_pubkey": "your-base64-pubkey",
  
  "ui": {
    "entry": "ui/index.html",
    "width": 400,
    "height": 300
  },
  
  "capabilities_required": [
    "network.http"
  ],
  
  "triggers": [
    {
      "type": "schedule",
      "cron": "0 9 * * *",
      "action": "push_weather"
    }
  ]
}

plugins/weather.py

python
from src.broker.workshop import BrokerPlugin
import httpx

class WeatherPlugin(BrokerPlugin):
    def on_trigger(self, trigger_name: str):
        if trigger_name == "push_weather":
            self.fetch_and_push()
    
    def fetch_and_push(self):
        # 调用天气 API
        resp = httpx.get("https://api.weather.com/v1/current", params={
            "location": "Beijing",
            "apikey": self.config.get("api_key")
        })
        data = resp.json()
        
        # 推送到聊天
        self.emit_event("chat.message", {
            "text": f"☀️ 今日天气:{data['temp']}°C,{data['condition']}"
        })

ui/index.html

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .weather { text-align: center; }
  </style>
</head>
<body>
  <div class="weather">
    <h2>🌤️ 天气助手</h2>
    <p>每天 9:00 自动推送</p>
    <button onclick="testPush()">测试推送</button>
  </div>
  <script>
    async function testPush() {
      const res = await fetch('/api/broker/weather_assistant/trigger/push_weather', {
        method: 'POST',
        headers: {'X-Broker-Token': window.brokerToken}
      });
      alert(res.ok ? '已推送' : '推送失败');
    }
  </script>
</body>
</html>

实例二:中等 Broker —— 待办同步器

目标:把 Familiars 待办同步到外部服务(Notion/Todoist)。

📦 todo_sync · 创意工坊
┌──────────────────────────────────────────────────────────────────────┐
│  manifest.json                                                       │
│  id: todo_sync                                                       │
│  capabilities: [network.http, storage.kv]                            │
│  role_defs: {sync_agent: {tools: [sync_to_notion, sync_to_todoist]}} │
│  recipes: [recipes/sync_recipe.json]                                 │
└───────────────────────────────┬──────────────────────────────────────┘

          ┌─────────────────────┼─────────────────────┐
          ▼                     ▼                     ▼
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ recipes/           │ │ plugins/sync.py    │ │ ui/index.html      │
│   sync_recipe.json │ │                    │ │                    │
│                    │ │ sync_to_notion()   │ │ 📋 待办同步         │
│ starter            │ │ sync_to_todoist()  │ │ [同步到 Notion]     │
│   ↓                │ │                    │ │ [同步到 Todoist]    │
│ fetch_todos        │ │ → storage.kv 缓存  │ │                    │
│   ↓                │ │ → network.http     │ │                    │
│ sync (sync_agent)  │ │                    │ │                    │
│   ↓                │ │                    │ │                    │
│ summary            │ │                    │ │                    │
└────────────────────┘ └────────────────────┘ └────────────────────┘

manifest.json

json
{
  "id": "todo_sync",
  "name": "待办同步器",
  "version": "1.0.0",
  "description": "同步待办到 Notion/Todoist",
  
  "capabilities_required": [
    "network.http",
    "storage.kv"
  ],
  
  "role_defs": {
    "sync_agent": {
      "description": "执行同步任务",
      "tools": ["sync_to_notion", "sync_to_todoist"]
    }
  },
  
  "recipes": ["recipes/sync_recipe.json"]
}

recipes/sync_recipe.json

json
{
  "id": "sync_todos",
  "name": "待办同步",
  "nodes": [
    {
      "id": "starter",
      "type": "starter",
      "config": {
        "inputs": [
          {"name": "target", "enum": ["notion", "todoist"]},
          {"name": "filter", "string", "default": "all"}
        ]
      }
    },
    {
      "id": "fetch_todos",
      "type": "llm_call",
      "config": {
        "tool_whitelist": ["todo_list"],
        "output_var": "todos"
      }
    },
    {
      "id": "sync",
      "type": "llm_call",
      "role": "sync_agent",
      "config": {
        "tool_whitelist": ["sync_to_notion", "sync_to_todoist"],
        "user_prompt_template": "同步以下待办到 {{target}}:{{todos}}"
      }
    },
    {
      "id": "summary",
      "type": "summary",
      "config": {
        "outputs": [{"name": "synced_count", "from": "sync.count"}]
      }
    }
  ]
}

实例三:复杂 Broker —— Ventaris 公会系统

目标:完整的公会系统(成员/任务/勋章/投票),参考 workspace/manager/brokers/ventaris/。这是目前代码库中最复杂的 Broker —— 4 个 tab 页、5 个插件、2 个 recipe、完整的 VTP 经济系统。

复杂度对比

维度实例二(待办同步)Ventaris 公会
插件数14(guild/tasks/medals/wallet)
recipe 数12(create_task/approve_task)
UI 页面单页4 tab(公会/任务/勋章/我的)
经济系统VTP 钱包 + 打赏 + 任务悬赏
权限模型6 角色 RBAC
📦 ventaris · 创意工坊
┌──────────────────────────────────────────────────────────────────────┐
│  manifest.json                                                       │
│  id: ventaris    version: 1.0.0                                      │
│  capabilities: [network.http, storage.kv]                            │
│  role_defs: {guild_master, task_master, medal_master, wallet_master} │
└───────────────────────────────┬──────────────────────────────────────┘

        ┌───────────────────────┼───────────────────────┐
        ▼                       ▼                       ▼
┌───────────────┐    ┌───────────────────┐    ┌───────────────────┐
│ ui/ (4 tabs)  │    │ plugins/ (4 files)│    │ recipes/ (2 files)│
│               │    │                   │    │                   │
│ ┌───────────┐ │    │ guild.py          │    │ create_task.json  │
│ │ 公会主页  │ │    │  invite/kick/role │    │  规划→执行→校验   │
│ └───────────┘ │    │  vote/proposal    │    └───────────────────┘
│ ┌───────────┐ │    │                   │    ┌───────────────────┐
│ │ 任务看板  │ │    │ tasks.py          │    │ approve_task.json │
│ │  [赏金]   │ │    │  create/approve   │    │  审批→发放奖励    │
│ └───────────┘ │    │  reward           │    └───────────────────┘
│ ┌───────────┐ │    │                   │
│ │ 勋章墙    │ │    │ medals.py         │
│ │  🏅 🏆    │ │    │  earn/display     │
│ └───────────┘ │    │                   │
│ ┌───────────┐ │    │ wallet.py         │
│ │ 我的主页  │ │    │  balance/transfer │
│ │  VTP 钱包 │ │    │  reward           │
│ └───────────┘ │    │                   │
└───────────────┘    └───────────────────┘

目录结构

ventaris/
├── manifest.json
├── ui/
│   ├── index.html
│   ├── tabs/
│   │   ├── guild.html      # 公会主页
│   │   ├── tasks.html      # 任务看板
│   │   ├── medals.html     # 勋章墙
│   │   └── profile.html    # 个人主页
│   └── components/
│       ├── TaskCard.js
│       ├── MedalWall.js
│       └── BountyBoard.js
├── plugins/
│   ├── guild.py            # 公会核心逻辑
│   ├── tasks.py            # 任务系统
│   ├── medals.py           # 勋章系统
│   └── wallet.py           # VTP 钱包
├── recipes/
│   ├── create_task.json
│   └── approve_task.json
└── triggers.json

关键能力

能力实现
成员管理plugins/guild.py: invite/kick/role
任务系统plugins/tasks.py: create/approve/reward
VTP 钱包plugins/wallet.py: balance/transfer/reward
勋章墙plugins/medals.py: earn/display
投票plugins/guild.py: vote/proposal

市场(relay)

客户端市场

bash
# 获取索引
curl https://api.familiars.cn/marketplace/index

# 安装
python main.py broker install-from-url https://api.familiars.cn/marketplace/download/my_broker

生产 relay

bash
# 发布
python main.py broker publish my_broker.broker.zip
# → 进入审核队列

# 查看状态
python main.py broker marketplace-index

# 审核(管理员)
python main.py broker approve <broker_id>

📄 deploy/relay/app/ — relay 服务器部署


常见坑

问题原因解决
安装失败manifest.id 与目录名不一致对齐两者
封面不显示cover.png 未上传到 relay发布时包含 cover
插件不加载未声明 capabilities_requiredmanifest 声明需要
密钥丢失~/.familiars/authors/*.key 被删无法恢复,需新密钥
UI 空白iframe 跨域检查 CORS 配置

调试

bash
# 列出已安装 broker
python main.py broker list

# 查看详情
python main.py broker inspect my_broker

# 查看日志
tail -f workspace/.bridge.log | grep broker

# 验证签名
python main.py broker verify my_broker.broker.zip

更多

  • 完整源码src/broker/
  • starter 模板workspace/manager/brokers/starter_broker/
  • Ventaris 示例workspace/manager/brokers/ventaris/
  • 完整来源BROKER_DEVELOPMENT.md

✨ Familiars · 多 Agent AI 桌面应用 —— 对话树记忆 · 长期记忆 · 工具系统 · 数字人 · Broker 生态