# 插件开发指南 > **Plugin Development Guide** — 天工智能体平台插件系统 本文档面向希望为天工智能体平台开发自定义节点的开发者。 --- ## 一、插件系统概览 插件系统允许开发者扩展工作流中的节点类型,自定义处理逻辑。插件注册后可在工作流编辑器中像内置节点一样使用。 ### 插件模型 ``` NodePlugin ├── id: UUID ├── name: 插件名称 ├── description: 描述 ├── plugin_type: code | http | transform | trigger | output ├── category: 分类 ├── config_schema: 配置项 JSON Schema ├── code: 插件代码(code 类型) ├── endpoint: HTTP 端点(http 类型) ├── inputs: 输入定义 [{name, type, required, default}] ├── outputs: 输出定义 [{name, type, description}] ├── is_public: 是否公开 ├── version: 版本号 ├── workspace_id: 所属工作区 └── user_id: 创建者 ``` ### API 端点 | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/v1/plugins` | 插件列表 | | POST | `/api/v1/plugins` | 创建插件 | | GET | `/api/v1/plugins/{id}` | 插件详情 | | PUT | `/api/v1/plugins/{id}` | 更新插件 | | DELETE | `/api/v1/plugins/{id}` | 删除插件 | | POST | `/api/v1/plugins/{id}/test` | 测试插件 | | POST | `/api/v1/plugins/{id}/publish` | 发布到市场 | | POST | `/api/v1/plugins/market/install` | 从市场安装 | | POST | `/api/v1/plugins/{id}/toggle` | 启用/禁用 | --- ## 二、Code 类型插件 Code 插件是最灵活的插件类型,直接编写 Python 代码实现自定义逻辑。 ### 代码模板 ```python """ 插件入口函数签名: def run(inputs: dict, config: dict, context: dict) -> dict 参数: inputs — 上游节点传递的输入数据 config — 用户在编辑器中配置的参数 context — 运行时上下文 {execution_id, agent_id, user_id, workspace_id, secrets} 返回: dict — 输出数据,传递给下游节点 异常: 抛出 PluginError("message") 会被框架捕获并记录到执行日志 """ import json import re from typing import Any, Dict class PluginError(Exception): """插件自定义异常""" pass def run(inputs: Dict[str, Any], config: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]: """ 示例:文本清洗 + 格式化插件 """ text = inputs.get("text", "") if not text: raise PluginError("输入 text 不能为空") # 读取配置 remove_html = config.get("remove_html", True) remove_extra_spaces = config.get("remove_extra_spaces", True) max_length = config.get("max_length", 0) result = text if remove_html: result = re.sub(r"<[^>]+>", "", result) if remove_extra_spaces: result = re.sub(r"\s+", " ", result).strip() if max_length > 0 and len(result) > max_length: result = result[:max_length] + "..." # 统计信息 original_length = len(text) cleaned_length = len(result) return { "text": result, "stats": { "original_length": original_length, "cleaned_length": cleaned_length, "reduction_pct": round((1 - cleaned_length / max(original_length, 1)) * 100, 1), }, } ``` ### 配置 Schema ```json { "type": "object", "properties": { "remove_html": { "type": "boolean", "title": "移除 HTML 标签", "default": true }, "remove_extra_spaces": { "type": "boolean", "title": "合并多余空白", "default": true }, "max_length": { "type": "integer", "title": "最大长度(0=不限制)", "default": 0, "minimum": 0 } } } ``` ### 创建 Code 插件 ```http POST /api/v1/plugins Authorization: Bearer Content-Type: application/json { "name": "文本清洗器", "description": "去除 HTML 标签、合并空白、截断过长文本", "plugin_type": "code", "category": "transform", "config_schema": { ... }, "code": "def run(inputs, config, context): ...", "inputs": [ {"name": "text", "type": "string", "required": true, "description": "待清洗的原始文本"} ], "outputs": [ {"name": "text", "type": "string", "description": "清洗后的文本"}, {"name": "stats", "type": "object", "description": "清洗统计信息"} ] } ``` --- ## 三、HTTP 类型插件 HTTP 插件封装外部 API 调用,可在工作流中直接使用。 ### 配置 Schema ```json { "type": "object", "properties": { "method": { "type": "string", "enum": ["GET", "POST", "PUT", "DELETE"], "title": "请求方法", "default": "POST" }, "url": { "type": "string", "title": "请求 URL", "description": "支持变量 {{变量名}}" }, "headers": { "type": "object", "title": "自定义请求头" }, "timeout": { "type": "integer", "title": "超时(秒)", "default": 30 } }, "required": ["url"] } ``` ### 创建 HTTP 插件示例 ```http POST /api/v1/plugins Authorization: Bearer Content-Type: application/json { "name": "天气查询", "description": "通过 OpenWeather API 查询城市天气", "plugin_type": "http", "category": "integration", "endpoint": "https://api.openweathermap.org/data/2.5/weather", "config_schema": { "type": "object", "properties": { "method": {"type": "string", "default": "GET"}, "url": {"type": "string", "default": "https://api.openweathermap.org/data/2.5/weather"}, "headers": {"type": "object", "default": {}}, "timeout": {"type": "integer", "default": 15} } }, "inputs": [ {"name": "city", "type": "string", "required": true, "description": "城市名称"}, {"name": "units", "type": "string", "required": false, "default": "metric", "description": "单位制"} ], "outputs": [ {"name": "temperature", "type": "number", "description": "温度"}, {"name": "humidity", "type": "number", "description": "湿度"}, {"name": "description", "type": "string", "description": "天气描述"} ] } ``` --- ## 四、插件沙箱安全 ### Code 插件执行环境 - 运行在受限的 Python 沙箱中 - 禁用模块:`os.system`, `subprocess`, `shutil`, `importlib` - 允许模块:`json`, `re`, `math`, `datetime`, `hashlib`, `base64`, `collections`, `itertools`, `typing` - 执行超时:默认 30 秒 - 内存限制:64MB ### 安全最佳实践 1. **不要硬编码密钥** — 通过 `context.secrets` 获取 2. **验证所有输入** — 不信任上游数据 3. **异常处理** — 抛 `PluginError` 而非裸 `Exception` 4. **避免无限循环** — 注意循环条件,配合超时 5. **不访问文件系统** — 沙箱已禁用 --- ## 五、插件测试 ### 在线测试 ```http POST /api/v1/plugins/{plugin_id}/test Content-Type: application/json { "inputs": { "text": "

