随着 Multica 平台(智能体任务平台)落地到我们的 Odoo 系统,"插件"和"插件包"这两个词开始出现在菜单里。这篇文档把它们讲清楚:是什么、怎么运转、能用来做什么。
一句话概念
插件(Plugin)是 Multica 平台的可安装扩展单元:作者把"一个外部服务 + 一份声明清单(manifest)"打成 zip 包发布上来;管理员审查它申请的权限后安装进工作区,宿主就能在合适的时机调用它,它也能在授权范围内回调宿主、读写数据。
插件包(Plugin Package)是插件的"发布身份":同一个插件标识(plugin_key)在一个工作区内只有一份插件包,每次发布都会产生一个不可变的新版本。
打个比方:插件包像应用商店里某个 App 的"商品页 + 历史版本列表",插件(安装,Installation)像你手机上实际装着的那份 App。
插件长什么样:一个 zip + 一份 manifest
插件以 bundle(zip 压缩包)形式发布,里面必须有一个 multica.plugin.json 清单文件,加上它引用的资源文件(比如技能文档)。manifest 声明三件事:
- 我是谁:
key(全局标识,如com.example.v2demo)、name、version、author; - 我要什么权限:
scopes(如issues:read、comments:write、net:api.example.com); - 我贡献什么:
contributes—— hooks(可被调用的能力端点)、resources(静态资源,目前支持 skill 技能文档);以及config(需要管理员安装时填写/选择的配置项,宿主负责渲染表单,插件不自带界面)。
一个精简的示例(三种 hook + 一个 skill 资源):
{
"manifest_version": 1,
"key": "com.example.v2demo",
"name": "V2 Demo",
"description": "示例插件",
"version": "1.0.0",
"author": {"name": "someone"},
"scopes": ["issues:read", "comments:read", "net:hooks.example.com"],
"config": {
"api_key": {"type": "secret", "label": "API 密钥", "required": true}
},
"contributes": {
"hooks": [
{
"key": "lookup",
"name": "Lookup",
"description": "帮智能体查询外部资料",
"input_schema": {"type": "object", "properties": {"q": {"type": "string"}}},
"triggers": ["agent"],
"transport": {"type": "http", "url": "https://hooks.example.com/lookup"}
},
{
"key": "tick",
"triggers": ["schedule"],
"schedule": {"cron": "*/5 * * * *", "timezone": "Asia/Shanghai"},
"transport": {"type": "http", "url": "https://hooks.example.com/tick"}
},
{
"key": "on_issue",
"triggers": ["event"], "events": ["issue.created"],
"transport": {"type": "http", "url": "https://hooks.example.com/on_issue"}
}
],
"resources": [
{"type": "skill", "key": "v2demo", "entry": "skills/v2demo/SKILL.md"}
]
}
}
注意钩子的 triggers 字段——它声明"谁可以调这个钩子",与能力本身正交。宿主只会按声明的触发器去调用。
生命周期:发布 → 预览 → 安装 → 升级 / 启停 / 卸载
- 发布(publish):作者把 zip 上传(REST 接口),宿主全量校验后把它落成一个不可变版本:manifest 规范化快照、内容摘要(digest)、bundle 文件一并入库。同一版本号重复发布会被拒绝(409),改了代码就发新版本。
- 预览(preview):安装分两步。第一步只读展示这个版本申请了哪些权限、要填哪些配置,不写任何东西——让同意页面"有东西可看"。
- 安装(install):管理员确认授权。授权必须是精确匹配:既不允许只授予 manifest 申请的一部分(插件会静默残废),也不允许多授(那是管理员没见过理由的访问)。安装时对 manifest 做字节级快照落地——批准的代码就是运行的代码,之后作者发新版不影响已装的这份。
- 升级:指向另一个版本号的第二次授权;配置按新 schema 剪裁。
- 启停(enable/disable):停用立即隐藏全部贡献(工具、调度、技能),但保留配置、密钥和存储——重新启用不是重装。
- 卸载:安装记录、调度、存储、密钥、执行记录、贡献的技能一并删除。
插件与宿主的三个接触面
Hook —— 宿主调用插件。 宿主按 manifest 声明,对插件的 HTTPS 端点发起签名 HTTP 调用(HMAC-SHA256,作者可用安装时发放的 whsec_ 签名密钥验证请求确实来自宿主)。触发器有五种:
| 触发器 | 含义 |
|---|---|
ui / manual |
用户在界面上点按钮、手动执行 |
agent |
智能体在任务中作为工具调用 |
event |
订阅的产品事件发生时异步投递 |
schedule |
按 cron 表达式定时执行 |
Action —— 插件回调宿主。 每次宿主调用插件时都随请求携带一个 5 分钟有效的一次性回调令牌(mpc_),插件用它调用宿主的 Public API v1:读取/更新 issue、读取/发表评论、读写自己的 KV 存储。通过插件写入的评论会以插件身份署名,和真人、智能体的发言区分开。
Resource —— 静态贡献。 目前支持 skill:安装时把 bundle 里的 SKILL.md 落进工作区技能库,供所有智能体加载使用,卸载时随之删除。
可以做些什么功能
把三个接触面组合起来,典型场景有:
- 给智能体加工具:声明
agent触发器的钩子,会在任务下发时作为工具出现在智能体的工具列表里(daemon 侧通过本地multica-pluginsMCP 服务器代理调用)。比如"查 ERP 库存""查物流轨迹""内部知识库检索"——把业务系统的查询能力直接交到智能体手上,而且权限、审计都在平台内闭环。 - 定时巡检:
schedule触发器 + cron 表达式 + 时区,最短 5 分钟一次;失败自动重试(最多 3 次),长时间停机后只补跑最近一次,不积压历史。比如每小时扫描异常订单、每天生成日报摘要。 - 事件联动:订阅
issue.created、issue.status_changed、comment.created、task.completed等七种事件,事件发生时异步投递到插件端点(绝不阻塞宿主请求)。比如新任务创建后推送到企业 IM、任务完成时同步外部系统。 - 分发技能:把领域知识、操作规范写成 SKILL.md 随插件分发,安装即对所有智能体生效。
- 回写系统:插件处理完后,可在授权范围内更新 issue、以插件身份发评论、用自己的存储记录状态(用户级/工作区级两个作用域)。
一个组合的例子——"订单守卫"插件:schedule 钩子每小时扫描待发货订单 → 发现异常时通过 Action API 回写 issue 并发一条署名评论 → 同时提供 agent 钩子,让智能体在任务里能查"这单为什么被拦下"。
授权与安全模型
这套体系的安全设计值得单独一提,因为它决定了"敢不敢装第三方插件":
- 权限是封闭集合:
issues:read/write、comments:read/write、tasks:read/write、agents:read、members:read、storage:user、storage:workspace、net:<域名>。manifest 申请未知权限直接拒绝。 - 外呼白名单:宿主只会调用
net:授权域名清单内的端点(精确主机匹配,不做后缀匹配),强制 HTTPS,且解析到私网/环回地址即拒绝(SSRF 防护);开发期本地调试可由运维显式放行 origin。 - 限速与熔断:每个钩子 120 次/分钟;后台投递(事件/调度)连续失败 5 次(5 分钟窗口)自动熔断暂停,恢复后继续。
- 密钥加密:
secret类型的配置用 Fernet 加密落库,任何读取端点都不回明文;唯一解密时机是发往插件自己服务器的调用。 - 令牌族:安装令牌
mpi_(可轮换,只存哈希)、回调令牌mpc_(5 分钟 TTL、调用结束即撤销)、daemon 令牌mdt_(24 小时)各司其职。 - 执行记录:每次调用留遥测(状态、耗时、错误),保留 7 天,回答"这个端点现在为什么失败"。
在本系统(Odoo)里怎么用
- 菜单入口:项目 → 智能体 → 插件包 / 插件(需要 Multica 管理员组)。插件包页查看已发布的包与不可变的版本历史;插件页查看各工作区(公司)的安装情况、启停,也可以手动补录安装——选好插件包和版本后,插件标识、版本号、授权快照会自动带出。
- 常规发布/安装入口是 REST API(对齐上游 multica 的 workspace 插件路由):
POST .../plugins/packages上传 zip 发布,POST .../plugins/preview+POST .../plugins两步安装,另有配置、令牌轮换、启停、卸载等接口。写操作仅限人类管理员,智能体不可改动插件面。
限制速查
| 项 | 限制 |
|---|---|
| 上传 zip | ≤ 2 MiB |
| 解压后总量 / 文件数 / 单文件 | ≤ 4 MiB / ≤ 512 个 / ≤ 1 MiB |
| manifest / 单个 skill 文件 | ≤ 1 MiB / ≤ 256 KiB |
| 钩子超时 / 响应体 | 默认 10 秒 / ≤ 1 MiB |
| 调度最短间隔 | 5 分钟 |
| 插件存储 | 每作用域 1000 个键、共 5 MiB |
小结
插件体系给 Multica 平台补上了"安全的第三方扩展"这块拼图:作者侧一个 zip + 一份 manifest 就能发布;管理员侧看得见权限、管得住外呼、审计得到调用;智能体侧获得新工具和新技能;业务侧获得定时、事件两类自动化触发。对内部而言,它也是把 Odoo 业务能力暴露给智能体的一条规范通道——写一个插件,比给每个智能体单独配 MCP 服务 + 凭证 + 文档要可控得多。