Skip to content

4. 渐进式加载

4.1 三阶段加载

typescript
class ProgressiveSkillLoader {
  // 阶段 1: 启动时加载元数据
  async loadMetadata(): Promise<SkillMetadata[]> {
    const skills = await this.scanSkills();

    return skills.map(s => ({
      name: s.name,
      description: s.description,
      triggers: s.triggers
      // 不加载完整内容
    }));

    // Token 消耗: ~100 tokens per skill
  }

  // 阶段 2: 检测时加载 frontmatter + 简介
  async loadSummary(skillName: string): Promise<SkillSummary> {
    const content = await this.readSkill(skillName);

    // 只提取前几段
    const summary = this.extractSummary(content);

    return {
      name: skillName,
      summary,
      sections: this.extractSectionTitles(content)
    };

    // Token 消耗: ~300 tokens per skill
  }

  // 阶段 3: 使用时加载完整内容
  async loadFull(skillName: string): Promise<Skill> {
    const content = await this.readSkill(skillName);

    // 加载完整内容
    return {
      name: skillName,
      content,
      references: await this.loadReferences(skillName)
    };

    // Token 消耗: ~2000 tokens per skill
  }

  // 提取摘要
  private extractSummary(content: string): string {
    // 提取 "When to Use" 和 "Prerequisites" 部分
    const sections = ['When to Use', 'Prerequisites'];
    const summary = [];

    for (const section of sections) {
      const regex = new RegExp(`## ${section}\\n([\\s\\S]*?)(?=## |$)`);
      const match = content.match(regex);
      if (match) {
        summary.push(`## ${section}\n${match[1].trim()}`);
      }
    }

    return summary.join('\n\n');
  }

  // 提取章节标题
  private extractSectionTitles(content: string): string[] {
    const matches = content.matchAll(/^## (.+)$/gm);
    return [...matches].map(m => m[1]);
  }
}

4.2 按需加载引用文档

typescript
class ReferenceLoader {
  // 解析引用链接
  parseReferences(skillContent: string): Reference[] {
    const references: Reference[] = [];

    // 匹配 [text](./references/file.md) 格式
    const regex = /\[([^\]]+)\]\(\.\/references\/([^)]+)\)/g;
    const matches = skillContent.matchAll(regex);

    for (const match of matches) {
      references.push({
        title: match[1],
        path: match[2],
        loaded: false
      });
    }

    return references;
  }

  // 按需加载引用
  async loadReference(skillName: string, refPath: string): Promise<string> {
    const fullPath = path.join(
      this.skillsDir,
      skillName,
      'references',
      refPath
    );

    if (!await fs.exists(fullPath)) {
      return `Reference not found: ${refPath}`;
    }

    return await fs.readFile(fullPath, 'utf-8');
  }

  // 智能加载:只加载被提及的引用
  async loadRelevantReferences(
    skillName: string,
    conversation: string[]
  ): Promise<Map<string, string>> {
    const skill = await this.loadSkill(skillName);
    const references = this.parseReferences(skill.content);
    const loaded = new Map<string, string>();

    for (const ref of references) {
      // 检查对话中是否提到这个引用
      const mentioned = conversation.some(msg =>
        msg.toLowerCase().includes(ref.title.toLowerCase())
      );

      if (mentioned) {
        const content = await this.loadReference(skillName, ref.path);
        loaded.set(ref.title, content);
      }
    }

    return loaded;
  }
}

前端面试知识库