This repository has been archived on 2026-08-12. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Cyrene/docs/api/plugin-development.md
T

181 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 插件开发指南
> 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) — 完整调用链路说明