开发 Skill 与 Control Plane Plugin
Skill 和 Control Plane Plugin 都能扩展 Ankole,但它们解决的问题不同。先选对扩展点,再开始写代码。
| 需要增加什么 | 选择 |
|---|---|
| 教 Agent 怎样完成某类工作 | Skill |
| 给 Agent 提供 MCP 工具及其使用方法 | Skill |
| 增加身份源、聊天适配器或 Provider 类型 | Control Plane Plugin |
| 增加控制面配置项或受监督后台进程 | Control Plane Plugin |
Skill 是 Agent 读取的文件,不需要重新编译控制面。Control Plane Plugin 是编译进控制面的第一方 Elixir 模块,需要注册,并在控制面下次启动时激活。
编写 Skill
一个 Skill 是包含 SKILL.md 的目录,也可以带参考资料、模板和 openai.yaml:
my-skill/
├── SKILL.md
├── openai.yaml
├── reference.md
└── templates/
目录名使用小写字母、数字、连字符或下划线。内置 Skill 放在 app/library/skills/,安装到某个 Agent 的 Skill 则保存在该 Agent 的文件空间。
写 frontmatter
SKILL.md 顶部的 YAML 用于发现和启用:
---
name: my-skill
description: "当 Agent 需要核对供应商合同时使用。"
default_enabled: true
category: productivity
tags: [Contracts]
ankole-runtime: background_job
platforms: [linux]
---
description 要说明具体触发条件,因为 Agent 会根据它决定是否读取 Skill。需要后台任务隔离时设置 ankole-runtime: background_job;只有依赖 Linux 工具时才设置 platforms: [linux]。
写正文
正文要让一个有能力但不了解项目约定的 Agent 完成任务。至少写清:
- 什么时候使用。
- 要读取哪些输入。
- 按什么顺序工作。
- 结果必须包含什么。
- 哪些动作禁止或需要确认。
参考资料和模板应从 SKILL.md 中按名称链接。Agent 只会按需读取这些文件,所以不能假设它会自动发现未被引用的资料。
声明 MCP 依赖
需要 MCP 工具时,在 openai.yaml 中声明:
dependencies:
tools:
- type: mcp
value: my-mcp-server
transport: streamable_http
url: https://mcp.example.com/mcp
bearer_token_env_var: MY_MCP_TOKEN
Agent 只有在启用这个 Skill 时才会看到相应工具。完整字段见 MCP 参考。
验证 Skill
在测试 Agent 上启用 Skill,给出一个真实任务,并检查 Agent 是否正确选中 Skill、读取所需资料并遵守完成标准。若 Agent 从未选中它,先改 description;若执行步骤不稳定,改正文中的顺序和约束。
开发 Control Plane Plugin
Control Plane Plugin 适合扩展控制面拥有的能力。模块实现 Ankole.Plugins.Plugin,最小实现只有一个稳定的 Plugin ID:
defmodule Ankole.Plugins.MyPlugin do
@behaviour Ankole.Plugins.Plugin
@impl true
def plugin_id, do: "my-plugin"
end
Plugin ID 使用小写 slug。其他回调按需要实现:
| 回调 | 用途 |
|---|---|
display_name/0、description/0 |
Console 中显示的名称与说明 |
adapter_declarations/0 |
声明身份源、聊天渠道或其他适配器 |
app_config_definitions/0 |
声明固定的 AppConfigure 配置项 |
app_config_patterns/0 |
声明带动态 ID 的配置项 |
children/0 |
启动长连接、Registry 或定期调和进程 |
注册 Plugin
把模块加入 config/config.exs:
config :ankole, :control_plane_plugin_modules, [
Ankole.Plugins.MyPlugin
]
注册后,Plugin 会出现在 Console 的目录中。管理员启用它后,控制面会在下一次启动时注册配置项、适配器和受监督进程。Plugin 不支持热加载。
声明适配器
adapter_declarations/0 返回适配器声明。contract_id 决定由哪个子系统读取:
@impl true
def adapter_declarations do
[
%{
contract_id: "signals_gateway.adapter",
id: "my-adapter",
plugin_id: plugin_id()
}
]
end
适配器的专属字段由对应子系统定义。聊天适配器应遵循 SignalsGateway 的契约;身份源和模型 Provider 也应使用各自现有的注册表,不要在 Plugin 内另建平行配置。
声明配置与后台进程
运维人员需要在运行期管理的设置应通过 app_config_definitions/0 或 app_config_patterns/0 声明。只有数据库可用前必须存在的启动参数才使用环境变量。
children/0 返回标准 OTP child spec。长连接和调和进程必须进入 Plugin 的监督树,随 Plugin 激活而启动,并在停用后的下次控制面启动时停止。
验证 Plugin
先运行控制面测试和静态检查,再从 Console 启用 Plugin 并重启控制面。确认它显示为已激活,配置项可见,声明的适配器能完成一次真实连接。若它包含外部协议,还要运行对应的集成测试。
继续阅读
- Skill 的启用、继承和安装方式见 Agent 能力库。
- Plugin 的发现与激活边界见 Control Plane Plugins。
- 新增 LLM Provider 见添加 Provider。