本文分享如何借鉴 OpenClaw、LangChain 等开源框架的架构设计思想,在 SkillLite 项目中实现核心模块轻量化与扩展模块可插拔,提升系统的可扩展性与可维护性。


一、背景与动机

在构建 AI Agent 执行引擎时,我们面临一个经典问题:如何在不牺牲灵活性的前提下,保持核心框架的简洁与稳定?

早期版本中,所有工具(文件操作、记忆检索、命令执行等)的逻辑都硬编码在单一模块里,通过冗长的 if-else 进行路由。这带来几个痛点:

  • 核心臃肿:每增加一个工具,都要修改核心逻辑,违反开闭原则

  • 难以测试:工具与编排逻辑耦合,单元测试成本高

  • 扩展困难:第三方想接入自定义工具,缺乏统一入口

在研究了 OpenClaw 的三层架构(Gateway / Channel / LLM)及其 Provider 插件系统Channel 适配器模式 后,我们决定将类似思想引入 SkillLite:核心只负责编排与注册,具体能力由扩展模块按需注入


二、OpenClaw 等框架的核心设计启示

2.1 OpenClaw 的三层架构

OpenClaw 将系统分为三层,每层职责清晰:

| 层级 | 职责 | 扩展方式 |

|------|------|----------|

| Gateway | 会话管理、消息调度、权限控制 | 核心稳定,极少改动 |

| Channel | 平台适配(WhatsApp、Telegram 等)、消息路由 | 新增平台 = 新增 Channel 适配器 |

| LLM | 模型接口、Tool Calling、流式响应 | Provider 插件系统,注册即用 |

关键启示:分层 + 注册表。核心层不关心具体实现,只通过接口与注册表与扩展交互。

2.2 Provider 插件系统的精髓

OpenClaw 的 LLM Provider 从硬编码 if-else 演进为插件系统:

// 旧设计:每加一个模型都要改核心代码

if (config.provider === 'anthropic') 
	return new AnthropicClient();

else if (config.provider === 'openai') 
	return new OpenAIClient();



// 新设计:统一接口 + 注册表

interface LLMProvider {

	name: string;

	chat(messages, options): AsyncIterator;

	supportTools(): boolean;

}

registry.register(new AnthropicProvider());

registry.register(new OpenAIProvider());

核心思想:定义统一接口,扩展通过注册表注入,核心代码零修改。

2.3 Channel 适配器模式

不同平台的消息格式各异,OpenClaw 通过 Adapter 模式 统一为 StandardMessage,Gateway 和 LLM 层只处理标准格式。新增平台只需实现 adaptMessage()sendMessage()


三、SkillLite 的架构设计

3.1 两层架构:系统层 + 用户层

我们将 SkillLite 抽象为两层:


┌─────────────────────────────────────────┐

│ System Layer (系统层) 					│

│ - ToolRegistry (工具注册表) 			│

│ - 内置工具按模块注册 (file/memory/command) │

│ - 直接访问 workspace					 │

└──────────────────┬──────────────────────┘

					│

					▼

┌──────────────────────────────────────────┐

│ User Layer (用户层) 						│

│ - Skills(可执行,作为工具供 LLM 调用) 		│

│ - 遵循 AgentSkills 协议 					│

└──────────────────────────────────────────┘

  • 系统层:提供 ToolRegistry 与内置扩展,负责编排与调度

  • 用户层:Skills 作为可执行工具,与内置工具一起供 LLM 调用

3.2 核心模块:纯框架层,零内置工具

核心模块 skilllite/core/ 只包含:

  • ToolRegistry:工具注册、查找、执行

  • AgenticLoop:LLM 调用与工具循环

  • ChatSession:会话、转录、记忆集成

  • PromptBuilder:提示词构建

关键设计:核心层不实现任何具体工具,只定义 register(name, schema, handler) 接口。所有内置工具都来自 extensions/

3.3 ToolRegistry:借鉴 OpenClaw 的注册表思想


class ToolRegistry:

"""工具注册表 - 统一注册与查找,替代硬编码 if-else 路由"""



	def register(self, name: str, schema: Dict, handler: Callable) -> None:

"""注册工具:名称、OpenAI 格式 schema、执行 handler"""

	self._tools[name] = ToolEntry(schema=schema, handler=handler)



	def get(self, name: str) -> Optional[ToolEntry]:

		"""按名称查找"""

		return self._tools.get(name)



	def execute(self, tool_name: str, tool_input: Dict) -> str:

		"""统一执行入口"""

		entry = self.get(tool_name)

		if not entry:

			return f"Error: No executor for tool: {tool_name}"

		return entry.handler(tool_input)

执行时只需 ToolRegistry.get(tool_name) 查找,与工具来源(file/memory/command/skill)无关。这与 OpenClaw 的 ProviderRegistry 思路一致。


四、扩展模块:按功能拆分的可插拔设计

4.1 extensions 目录结构


skilllite/

├── core/ # 纯框架层(无内置工具实现)

│ ├── tool_registry.py # ToolRegistry 实现