Hello World

" }, "config": { "remove_html": true, "remove_extra_spaces": true } } ``` 响应: ```json { "success": true, "outputs": { "text": "Hello World", "stats": { "original_length": 27, "cleaned_length": 11, "reduction_pct": 59.3 } }, "execution_time_ms": 12, "logs": [] } ``` ### 本地测试脚本 ```python # test_plugin.py from app.models.plugin import NodePlugin from app.services.plugin_service import execute_code_plugin def test_my_plugin(): plugin = NodePlugin( name="测试插件", plugin_type="code", code=""" def run(inputs, config, context): text = inputs.get("text", "") return {"result": text.upper()} """ ) result = execute_code_plugin( plugin, inputs={"text": "hello world"}, config={}, context={"execution_id": "test-123"}, ) assert result["result"] == "HELLO WORLD" print("测试通过") if __name__ == "__main__": test_my_plugin() ``` --- ## 六、发布到插件市场 ### 发布流程 1. 创建并测试插件 2. 设置为公开:`is_public = true` 3. 添加标签和分类 4. 编写清晰的描述和文档 5. 发布: ```http POST /api/v1/plugins/{plugin_id}/publish Authorization: Bearer ``` ### 市场安装 其他用户可以通过插件市场安装你的插件: ```http POST /api/v1/plugins/market/install Authorization: Bearer Content-Type: application/json { "plugin_id": "source-plugin-uuid", "workspace_id": "target-workspace-uuid" } ``` --- ## 七、最佳实践 ### 命名规范 - **插件名称**:简洁描述功能,如"文本清洗器"/"天气查询" - **输入输出**:使用语义化的字段名,如 `text`/`result` 而非 `data`/`out` - **分类**:选择最匹配的类型(code/http/transform/trigger/output) ### 错误处理 ```python def run(inputs, config, context): # 1. 必填输入检查 if not inputs.get("required_field"): raise PluginError("缺少必填输入: required_field") # 2. 类型验证 value = inputs.get("number_field") if not isinstance(value, (int, float)): raise PluginError("number_field 必须是数字") # 3. 业务逻辑... try: result = do_work(value, config) except Exception as e: raise PluginError(f"处理失败: {str(e)}") # 4. 返回结构化输出 return {"result": result} ``` ### 性能优化 - 避免在输入循环中使用正则(预编译 `re.compile`) - HTTP 插件设置合理的超时时间 - 大量数据处理使用生成器而非列表 - 缓存重复计算的结果 --- > 相关文档:[开发指南](./development-guide.md) | [API 参考](./api-reference.md) | [架构设计](./architecture.md)