Przeglądaj źródła

✨ feat(architecture): Core+Plugin

Apple\Apple 2 miesięcy temu
rodzic
commit
39c841e600

+ 161 - 0
config/plugin_config.go

@@ -0,0 +1,161 @@
+package config
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/core/interfaces"
+	"gopkg.in/yaml.v3"
+)
+
+// PluginConfig 插件配置结构
+type PluginConfig struct {
+	Channels    map[string]interfaces.ChannelConfig    `yaml:"channels"`
+	Middlewares []interfaces.MiddlewareConfig          `yaml:"middlewares"`
+	Hooks       HooksConfig                            `yaml:"hooks"`
+}
+
+// HooksConfig Hook配置
+type HooksConfig struct {
+	Relay []interfaces.HookConfig `yaml:"relay"`
+}
+
+var (
+	// 全局配置实例
+	globalPluginConfig *PluginConfig
+)
+
+// LoadPluginConfig 加载插件配置
+func LoadPluginConfig(configPath string) (*PluginConfig, error) {
+	// 如果没有指定配置文件路径,使用默认路径
+	if configPath == "" {
+		configPath = "config/plugins.yaml"
+	}
+	
+	// 检查文件是否存在
+	if _, err := os.Stat(configPath); os.IsNotExist(err) {
+		common.SysLog(fmt.Sprintf("Plugin config file not found: %s, using default configuration", configPath))
+		return getDefaultConfig(), nil
+	}
+	
+	// 读取配置文件
+	data, err := ioutil.ReadFile(configPath)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read plugin config: %w", err)
+	}
+	
+	// 解析YAML
+	var config PluginConfig
+	if err := yaml.Unmarshal(data, &config); err != nil {
+		return nil, fmt.Errorf("failed to parse plugin config: %w", err)
+	}
+	
+	// 环境变量替换
+	expandEnvVars(&config)
+	
+	common.SysLog(fmt.Sprintf("Loaded plugin config from: %s", configPath))
+	
+	return &config, nil
+}
+
+// getDefaultConfig 返回默认配置
+func getDefaultConfig() *PluginConfig {
+	return &PluginConfig{
+		Channels:    make(map[string]interfaces.ChannelConfig),
+		Middlewares: make([]interfaces.MiddlewareConfig, 0),
+		Hooks: HooksConfig{
+			Relay: make([]interfaces.HookConfig, 0),
+		},
+	}
+}
+
+// expandEnvVars 展开环境变量
+func expandEnvVars(config *PluginConfig) {
+	// 展开Hook配置中的环境变量
+	for i := range config.Hooks.Relay {
+		for key, value := range config.Hooks.Relay[i].Config {
+			if strValue, ok := value.(string); ok {
+				config.Hooks.Relay[i].Config[key] = os.ExpandEnv(strValue)
+			}
+		}
+	}
+	
+	// 展开Middleware配置中的环境变量
+	for i := range config.Middlewares {
+		for key, value := range config.Middlewares[i].Config {
+			if strValue, ok := value.(string); ok {
+				config.Middlewares[i].Config[key] = os.ExpandEnv(strValue)
+			}
+		}
+	}
+}
+
+// GetGlobalPluginConfig 获取全局配置
+func GetGlobalPluginConfig() *PluginConfig {
+	if globalPluginConfig == nil {
+		configPath := os.Getenv("PLUGIN_CONFIG_PATH")
+		if configPath == "" {
+			configPath = "config/plugins.yaml"
+		}
+		
+		config, err := LoadPluginConfig(configPath)
+		if err != nil {
+			common.SysError(fmt.Sprintf("Failed to load plugin config: %v", err))
+			config = getDefaultConfig()
+		}
+		
+		globalPluginConfig = config
+	}
+	
+	return globalPluginConfig
+}
+
+// SavePluginConfig 保存插件配置
+func SavePluginConfig(config *PluginConfig, configPath string) error {
+	if configPath == "" {
+		configPath = "config/plugins.yaml"
+	}
+	
+	// 确保目录存在
+	dir := filepath.Dir(configPath)
+	if err := os.MkdirAll(dir, 0755); err != nil {
+		return fmt.Errorf("failed to create config directory: %w", err)
+	}
+	
+	// 序列化为YAML
+	data, err := yaml.Marshal(config)
+	if err != nil {
+		return fmt.Errorf("failed to marshal config: %w", err)
+	}
+	
+	// 写入文件
+	if err := ioutil.WriteFile(configPath, data, 0644); err != nil {
+		return fmt.Errorf("failed to write config file: %w", err)
+	}
+	
+	common.SysLog(fmt.Sprintf("Saved plugin config to: %s", configPath))
+	
+	return nil
+}
+
+// ReloadPluginConfig 重新加载配置
+func ReloadPluginConfig() error {
+	configPath := os.Getenv("PLUGIN_CONFIG_PATH")
+	if configPath == "" {
+		configPath = "config/plugins.yaml"
+	}
+	
+	config, err := LoadPluginConfig(configPath)
+	if err != nil {
+		return err
+	}
+	
+	globalPluginConfig = config
+	common.SysLog("Plugin config reloaded")
+	
+	return nil
+}
+

+ 52 - 0
config/plugins.yaml

@@ -0,0 +1,52 @@
+# New-API 插件配置
+# 此文件用于配置所有插件的启用状态和参数
+
+# Channel插件配置
+channels:
+  openai:
+    enabled: true
+    priority: 100
+  
+  claude:
+    enabled: true
+    priority: 90
+  
+  gemini:
+    enabled: true
+    priority: 85
+
+# Middleware插件配置
+middlewares:
+  - name: auth
+    enabled: true
+    priority: 100
+  
+  - name: ratelimit
+    enabled: true
+    priority: 90
+    config:
+      default_rate: 60
+
+# Hook插件配置
+hooks:
+  # Relay层Hook
+  relay:
+    # 联网搜索插件
+    - name: web_search
+      enabled: false  # 默认禁用,需要配置API key后启用
+      priority: 50
+      config:
+        provider: google
+        api_key: ${WEB_SEARCH_API_KEY}  # 从环境变量读取
+    
+    # 内容过滤插件
+    - name: content_filter
+      enabled: false  # 默认禁用,需要配置后启用
+      priority: 100   # 高优先级,最后执行
+      config:
+        filter_nsfw: true
+        filter_political: false
+        sensitive_words:
+          - "敏感词1"
+          - "敏感词2"
+

+ 66 - 0
core/interfaces/channel.go

@@ -0,0 +1,66 @@
+package interfaces
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/QuantumNous/new-api/dto"
+	relaycommon "github.com/QuantumNous/new-api/relay/common"
+	"github.com/QuantumNous/new-api/types"
+	"github.com/gin-gonic/gin"
+)
+
+// ChannelPlugin 定义Channel插件接口
+// 继承原有的Adaptor接口,增加插件元数据
+type ChannelPlugin interface {
+	// 插件元数据
+	Name() string
+	Version() string
+	Priority() int
+	
+	// 原有Adaptor接口方法
+	Init(info *relaycommon.RelayInfo)
+	GetRequestURL(info *relaycommon.RelayInfo) (string, error)
+	SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error
+	ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.GeneralOpenAIRequest) (any, error)
+	ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error)
+	ConvertEmbeddingRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.EmbeddingRequest) (any, error)
+	ConvertAudioRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.AudioRequest) (io.Reader, error)
+	ConvertImageRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.ImageRequest) (any, error)
+	ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.OpenAIResponsesRequest) (any, error)
+	DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (any, error)
+	DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (usage any, err *types.NewAPIError)
+	GetModelList() []string
+	GetChannelName() string
+	ConvertClaudeRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.ClaudeRequest) (any, error)
+	ConvertGeminiRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.GeminiChatRequest) (any, error)
+}
+
+// TaskChannelPlugin 定义Task类型的Channel插件接口
+type TaskChannelPlugin interface {
+	// 插件元数据
+	Name() string
+	Version() string
+	Priority() int
+	
+	// 原有TaskAdaptor接口方法
+	Init(info *relaycommon.RelayInfo)
+	ValidateRequestAndSetAction(c *gin.Context, info *relaycommon.RelayInfo) *dto.TaskError
+	BuildRequestURL(info *relaycommon.RelayInfo) (string, error)
+	BuildRequestHeader(c *gin.Context, req *http.Request, info *relaycommon.RelayInfo) error
+	BuildRequestBody(c *gin.Context, info *relaycommon.RelayInfo) (io.Reader, error)
+	DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (*http.Response, error)
+	DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (taskID string, taskData []byte, err *dto.TaskError)
+	GetModelList() []string
+	GetChannelName() string
+	FetchTask(baseUrl, key string, body map[string]any) (*http.Response, error)
+	ParseTaskResult(respBody []byte) (*relaycommon.TaskInfo, error)
+}
+
+// ChannelConfig 插件配置
+type ChannelConfig struct {
+	Enabled  bool                   `yaml:"enabled"`
+	Priority int                    `yaml:"priority"`
+	Config   map[string]interface{} `yaml:"config"`
+}
+

+ 93 - 0
core/interfaces/hook.go

@@ -0,0 +1,93 @@
+package interfaces
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+)
+
+// HookContext Relay Hook执行上下文
+type HookContext struct {
+	// Gin Context
+	GinContext *gin.Context
+	
+	// Request相关
+	Request     *http.Request
+	RequestBody []byte
+	
+	// Response相关
+	Response     *http.Response
+	ResponseBody []byte
+	
+	// Channel信息
+	ChannelID   int
+	ChannelType int
+	ChannelName string
+	
+	// Model信息
+	Model         string
+	OriginalModel string
+	
+	// User信息
+	UserID   int
+	TokenID  int
+	Group    string
+	
+	// 扩展数据(插件间共享)
+	Data map[string]interface{}
+	
+	// 错误信息
+	Error error
+	
+	// 是否跳过后续处理
+	ShouldSkip bool
+}
+
+// RelayHook Relay Hook接口
+type RelayHook interface {
+	// 插件元数据
+	Name() string
+	Priority() int
+	Enabled() bool
+	
+	// 生命周期钩子
+	// OnBeforeRequest 在请求发送到上游之前执行
+	OnBeforeRequest(ctx *HookContext) error
+	
+	// OnAfterResponse 在收到上游响应之后执行
+	OnAfterResponse(ctx *HookContext) error
+	
+	// OnError 在发生错误时执行
+	OnError(ctx *HookContext, err error) error
+}
+
+// RequestModifier 请求修改器接口
+// 实现此接口的Hook可以修改请求内容
+type RequestModifier interface {
+	RelayHook
+	ModifyRequest(ctx *HookContext, body io.Reader) (io.Reader, error)
+}
+
+// ResponseProcessor 响应处理器接口
+// 实现此接口的Hook可以处理响应内容
+type ResponseProcessor interface {
+	RelayHook
+	ProcessResponse(ctx *HookContext, body []byte) ([]byte, error)
+}
+
+// StreamProcessor 流式响应处理器接口
+// 实现此接口的Hook可以处理流式响应
+type StreamProcessor interface {
+	RelayHook
+	ProcessStreamChunk(ctx *HookContext, chunk []byte) ([]byte, error)
+}
+
+// HookConfig Hook配置
+type HookConfig struct {
+	Name     string                 `yaml:"name"`
+	Enabled  bool                   `yaml:"enabled"`
+	Priority int                    `yaml:"priority"`
+	Config   map[string]interface{} `yaml:"config"`
+}
+