│ ├── loops.py # AgenticLoop,从 extensions.long_text 引入长文本处理

│ └── chat_session.py # 会话编排

├── extensions/ # 内置扩展(集中维护,通过 register_extensions 引入)

│ ├── __init__.py # register_extensions() 统一注册

│ ├── file.py # read_file, write_file, list_directory, file_exists

│ ├── command.py # run_command, preview_server

│ ├── memory.py # memory_search, memory_write, memory_list

│ └── long_text.py # 长文本截断与分段总结

└── builtin_tools.py # 底层实现(file/command 工具逻辑)

每个扩展模块只负责一类工具,通过 register(registry, ctx, executor) 向 ToolRegistry 注册。

4.2 统一注册入口


def register_extensions(

	registry,

	ctx: ExtensionsContext,

	enable_file_tools: bool = True,

	enable_memory_tools: bool = True,

	enable_command_tools: bool = True,

) -> None:

"""按需注册扩展工具到 registry"""

if enable_file_tools:

	file_tools.register(registry, ctx, executor)

if enable_command_tools:

	command_tools.register(registry, ctx, executor)

if enable_memory_tools:

	memory_tools.register(registry, ctx)

可配置开关:用户可选择性启用/禁用某类工具,进一步减轻核心负担。

4.3 扩展模块示例:file 与 long_text

file.py:只负责注册,逻辑委托给 builtin_tools


def register(registry, ctx, executor=None) -> None:

	for tool_def in get_file_tools():

		name = tool_def.get("function", {}).get("name", "")

	if name:

		registry.register(name, tool_def, executor)

long_text.py:独立的长文本处理策略,被 AgenticLoop 按需引入

  • 策略:head + tail(文章首尾最重要)

  • 超长工具结果自动分段总结,避免 context overflow

核心的 loops.pyfrom ..extensions.long_text import summarize_long_content,不关心具体实现细节。


五、核心轻量化与可扩展性收益

5.1 核心轻量化

| 维度 | 改进前 | 改进后 |

|------|--------|--------|

| 工具路由 | 硬编码 if-else,每加工具改核心 | ToolRegistry 统一查找,核心零修改 |

| 内置工具 | 散落在 chat_session 等模块 | 集中在 extensions/,按模块注册 |

| 依赖方向 | 核心依赖具体工具实现 | 核心只依赖 ToolRegistry 接口,extensions 依赖 core |

核心代码行数减少,职责更单一,符合「高内聚、低耦合」。

5.2 可扩展性提升

| 场景 | 实现方式 |

|------|----------|

| 新增内置工具 | 新建 extensions/xxx.py,实现 register(),在 register_extensions 中调用 |

| 第三方自定义工具 | 直接 registry.register(name, schema, handler),无需改 core |

| 禁用某类工具 | register_extensions(..., enable_command_tools=False) |

| 长文本策略可配置 | long_text 参数可经 env 或 SkillManager 注入(待实施) |

5.3 与 OpenClaw 的对照

| 设计点 | OpenClaw | SkillLite |

|--------|----------|-----------|

| 注册表 | ProviderRegistry、Channel 注册 | ToolRegistry |

| 适配器 | Channel 适配不同平台消息格式 | 扩展模块适配不同工具类型 |

| 分层 | Gateway / Channel / LLM | System Layer / User Layer + core / extensions |

| 插件化 | Provider 实现接口即注册 | 扩展实现 register() 即注册 |


六、实施经验与后续规划

6.1 已完成的架构优化

  • mcp/server.py 拆分为 handlers/security、handlers/executor、tools

  • init_deps.py 拆分为 audit、resolve、lock 子模块

  • ToolRegistry + extensions 替代硬编码工具路由

6.2 待实施的扩展增强

根据 FINAL_DESIGN.md,计划引入 ExtensionRegistry + enhance 模式,支持 Skills 扩展系统工具,进一步强化可扩展性。

6.3 架构健康度自评

| 维度 | 评分 | 说明 |

|------|------|------|

| 模块边界 | 4/5 | core 与 cli、extensions 分离清晰 |

| 职责单一 | 4/5 | ToolRegistry、AgenticLoop、ChatSession 分工明确 |

| 可扩展性 | 4/5 | 适配器模式、custom_tools、按需注册支持良好 |


七、总结

借鉴 OpenClaw 等框架的分层架构注册表模式适配器模式,我们在 SkillLite 中实现了:

  1. 核心轻量化:core 只负责编排与注册,不实现具体工具

  2. 扩展可插拔:extensions 按功能拆分,通过 register_extensions 统一注入

  3. 统一执行入口:ToolRegistry 提供 get / execute,与工具来源无关

  4. 可配置开关:按需启用/禁用某类扩展,减少不必要的依赖

这种设计让新增工具、接入第三方能力、调整策略都无需改动核心代码,显著提升了系统的可维护性与可扩展性。如果你也在构建 Agent 框架,不妨参考 OpenClaw 的架构思想,从「注册表 + 分层」入手,让核心保持稳定,让扩展自由生长。


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