Chrome Skills重磅上线!浏览器秒变"龙虾助理",开发者必看

Chrome Skills重磅上线!浏览器秒变"龙虾助理",开发者必看

从开发者视角深度解析Chrome Skills功能,提供实战代码和最佳实践


导读

2026年4月,谷歌在Chrome浏览器中正式上线Skills功能,将OpenClaw(龙虾)的强大自动化能力深度集成到浏览器生态。

对于开发者来说,这不仅仅是一个新的功能,更是浏览器插件开发的新范式。本文将从技术实现、API设计、性能优化和最佳实践等角度,为开发者提供完整的Chrome Skills开发指南。


一、Chrome Skills技术架构

1.1 整体架构设计

Chrome Skills采用了现代化的分层架构:

typescript 复制代码
interface ChromeSkillsArchitecture {
  // 用户交互层
  ui: {
    sidebarPanel: SidebarUI,
    popup: PopupUI,
    omnibox: OmniboxIntegration,
    contextMenu: ContextMenuHandler
  },
  
  // 技能管理层
  skillManagement: {
    storage: SkillStorageManager,
    versionControl: SkillVersionManager,
    registry: SkillRegistry,
    permissionManager: PermissionManager
  },
  
  // 执行引擎层
  executionEngine: {
    geminiClient: GeminiClient,
    taskScheduler: TaskScheduler,
    agentOrchestrator: AgentOrchestrator,
    resultCache: ResultCacheManager
  },
  
  // 数据持久化层
  persistence: {
    localStore: chrome.storage.local,
    syncStore: chrome.storage.sync,
    cacheManager: CacheManager,
    auditLogger: AuditLogger
  }
}

// 初始化架构
const skills = new ChromeSkillsArchitecture();
await skills.initialize();

1.2 核心接口定义

typescript 复制代码
// 技能接口定义
interface Skill {
  id: string;
  name: string;
  description: string;
  version: string;
  
  // 执行配置
  executionConfig: {
    type: 'simple' | 'agent' | 'multi_step';
    timeout: number;
    maxTokens: number;
    temperature: number;
  },
  
  // 提示词模板
  promptTemplate: string;
  variables: SkillVariable[];
  
  // 权限要求
  permissions: Permission[];
  
  // API配置
  apiProvider: 'gemini' | 'local' | 'custom';
}

// 执行接口
interface SkillExecutor {
  execute(
    skill: Skill,
    context: BrowserContext
  ): Promise<ExecutionResult>;
}

// 浏览器上下文
interface BrowserContext {
  activeTab: chrome.tabs.Tab;
  allTabs: chrome.tabs.Tab[];
  selection: string;
  clipboard: string;
  history: chrome.history.HistoryItem[];
  bookmarks: chrome.bookmarks.BookmarkTreeNode[];
}

// 执行结果
interface ExecutionResult {
  success: boolean;
  content?: string;
  error?: string;
  usage?: {
    promptTokens: number;
    completionTokens: number;
    totalTokens: number;
  };
  executionTime: number;
}

二、Gemini API集成

2.1 API客户端封装

javascript 复制代码
import { GoogleGenerativeAI } from '@google/generative-ai';

class GeminiAPIClient {
  private apiKey: string;
  private model: string;
  private client: GoogleGenerativeAI;
  
  constructor(apiKey: string, model: string = 'gemini-2.0-pro') {
    this.apiKey = apiKey;
    this.model = model;
    this.client = new GoogleGenerativeAI({ apiKey: this.apiKey });
  }
  