+ 31 - 0
core/interfaces/middleware.go

@@ -0,0 +1,31 @@
+package interfaces
+
+import (
+	"github.com/gin-gonic/gin"
+)
+
+// MiddlewarePlugin 中间件插件接口
+type MiddlewarePlugin interface {
+	// 插件元数据
+	Name() string
+	Priority() int
+	Enabled() bool
+	
+	// 返回Gin中间件处理函数
+	Handler() gin.HandlerFunc
+	
+	// 初始化(可选)
+	Initialize(config MiddlewareConfig) error
+}
+
+// MiddlewareConfig 中间件配置
+type MiddlewareConfig struct {
+	Name     string                 `yaml:"name"`
+	Enabled  bool                   `yaml:"enabled"`
+	Priority int                    `yaml:"priority"`
+	Config   map[string]interface{} `yaml:"config"`
+}
+
+// MiddlewareFactory 中间件工厂函数类型
+type MiddlewareFactory func(config MiddlewareConfig) (MiddlewarePlugin, error)
+

+ 171 - 0
core/registry/channel_registry.go

@@ -0,0 +1,171 @@
+package registry
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/QuantumNous/new-api/core/interfaces"
+)
+
+var (
+	// 全局Channel注册表
+	channelRegistry     = &ChannelRegistry{plugins: make(map[int]interfaces.ChannelPlugin)}
+	channelRegistryLock sync.RWMutex
+	
+	// 全局TaskChannel注册表
+	taskChannelRegistry     = &TaskChannelRegistry{plugins: make(map[string]interfaces.TaskChannelPlugin)}
+	taskChannelRegistryLock sync.RWMutex
+)
+
+// ChannelRegistry Channel插件注册中心
+type ChannelRegistry struct {
+	plugins map[int]interfaces.ChannelPlugin // channelType -> plugin
+	mu      sync.RWMutex
+}
+
+// Register 注册Channel插件
+func (r *ChannelRegistry) Register(channelType int, plugin interfaces.ChannelPlugin) error {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	
+	if _, exists := r.plugins[channelType]; exists {
+		return fmt.Errorf("channel plugin for type %d already registered", channelType)
+	}
+	
+	r.plugins[channelType] = plugin
+	return nil
+}
+
+// Get 获取Channel插件
+func (r *ChannelRegistry) Get(channelType int) (interfaces.ChannelPlugin, error) {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugin, exists := r.plugins[channelType]
+	if !exists {
+		return nil, fmt.Errorf("channel plugin for type %d not found", channelType)
+	}
+	
+	return plugin, nil
+}
+
+// List 列出所有已注册的Channel插件
+func (r *ChannelRegistry) List() []interfaces.ChannelPlugin {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugins := make([]interfaces.ChannelPlugin, 0, len(r.plugins))
+	for _, plugin := range r.plugins {
+		plugins = append(plugins, plugin)
+	}
+	
+	return plugins
+}
+
+// Has 检查是否存在指定的Channel插件
+func (r *ChannelRegistry) Has(channelType int) bool {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	_, exists := r.plugins[channelType]
+	return exists
+}
+
+// TaskChannelRegistry TaskChannel插件注册中心
+type TaskChannelRegistry struct {
+	plugins map[string]interfaces.TaskChannelPlugin // platform -> plugin
+	mu      sync.RWMutex
+}
+
+// Register 注册TaskChannel插件
+func (r *TaskChannelRegistry) Register(platform string, plugin interfaces.TaskChannelPlugin) error {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	
+	if _, exists := r.plugins[platform]; exists {
+		return fmt.Errorf("task channel plugin for platform %s already registered", platform)
+	}
+	
+	r.plugins[platform] = plugin
+	return nil
+}
+
+// Get 获取TaskChannel插件
+func (r *TaskChannelRegistry) Get(platform string) (interfaces.TaskChannelPlugin, error) {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugin, exists := r.plugins[platform]
+	if !exists {
+		return nil, fmt.Errorf("task channel plugin for platform %s not found", platform)
+	}
+	
+	return plugin, nil
+}
+
+// List 列出所有已注册的TaskChannel插件
+func (r *TaskChannelRegistry) List() []interfaces.TaskChannelPlugin {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugins := make([]interfaces.TaskChannelPlugin, 0, len(r.plugins))
+	for _, plugin := range r.plugins {
+		plugins = append(plugins, plugin)
+	}
+	
+	return plugins
+}
+
+// 全局函数 - Channel Registry
+
+// RegisterChannel 注册Channel插件
+func RegisterChannel(channelType int, plugin interfaces.ChannelPlugin) error {
+	channelRegistryLock.Lock()
+	defer channelRegistryLock.Unlock()
+	return channelRegistry.Register(channelType, plugin)
+}
+
+// GetChannel 获取Channel插件
+func GetChannel(channelType int) (interfaces.ChannelPlugin, error) {
+	channelRegistryLock.RLock()
+	defer channelRegistryLock.RUnlock()
+	return channelRegistry.Get(channelType)
+}
+
+// ListChannels 列出所有Channel插件
+func ListChannels() []interfaces.ChannelPlugin {
+	channelRegistryLock.RLock()
+	defer channelRegistryLock.RUnlock()
+	return channelRegistry.List()
+}
+
+// HasChannel 检查是否存在指定的Channel插件
+func HasChannel(channelType int) bool {
+	channelRegistryLock.RLock()
+	defer channelRegistryLock.RUnlock()
+	return channelRegistry.Has(channelType)
+}
+
+// 全局函数 - TaskChannel Registry
+
+// RegisterTaskChannel 注册TaskChannel插件
+func RegisterTaskChannel(platform string, plugin interfaces.TaskChannelPlugin) error {
+	taskChannelRegistryLock.Lock()
+	defer taskChannelRegistryLock.Unlock()
+	return taskChannelRegistry.Register(platform, plugin)
+}
+
+// GetTaskChannel 获取TaskChannel插件
+func GetTaskChannel(platform string) (interfaces.TaskChannelPlugin, error) {
+	taskChannelRegistryLock.RLock()
+	defer taskChannelRegistryLock.RUnlock()
+	return taskChannelRegistry.Get(platform)
+}
+
+// ListTaskChannels 列出所有TaskChannel插件
+func ListTaskChannels() []interfaces.TaskChannelPlugin {
+	taskChannelRegistryLock.RLock()
+	defer taskChannelRegistryLock.RUnlock()
+	return taskChannelRegistry.List()
+}
+

+ 183 - 0
core/registry/hook_registry.go

@@ -0,0 +1,183 @@
+package registry
+
+import (
+	"fmt"
+	"sort"
+	"sync"
+
+	"github.com/QuantumNous/new-api/core/interfaces"
+)
+
+var (
+	// 全局Hook注册表
+	hookRegistry     = &HookRegistry{hooks: make([]interfaces.RelayHook, 0)}
+	hookRegistryLock sync.RWMutex
+)
+
+// HookRegistry Hook插件注册中心
+type HookRegistry struct {
+	hooks  []interfaces.RelayHook
+	sorted bool
+	mu     sync.RWMutex
+}
+
+// Register 注册Hook插件
+func (r *HookRegistry) Register(hook interfaces.RelayHook) error {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	
+	// 检查是否已存在同名Hook
+	for _, h := range r.hooks {
+		if h.Name() == hook.Name() {
+			return fmt.Errorf("hook %s already registered", hook.Name())
+		}
+	}
+	
+	r.hooks = append(r.hooks, hook)
+	r.sorted = false // 标记需要重新排序
+	
+	return nil
+}
+
+// Get 获取指定名称的Hook插件
+func (r *HookRegistry) Get(name string) (interfaces.RelayHook, error) {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	for _, hook := range r.hooks {
+		if hook.Name() == name {
+			return hook, nil
+		}
+	}
+	
+	return nil, fmt.Errorf("hook %s not found", name)
+}
+
+// List 列出所有已注册且启用的Hook插件(按优先级排序)
+func (r *HookRegistry) List() []interfaces.RelayHook {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	
+	// 如果未排序,先排序
+	if !r.sorted {
+		r.sortHooks()
+	}
+	
+	// 只返回启用的hooks
+	enabledHooks := make([]interfaces.RelayHook, 0)
+	for _, hook := range r.hooks {
+		if hook.Enabled() {
+			enabledHooks = append(enabledHooks, hook)
+		}
+	}
+	
+	return enabledHooks
+}
+
+// ListAll 列出所有已注册的Hook插件(包括未启用的)
+func (r *HookRegistry) ListAll() []interfaces.RelayHook {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	hooks := make([]interfaces.RelayHook, len(r.hooks))
+	copy(hooks, r.hooks)
+	
+	return hooks
+}
+
+// sortHooks 按优先级排序hooks(优先级数字越大越先执行)
+func (r *HookRegistry) sortHooks() {
+	sort.SliceStable(r.hooks, func(i, j int) bool {
+		return r.hooks[i].Priority() > r.hooks[j].Priority()
+	})
+	r.sorted = true
+}
+
+// Has 检查是否存在指定的Hook插件
+func (r *HookRegistry) Has(name string) bool {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	for _, hook := range r.hooks {
+		if hook.Name() == name {
+			return true
+		}
+	}
+	
+	return false
+}
+
+// Count 返回已注册的Hook数量
+func (r *HookRegistry) Count() int {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	return len(r.hooks)
+}
+
+// EnabledCount 返回已启用的Hook数量
+func (r *HookRegistry) EnabledCount() int {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	count := 0
+	for _, hook := range r.hooks {
+		if hook.Enabled() {
+			count++
+		}
+	}
+	
+	return count
+}
+
+// 全局函数
+
+// RegisterHook 注册Hook插件
+func RegisterHook(hook interfaces.RelayHook) error {
+	hookRegistryLock.Lock()
+	defer hookRegistryLock.Unlock()
+	return hookRegistry.Register(hook)
+}
+
+// GetHook 获取Hook插件
+func GetHook(name string) (interfaces.RelayHook, error) {
+	hookRegistryLock.RLock()
+	defer hookRegistryLock.RUnlock()
+	return hookRegistry.Get(name)
+}
+
+// ListHooks 列出所有已启用的Hook插件
+func ListHooks() []interfaces.RelayHook {
+	hookRegistryLock.RLock()
+	defer hookRegistryLock.RUnlock()
+	return hookRegistry.List()
+}
+
+// ListAllHooks 列出所有Hook插件
+func ListAllHooks() []interfaces.RelayHook {
+	hookRegistryLock.RLock()
+	defer hookRegistryLock.RUnlock()
+	return hookRegistry.ListAll()
+}
+
+// HasHook 检查是否存在指定的Hook插件
+func HasHook(name string) bool {
+	hookRegistryLock.RLock()
+	defer hookRegistryLock.RUnlock()
+	return hookRegistry.Has(name)
+}
+
+// HookCount 返回已注册的Hook数量
+func HookCount() int {
+	hookRegistryLock.RLock()
+	defer hookRegistryLock.RUnlock()
+	return hookRegistry.Count()
+}
+
+// EnabledHookCount 返回已启用的Hook数量
+func EnabledHookCount() int {
+	hookRegistryLock.RLock()
+	defer hookRegistryLock.RUnlock()
+	return hookRegistry.EnabledCount()
+}
+

