# 插件开发指南 > Cyrene 插件系统允许第三方开发者为昔涟扩展新工具。插件用 Go 编写,只需实现 `Plugin` 和 `Tool` 接口即可被自动发现和调用。 --- ## 核心接口 ### Plugin(插件入口) ```go type Plugin interface { Metadata() PluginMetadata // 插件元信息 Init(ctx context.Context, config PluginConfig) error Start(ctx context.Context, host HostAPI) error Tools() []Tool // 返回插件提供的工具列表 } ``` ### Tool(工具定义) ```go type Tool interface { Definition() ToolDefinition // 工具的 name/description/parameters Execute(ctx context.Context, args map[string]interface{}) (*ToolResult, error) Validate(args map[string]interface{}) error } ``` **LLM 通过 `Definition()` 返回的 `description` 判断何时调用此工具**——所以描述要写得清晰准确。 ### ToolDefinition ```go type ToolDefinition struct { Name string // 工具名(LLM 用 function_call name 匹配) Description string // 描述——LLM 据此判断要不要调用 Parameters map[string]interface{} // JSON Schema 参数定义 } ``` --- ## 最小示例 ```go package myplugin import "git.yeij.top/AskaEth/Cyrene-Plugins/sdk" type HelloPlugin struct{} func (p *HelloPlugin) Metadata() sdk.PluginMetadata { return sdk.PluginMetadata{ Name: "hello", Version: "1.0.0", Author: "your-name", Description: "示例插件:向用户问好", } } func (p *HelloPlugin) Init(ctx context.Context, cfg sdk.PluginConfig) error { return nil } func (p *HelloPlugin) Start(ctx context.Context, host sdk.HostAPI) error { return nil } func (p *HelloPlugin) Stop(ctx context.Context) error { return nil } func (p *HelloPlugin) Tools() []sdk.Tool { return []sdk.Tool{&HelloTool{}} } // --- Tool --- type HelloTool struct{} func (t *HelloTool) Definition() sdk.ToolDefinition { return sdk.ToolDefinition{ Name: "hello", Description: "向用户打招呼。当用户说你好/嗨/哈喽时调用。", Parameters: map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "name": map[string]string{"type": "string", "description": "用户名字(可选)"}, }, }, } } func (t *HelloTool) Execute(ctx context.Context, args map[string]interface{}) (*sdk.ToolResult, error) { name, _ := args["name"].(string) if name == "" { name = "开拓者" } return &sdk.ToolResult{Success: true, Output: name + ",昔涟向你问好♪"}, nil } func (t *HelloTool) Validate(args map[string]interface{}) error { return nil } ``` --- ## 注册到 Cyrene ### 方式一:plugins.json(推荐) 1. 将插件代码放到 `backend/plugins/<插件名>/` 2. 在 `backend/ai-core/plugins.json` 中添加条目: ```json { "name": "my-hello", "import": "git.yeij.top/AskaEth/Cyrene-Plugins/my-hello", "struct": "HelloPlugin" } ``` 3. 运行代码生成器: ```bash cd backend/ai-core/cmd && go run gen_plugins.go ``` 4. 重新编译 ai-core ### 方式二:直接注册(需要构造参数的插件) 在 `ai-core/cmd/main.go` 中添加: ```go for _, t := range (&myplugin.HelloPlugin{}).Tools() { toolRegistry.Register(t) } ``` ### 插件目录结构 ``` backend/plugins/ ← 第三方插件目录 my-hello/ plugin.json ← 插件声明(name, version, struct) main.go ← 插件入口 ``` `plugin.json` 格式: ```json { "name": "my-hello", "version": "1.0.0", "author": "your-name", "description": "我的第一个插件" } ``` --- ## ToolResult 格式 ```go type ToolResult struct { ToolName string `json:"tool_name"` Success bool `json:"success"` Output string `json:"output,omitempty"` // 成功时的结果文本 Error string `json:"error,omitempty"` // 失败时的错误信息 } ``` `Output` 会直接注入 LLM 对话,所以要写成自然语言格式。 --- ## 调用机制 ``` 用户: "帮我打个招呼" → LLM 看到所有工具的 Definition() → 判断需要调用 hello 工具 → function_call: {name: "hello", arguments: {name: "开拓者"}} → ToolRegistry.Execute("hello", {name: "开拓者"}) → HelloTool.Execute() → "开拓者,昔涟向你问好♪" → LLM 将结果融入回复 ``` 17 个内置工具也是同样的机制,插件和内置工具对 LLM 来说无区别。 --- ## 相关仓库 - [cyrene-plugins](https://git.yeij.top/AskaEth/Cyrene-Plugins) — 插件 SDK + 内置插件源码 - [工具调用系统介绍](tool-system.md) — 完整调用链路说明