  async generate(prompt: string, options?: GenerationOptions): Promise<GenerationResponse> {
    const generationConfig = {
      model: this.model,
      generationConfig: {
        temperature: options?.temperature || 0.7,
        topP: options?.topP || 1,
        topK: options?.topK || 40,
        maxOutputTokens: options?.maxTokens || 2048,
      },
    };
    
    try {
      const startTime = performance.now();
      
      const result = await this.client.generateContent({
        contents: [{ role: 'user', parts: [{ text: prompt }] }],
        generationConfig,
      });
      
      const endTime = performance.now();
      const executionTime = endTime - startTime;
      
      return {
        success: true,
        text: result.response.text(),
        usage: {
          promptTokens: result.response.promptTokenCount,
          completionTokens: result.response.candidatesTokenCount,
          totalTokens: result.response.totalTokenCount,
        },
        executionTime,
        model: this.model
      };
      
    } catch (error) {
      console.error('Gemini API error:', error);
      return {
        success: false,
        error: error.message
      };
    }
  }

// 使用示例
const geminiClient = new GeminiAPIClient('your-api-key');

const result = await geminiClient.generate('分析这个网页内容...', {
  temperature: 0.8,
  maxTokens: 1024
});

console.log('生成结果:', result);

2.2 流式响应处理

javascript 复制代码
class StreamingGeminiClient extends GeminiAPIClient {
  async *generateStream(prompt: string): AsyncGenerator<StreamChunk> {
    const generationConfig = {
      model: this.model,
      generationConfig: {
        temperature: 0.7,
      topP: 1,
        topK: 40,
        maxOutputTokens: 4096,
      },
    };
    
    try {
      const result = await this.client.generateContentStream({
        contents: [{ role: 'user', parts: [{ text: prompt }] }],
        generationConfig,
      });
      
      const stream = result.stream;
      const reader = stream.getReader();
      
      let fullText = '';
      let chunkCount = 0;
      
      while (true) {
        const { done, value } = await reader.read();
        
        if (done) {
          break;
        }
        
        if (value) {
          chunkCount++;
          const chunk = value.parts[0]?.text;
          if (chunk) {
            fullText += chunk;
            
            // 触发进度事件
            this.onProgress?.({
              chunk,
              chunkNumber: chunkCount,
              partialText: fullText
            });
          }
        }
      }
      
      return {
        success: true,
        text: fullText,
        chunks: chunkCount
      };
      
    } catch (error) {
      console.error('Stream error:', error);
      return {
        success: false,
        error: error.message
      };
    }
  }
}

// 流式处理使用示例
const streamingClient = new StreamingGeminiClient('your-api-key');

// 设置进度回调
streamingClient.onProgress = (progress) => {
  console.log(`收到第${progress.chunkNumber}个片段:`, progress.partialText.substring(-50));
  
  // 可以实时更新UI
  if (typeof updateUI === 'function') {
    updateUI(progress.partialText);
  }
};

// 执行流式生成
async function executeStreamingSkill(skillPrompt) {
  const generator = streamingClient.generateStream(skillPrompt);
  
  for await (const chunk of generator) {
    console.log('处理流式响应:', chunk);
  }
  
  console.log('生成完成:', chunk.text);
}

三、实战代码示例

3.1 网页分析技能

javascript 复制代码
// manifest.json
{
  "manifest_version": 3,
  "name": "网页分析助手",
  "version": "1.0.0",
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
  "background": {
    "service_worker": "background.js",
    "type": "module"
  }
}

// background.js - Service Worker
import { GeminiAPIClient } from './gemini-client.js';

class SkillManager {
  constructor() {
    this.geminiClient = new GeminiAPIClient(
      chrome.storage.local.get('gemini_api_key') || 'default-key'
    );
    this.skills = {
      'web_analysis': {
        id: 'web_analysis',
        name: '网页内容分析',
        promptTemplate: `
          你是一个专业的网页内容分析助手。请分析当前网页内容,按照以下要求生成分析:
          
          1. 提取核心观点(不超过3个)
          2. 总结关键信息(不超过5条)
          3. 评估内容质量(1-5分)
          4. 给出阅读建议(1-2条)
          
          当前网页内容:
          {page_content}
        `,
        variables: [
          {
            name: 'page_content',
            type: 'text',
            required: true
          }
        ],
        executionConfig: {
          type: 'simple',
          timeout: 30000,
          maxTokens: 1024
        }
      }
    };
  }
  
  async executeSkill(skillId: string, context: any) {
    const skill = this.skills[skillId];
    if (!skill) {
      throw new Error(`Skill ${skillId} not found`);
    }
    
    // 执行技能
    const result = await this.geminiClient.generate(
      skill.promptTemplate,
      {
        temperature: skill.executionConfig.temperature,
        maxTokens: skill.executionConfig.maxTokens
      }
    );
    
    // 返回结果给content script
    return {
      skillId,
      success: result.success,
      content: result.text,
      usage: result.usage
    };
  }
}

// content.js - 内容脚本
class ContentAnalyzer {
  async analyzeCurrentPage() {
    // 获取当前页面内容
    const [tab] = await chrome.tabs.query({ active: true });
    
    if (!tab[0]) {
      throw new Error('No active tab');
    }
    
    try {
      // 提取页面内容
      const [result] = await chrome.scripting.executeScript({
        target: { tabId: tab[0].id },
        func: () => {
          // 提取页面标题、正文等内容
          const title = document.querySelector('h1')?.textContent || document.title;
          const content = document.body?.innerText || '';
          const metaDescription = document.querySelector('meta[name="description"]')?.content || '';
          
          return {
            title,
            content,
            metaDescription,
            url: tab[0].url
          };
        }
      });
      
      if (!result || result[0].error) {
        throw new Error('Failed to extract content');
      }
      
      const pageContent = result[0].result;
      
      // 调用background进行技能执行
      const response = await chrome.runtime.sendMessage({
        action: 'executeSkill',
        skillId: 'web_analysis',
        context: pageContent
      });
      
      // 显示分析结果
      this.displayAnalysisResult(response);
      
    } catch (error) {
      console.error('Analysis failed:', error);
      this.displayError(error.message);
    }
  }
  