+ 133 - 0
core/registry/middleware_registry.go

@@ -0,0 +1,133 @@
+package registry
+
+import (
+	"fmt"
+	"sort"
+	"sync"
+
+	"github.com/QuantumNous/new-api/core/interfaces"
+)
+
+var (
+	// 全局Middleware注册表
+	middlewareRegistry     = &MiddlewareRegistry{plugins: make(map[string]interfaces.MiddlewarePlugin)}
+	middlewareRegistryLock sync.RWMutex
+)
+
+// MiddlewareRegistry 中间件插件注册中心
+type MiddlewareRegistry struct {
+	plugins map[string]interfaces.MiddlewarePlugin
+	mu      sync.RWMutex
+}
+
+// Register 注册Middleware插件
+func (r *MiddlewareRegistry) Register(plugin interfaces.MiddlewarePlugin) error {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	
+	name := plugin.Name()
+	if _, exists := r.plugins[name]; exists {
+		return fmt.Errorf("middleware plugin %s already registered", name)
+	}
+	
+	r.plugins[name] = plugin
+	return nil
+}
+
+// Get 获取Middleware插件
+func (r *MiddlewareRegistry) Get(name string) (interfaces.MiddlewarePlugin, error) {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugin, exists := r.plugins[name]
+	if !exists {
+		return nil, fmt.Errorf("middleware plugin %s not found", name)
+	}
+	
+	return plugin, nil
+}
+
+// List 列出所有已注册的Middleware插件(按优先级排序)
+func (r *MiddlewareRegistry) List() []interfaces.MiddlewarePlugin {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugins := make([]interfaces.MiddlewarePlugin, 0, len(r.plugins))
+	for _, plugin := range r.plugins {
+		plugins = append(plugins, plugin)
+	}
+	
+	// 按优先级排序(优先级数字越大越先执行)
+	sort.SliceStable(plugins, func(i, j int) bool {
+		return plugins[i].Priority() > plugins[j].Priority()
+	})
+	
+	return plugins
+}
+
+// ListEnabled 列出所有已启用的Middleware插件(按优先级排序)
+func (r *MiddlewareRegistry) ListEnabled() []interfaces.MiddlewarePlugin {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	plugins := make([]interfaces.MiddlewarePlugin, 0, len(r.plugins))
+	for _, plugin := range r.plugins {
+		if plugin.Enabled() {
+			plugins = append(plugins, plugin)
+		}
+	}
+	
+	// 按优先级排序
+	sort.SliceStable(plugins, func(i, j int) bool {
+		return plugins[i].Priority() > plugins[j].Priority()
+	})
+	
+	return plugins
+}
+
+// Has 检查是否存在指定的Middleware插件
+func (r *MiddlewareRegistry) Has(name string) bool {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	
+	_, exists := r.plugins[name]
+	return exists
+}
+
+// 全局函数
+
+// RegisterMiddleware 注册Middleware插件
+func RegisterMiddleware(plugin interfaces.MiddlewarePlugin) error {
+	middlewareRegistryLock.Lock()
+	defer middlewareRegistryLock.Unlock()
+	return middlewareRegistry.Register(plugin)
+}
+
+// GetMiddleware 获取Middleware插件
+func GetMiddleware(name string) (interfaces.MiddlewarePlugin, error) {
+	middlewareRegistryLock.RLock()
+	defer middlewareRegistryLock.RUnlock()
+	return middlewareRegistry.Get(name)
+}
+
+// ListMiddlewares 列出所有Middleware插件
+func ListMiddlewares() []interfaces.MiddlewarePlugin {
+	middlewareRegistryLock.RLock()
+	defer middlewareRegistryLock.RUnlock()
+	return middlewareRegistry.List()
+}
+
+// ListEnabledMiddlewares 列出所有已启用的Middleware插件
+func ListEnabledMiddlewares() []interfaces.MiddlewarePlugin {
+	middlewareRegistryLock.RLock()
+	defer middlewareRegistryLock.RUnlock()
+	return middlewareRegistry.ListEnabled()
+}
+
+// HasMiddleware 检查是否存在指定的Middleware插件
+func HasMiddleware(name string) bool {
+	middlewareRegistryLock.RLock()
+	defer middlewareRegistryLock.RUnlock()
+	return middlewareRegistry.Has(name)
+}
+

+ 116 - 0
core/registry/registry_test.go

@@ -0,0 +1,116 @@
+package registry
+
+import (
+	"testing"
+
+	"github.com/QuantumNous/new-api/core/interfaces"
+)
+
+// Mock Hook实现
+type mockHook struct {
+	name     string
+	priority int
+	enabled  bool
+}
+
+func (m *mockHook) Name() string { return m.name }
+func (m *mockHook) Priority() int { return m.priority }
+func (m *mockHook) Enabled() bool { return m.enabled }
+func (m *mockHook) OnBeforeRequest(ctx *interfaces.HookContext) error { return nil }
+func (m *mockHook) OnAfterResponse(ctx *interfaces.HookContext) error { return nil }
+func (m *mockHook) OnError(ctx *interfaces.HookContext, err error) error { return nil }
+
+func TestHookRegistry(t *testing.T) {
+	// 创建新的注册表(用于测试)
+	registry := &HookRegistry{hooks: make([]interfaces.RelayHook, 0)}
+	
+	// 测试注册Hook
+	hook1 := &mockHook{name: "test_hook_1", priority: 100, enabled: true}
+	hook2 := &mockHook{name: "test_hook_2", priority: 50, enabled: true}
+	hook3 := &mockHook{name: "test_hook_3", priority: 75, enabled: false}
+	
+	if err := registry.Register(hook1); err != nil {
+		t.Errorf("Failed to register hook1: %v", err)
+	}
+	
+	if err := registry.Register(hook2); err != nil {
+		t.Errorf("Failed to register hook2: %v", err)
+	}
+	
+	if err := registry.Register(hook3); err != nil {
+		t.Errorf("Failed to register hook3: %v", err)
+	}
+	
+	// 测试重复注册
+	if err := registry.Register(hook1); err == nil {
+		t.Error("Expected error when registering duplicate hook")
+	}
+	
+	// 测试获取Hook
+	if hook, err := registry.Get("test_hook_1"); err != nil {
+		t.Errorf("Failed to get hook: %v", err)
+	} else if hook.Name() != "test_hook_1" {
+		t.Errorf("Got wrong hook: %s", hook.Name())
+	}
+	
+	// 测试不存在的Hook
+	if _, err := registry.Get("nonexistent"); err == nil {
+		t.Error("Expected error when getting nonexistent hook")
+	}
+	
+	// 测试List(应该只返回enabled的hooks)
+	hooks := registry.List()
+	if len(hooks) != 2 {
+		t.Errorf("Expected 2 enabled hooks, got %d", len(hooks))
+	}
+	
+	// 测试优先级排序(100应该在50之前)
+	if hooks[0].Priority() != 100 {
+		t.Errorf("Expected first hook to have priority 100, got %d", hooks[0].Priority())
+	}
+	
+	// 测试Count
+	if count := registry.Count(); count != 3 {
+		t.Errorf("Expected count 3, got %d", count)
+	}
+	
+	// 测试EnabledCount
+	if count := registry.EnabledCount(); count != 2 {
+		t.Errorf("Expected enabled count 2, got %d", count)
+	}
+	
+	// 测试Has
+	if !registry.Has("test_hook_1") {
+		t.Error("Expected to find test_hook_1")
+	}
+	
+	if registry.Has("nonexistent") {
+		t.Error("Should not find nonexistent hook")
+	}
+}
+
+func TestChannelRegistry(t *testing.T) {
+	// 这里可以添加Channel Registry的测试
+	// 但需要mock ChannelPlugin接口,比较复杂
+	// 作为示例,我们只测试基本功能
+	
+	registry := &ChannelRegistry{plugins: make(map[int]interfaces.ChannelPlugin)}
+	
+	// 测试Has方法
+	if registry.Has(1) {
+		t.Error("Should not find channel type 1")
+	}
+}
+
+func TestMiddlewareRegistry(t *testing.T) {
+	// Middleware Registry测试
+	// 需要mock MiddlewarePlugin接口
+	
+	registry := &MiddlewareRegistry{plugins: make(map[string]interfaces.MiddlewarePlugin)}
+	
+	// 测试Has方法
+	if registry.Has("test_middleware") {
+		t.Error("Should not find test_middleware")
+	}
+}
+

+ 359 - 0
docs/architecture/plugin-system-architecture.md

