1000行代码实现极简版openclaw(附源码)(10)

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

09 - Skill 系统:可扩展架构 github 源码(欢迎star)

目标

实现可插拔的 Skill 系统,允许动态扩展功能。

核心概念

Skill = 一个功能模块,包含:

  • SKILL.md:描述文件
  • index.ts:工具实现

完整代码

创建 src/skills/loader.ts

import { Tool } from '../core/types.js';
import { readdirSync, existsSync, readFileSync } from 'fs';
import { join, resolve } from 'path';

export interface Skill { definition: any; tools: Tool[]; enabled: boolean; }

export class SkillLoader {
  private loadedSkills = new Map<string, Skill>();

  constructor(private skillsDir: string) {}

  async loadSkills(configs: any[] = []): Promise<Skill[]> {
    const skills: Skill[] = [];
    if (!existsSync(this.skillsDir)) return skills;

    const entries = readdirSync(this.skillsDir, { withFileTypes: true });
    
    for (const entry of entries) {
      if (!entry.isDirectory()) continue;
      const skillPath = join(this.skillsDir, entry.name);
      const skill = await this.loadSkill(skillPath);
      if (skill) {
        skills.push(skill);
        this.loadedSkills.set(skill.definition.name, skill);
      }
    }
    return skills;
  }

  private async loadSkill(skillPath: string): Promise<Skill | null> {
    const skillMdPath = join(skillPath, 'SKILL.md');
    if (!existsSync(skillMdPath)) return null;

    const definition = this.parseSkillMd(readFileSync(skillMdPath, 'utf-8'));
    if (!definition) return null;

    const tools = await this.loadSkillTools(skillPath, definition);
    return { definition, tools, enabled: true };
  }

  private parseSkillMd(content: string): any {
    const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
    if (!frontmatterMatch) return null;
    
    const yaml = frontmatterMatch[1];
    const definition: any = { tools: [] };
    
    const nameMatch = yaml.match(/^name:\s*(.+)$/m);
    if (nameMatch) definition.name = nameMatch[1].trim();
    
    return definition;
  }

  private async loadSkillTools(skillPath: string, definition: any): Promise<Tool[]> {
    const indexPath = join(skillPath, 'index.ts');
    if (existsSync(indexPath)) {
      try {
        const module = await import('file://' + resolve(indexPath));
        if (module.default && Array.isArray(module.default)) {
          return module.default;
        }
      } catch (e) {
        console.error(`[Skill] 加载失败 ${definition.name}:`, e);
      }
    }
    return [];
  }
}

示例 Skill

创建 skills/calculator/SKILL.md

---
name: calculator
description: 数学计算工具
tools:
  - name: calculate
    description: 计算数学表达式
---

创建 skills/calculator/index.ts

import { Tool } from '../../src/core/types.js';

const calculateTool: Tool = {
  name: 'calculate',
  description: '计算数学表达式',
  parameters: {
    expression: { type: 'string', description: '表达式', required: true },
  },
  execute: async ({ expression }) => {
    try {
      return String(eval(expression as string));
    } catch {
      return '计算错误';
    }
  },
};

export default [calculateTool];

关键点

  1. 约定优于配置:通过 SKILL.md 描述
  2. 动态导入:运行时加载
  3. 热插拔:可以动态启用/禁用

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lch丶lch

创作不易,赠我咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值