  displayAnalysisResult(result) {
    // 创建结果展示面板
    const panel = document.createElement('div');
    panel.className = 'skill-result-panel';
    panel.innerHTML = `
      <div class="skill-header">
        <h2>📊 网页分析结果</h2>
      </div>
      <div class="skill-content">
        ${this.formatContent(result.content)}
      </div>
      <div class="skill-footer">
        <button id="closePanel">关闭</button>
      </div>
    `;
    
    document.body.appendChild(panel);
    
    // 添加关闭按钮事件
    document.getElementById('closePanel')?.addEventListener('click', () => {
      panel.remove();
    });
  }
  
  formatContent(content) {
    // 格式化分析内容
    return content
      .replace(/\n\n/g, '<br><br>')
      .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
      .replace(/_([^_]+)_/g, '<em>$1</em>');
  }
}

// 初始化分析器
const analyzer = new ContentAnalyzer();
// 监听页面加载完成事件
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === 'analyzePage') {
    analyzer.analyzeCurrentPage();
    sendResponse({ success: true });
  }
});

3.2 多标签页数据聚合技能

javascript 复制代码
// 跨标签页数据聚合
class CrossTabDataAggregator {
  constructor() {
    this.activeTasks = new Map();
    this.collectedData = new Map();
  }
  
  async aggregateData(skillConfig: any) {
    // 1. 获取所有标签页
    const tabs = await chrome.tabs.query({});
    
    // 2. 提取每个页面的数据
    const tasks = tabs.map(tab => ({
      tabId: tab.id,
      url: tab.url,
      status: 'pending'
    }));
    
    // 3. 并发执行数据提取
    const results = await Promise.all(
      tasks.map(task => this.extractPageData(task))
    );
    
    // 4. 汇总数据
    return this.aggregateResults(results);
  }
  
  async extractPageData(task) {
    const { tabId, url } = task;
    
    try {
      const [result] = await chrome.scripting.executeScript({
        target: { tabId },
        func: () => {
          // 页面数据提取逻辑
          const data = this.extractPageData();
          
          return {
            success: true,
            data,
            tabId
          };
        }
      });
      
      task.status = 'completed';
      task.result = result;
      task.data = result;
      
      return result;
      
    } catch (error) {
      task.status = 'failed';
      task.error = error.message;
      return { success: false, error };
    }
  }
  
  extractPageData() {
    // 实现页面数据提取
    // 根据具体页面类型实现不同的提取逻辑
    
    const commonElements = {
      products: document.querySelectorAll('.product-item'),
      prices: document.querySelectorAll('.price-tag'),
      titles: document.querySelectorAll('h1, h2, h3'),
      descriptions: document.querySelectorAll('.description')
    };
    
    return {
      products: Array.from(commonElements.products).map(el => ({
        name: el.querySelector('.name')?.textContent,
        price: el.querySelector('.price')?.textContent
      })),
      prices: Array.from(commonElements.prices).map(el => el.textContent),
      titles: Array.from(commonElements.titles).map(el => el.textContent),
      descriptions: Array.from(commonElements.descriptions).map(el => el.textContent)
    };
  }
  
  aggregateResults(results) {
    // 汇总所有标签页的数据
    const aggregated = {
      totalTabs: results.length,
      successfulTabs: results.filter(r => r.success).length,
      allProducts: results.flatMap(r => r.data?.products || []),
      allPrices: results.flatMap(r => r.data?.prices || []),
      allTitles: results.flatMap(r => r.data?.titles || []),
      allDescriptions: results.flatMap(r => r.data?.descriptions || []),
      timestamp: Date.now()
    };
    
    // 发送结果
    chrome.runtime.sendMessage({
      action: 'aggregationComplete',
      data: aggregated
    });
    
    return aggregated;
  }
}

// 使用示例
const aggregator = new CrossTabDataAggregator();

// 执行数据聚合
const aggregationConfig = {
  targetTabs: 'all',
  dataTypes: ['products', 'prices', 'titles']
};

const result = await aggregator.aggregateData(aggregationConfig);
console.log('聚合结果:', result);

四、性能优化策略

