diff --git a/README.md b/README.md index 291f99f..fd6275f 100644 --- a/README.md +++ b/README.md @@ -207,8 +207,8 @@ Cyrene/ | [docs/api/gateway-api.md](docs/api/gateway-api.md) | 客户端 API 文档 | | [docs/api/ethend.md](docs/api/ethend.md) | ethend CLI + Web 控制台文档 | | [docs/api/backend-services/](docs/api/backend-services/) | 后端服务 API 文档 | -| [docs/dev_must_read.md](docs/dev_must_read.md) | 开发者必读 | -| [docs/pg-backup-migration.md](docs/pg-backup-migration.md) | PG 备份与迁移指南 | +| [docs/api/backend-services/tool-system.md](docs/api/backend-services/tool-system.md) | 工具调用系统 | +| [docs/api/plugin-development.md](docs/api/plugin-development.md) | 插件开发指南 | --- diff --git a/docs/api/plugin-development.md b/docs/api/plugin-development.md new file mode 100644 index 0000000..e5f070f --- /dev/null +++ b/docs/api/plugin-development.md @@ -0,0 +1,141 @@ +# 插件开发指南 + +> 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 + +在 `ai-core/cmd/main.go` 的工具注册区添加一行: + +```go +registerPluginTools(toolRegistry, &myplugin.HelloPlugin{}) +``` + +重启 ai-core,LLM 即可在对话中自动调用 `hello` 工具。 + +--- + +## 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) — 完整调用链路说明