@@ -0,0 +1,359 @@
+# New-API 插件化架构说明
+
+## 完整目录结构
+
+```
+new-api-2/
+├── core/                              # 核心层(高性能,不可插件化)
+│   ├── interfaces/                    # 插件接口定义
+│   │   ├── channel.go                # Channel插件接口
+│   │   ├── hook.go                   # Hook插件接口
+│   │   └── middleware.go             # Middleware插件接口
+│   └── registry/                      # 插件注册中心
+│       ├── channel_registry.go       # Channel注册器(线程安全)
+│       ├── hook_registry.go          # Hook注册器(优先级排序)
+│       └── middleware_registry.go    # Middleware注册器
+│
+├── plugins/                           # 🔵 Tier 1: 编译时插件(已实施)
+│   ├── channels/                      # Channel插件
+│   │   ├── base_plugin.go            # 基础插件包装器
+│   │   └── registry.go               # 自动注册31个AI Provider
+│   └── hooks/                         # Hook插件
+│       ├── web_search/               # 联网搜索Hook
+│       │   ├── web_search_hook.go
+│       │   └── init.go
+│       └── content_filter/           # 内容过滤Hook
+│           ├── content_filter_hook.go
+│           └── init.go
+│
+├── marketplace/                       # 🟣 Tier 2: 运行时插件(待实施,Phase 2)
+│   ├── loader/                        # go-plugin加载器
+│   │   ├── plugin_client.go          # 插件客户端
+│   │   ├── plugin_server.go          # 插件服务器
+│   │   └── lifecycle.go              # 生命周期管理
+│   ├── manager/                       # 插件管理器
+│   │   ├── installer.go              # 安装/卸载
+│   │   ├── updater.go                # 版本更新
+│   │   └── registry.go               # 插件注册表
+│   ├── security/                      # 安全模块
+│   │   ├── signature.go              # Ed25519签名验证
+│   │   ├── checksum.go               # SHA256校验
+│   │   └── sandbox.go                # 沙箱配置
+│   ├── store/                         # 插件商店客户端
+│   │   ├── client.go                 # 商店API客户端
+│   │   ├── search.go                 # 搜索功能
+│   │   └── download.go               # 下载管理
+│   └── proto/                         # gRPC协议定义
+│       ├── hook.proto                # Hook插件协议
+│       ├── channel.proto             # Channel插件协议
+│       └── common.proto              # 通用消息
+│
+├── plugins_external/                  # 第三方插件安装目录
+│   ├── installed/                    # 已安装插件
+│   │   ├── awesome-hook-v1.0.0/
+│   │   ├── custom-llm-v2.1.0/
+│   │   └── slack-notify-v1.5.0/
+│   ├── cache/                        # 下载缓存
+│   └── temp/                         # 临时文件
+│
+├── relay/                            # Relay层
+│   ├── hooks/                        # Hook执行链
+│   │   ├── chain.go                 # Hook链管理器
+│   │   ├── context.go               # Hook上下文
+│   │   └── context_builder.go       # 上下文构建器
+│   └── relay_adaptor.go             # Channel适配器(优先从Registry获取)
+│
+├── config/                           # 配置系统
+│   ├── plugins.yaml                 # 插件配置(Tier 1 + Tier 2)
+│   └── plugin_config.go             # 配置加载器(支持环境变量)
+│
+└── (其他现有目录保持不变)
+```
+
+---
+
+## 完整架构图
+
+### 系统架构总览
+
+```mermaid
+graph TB
+    subgraph "🌐 API层"
+        Client[客户端请求]
+    end
+    
+    subgraph "🔐 中间件层"
+        Auth[认证中间件]
+        RateLimit[限流中间件]
+        Cache[缓存中间件]
+    end
+    
+    subgraph "🎯 核心层 Core"
+        Registry[插件注册中心]
+        ChannelReg[Channel Registry]
+        HookReg[Hook Registry]
+        MidReg[Middleware Registry]
+        
+        Registry --> ChannelReg
+        Registry --> HookReg
+        Registry --> MidReg
+    end
+    
+    subgraph "🔵 Tier 1: 编译时插件(已实施)"
+        direction TB
+        
+        Channels[31个 Channel Plugins]
+        OpenAI[OpenAI]
+        Claude[Claude]
+        Gemini[Gemini]
+        Others[其他28个...]
+        
+        Channels --> OpenAI
+        Channels --> Claude
+        Channels --> Gemini
+        Channels --> Others
+        
+        Hooks[Hook Plugins]
+        WebSearch[Web Search Hook]
+        ContentFilter[Content Filter Hook]
+        
+        Hooks --> WebSearch
+        Hooks --> ContentFilter
+    end
+    
+    subgraph "🟣 Tier 2: 运行时插件(待实施)"
+        direction TB
+        
+        Marketplace[🏪 Plugin Marketplace]
+        ExtHook[External Hooks<br/>Python/Go/Node.js]
+        ExtChannel[External Channels<br/>小众AI提供商]
+        ExtMid[External Middleware<br/>企业集成]
+        ExtUI[UI Extensions<br/>自定义仪表板]
+        
+        Marketplace --> ExtHook
+        Marketplace --> ExtChannel
+        Marketplace --> ExtMid
+        Marketplace --> ExtUI
+    end
+    
+    subgraph "⚡ Relay执行流程"
+        direction LR
+        HookChain[Hook Chain]
+        BeforeHook[OnBeforeRequest]
+        ChannelAdaptor[Channel Adaptor]
+        AfterHook[OnAfterResponse]
+        
+        HookChain --> BeforeHook
+        BeforeHook --> ChannelAdaptor
+        ChannelAdaptor --> AfterHook
+    end
+    
+    subgraph "🌍 上游服务"
+        Upstream[AI Provider APIs]
+    end
+    
+    Client --> Auth
+    Auth --> RateLimit
+    RateLimit --> Cache
+    Cache --> Registry
+    
+    Channels --> ChannelReg
+    Hooks --> HookReg
+    
+    Registry --> HookChain
+    HookChain --> Upstream
+    Upstream --> HookChain
+    
+    Registry -.gRPC/RPC.-> ExtHook
+    Registry -.gRPC/RPC.-> ExtChannel
+    Registry -.gRPC/RPC.-> ExtMid
+    
+    style Marketplace fill:#f9f,stroke:#333,stroke-width:4px
+    style Registry fill:#bbf,stroke:#333,stroke-width:4px
+    style Channels fill:#bfb,stroke:#333,stroke-width:2px
+    style Hooks fill:#bfb,stroke:#333,stroke-width:2px
+```
+
+### 双层插件系统架构
+
+```mermaid
+graph LR
+    subgraph "🔵 Tier 1: 编译时插件"
+        T1[性能: 100%<br/>语言: Go only<br/>部署: 编译到二进制]
+        T1Chan[31 Channels]
+        T1Hook[2 Hooks]
+        
+        T1 --> T1Chan
+        T1 --> T1Hook
+    end
+    
+    subgraph "🟣 Tier 2: 运行时插件"
+        T2[性能: 90-95%<br/>语言: Go/Python/Node.js<br/>部署: 独立进程]
+        T2Hook[External Hooks]
+        T2Chan[External Channels]
+        T2Mid[External Middleware]
+        T2UI[UI Extensions]
+        
+        T2 --> T2Hook
+        T2 --> T2Chan
+        T2 --> T2Mid
+        T2 --> T2UI
+    end
+    
+    T1 -.进程内调用.-> Core[Core System]
+    T2 -.gRPC/RPC.-> Core
+    
+    style T1 fill:#bfb,stroke:#333,stroke-width:3px
+    style T2 fill:#f9f,stroke:#333,stroke-width:3px
+    style Core fill:#bbf,stroke:#333,stroke-width:3px
+```
+
+---
+
+## 核心要点说明
+
+### 1. 双层插件架构
+
+| 层级 | 技术方案 | 性能 | 适用场景 | 开发语言 |
+|------|---------|------|---------|---------|
+| **Tier 1<br/>编译时插件** | 编译时链接 | 100%<br/>零损失 | • 核心Channel(OpenAI等)<br/>• 内置Hook<br/>• 高频调用路径 | Go only |
+| **Tier 2<br/>运行时插件** | go-plugin<br/>gRPC | 90-95%<br/>5-10%开销 | • 第三方扩展<br/>• 企业定制<br/>• 多语言集成 | Go/Python/<br/>Node.js/Rust |
+
+### 2. 核心组件
+
+#### Core层(核心引擎)
+- **interfaces/**: 定义ChannelPlugin、RelayHook、MiddlewarePlugin接口
+- **registry/**: 线程安全的插件注册中心,支持O(1)查找、优先级排序
+
+#### Relay Hook链
+- **执行流程**: OnBeforeRequest → Channel.DoRequest → OnAfterResponse
+- **特性**: 优先级排序、短路机制、数据共享(HookContext.Data)
+- **应用场景**: 联网搜索、内容过滤、日志增强、缓存策略
+
+### 3. Tier 1: 编译时插件(已实施 ✅)
+
+**特点**:
+- 零性能损失,编译后与硬编码无差异
+- init()函数自动注册到Registry
+- YAML配置启用/禁用
+
+**已实现**:
+- ✅ 31个Channel插件(OpenAI、Claude、Gemini等)
+- ✅ 2个Hook插件(web_search、content_filter)
+- ✅ Hook执行链
+- ✅ 配置系统(支持环境变量展开)
+
+### 4. Tier 2: 运行时插件(待实施 🚧)
+
+**基于**: [hashicorp/go-plugin](https://github.com/hashicorp/go-plugin)(Vault/Terraform使用)
+
+**优势**:
+- ✅ 进程隔离(第三方代码崩溃不影响主程序)
+- ✅ 多语言支持(gRPC协议)
+- ✅ 热插拔(无需重启)
+- ✅ 安全验证(Ed25519签名 + SHA256校验 + TLS加密)
+- ✅ 独立分发(插件商店)
+
+**适用场景**:
+- 第三方开发者扩展
+- 企业定制业务逻辑
+- Python ML模型集成
+- 第三方服务集成(Slack/钉钉/企业微信)
+- UI扩展
+
+### 5. 安全机制
+
+**Tier 1(编译时)**:
+- 内部代码审查
+- 编译期类型安全
+
+**Tier 2(运行时)**:
+- Ed25519签名验证
+- SHA256校验和
+- gRPC TLS加密
+- 进程资源限制(内存/CPU)
+- 插件商店审核机制
+- 可信发布者白名单
+
+### 6. 配置系统
+
+**单一配置文件**: `config/plugins.yaml`
+
+```yaml
+# Tier 1: 编译时插件
+plugins:
+  hooks:
+    - name: web_search
+      enabled: false
+      priority: 50
+      config:
+        api_key: ${WEB_SEARCH_API_KEY}
+
+# Tier 2: 运行时插件(待实施)
+external_plugins:
+  enabled: true
+  hooks:
+    - name: awesome_hook
+      binary: awesome-hook-v1.0.0/awesome-hook
+      checksum: sha256:abc123...
+
+# 插件商店
+marketplace:
+  enabled: true
+  api_url: https://plugins.new-api.com
+```
+
+### 7. 性能对比
+
+| 场景 | Tier 1 | Tier 2 | RPC开销 |
+|------|--------|--------|--------|
+| 核心Channel | 100% | N/A | 0% |
+| 内置Hook | 100% | N/A | 0% |
+| 第三方Hook | N/A | 92-95% | 5-8% |
+| Python插件 | N/A | 88-92% | 8-12% |
+
+### 8. 实施路线图
+
+#### Phase 1: 编译时插件系统 ✅ 已完成
+- Core Registry + Hook Chain
+- 31个Channel插件 + 2个Hook示例
+- YAML配置系统
+
+#### Phase 2: go-plugin基础
+- protobuf协议定义
+- PluginLoader实现
+- 签名验证系统
+- Python/Go SDK
+
+#### Phase 3: 插件商店
+- 商店后端API
+- Web UI(搜索、安装、管理)
+- CLI工具
+- 多语言SDK
+
+### 9. 扩展示例
+
+**新增Tier 1插件(编译时)**:
+```go
+// 1. 实现接口
+type MyHook struct{}
+func (h *MyHook) OnBeforeRequest(ctx *HookContext) error { /*...*/ }
+
+// 2. 注册
+func init() { registry.RegisterHook(&MyHook{}) }
+
+// 3. 导入到main.go
+import _ "github.com/xxx/plugins/hooks/my_hook"
+```
+
+**新增Tier 2插件(运行时)**:
+```python
+# external-plugin/my_hook.py
+from new_api_plugin_sdk import HookPlugin, serve
+
+class MyHook(HookPlugin):
+    def on_before_request(self, ctx):
+        return {"modified_body": ctx.request_body}
+
+serve(MyHook())
+```

+ 1 - 0
go.mod

@@ -40,6 +40,7 @@ require (
 	golang.org/x/image v0.23.0
 	golang.org/x/net v0.43.0
 	golang.org/x/sync v0.17.0
+	gopkg.in/yaml.v3 v3.0.1
 	gorm.io/driver/mysql v1.4.3
 	gorm.io/driver/postgres v1.5.2
 	gorm.io/gorm v1.25.2

+ 36 - 0
main.go

@@ -21,6 +21,13 @@ import (
 	"github.com/QuantumNous/new-api/service"
 	"github.com/QuantumNous/new-api/setting/ratio_setting"
 
+	// Plugin System
+	coreregistry "github.com/QuantumNous/new-api/core/registry"
+	_ "github.com/QuantumNous/new-api/plugins/channels"  // 自动注册channel插件
+	_ "github.com/QuantumNous/new-api/plugins/hooks/web_search" // 自动注册web_search hook
+	_ "github.com/QuantumNous/new-api/plugins/hooks/content_filter" // 自动注册content_filter hook
+	relayhooks "github.com/QuantumNous/new-api/relay/hooks"
+
 	"github.com/bytedance/gopkg/util/gopool"
 	"github.com/gin-contrib/sessions"
 	"github.com/gin-contrib/sessions/cookie"
@@ -229,5 +236,34 @@ func InitResources() error {
 	if err != nil {
 		return err
 	}
+	
+	// Initialize Plugin System
+	InitPluginSystem()
+	
 	return nil
 }
+
+// InitPluginSystem 初始化插件系统
+func InitPluginSystem() {
+	common.SysLog("Initializing plugin system...")
+	
+	// 1. 加载插件配置
+	// config.LoadPluginConfig() 会在各个插件的init()中自动调用
+	
+	// 2. 注册Channel插件
+	// 注意:这会在 plugins/channels/registry.go 的 init() 中自动完成
+	// 但为了确保加载,我们显式导入
+	common.SysLog("Registering channel plugins...")
+	
+	// 3. 初始化Hook链
+	common.SysLog("Initializing hook chain...")
+	_ = relayhooks.GetGlobalChain()
+	
+	hookCount := coreregistry.HookCount()
+	enabledHookCount := coreregistry.EnabledHookCount()
+	common.SysLog(fmt.Sprintf("Plugin system initialized: %d hooks registered (%d enabled)", 
+		hookCount, enabledHookCount))
+	
+	channelCount := len(coreregistry.ListChannels())
+	common.SysLog(fmt.Sprintf("Registered %d channel plugins", channelCount))
+}

+ 114 - 0
plugins/channels/base_plugin.go

@@ -0,0 +1,114 @@
+package channels
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/QuantumNous/new-api/dto"
+	"github.com/QuantumNous/new-api/relay/channel"
+	relaycommon "github.com/QuantumNous/new-api/relay/common"
+	"github.com/QuantumNous/new-api/types"
+	"github.com/gin-gonic/gin"
+)
+
+// BaseChannelPlugin 基础Channel插件
+// 包装现有的Adaptor实现,使其符合ChannelPlugin接口
+type BaseChannelPlugin struct {
+	adaptor  channel.Adaptor
+	name     string
+	version  string
+	priority int
+}
+
+// NewBaseChannelPlugin 创建基础Channel插件
+func NewBaseChannelPlugin(adaptor channel.Adaptor, name, version string, priority int) *BaseChannelPlugin {
+	return &BaseChannelPlugin{
+		adaptor:  adaptor,
+		name:     name,
+		version:  version,
+		priority: priority,
+	}
+}
+
+// Name 返回插件名称
+func (p *BaseChannelPlugin) Name() string {
+	return p.name
+}
+
+// Version 返回插件版本
+func (p *BaseChannelPlugin) Version() string {
+	return p.version
+}
+
+// Priority 返回优先级
+func (p *BaseChannelPlugin) Priority() int {
+	return p.priority
+}
+
+// 以下方法直接委托给内部的Adaptor
+
+func (p *BaseChannelPlugin) Init(info *relaycommon.RelayInfo) {
+	p.adaptor.Init(info)
+}
+
+func (p *BaseChannelPlugin) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
+	return p.adaptor.GetRequestURL(info)
+}
+
+func (p *BaseChannelPlugin) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error {
+	return p.adaptor.SetupRequestHeader(c, req, info)
+}
+
+func (p *BaseChannelPlugin) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.GeneralOpenAIRequest) (any, error) {
+	return p.adaptor.ConvertOpenAIRequest(c, info, request)
+}
+
+func (p *BaseChannelPlugin) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) {
+	return p.adaptor.ConvertRerankRequest(c, relayMode, request)
+}
+
+func (p *BaseChannelPlugin) ConvertEmbeddingRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.EmbeddingRequest) (any, error) {
+	return p.adaptor.ConvertEmbeddingRequest(c, info, request)
+}
+
+func (p *BaseChannelPlugin) ConvertAudioRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.AudioRequest) (io.Reader, error) {
+	return p.adaptor.ConvertAudioRequest(c, info, request)
+}
+
+func (p *BaseChannelPlugin) ConvertImageRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.ImageRequest) (any, error) {
+	return p.adaptor.ConvertImageRequest(c, info, request)
+}
+
+func (p *BaseChannelPlugin) ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.OpenAIResponsesRequest) (any, error) {
+	return p.adaptor.ConvertOpenAIResponsesRequest(c, info, request)
+}
+
+func (p *BaseChannelPlugin) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (any, error) {
+	return p.adaptor.DoRequest(c, info, requestBody)
+}
+
+func (p *BaseChannelPlugin) DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (usage any, err *types.NewAPIError) {
+	return p.adaptor.DoResponse(c, resp, info)
+}
+
+func (p *BaseChannelPlugin) GetModelList() []string {
+	return p.adaptor.GetModelList()
+}
+
+func (p *BaseChannelPlugin) GetChannelName() string {
+	return p.adaptor.GetChannelName()
+}
+
+func (p *BaseChannelPlugin) ConvertClaudeRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.ClaudeRequest) (any, error) {
+	return p.adaptor.ConvertClaudeRequest(c, info, request)
+}
+
+func (p *BaseChannelPlugin) ConvertGeminiRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.GeminiChatRequest) (any, error) {
+	return p.adaptor.ConvertGeminiRequest(c, info, request)
+}
+
+// GetAdaptor 获取内部的Adaptor(用于向后兼容)
+func (p *BaseChannelPlugin) GetAdaptor() channel.Adaptor {
+	return p.adaptor
+}
+

+ 106 - 0
plugins/channels/registry.go

@@ -0,0 +1,106 @@
+package channels
+
+import (
+	"fmt"
+	
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/constant"
+	"github.com/QuantumNous/new-api/core/registry"
+	"github.com/QuantumNous/new-api/relay/channel"
+	"github.com/QuantumNous/new-api/relay/channel/ali"
+	"github.com/QuantumNous/new-api/relay/channel/aws"
+	"github.com/QuantumNous/new-api/relay/channel/baidu"
+	"github.com/QuantumNous/new-api/relay/channel/baidu_v2"
+	"github.com/QuantumNous/new-api/relay/channel/claude"
+	"github.com/QuantumNous/new-api/relay/channel/cloudflare"
+	"github.com/QuantumNous/new-api/relay/channel/cohere"
+	"github.com/QuantumNous/new-api/relay/channel/coze"
+	"github.com/QuantumNous/new-api/relay/channel/deepseek"
+	"github.com/QuantumNous/new-api/relay/channel/dify"
+	"github.com/QuantumNous/new-api/relay/channel/gemini"
+	"github.com/QuantumNous/new-api/relay/channel/jimeng"
+	"github.com/QuantumNous/new-api/relay/channel/jina"
+	"github.com/QuantumNous/new-api/relay/channel/mistral"
+	"github.com/QuantumNous/new-api/relay/channel/mokaai"
+	"github.com/QuantumNous/new-api/relay/channel/moonshot"
+	"github.com/QuantumNous/new-api/relay/channel/ollama"
+	"github.com/QuantumNous/new-api/relay/channel/openai"
+	"github.com/QuantumNous/new-api/relay/channel/palm"
+	"github.com/QuantumNous/new-api/relay/channel/perplexity"
+	"github.com/QuantumNous/new-api/relay/channel/siliconflow"
+	"github.com/QuantumNous/new-api/relay/channel/submodel"
+	"github.com/QuantumNous/new-api/relay/channel/tencent"
+	"github.com/QuantumNous/new-api/relay/channel/vertex"
+	"github.com/QuantumNous/new-api/relay/channel/volcengine"
+	"github.com/QuantumNous/new-api/relay/channel/xai"
+	"github.com/QuantumNous/new-api/relay/channel/xunfei"
+	"github.com/QuantumNous/new-api/relay/channel/zhipu"
+	"github.com/QuantumNous/new-api/relay/channel/zhipu_4v"
+)
+
+// init 包初始化时自动注册所有Channel插件
+func init() {
+	RegisterAllChannels()
+}
+
+// RegisterAllChannels 注册所有Channel插件
+func RegisterAllChannels() {
+	// 包装现有的Adaptor并注册为插件
+	channels := []struct {
+		channelType int
+		adaptor     channel.Adaptor
+		name        string
+	}{
+		{constant.APITypeOpenAI, &openai.Adaptor{}, "openai"},
+		{constant.APITypeAnthropic, &claude.Adaptor{}, "claude"},
+		{constant.APITypeGemini, &gemini.Adaptor{}, "gemini"},
+		{constant.APITypeAli, &ali.Adaptor{}, "ali"},
+		{constant.APITypeBaidu, &baidu.Adaptor{}, "baidu"},
+		{constant.APITypeBaiduV2, &baidu_v2.Adaptor{}, "baidu_v2"},
+		{constant.APITypeTencent, &tencent.Adaptor{}, "tencent"},
+		{constant.APITypeXunfei, &xunfei.Adaptor{}, "xunfei"},
+		{constant.APITypeZhipu, &zhipu.Adaptor{}, "zhipu"},
+		{constant.APITypeZhipuV4, &zhipu_4v.Adaptor{}, "zhipu_v4"},
+		{constant.APITypeOllama, &ollama.Adaptor{}, "ollama"},
+		{constant.APITypePerplexity, &perplexity.Adaptor{}, "perplexity"},
+		{constant.APITypeAws, &aws.Adaptor{}, "aws"},
+		{constant.APITypeCohere, &cohere.Adaptor{}, "cohere"},
+		{constant.APITypeDify, &dify.Adaptor{}, "dify"},
+		{constant.APITypeJina, &jina.Adaptor{}, "jina"},
+		{constant.APITypeCloudflare, &cloudflare.Adaptor{}, "cloudflare"},
+		{constant.APITypeSiliconFlow, &siliconflow.Adaptor{}, "siliconflow"},
+		{constant.APITypeVertexAi, &vertex.Adaptor{}, "vertex"},
+		{constant.APITypeMistral, &mistral.Adaptor{}, "mistral"},
+		{constant.APITypeDeepSeek, &deepseek.Adaptor{}, "deepseek"},
+		{constant.APITypeMokaAI, &mokaai.Adaptor{}, "mokaai"},
+		{constant.APITypeVolcEngine, &volcengine.Adaptor{}, "volcengine"},
+		{constant.APITypeXai, &xai.Adaptor{}, "xai"},
+		{constant.APITypeCoze, &coze.Adaptor{}, "coze"},
+		{constant.APITypeJimeng, &jimeng.Adaptor{}, "jimeng"},
+		{constant.APITypeMoonshot, &moonshot.Adaptor{}, "moonshot"},
+		{constant.APITypeSubmodel, &submodel.Adaptor{}, "submodel"},
+		{constant.APITypePaLM, &palm.Adaptor{}, "palm"},
+		// OpenRouter 和 Xinference 使用 OpenAI adaptor
+		{constant.APITypeOpenRouter, &openai.Adaptor{}, "openrouter"},
+		{constant.APITypeXinference, &openai.Adaptor{}, "xinference"},
+	}
+	
+	registeredCount := 0
+	for _, ch := range channels {
+		plugin := NewBaseChannelPlugin(
+			ch.adaptor,
+			ch.name,
+			"1.0.0",
+			100, // 默认优先级
+		)
+		
+		if err := registry.RegisterChannel(ch.channelType, plugin); err != nil {
+			common.SysError("Failed to register channel plugin: " + ch.name + ", error: " + err.Error())
+		} else {
+			registeredCount++
+		}
+	}
+	
+	common.SysLog(fmt.Sprintf("Registered %d channel plugins", registeredCount))
+}
+

+ 186 - 0
plugins/hooks/content_filter/content_filter_hook.go

@@ -0,0 +1,186 @@
+package content_filter
+
+import (
+	"encoding/json"
+	"strings"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/core/interfaces"
+)
+
+// ContentFilterHook 内容过滤Hook
+// 在响应返回前过滤敏感内容
+type ContentFilterHook struct {
+	enabled           bool
+	priority          int
+	sensitiveWords    []string
+	filterNSFW        bool
+	filterPolitical   bool
+	replacementText   string
+}
+
+// NewContentFilterHook 创建ContentFilterHook实例
+func NewContentFilterHook(config map[string]interface{}) *ContentFilterHook {
+	hook := &ContentFilterHook{
+		enabled:         true,
+		priority:        100, // 高优先级,最后执行
+		sensitiveWords:  []string{},
+		filterNSFW:      true,
+		filterPolitical: false,
+		replacementText: "[已过滤]",
+	}
+	
+	if enabled, ok := config["enabled"].(bool); ok {
+		hook.enabled = enabled
+	}
+	
+	if priority, ok := config["priority"].(int); ok {
+		hook.priority = priority
+	}
+	
+	if filterNSFW, ok := config["filter_nsfw"].(bool); ok {
+		hook.filterNSFW = filterNSFW
+	}
+	
+	if filterPolitical, ok := config["filter_political"].(bool); ok {
+		hook.filterPolitical = filterPolitical
+	}
+	
+	if words, ok := config["sensitive_words"].([]interface{}); ok {
+		for _, word := range words {
+			if w, ok := word.(string); ok {
+				hook.sensitiveWords = append(hook.sensitiveWords, w)
+			}
+		}
+	}
+	
+	return hook
+}
+
+// Name 返回Hook名称
+func (h *ContentFilterHook) Name() string {
+	return "content_filter"
+}
+
+// Priority 返回优先级
+func (h *ContentFilterHook) Priority() int {
+	return h.priority
+}
+
+// Enabled 返回是否启用
+func (h *ContentFilterHook) Enabled() bool {
+	return h.enabled
+}
+
+// OnBeforeRequest 请求前处理(不需要处理)
+func (h *ContentFilterHook) OnBeforeRequest(ctx *interfaces.HookContext) error {
+	return nil
+}
+
+// OnAfterResponse 响应后处理 - 过滤内容
+func (h *ContentFilterHook) OnAfterResponse(ctx *interfaces.HookContext) error {
+	if !h.Enabled() {
+		return nil
+	}
+	
+	// 只处理chat completion响应
+	if !strings.Contains(ctx.Request.URL.Path, "chat/completions") {
+		return nil
+	}
+	
+	// 如果没有响应体,跳过
+	if len(ctx.ResponseBody) == 0 {
+		return nil
+	}
+	
+	// 解析响应
+	var response map[string]interface{}
+	if err := json.Unmarshal(ctx.ResponseBody, &response); err != nil {
+		return nil // 忽略解析错误
+	}
+	
+	// 过滤内容
+	filtered := h.filterResponse(response)
+	
+	// 如果内容被修改,更新响应体
+	if filtered {
+		modifiedBody, err := json.Marshal(response)
+		if err != nil {
+			return err
+		}
+		ctx.ResponseBody = modifiedBody
+		
+		// 记录过滤事件
+		ctx.Data["content_filtered"] = true
+		common.SysLog("Content filter applied to response")
+	}
+	
+	return nil
+}
+
+// OnError 错误处理
+func (h *ContentFilterHook) OnError(ctx *interfaces.HookContext, err error) error {
+	return nil
+}
+
+// filterResponse 过滤响应内容
+func (h *ContentFilterHook) filterResponse(response map[string]interface{}) bool {
+	modified := false
+	
+	// 获取choices数组
+	choices, ok := response["choices"].([]interface{})
+	if !ok {
+		return false
+	}
+	
+	// 遍历每个choice
+	for _, choice := range choices {
+		choiceMap, ok := choice.(map[string]interface{})
+		if !ok {
+			continue
+		}
+		
+		// 获取message
+		message, ok := choiceMap["message"].(map[string]interface{})
+		if !ok {
+			continue
+		}
+		
+		// 获取content
+		content, ok := message["content"].(string)
+		if !ok {
+			continue
+		}
+		
+		// 过滤内容
+		filteredContent := h.filterText(content)
+		
+		// 如果内容被修改
+		if filteredContent != content {
+			message["content"] = filteredContent
+			modified = true
+		}
+	}
+	
+	return modified
+}
+
+// filterText 过滤文本内容
+func (h *ContentFilterHook) filterText(text string) string {
+	filtered := text
+	
+	// 过滤敏感词
+	for _, word := range h.sensitiveWords {
+		if strings.Contains(filtered, word) {
+			filtered = strings.ReplaceAll(filtered, word, h.replacementText)
+		}
+	}
+	
+	// TODO: 实现更复杂的过滤逻辑
+	// - NSFW内容检测
+	// - 政治敏感内容检测
+	// - 使用AI模型进行内容分类
+	
+	return filtered
+}
+

+ 39 - 0
plugins/hooks/content_filter/init.go

@@ -0,0 +1,39 @@
+package content_filter
+
+import (
+	"os"
+	"strings"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/core/registry"
+)
+
+func init() {
+	// 从环境变量读取配置
+	config := map[string]interface{}{
+		"enabled":          os.Getenv("CONTENT_FILTER_ENABLED") == "true",
+		"priority":         100,
+		"filter_nsfw":      os.Getenv("CONTENT_FILTER_NSFW") != "false",
+		"filter_political": os.Getenv("CONTENT_FILTER_POLITICAL") == "true",
+	}
+	
+	// 读取敏感词列表
+	if wordsEnv := os.Getenv("CONTENT_FILTER_WORDS"); wordsEnv != "" {
+		words := strings.Split(wordsEnv, ",")
+		config["sensitive_words"] = words
+	}
+	
+	// 创建并注册Hook
+	hook := NewContentFilterHook(config)
+	
+	if err := registry.RegisterHook(hook); err != nil {
+		common.SysError("Failed to register content_filter hook: " + err.Error())
+	} else {
+		if hook.Enabled() {
+			common.SysLog("Content filter hook registered and enabled")
+		} else {
+			common.SysLog("Content filter hook registered but disabled")
+		}
+	}
+}
+

+ 39 - 0
plugins/hooks/web_search/init.go

@@ -0,0 +1,39 @@
+package web_search
+
+import (
+	"os"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/core/registry"
+)
+
+func init() {
+	// 从环境变量读取配置
+	config := map[string]interface{}{
+		"enabled":  os.Getenv("WEB_SEARCH_ENABLED") == "true",
+		"api_key":  os.Getenv("WEB_SEARCH_API_KEY"),
+		"provider": getEnvOrDefault("WEB_SEARCH_PROVIDER", "google"),
+		"priority": 50,
+	}
+	
+	// 创建并注册Hook
+	hook := NewWebSearchHook(config)
+	
+	if err := registry.RegisterHook(hook); err != nil {
+		common.SysError("Failed to register web_search hook: " + err.Error())
+	} else {
+		if hook.Enabled() {
+			common.SysLog("Web search hook registered and enabled")
+		} else {
+			common.SysLog("Web search hook registered but disabled (missing API key or not enabled)")
+		}
+	}
+}
+
+func getEnvOrDefault(key, defaultValue string) string {
+	if value := os.Getenv(key); value != "" {
+		return value
+	}
+	return defaultValue
+}
+

+ 281 - 0
plugins/hooks/web_search/web_search_hook.go

@@ -0,0 +1,281 @@
+package web_search
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"strings"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/core/interfaces"
+)
+
+// WebSearchHook 联网搜索Hook插件
+// 在请求发送前检测是否需要联网搜索,如果需要则调用搜索API并将结果注入到请求中
+type WebSearchHook struct {
+	enabled  bool
+	priority int
+	apiKey   string
+	provider string // google, bing, etc
+}
+
+// NewWebSearchHook 创建WebSearchHook实例
+func NewWebSearchHook(config map[string]interface{}) *WebSearchHook {
+	hook := &WebSearchHook{
+		enabled:  true,
+		priority: 50, // 中等优先级
+		provider: "google",
+	}
+	
+	if apiKey, ok := config["api_key"].(string); ok {
+		hook.apiKey = apiKey
+	}
+	
+	if provider, ok := config["provider"].(string); ok {
+		hook.provider = provider
+	}
+	
+	if priority, ok := config["priority"].(int); ok {
+		hook.priority = priority
+	}
+	
+	if enabled, ok := config["enabled"].(bool); ok {
+		hook.enabled = enabled
+	}
+	
+	return hook
+}
+
+// Name 返回Hook名称
+func (h *WebSearchHook) Name() string {
+	return "web_search"
+}
+
+// Priority 返回优先级
+func (h *WebSearchHook) Priority() int {
+	return h.priority
+}
+
+// Enabled 返回是否启用
+func (h *WebSearchHook) Enabled() bool {
+	return h.enabled && h.apiKey != ""
+}
+
+// OnBeforeRequest 请求前处理
+func (h *WebSearchHook) OnBeforeRequest(ctx *interfaces.HookContext) error {
+	if !h.Enabled() {
+		return nil
+	}
+	
+	// 只处理chat completion请求
+	if !strings.Contains(ctx.Request.URL.Path, "chat/completions") {
+		return nil
+	}
+	
+	// 检查请求体中是否包含搜索关键词
+	if len(ctx.RequestBody) == 0 {
+		return nil
+	}
+	
+	// 解析请求体
+	var requestData map[string]interface{}
+	if err := json.Unmarshal(ctx.RequestBody, &requestData); err != nil {
+		return nil // 忽略解析错误
+	}
+	
+	// 检查是否需要搜索(简单示例:检查最后一条消息是否包含 [search] 标记)
+	if !h.shouldSearch(requestData) {
+		return nil
+	}
+	
+	// 执行搜索
+	searchQuery := h.extractSearchQuery(requestData)
+	if searchQuery == "" {
+		return nil
+	}
+	
+	common.SysLog(fmt.Sprintf("Web search triggered for query: %s", searchQuery))
+	
+	// 调用搜索API
+	searchResults, err := h.performSearch(searchQuery)
+	if err != nil {
+		common.SysError(fmt.Sprintf("Web search failed: %v", err))
+		return nil // 不中断请求,只记录错误
+	}
+	
+	// 将搜索结果注入到请求中
+	h.injectSearchResults(requestData, searchResults)
+	
+	// 更新请求体
+	modifiedBody, err := json.Marshal(requestData)
+	if err != nil {
+		return err
+	}
+	
+	ctx.RequestBody = modifiedBody
+	
+	// 存储到Data中供后续使用
+	ctx.Data["web_search_performed"] = true
+	ctx.Data["web_search_query"] = searchQuery
+	
+	return nil
+}
+
+// OnAfterResponse 响应后处理
+func (h *WebSearchHook) OnAfterResponse(ctx *interfaces.HookContext) error {
+	// 可以在这里记录搜索使用情况等
+	if performed, ok := ctx.Data["web_search_performed"].(bool); ok && performed {
+		query := ctx.Data["web_search_query"].(string)
+		common.SysLog(fmt.Sprintf("Web search completed for query: %s", query))
+	}
+	return nil
+}
+
+// OnError 错误处理
+func (h *WebSearchHook) OnError(ctx *interfaces.HookContext, err error) error {
+	// 记录错误但不影响主流程
+	if performed, ok := ctx.Data["web_search_performed"].(bool); ok && performed {
+		common.SysError(fmt.Sprintf("Request failed after web search: %v", err))
+	}
+	return nil
+}
+
+// shouldSearch 判断是否需要搜索
+func (h *WebSearchHook) shouldSearch(requestData map[string]interface{}) bool {
+	messages, ok := requestData["messages"].([]interface{})
+	if !ok || len(messages) == 0 {
+		return false
+	}
+	
+	// 检查最后一条消息
+	lastMessage, ok := messages[len(messages)-1].(map[string]interface{})
+	if !ok {
+		return false
+	}
+	
+	content, ok := lastMessage["content"].(string)
+	if !ok {
+		return false
+	}
+	
+	// 简单示例:检查是否包含 [search] 或 [联网] 标记
+	return strings.Contains(content, "[search]") || 
+	       strings.Contains(content, "[联网]") ||
+	       strings.Contains(content, "[web]")
+}
+
+// extractSearchQuery 提取搜索查询
+func (h *WebSearchHook) extractSearchQuery(requestData map[string]interface{}) string {
+	messages, ok := requestData["messages"].([]interface{})
+	if !ok || len(messages) == 0 {
+		return ""
+	}
+	
+	lastMessage, ok := messages[len(messages)-1].(map[string]interface{})
+	if !ok {
+		return ""
+	}
+	
+	content, ok := lastMessage["content"].(string)
+	if !ok {
+		return ""
+	}
+	
+	// 移除标记,保留实际查询内容
+	query := strings.ReplaceAll(content, "[search]", "")
+	query = strings.ReplaceAll(query, "[联网]", "")
+	query = strings.ReplaceAll(query, "[web]", "")
+	query = strings.TrimSpace(query)
+	
+	return query
+}
+
+// performSearch 执行搜索
+func (h *WebSearchHook) performSearch(query string) (string, error) {
+	// 这里是示例实现,实际应该调用真实的搜索API
+	// 例如:Google Custom Search API, Bing Search API等
+	
+	if h.apiKey == "" {
+		return "", fmt.Errorf("search API key not configured")
+	}
+	
+	// 示例:返回模拟结果
+	// 实际实现需要调用真实API
+	return h.mockSearch(query)
+}
+
+// mockSearch 模拟搜索(示例)
+func (h *WebSearchHook) mockSearch(query string) (string, error) {
+	// 这只是一个示例实现
+	// 实际应该调用真实的搜索API
+	
+	common.SysLog(fmt.Sprintf("[Mock] Searching for: %s", query))
+	
+	// 返回模拟的搜索结果
+	return fmt.Sprintf("搜索结果 (模拟):关于 '%s' 的最新信息...", query), nil
+}
+
+// realSearch 真实搜索实现示例(需要配置API)
+func (h *WebSearchHook) realSearch(query string) (string, error) {
+	// 示例:使用Google Custom Search API
+	url := fmt.Sprintf("https://www.googleapis.com/customsearch/v1?key=%s&cx=YOUR_CX&q=%s", 
+		h.apiKey, query)
+	
+	resp, err := http.Get(url)
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+	
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+	
+	// 解析搜索结果
+	var result map[string]interface{}
+	if err := json.Unmarshal(body, &result); err != nil {
+		return "", err
+	}
+	
+	// 提取搜索结果摘要
+	// 这里需要根据实际API响应格式处理
+	return string(body), nil
+}
+
+// injectSearchResults 将搜索结果注入到请求中
+func (h *WebSearchHook) injectSearchResults(requestData map[string]interface{}, results string) {
+	messages, ok := requestData["messages"].([]interface{})
+	if !ok {
+		return
+	}
+	
+	// 在用户消息前插入系统消息,包含搜索结果
+	systemMessage := map[string]interface{}{
+		"role": "system",
+		"content": fmt.Sprintf("以下是针对用户查询的最新搜索结果:\n\n%s\n\n请基于这些信息回答用户的问题。", results),
+	}
+	
+	// 插入到消息列表的适当位置
+	updatedMessages := make([]interface{}, 0, len(messages)+1)
+	
+	// 如果第一条是系统消息,在其后插入
+	if len(messages) > 0 {
+		if firstMsg, ok := messages[0].(map[string]interface{}); ok {
+			if role, ok := firstMsg["role"].(string); ok && role == "system" {
+				updatedMessages = append(updatedMessages, messages[0])
+				updatedMessages = append(updatedMessages, systemMessage)
+				updatedMessages = append(updatedMessages, messages[1:]...)
+				requestData["messages"] = updatedMessages
+				return
+			}
+		}
+	}
+	
+	// 否则插入到开头
+	updatedMessages = append(updatedMessages, systemMessage)
+	updatedMessages = append(updatedMessages, messages...)
+	requestData["messages"] = updatedMessages
+}
+

+ 136 - 0
relay/hooks/chain.go

@@ -0,0 +1,136 @@
+package hooks
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/core/interfaces"
+	"github.com/QuantumNous/new-api/core/registry"
+)
+
+var (
+	// 全局Hook链实例(单例)
+	globalChain     *HookChain
+	globalChainOnce sync.Once
+)
+
+// HookChain Hook执行链
+type HookChain struct {
+	hooks []interfaces.RelayHook
+	mu    sync.RWMutex
+}
+
+// GetGlobalChain 获取全局Hook链实例
+func GetGlobalChain() *HookChain {
+	globalChainOnce.Do(func() {
+		globalChain = &HookChain{
+			hooks: make([]interfaces.RelayHook, 0),
+		}
+		// 从注册中心加载hooks
+		globalChain.LoadHooks()
+	})
+	return globalChain
+}
+
+// LoadHooks 从注册中心加载hooks
+func (c *HookChain) LoadHooks() {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	
+	c.hooks = registry.ListHooks()
+	common.SysLog(fmt.Sprintf("Loaded %d enabled hooks", len(c.hooks)))
+}
+
+// ReloadHooks 重新加载hooks
+func (c *HookChain) ReloadHooks() {
+	c.LoadHooks()
+	common.SysLog("Hooks reloaded")
+}
+
+// ExecuteBeforeRequest 执行所有BeforeRequest钩子
+func (c *HookChain) ExecuteBeforeRequest(ctx *interfaces.HookContext) error {
+	c.mu.RLock()
+	hooks := c.hooks
+	c.mu.RUnlock()
+	
+	for _, hook := range hooks {
+		if !hook.Enabled() {
+			continue
+		}
+		
+		if ctx.ShouldSkip {
+			break
+		}
+		
+		if err := hook.OnBeforeRequest(ctx); err != nil {
+			common.SysError(fmt.Sprintf("Hook %s OnBeforeRequest error: %v", hook.Name(), err))
+			return fmt.Errorf("hook %s failed: %w", hook.Name(), err)
+		}
+	}
+	
+	return nil
+}
+
+// ExecuteAfterResponse 执行所有AfterResponse钩子
+func (c *HookChain) ExecuteAfterResponse(ctx *interfaces.HookContext) error {
+	c.mu.RLock()
+	hooks := c.hooks
+	c.mu.RUnlock()
+	
+	for _, hook := range hooks {
+		if !hook.Enabled() {
+			continue
+		}
+		
+		if ctx.ShouldSkip {
+			break
+		}
+		
+		if err := hook.OnAfterResponse(ctx); err != nil {
+			common.SysError(fmt.Sprintf("Hook %s OnAfterResponse error: %v", hook.Name(), err))
+			return fmt.Errorf("hook %s failed: %w", hook.Name(), err)
+		}
+	}
+	
+	return nil
+}
+
+// ExecuteOnError 执行所有OnError钩子
+func (c *HookChain) ExecuteOnError(ctx *interfaces.HookContext, err error) error {
+	c.mu.RLock()
+	hooks := c.hooks
+	c.mu.RUnlock()
+	
+	for _, hook := range hooks {
+		if !hook.Enabled() {
+			continue
+		}
+		
+		if hookErr := hook.OnError(ctx, err); hookErr != nil {
+			common.SysError(fmt.Sprintf("Hook %s OnError failed: %v", hook.Name(), hookErr))
+			// OnError钩子的错误不会中断执行
+		}
+	}
+	
+	return err
+}
+
+// GetHooks 获取当前hook列表
+func (c *HookChain) GetHooks() []interfaces.RelayHook {
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+	
+	hooks := make([]interfaces.RelayHook, len(c.hooks))
+	copy(hooks, c.hooks)
+	return hooks
+}
+
+// Count 返回hook数量
+func (c *HookChain) Count() int {
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+	
+	return len(c.hooks)
+}
+

+ 212 - 0
relay/hooks/chain_test.go

@@ -0,0 +1,212 @@
+package hooks
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/QuantumNous/new-api/core/interfaces"
+	"github.com/QuantumNous/new-api/core/registry"
+)
+
+// Mock Hook实现
+type testHook struct {
+	name              string
+	priority          int
+	enabled           bool
+	beforeCalled      bool
+	afterCalled       bool
+	errorCalled       bool
+	shouldReturnError bool
+}
+
+func (h *testHook) Name() string     { return h.name }
+func (h *testHook) Priority() int    { return h.priority }
+func (h *testHook) Enabled() bool    { return h.enabled }
+
+func (h *testHook) OnBeforeRequest(ctx *interfaces.HookContext) error {
+	h.beforeCalled = true
+	if h.shouldReturnError {
+		return errors.New("test error")
+	}
+	return nil
+}
+
+func (h *testHook) OnAfterResponse(ctx *interfaces.HookContext) error {
+	h.afterCalled = true
+	if h.shouldReturnError {
+		return errors.New("test error")
+	}
+	return nil
+}
+
+func (h *testHook) OnError(ctx *interfaces.HookContext, err error) error {
+	h.errorCalled = true
+	return nil
+}
+
+func TestHookChainExecution(t *testing.T) {
+	// 创建测试hooks
+	hook1 := &testHook{name: "hook1", priority: 100, enabled: true}
+	hook2 := &testHook{name: "hook2", priority: 50, enabled: true}
+	hook3 := &testHook{name: "hook3", priority: 75, enabled: false} // disabled
+	
+	// 创建Hook链
+	chain := &HookChain{
+		hooks: []interfaces.RelayHook{hook1, hook2, hook3},
+	}
+	
+	// 创建测试上下文
+	ctx := &interfaces.HookContext{
+		Data: make(map[string]interface{}),
+	}
+	
+	// 测试ExecuteBeforeRequest
+	if err := chain.ExecuteBeforeRequest(ctx); err != nil {
+		t.Errorf("ExecuteBeforeRequest failed: %v", err)
+	}
+	
+	// 检查enabled的hooks是否被调用
+	if !hook1.beforeCalled {
+		t.Error("hook1 OnBeforeRequest should be called")
+	}
+	
+	if !hook2.beforeCalled {
+		t.Error("hook2 OnBeforeRequest should be called")
+	}
+	
+	// disabled的hook不应该被调用
+	if hook3.beforeCalled {
+		t.Error("hook3 OnBeforeRequest should not be called (disabled)")
+	}
+	
+	// 测试ExecuteAfterResponse
+	if err := chain.ExecuteAfterResponse(ctx); err != nil {
+		t.Errorf("ExecuteAfterResponse failed: %v", err)
+	}
+	
+	if !hook1.afterCalled {
+		t.Error("hook1 OnAfterResponse should be called")
+	}
+	
+	if !hook2.afterCalled {
+		t.Error("hook2 OnAfterResponse should be called")
+	}
+	
+	// 测试ExecuteOnError
+	testErr := errors.New("test error")
+	if err := chain.ExecuteOnError(ctx, testErr); err != testErr {
+		t.Error("ExecuteOnError should return original error")
+	}
+	
+	if !hook1.errorCalled {
+		t.Error("hook1 OnError should be called")
+	}
+}
+
+func TestHookChainErrorHandling(t *testing.T) {
+	// 创建会返回错误的hook
+	errorHook := &testHook{
+		name:              "error_hook",
+		priority:          100,
+		enabled:           true,
+		shouldReturnError: true,
+	}
+	
+	chain := &HookChain{
+		hooks: []interfaces.RelayHook{errorHook},
+	}
+	
+	ctx := &interfaces.HookContext{
+		Data: make(map[string]interface{}),
+	}
+	
+	// 测试错误处理
+	if err := chain.ExecuteBeforeRequest(ctx); err == nil {
+		t.Error("Expected error from ExecuteBeforeRequest")
+	}
+}
+
+func TestHookChainShouldSkip(t *testing.T) {
+	hook1 := &testHook{name: "hook1", priority: 100, enabled: true}
+	hook2 := &testHook{name: "hook2", priority: 50, enabled: true}
+	
+	chain := &HookChain{
+		hooks: []interfaces.RelayHook{hook1, hook2},
+	}
+	
+	ctx := &interfaces.HookContext{
+		Data:       make(map[string]interface{}),
+		ShouldSkip: true, // 设置跳过标记
+	}
+	
+	// 执行
+	if err := chain.ExecuteBeforeRequest(ctx); err != nil {
+		t.Errorf("ExecuteBeforeRequest failed: %v", err)
+	}
+	
+	// 由于ShouldSkip为true,hooks不应该被调用
+	// 注意:当前实现在第一个hook执行后才会检查ShouldSkip
+	// 所以hook1会被调用,但hook2不会
+}
+
+func TestHookChainCount(t *testing.T) {
+	hook1 := &testHook{name: "hook1", priority: 100, enabled: true}
+	hook2 := &testHook{name: "hook2", priority: 50, enabled: true}
+	
+	chain := &HookChain{
+		hooks: []interfaces.RelayHook{hook1, hook2},
+	}
+	
+	if count := chain.Count(); count != 2 {
+		t.Errorf("Expected count 2, got %d", count)
+	}
+}
+
+func TestHookChainGetHooks(t *testing.T) {
+	hook1 := &testHook{name: "hook1", priority: 100, enabled: true}
+	hook2 := &testHook{name: "hook2", priority: 50, enabled: true}
+	
+	chain := &HookChain{
+		hooks: []interfaces.RelayHook{hook1, hook2},
+	}
+	
+	hooks := chain.GetHooks()
+	if len(hooks) != 2 {
+		t.Errorf("Expected 2 hooks, got %d", len(hooks))
+	}
+}
+
+func TestGlobalChain(t *testing.T) {
+	// 测试全局链的单例模式
+	chain1 := GetGlobalChain()
+	chain2 := GetGlobalChain()
+	
+	if chain1 != chain2 {
+		t.Error("GetGlobalChain should return the same instance")
+	}
+}
+
+// 集成测试:测试完整的注册和执行流程
+func TestIntegration(t *testing.T) {
+	// 注册测试hook
+	testHook := &testHook{
+		name:     "integration_test_hook",
+		priority: 100,
+		enabled:  true,
+	}
+	
+	if err := registry.RegisterHook(testHook); err != nil {
+		// 如果已注册,跳过错误
+		t.Logf("Hook already registered (expected in some cases): %v", err)
+	}
+	
+	// 创建新的hook链并加载
+	chain := &HookChain{hooks: make([]interfaces.RelayHook, 0)}
+	chain.LoadHooks()
+	
+	// 检查是否加载了hooks
+	if chain.Count() == 0 {
+		t.Log("No hooks loaded (expected if registry is clean)")
+	}
+}
+

+ 79 - 0
relay/hooks/context_builder.go

@@ -0,0 +1,79 @@
+package hooks
+
+import (
+	"net/http"
+
+	"github.com/QuantumNous/new-api/common"
+	"github.com/QuantumNous/new-api/constant"
+	"github.com/QuantumNous/new-api/core/interfaces"
+	"github.com/gin-gonic/gin"
+)
+
+// BuildHookContext 从Gin Context构建HookContext
+func BuildHookContext(c *gin.Context) *interfaces.HookContext {
+	ctx := &interfaces.HookContext{
+		GinContext: c,
+		Request:    c.Request,
+		Data:       make(map[string]interface{}),
+	}
+	
+	// 提取Channel信息
+	if channelID, ok := common.GetContextKey(c, constant.ContextKeyChannelId); ok {
+		if id, ok := channelID.(int); ok {
+			ctx.ChannelID = id
+		}
+	}
+	
+	if channelType, ok := common.GetContextKey(c, constant.ContextKeyChannelType); ok {
+		if t, ok := channelType.(int); ok {
+			ctx.ChannelType = t
+		}
+	}
+	
+	if channelName, ok := common.GetContextKey(c, constant.ContextKeyChannelName); ok {
+		if name, ok := channelName.(string); ok {
+			ctx.ChannelName = name
+		}
+	}
+	
+	// 提取Model信息
+	if originalModel, ok := common.GetContextKey(c, constant.ContextKeyOriginalModel); ok {
+		if m, ok := originalModel.(string); ok {
+			ctx.OriginalModel = m
+			ctx.Model = m // 使用OriginalModel作为Model
+		}
+	}
+	
+	// 提取User信息
+	if userID, ok := common.GetContextKey(c, constant.ContextKeyUserId); ok {
+		if id, ok := userID.(int); ok {
+			ctx.UserID = id
+		}
+	}
+	
+	if tokenID, ok := common.GetContextKey(c, constant.ContextKeyTokenId); ok {
+		if id, ok := tokenID.(int); ok {
+			ctx.TokenID = id
+		}
+	}
+	
+	if group, ok := common.GetContextKey(c, constant.ContextKeyUsingGroup); ok {
+		if g, ok := group.(string); ok {
+			ctx.Group = g
+		}
+	}
+	
+	return ctx
+}
+
+// UpdateHookContextWithResponse 更新HookContext的Response信息
+func UpdateHookContextWithResponse(ctx *interfaces.HookContext, resp *http.Response, body []byte) {
+	ctx.Response = resp
+	ctx.ResponseBody = body
+}
+
+// UpdateHookContextWithRequest 更新HookContext的Request信息
+func UpdateHookContextWithRequest(ctx *interfaces.HookContext, body []byte) {
+	ctx.RequestBody = body
+}
+

+ 14 - 0
relay/relay_adaptor.go

@@ -4,6 +4,8 @@ import (
 	"strconv"
 
 	"github.com/QuantumNous/new-api/constant"
+	"github.com/QuantumNous/new-api/core/registry"
+	pluginchannels "github.com/QuantumNous/new-api/plugins/channels"
 	"github.com/QuantumNous/new-api/relay/channel"
 	"github.com/QuantumNous/new-api/relay/channel/ali"
 	"github.com/QuantumNous/new-api/relay/channel/aws"
@@ -44,7 +46,19 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
+// GetAdaptor 获取Channel适配器(优先从插件注册中心获取,保持向后兼容)
 func GetAdaptor(apiType int) channel.Adaptor {
+	// 优先从插件注册中心获取
+	if plugin, err := registry.GetChannel(apiType); err == nil {
+		// 如果是BaseChannelPlugin,提取内部的Adaptor
+		if basePlugin, ok := plugin.(*pluginchannels.BaseChannelPlugin); ok {
+			return basePlugin.GetAdaptor()
+		}
+		// 否则直接返回plugin(它也实现了Adaptor接口)
+		return plugin
+	}
+	
+	// 向后兼容:如果注册中心没有,使用原有的硬编码方式
 	switch apiType {
 	case constant.APITypeAli:
 		return &ali.Adaptor{}