4.1 内存管理优化

javascript 复制代码
class MemoryOptimizedSkillManager {
  constructor() {
    this.skills = new Map();
    this.cache = new LRUCache(100); // 最多缓存100个结果
    this.memoryPool = new Pool(10);  // 对象池复用
  }
  
  async getSkill(skillId: string) {
    // 1. 检查缓存
    const cached = this.cache.get(skillId);
    if (cached && !this.isExpired(cached)) {
      return cached.data;
    }
    
    // 2. 从存储加载
    const skill = await this.loadSkill(skillId);
    if (!skill) {
      throw new Error(`Skill ${skillId} not found`);
    }
    
    // 3. 缓存结果
    this.cache.set(skillId, {
      data: skill,
      timestamp: Date.now()
    });
    
    return skill;
  }
  
  isExpired(cachedItem) {
    const ttl = 5 * 60 * 1000; // 5分钟TTL
    return Date.now() - cachedItem.timestamp > ttl;
  }
}

// LRU缓存实现
class LRUCache {
  constructor(maxSize) {
    this.maxSize = maxSize;
    this.cache = new Map();
    this.accessOrder = [];
  }
  
  get(key) {
    const item = this.cache.get(key);
    
    if (item) {
      // 更新访问顺序
      this.accessOrder = this.accessOrder.filter(k => k !== key);
      this.accessOrder.push(key);
      
      return item.data;
    }
    
    return undefined; // 缓存未命中
  }
  
  set(key, data) {
    // 检查容量
    if (this.cache.size >= this.maxSize) {
      this.evict();
    }
    
    this.cache.set(key, {
      data,
      timestamp: Date.now()
    });
  }
  
  evict() {
    // LRU淘汰策略
    const oldestKey = this.accessOrder.shift();
    this.cache.delete(oldestKey);
  }
}

4.2 异步任务队列优化

javascript 复制代码
class AsyncTaskQueue {
  constructor(maxConcurrent = 3) {
    this.queue = [];
    this.activeCount = 0;
    this.maxConcurrent = maxConcurrent;
    this.results = new Map();
  }
  
  async enqueue(task) {
    return new Promise((resolve, reject) => {
      this.queue.push({
        task,
        resolve,
        reject,
        timestamp: Date.now()
      });
      
      this.processQueue();
    });
  }
  
  processQueue() {
    while (this.activeCount < this.maxConcurrent && this.queue.length > 0) {
      const { task, resolve, reject } = this.queue.shift();
      
      this.activeCount++;
      
      task()
        .then(result => {
          this.results.set(task.id, {
            success: true,
            result,
            timestamp: Date.now()
          });
          resolve(result);
        })
        .catch(error => {
          this.results.set(task.id, {
            success: false,
            error,
            timestamp: Date.now()
          });
          reject(error);
        })
        .finally(() => {
          this.activeCount--;
        });
    }
  }
  
  async getResult(taskId) {
    return new Promise((resolve, reject) => {
      const checkInterval = setInterval(() => {
        const result = this.results.get(taskId);
        
        if (result) {
          clearInterval(checkInterval);
          resolve(result);
        } else if (this.queue.length === 0 && this.activeCount === 0) {
          clearInterval(checkInterval);
          reject(new Error('Task failed and queue is empty'));
        }
      }, 100);
    });
  }
}

// 使用示例
const taskQueue = new AsyncTaskQueue(5);

// 添加任务
const task1 = {
  id: 'task1',
  fn: async () => {
    console.log('Executing task 1...');
    await new Promise(resolve => setTimeout(resolve, 2000));
    return 'Task 1 result';
  }
};

const task2 = {
  id: 'task2',
  fn: async () => {
    console.log('Executing task 2...');
    await new Promise(resolve => setTimeout(resolve, 1500));
    return 'Task 2 result';
  }
};

// 并发执行任务
const results = await Promise.all([
  taskQueue.enqueue(task1),
  taskQueue.enqueue(task2)
]);

console.log('All tasks completed:', results);

五、安全与权限管理

5.1 最小权限原则

javascript 复制代码
// 权限请求策略
class MinimalPermissionManager {
  constructor() {
    this.requiredPermissions = [];
    this.optionalPermissions = [];
  }
  
  async requestPermissions(permissions) {
    // 只请求必要的权限
    const minimalPermissions = this.filterMinimalPermissions(permissions);
    
    const granted = await chrome.permissions.request(minimalPermissions);
    
    if (granted) {
      console.log('Permissions granted:', minimalPermissions);
      return true;
    } else {
      console.error('Permissions denied:', minimalPermissions);
      return false;
    }
  }
  
