# 自定义节点系统设计说明 ## 🎯 设计目标 为 TraceStudio 提供一个**安全、易用、可扩展**的自定义节点系统,类似 ComfyUI 的插件机制,但增强了安全性和用户体验。 ## 🏗️ 核心架构 ### 1. 三层安全防护 ``` ┌─────────────────────────────────────┐ │ 前端编辑器 (UI层) │ │ - Monaco Editor 语法高亮 │ │ - 实时验证反馈 │ │ - 操作确认对话框 │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ 代码验证器 (node_validator.py) │ │ - AST 语法分析 │ │ - 黑名单检查 (os, eval, subprocess) │ │ - 节点规范验证 (继承、方法) │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ 沙箱执行器 (node_sandbox.py) │ │ - 超时限制 (30s) │ │ - 内存限制 (512MB) │ │ - 异常捕获 │ └─────────────────────────────────────┘ ``` ### 2. 动态加载机制 ```python # 工作流程 1. 用户保存节点文件 (.py) 2. 验证器检查代码安全性 3. 动态导入模块 (importlib) 4. 提取节点类 (继承TraceNode) 5. 注册到节点注册表 6. 立即可用,无需重启服务器 ``` ## 🔒 安全机制详解 ### 危险操作黑名单 | 类别 | 禁止项 | 原因 | |------|--------|------| | **系统操作** | `os`, `subprocess`, `sys` | 防止执行系统命令 | | **动态执行** | `eval`, `exec`, `compile` | 防止代码注入 | | **模块导入** | `__import__`, `importlib` | 防止绕过限制 | | **文件操作** | `open` (警告) | 防止任意文件读写 | ### AST 检查示例 ```python # ❌ 会被拒绝 import os os.system('rm -rf /') eval("malicious_code()") # ✅ 允许 import pandas as pd import numpy as np data = pd.DataFrame(...) result = np.mean(data['column']) ``` ### 执行沙箱 ```python # 超时保护 def execute_with_timeout(node, inputs, timeout=30): thread = Thread(target=node.execute, args=(inputs,)) thread.start() thread.join(timeout) if thread.is_alive(): raise TimeoutError("节点执行超时") ``` ## 📝 节点开发流程 ### Step 1: 创建节点文件 ```python # custom_nodes/my_node.py from app.core.node_base import TraceNode class MyNode(TraceNode): @staticmethod def get_metadata(): return { "display_name": "我的节点", "category": "Custom", "inputs": [...], "outputs": [...], "params": [...] } def execute(self, inputs): # 实现逻辑 return {...} ``` ### Step 2: 前端验证 ```typescript // 点击"验证代码"按钮 const response = await api.validateCustomNode(code) if (response.validation.valid) { // ✅ 通过:显示检测到的节点类 showSuccess(response.validation.node_classes) } else { // ❌ 失败:显示错误信息 showErrors(response.validation.errors) } ``` ### Step 3: 保存并加载 ```typescript // 点击"保存"按钮 const response = await api.saveCustomNode(filename, code) // 自动执行: // 1. 二次确认(如果文件存在) // 2. 备份旧文件 // 3. 保存新文件 // 4. 动态加载节点类 // 5. 注册到系统 ``` ## 🎨 用户界面设计 ### 编辑器布局 ``` ┌────────────────────────────────────────────────┐ │ [新建] [示例] | [验证] [保存] [关闭] | [刷新] │ <- 工具栏 ├──────────────┬─────────────────────────────────┤ │ 节点列表 │ 代码编辑器 │ │ ┌────────┐ │ 1 from app.core.node_base... │ │ │ node.py│ │ 2 class MyNode(TraceNode): │ │ │ ✅ │ │ 3 def execute(self,... │ │ └────────┘ │ 4 return {...} │ │ │ │ │ ├─────────────────────────────────┤ │ │ 验证结果 │ │ │ ✅ 检测到节点: MyNode │ │ │ ⚠️ 建议实现 get_metadata() │ └──────────────┴─────────────────────────────────┘ ``` ### 操作确认对话框 ``` ┌──────────────────────────────────────┐ │ ⚠️ 覆盖确认 │ ├──────────────────────────────────────┤ │ 文件 "my_node.py" 已存在 │ │ │ │ 修改时间: 2026-01-07 14:30:00 │ │ 包含节点: DataFilterNode │ │ │ │ 是否覆盖? │ │ │ │ [取消] [确定覆盖] │ └──────────────────────────────────────┘ ``` ## 🧪 测试用例 ### 1. 安全测试 ```python # test_security.py def test_dangerous_imports(): code = "import os\nos.system('ls')" result = validate_node_code(code) assert not result['valid'] assert '禁止导入危险模块' in result['errors'][0] ``` ### 2. 功能测试 ```python def test_valid_node(): code = """ from app.core.node_base import TraceNode class TestNode(TraceNode): @staticmethod def get_metadata(): return {"display_name": "Test"} def execute(self, inputs): return {"output": inputs['input']} """ result = validate_node_code(code) assert result['valid'] assert 'TestNode' in result['node_classes'] ``` ## 📊 性能优化 ### 缓存机制 ```python class NodeLoader: def __init__(self): self.loaded_nodes = {} # 类缓存 self.node_metadata = {} # 元数据缓存 def get_node_class(self, name): # 直接从缓存返回,无需重新导入 return self.loaded_nodes.get(name) ``` ### 热重载 ```python # 修改节点文件后 loader.load_node('my_node.py', force_reload=True) # 自动执行: # 1. 卸载旧模块 # 2. 重新导入模块 # 3. 更新缓存 # 4. 无需重启服务器 ``` ## 🔄 与文件管理器的区别 | 特性 | custom_nodes | 文件管理器 | |------|-------------|-----------| | **访问权限** | 所有用户共享 | 根目录共享,用户目录隔离 | | **操作限制** | 需验证+确认 | 直接操作 | | **文件类型** | 仅 `.py` | 所有类型 | | **加载机制** | 动态导入 | 静态文件 | | **安全检查** | AST验证 | 路径检查 | ## 🚀 未来扩展 ### 1. 节点市场 ``` - 节点分享平台 - 版本管理 - 依赖声明 - 一键安装 ``` ### 2. 更严格的沙箱 ```python # 使用 RestrictedPython from RestrictedPython import compile_restricted code = compile_restricted(user_code) ``` ### 3. GPU 支持 ```python class GPUNode(TraceNode): @property def requires_gpu(self): return True def execute(self, inputs): # CUDA 加速 import torch ... ``` ## 📖 API 端点总结 ``` GET /api/custom-nodes/list # 列出所有节点 POST /api/custom-nodes/validate # 验证代码 GET /api/custom-nodes/read/{file} # 读取代码 POST /api/custom-nodes/save # 保存节点 POST /api/custom-nodes/action # 操作节点 GET /api/custom-nodes/loaded # 已加载节点 POST /api/custom-nodes/reload-all # 重新加载 GET /api/custom-nodes/example # 示例代码 ``` ## 🎓 设计优势 1. **安全性** ✅ - 多层安全检查 - 危险操作黑名单 - 沙箱执行环境 2. **易用性** ✅ - 可视化编辑器 - 实时验证反馈 - 示例代码模板 3. **可扩展性** ✅ - 热重载机制 - 插件化架构 - 标准化接口 4. **用户体验** ✅ - 二次确认防误操作 - 自动备份机制 - 详细错误提示 ## 💡 最佳实践建议 1. **开发节点时** - 先使用示例代码模板 - 频繁点击"验证代码" - 编写完整的 docstring 2. **测试节点时** - 使用小数据集测试 - 检查边界条件 - 捕获异常情况 3. **生产使用时** - 定期备份节点文件 - 记录节点版本号 - 监控执行时间 --- **设计理念**: 在保证安全性的前提下,最大化用户的创作自由度。