  filterMinimalPermissions(requested) {
    // 移除不必要的权限
    const dangerousPermissions = ['<all_urls>', 'history', 'bookmarks'];
    
    return requested.filter(perm => 
      !dangerousPermissions.includes(perm)
    );
  }
}

// 使用示例
const permissionManager = new MinimalPermissionManager();

// 只请求必要的权限
const necessaryPermissions = ['activeTab', 'scripting'];
const granted = await permissionManager.requestPermissions(necessaryPermissions);

六、开发工具与调试

6.1 技能调试工具

javascript 复制代码
// 技能调试器UI
class SkillDebugger {
  constructor() {
    this.currentSkill = null;
    this.variables = {};
    this.executionHistory = [];
    this.isRecording = false;
  }
  
  loadSkill(skillId) {
    chrome.storage.local.get([`skill_${skillId}`], (result) => {
      if (result[`skill_${skillId}`]) {
        this.currentSkill = result[`skill_${skillId}`];
        this.renderSkillEditor();
      }
    });
  }
  
  renderSkillEditor() {
    if (!this.currentSkill) return;
    
    const container = document.getElementById('skill-editor-container');
    if (!container) return;
    
    container.innerHTML = `
      <div class="skill-editor">
        <div class="skill-info">
          <h3>${this.currentSkill.name}</h3>
          <p>${this.currentSkill.description}</p>
        </div>
        
        <div class="variables-section">
          <h4>变量定义</h4>
          <div id="variables-editor"></div>
          <button id="add-variable">+ 添加变量</button>
        </div>
        
        <div class="prompt-section">
          <h4>提示词模板</h4>
          <textarea id="prompt-editor" rows="10">${this.currentSkill.promptTemplate}</textarea>
        </div>
        
        <div class="actions">
          <button id="save-skill">保存技能</button>
          <button id="test-skill">测试技能</button>
          <button id="record-macro">录制宏</button>
        </div>
        
        <div class="execution-history">
          <h4>执行历史</h4>
          <div id="history-list"></div>
        </div>
      </div>
    `;
    
    // 添加事件监听
    this.attachEventListeners();
  }
  
  attachEventListeners() {
    document.getElementById('save-skill')?.addEventListener('click', () => {
      this.saveSkill();
    });
    
    document.getElementById('test-skill')?.addEventListener('click', () => {
      this.testSkill();
    });
    
    document.getElementById('add-variable')?.addEventListener('click', () => {
      this.addVariable();
    });
    
    document.getElementById('record-macro')?.addEventListener('click', () => {
      this.recordMacro();
    });
  }
}

// 使用调试器
const debugger = new SkillDebugger();
debugger.loadSkill('web_analysis');

七、总结与最佳实践

7.1 开发最佳实践

  1. 模块化设计

    • 将功能拆分为独立模块
    • 降低耦合度
    • 便于测试和维护
  2. 错误处理

    • 完善的错误捕获机制
    • 提供友好的错误提示
    • 实现优雅的降级
  3. 性能优化

    • 使用缓存减少API调用
    • 实现异步处理
    • 优化内存使用
  4. 安全考虑

    • 最小权限原则
    • 数据加密存储
    • 用户隐私保护
  5. 用户体验

    • 提供实时反馈
    • 优化加载速度
    • 设计直观的界面

相关推荐
爱吃的小肥羊20 小时前
我被灰度到了,实测 GPT-imagev2,中文直接封神!
aigc·openai
机器之心1 天前
太反差了!那边Claude强制「刷脸」认证,这边国内Coding Plan被外国人疯抢
人工智能·openai
机器之心1 天前
当AI迈入Harness时代:以MiniMax为样本看智能体云端新基建
人工智能·openai
爱吃的小肥羊1 天前
一个问题,GPT-6是否值得期待???
aigc·openai
小丑依然是我1 天前
AntV Harness:LLM 自我进化的闭环优化系统
人工智能·openai
掘金一周1 天前
现在面试 AI 相关问题,不把底层原理扒得明明白白,真的分分钟被问麻😭 | 沸点周刊 4.16
openai·ai编程·沸点
djoy1 天前
蛤?新买的Macbook pro M5合盖一晚掉13%的电? 让我来拯救你的mac电池
openai
树獭叔叔1 天前
OpenCLI:让任何网站成为你的命令行工具
后端·aigc·openai
机器之心1 天前
从「片段生成」到「长视频漫游」:OmniRoam探索轨迹可控的长视频生成新范式
人工智能·openai
怕浪猫1 天前
第14章 高级 Agent:LangGraph 与状态机
langchain·openai·ai编程