尚未安裝 OpenClaw?點此查看一鍵安裝指令
curl -fsSL https://openclaw.ai/install.sh | bash
iwr -useb https://openclaw.ai/install.ps1 | iex
curl -fsSL https://openclaw.ai/install.cmd -o install.cmd && install.cmd && del install.cmd
擔心影響電腦?ClawTank 免安裝雲端運行,免除誤刪風險
Key Findings
  • OpenClaw Skill 是代理系統的能力擴充核心——每個 Skill 封裝一項獨立功能,代理可在任務執行中自主決定調用哪些 Skill 來完成目標[1]
  • GoPlaces Skill 透過 google_places_api_key 連接 Google Places API,讓代理具備地點搜尋、評論分析與商家資訊查詢能力——是外部 API 整合的經典範例[3]
  • 自訂 Skill 僅需三個核心檔案:manifest.json(能力宣告)、index.js(邏輯實作)與 README.md(使用說明),最快 30 分鐘即可完成開發與測試[4]
  • find-skills 指令可搜尋 OpenClaw Skill Registry 中數百個社群貢獻的 Skill,支援分類過濾與版本比對[2]
  • 企業級 Skill 整合需考量認證管理、錯誤重試、速率限制與稽核日誌——本文提供完整的設計模式與可直接使用的程式碼範例

當你在 OpenClaw 中下達「幫我找台北信義區評價最高的義式餐廳」這樣的指令時,代理並不是透過搜尋引擎爬取網頁——它調用的是一個名為 GoPlaces 的 Skill,直接透過 Google Places API 取得結構化的商家資料、評分與使用者評論。這正是 OpenClaw Skill 系統的精髓:將外部世界的能力封裝為代理可調用的模組化工具

在 OpenClaw 的架構中,Skill 是代理與真實世界互動的橋樑。沒有 Skill,代理只是一個能產生文字的語言模型;有了 Skill,它才能查詢資料庫、操控瀏覽器、發送電子郵件、甚至控制 IoT 裝置。Skill 系統的設計決定了 OpenClaw 的擴展性與實用性上限。

然而,社群提供的現成 Skill 不可能覆蓋每一家企業的內部系統。當你需要讓代理存取公司的 CRM、查詢內部知識庫、或觸發特定業務流程時,你需要自訂 Skill。本文將從 OpenClaw Skill 的架構原理出發,以 GoPlaces Skill 為實戰案例,帶你走完「從零開發到企業級整合」的完整流程。

一、OpenClaw Skill 架構總覽

在深入 GoPlaces Skill 的實作之前,我們需要先理解 OpenClaw 的 Skill 系統是如何運作的。Skill 在 OpenClaw 的四層架構(Gateway、Node、Channel、Skill)中位於最底層,但它是代理「做事」的實際執行者。[1]

1.1 Skill 的角色與運行機制

當使用者透過 CLI 或 Web UI 發送一個任務給代理,處理流程如下:

  1. Channel 層接收使用者輸入,轉發給 Gateway
  2. Gateway 層將任務指派給可用的 Node
  3. Node 層調用 LLM 進行推理,LLM 決定需要調用哪些 Skill
  4. Skill 層執行具體操作(API 調用、檔案操作、Shell 指令等),將結果回傳給 Node
  5. Node 將 Skill 回傳的結果整合進 LLM 的上下文,繼續推理或產生最終回覆

關鍵在第 3 步:LLM 透過 Skill 的 manifest.json 中定義的能力描述(capability description)來決定何時、如何調用某個 Skill。這與 Function Calling 的機制本質相同——Skill 是 OpenClaw 對 Function Calling 概念的封裝與擴展。

1.2 Skill 的目錄結構

每個 OpenClaw Skill 遵循標準化的目錄結構:

my-custom-skill/
├── manifest.json        # Skill 中繼資料與能力宣告
├── index.js             # Entry Point(或 index.ts)
├── config.schema.json   # 可選:使用者可配置參數的 JSON Schema
├── lib/                 # 可選:輔助模組
│   ├── api-client.js
│   └── utils.js
├── tests/               # 可選:測試檔案
│   └── index.test.js
├── package.json         # 依賴管理
└── README.md            # 使用說明

其中,manifest.json 是整個 Skill 的核心宣告檔。它告訴 OpenClaw 這個 Skill 能做什麼、需要什麼權限、接受哪些參數。

1.3 manifest.json 深度解析

一個標準的 manifest.json 結構如下:

{
"name": "my-custom-skill",
"version": "1.0.0",
"description": "A custom skill that does something useful",
"author": "your-name",
"license": "MIT",
"entry": "index.js",
"capabilities": [
  {
    "name": "do_something",
    "description": "Performs a specific action based on user input. Use this when the user asks to do something related to X.",
    "parameters": {
      "type": "object",
      "properties": {
        "query": {
          "type": "string",
          "description": "The user's query or input"
        },
        "options": {
          "type": "object",
          "description": "Optional configuration",
          "properties": {
            "limit": {
              "type": "number",
              "description": "Maximum number of results",
              "default": 10
            }
          }
        }
      },
      "required": ["query"]
    }
  }
],
"config": {
  "api_key": {
    "type": "string",
    "description": "API key for the external service",
    "required": true,
    "secret": true
  }
},
"permissions": ["network"],
"tags": ["api", "search", "custom"]
}

幾個需要特別注意的欄位:

  • capabilities:這是 LLM 判斷是否調用此 Skill 的依據。description 必須清晰描述功能與使用場景——寫得太模糊,LLM 不知道何時該用;寫得太籠統,則可能被錯誤調用
  • config:定義使用者在 openclaw.json 中需要填寫的配置項。標記為 secret: true 的欄位會在日誌中自動遮罩
  • permissions:宣告 Skill 需要的系統權限(networkfilesystemshell 等),未宣告的權限將被拒絕

1.4 Entry Point 的標準介面

OpenClaw 要求每個 Skill 的 Entry Point 匯出一個符合特定介面的物件:[1]

// index.js — Skill Entry Point
module.exports = {
// 初始化:接收 config 與 context
async initialize(config, context) {
  // config: 使用者在 openclaw.json 中的設定
  // context: OpenClaw 提供的執行環境
  this.apiKey = config.api_key;
  this.logger = context.logger;
  this.logger.info('Skill initialized successfully');
},

// 能力實作:每個 capability 對應一個方法
async do_something(params, context) {
  const { query, options = {} } = params;
  const limit = options.limit || 10;

  try {
    const results = await this.callExternalAPI(query, limit);
    return {
      success: true,
      data: results,
      message: `Found ${results.length} results for "${query}"`
    };
  } catch (error) {
    this.logger.error(`Skill execution failed: ${error.message}`);
    return {
      success: false,
      error: error.message
    };
  }
},

// 清理:Skill 卸載時調用
async cleanup() {
  this.logger.info('Skill cleanup completed');
}
};

這個介面設計有三個重要特性:

  • 生命週期管理initialize → 能力方法 → cleanup,確保資源正確分配與釋放
  • 一致的回傳格式:所有能力方法回傳 { success, data, message }{ success, error },讓 Node 能統一處理
  • Context 注入:OpenClaw 透過 context 物件提供 logger、workspace 資訊、其他 Skill 的引用等,避免 Skill 之間的直接耦合

二、GoPlaces Skill 實戰:Google Places API 整合

GoPlaces 是 OpenClaw 社群中最受歡迎的 Skill 之一,它將 Google Places API 封裝為代理可調用的地理位置搜尋能力。許多使用者在搜尋「openclaw goplaces skill google_places_api_key」時遇到的問題,核心都是 API Key 的配置流程。本節將從頭到尾走一遍完整設定。[3]

2.1 取得 Google Places API Key

在配置 GoPlaces Skill 之前,你需要先從 Google Cloud 取得一個有效的 API Key:

  1. 前往 Google Cloud Console
  2. 建立新專案(或選擇現有專案)
  3. 導航至「API 和服務」→「資料庫」
  4. 搜尋並啟用 Places API(注意:不是 Places API (New),兩者的端點不同)
  5. 導航至「API 和服務」→「憑證」
  6. 點擊「建立憑證」→「API 金鑰」
  7. 強烈建議限制此金鑰僅可調用 Places API,並設定 IP 或 HTTP Referrer 限制

費用注意事項:Google Places API 採用按次計費模式。Nearby Search 每次請求 $0.032、Place Details 每次 $0.017、Text Search 每次 $0.032。Google 每月提供 $200 的免費額度,約可支撐 6,250 次 Nearby Search 請求。建議在 Cloud Console 設定預算警示,避免代理大量調用時產生超出預期的費用。[3]

2.2 在 openclaw.json 中配置 google_places_api_key

取得 API Key 後,需要在 OpenClaw 的設定檔中配置 GoPlaces Skill。開啟你的 openclaw.json(通常位於 ~/.config/openclaw/openclaw.json),加入以下設定:

{
"skills": {
  "goplaces": {
    "enabled": true,
    "config": {
      "google_places_api_key": "YOUR_GOOGLE_PLACES_API_KEY",
      "default_language": "zh-TW",
      "default_region": "tw",
      "max_results": 20,
      "cache_ttl": 3600
    }
  }
}
}

各欄位說明:

  • google_places_api_key(必填):你在 Google Cloud Console 取得的 API 金鑰
  • default_language:預設回傳語言,zh-TW 為繁體中文。代理也可在每次調用時動態指定
  • default_region:搜尋偏好的地區代碼,影響搜尋結果排序
  • max_results:單次搜尋的最大回傳數量,預設 20(Google API 上限為 60,分三頁)
  • cache_ttl:搜尋結果快取時間(秒),避免對相同查詢重複計費

2.3 使用環境變數保護 API Key

直接在 openclaw.json 中明文儲存 API Key 是不安全的——特別是當你的設定檔納入版本控制時。GoPlaces Skill 支援透過環境變數引用金鑰:

{
"skills": {
  "goplaces": {
    "enabled": true,
    "config": {
      "google_places_api_key": "${GOOGLE_PLACES_API_KEY}",
      "default_language": "zh-TW"
    }
  }
}
}

然後在你的 Shell 設定檔(~/.zshrc~/.bashrc)中加入:

# Google Places API Key for OpenClaw GoPlaces Skill
export GOOGLE_PLACES_API_KEY="AIzaSy..."

重新載入 Shell 後,OpenClaw 會在初始化 Skill 時自動解析環境變數。你可以用以下指令驗證設定是否正確:

# 檢查 GoPlaces Skill 狀態
openclaw skills check goplaces

# 預期輸出
# Skill: goplaces
# Status: ready
# Config:
#   google_places_api_key: AIza****** (masked)
#   default_language: zh-TW
#   default_region: tw

2.4 GoPlaces Skill 的能力與使用範例

GoPlaces Skill 提供以下能力(capabilities):

  • search_places:依關鍵字搜尋地點(Text Search)
  • nearby_places:依座標與半徑搜尋附近地點(Nearby Search)
  • place_details:查詢特定地點的詳細資訊(營業時間、電話、評論等)
  • place_photos:取得地點的照片 URL

在實際使用中,你只需用自然語言下達指令,代理會自動選擇合適的能力:

# 搜尋地點
openclaw "找台北信義區評價 4.5 以上的義式餐廳,列出前 5 名"

# 代理內部調用路徑:
# 1. LLM 判斷需要 search_places capability
# 2. 調用 goplaces.search_places({
#      query: "義式餐廳 台北信義區",
#      min_rating: 4.5,
#      max_results: 5
#    })
# 3. Google Places API 回傳結構化資料
# 4. LLM 整理為使用者友善的格式

# 查詢特定地點詳情
openclaw "查詢 '鼎泰豐 信義店' 的營業時間和最近的評論"

# 附近搜尋
openclaw "我現在在台北 101(25.0339, 121.5645),找半徑 500 公尺內的咖啡廳"

2.5 GoPlaces 常見問題排解

以下是我們在企業部署中最常遇到的 GoPlaces 設定問題:

問題 1:REQUEST_DENIED 錯誤

# 錯誤訊息
# [goplaces] Google Places API error: REQUEST_DENIED
# "This API project is not authorized to use this API."

原因通常是 API Key 未啟用 Places API,或金鑰限制排除了 OpenClaw 的存取。解法:回到 Google Cloud Console,確認 Places API 已啟用,且金鑰的限制條件允許從你的伺服器 IP 調用。

問題 2:OVER_QUERY_LIMIT 錯誤

代理在短時間內大量調用 Places API 時會觸發速率限制。GoPlaces Skill 內建重試機制,但建議在 openclaw.json 中設定 cache_ttl 以減少重複請求,並在 Google Cloud Console 啟用 QPS(Queries Per Second)限制。

問題 3:回傳結果為英文

確認 default_language 設定為 zh-TW。若特定查詢仍回傳英文,可能是該地點在 Google Maps 中沒有中文名稱——這是 Google 資料本身的限制。

三、自訂 Skill 開發流程

理解了 GoPlaces 的架構後,讓我們從零開始建立一個自訂 Skill。這個範例將建立一個「天氣查詢 Skill」,串接 OpenWeatherMap API。[1]

3.1 初始化 Skill 專案

OpenClaw CLI 提供了 Skill 腳手架指令:

# 建立新的 Skill 專案
openclaw skills create weather-lookup

# 執行後產生的目錄結構
# weather-lookup/
# ├── manifest.json
# ├── index.js
# ├── config.schema.json
# ├── package.json
# └── README.md

3.2 定義 manifest.json

修改 manifest.json,定義 Skill 的能力:

{
"name": "weather-lookup",
"version": "1.0.0",
"description": "Query current weather and forecasts using OpenWeatherMap API",
"author": "meta-intelligence",
"license": "MIT",
"entry": "index.js",
"capabilities": [
  {
    "name": "get_current_weather",
    "description": "Get the current weather conditions for a specific city or location. Use this when the user asks about current weather, temperature, humidity, or wind conditions.",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "City name, e.g. 'Taipei', 'Tokyo', 'New York'"
        },
        "units": {
          "type": "string",
          "enum": ["metric", "imperial"],
          "description": "Temperature units: metric (Celsius) or imperial (Fahrenheit)",
          "default": "metric"
        }
      },
      "required": ["city"]
    }
  },
  {
    "name": "get_forecast",
    "description": "Get a 5-day weather forecast for a specific city. Use this when the user asks about future weather conditions or weekly forecasts.",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "City name"
        },
        "days": {
          "type": "number",
          "description": "Number of forecast days (1-5)",
          "default": 3
        },
        "units": {
          "type": "string",
          "enum": ["metric", "imperial"],
          "default": "metric"
        }
      },
      "required": ["city"]
    }
  }
],
"config": {
  "openweathermap_api_key": {
    "type": "string",
    "description": "API key from OpenWeatherMap",
    "required": true,
    "secret": true
  }
},
"permissions": ["network"],
"tags": ["weather", "api", "forecast"]
}

撰寫 capabilities.description 的技巧:使用「Use this when...」句型明確告訴 LLM 何時該調用此能力,避免與其他 Skill 的能力產生歧義。

3.3 實作 Entry Point

index.js 中實作核心邏輯:

const https = require('https');

const BASE_URL = 'https://api.openweathermap.org/data/2.5';

module.exports = {
async initialize(config, context) {
  this.apiKey = config.openweathermap_api_key;
  this.logger = context.logger;

  if (!this.apiKey) {
    throw new Error('openweathermap_api_key is required');
  }

  // 驗證 API Key 有效性
  try {
    await this._request('/weather', { q: 'London' });
    this.logger.info('Weather Lookup Skill initialized');
  } catch (err) {
    throw new Error(`Invalid API key: ${err.message}`);
  }
},

async get_current_weather(params) {
  const { city, units = 'metric' } = params;

  const data = await this._request('/weather', {
    q: city,
    units,
    lang: 'zh_tw'
  });

  return {
    success: true,
    data: {
      city: data.name,
      country: data.sys.country,
      temperature: data.main.temp,
      feels_like: data.main.feels_like,
      humidity: data.main.humidity,
      description: data.weather[0].description,
      wind_speed: data.wind.speed,
      units: units === 'metric' ? '°C' : '°F'
    },
    message: `${data.name} 目前天氣:${data.weather[0].description},氣溫 ${data.main.temp}${units === 'metric' ? '°C' : '°F'}`
  };
},

async get_forecast(params) {
  const { city, days = 3, units = 'metric' } = params;

  const data = await this._request('/forecast', {
    q: city,
    units,
    cnt: days * 8, // API 回傳每 3 小時一筆
    lang: 'zh_tw'
  });

  const dailyForecasts = this._aggregateDaily(data.list, days);

  return {
    success: true,
    data: {
      city: data.city.name,
      country: data.city.country,
      forecasts: dailyForecasts
    },
    message: `${data.city.name} 未來 ${days} 天天氣預報已取得`
  };
},

// 私有方法:HTTP 請求封裝
_request(endpoint, queryParams) {
  return new Promise((resolve, reject) => {
    const params = new URLSearchParams({
      ...queryParams,
      appid: this.apiKey
    });

    const url = `${BASE_URL}${endpoint}?${params}`;

    https.get(url, (res) => {
      let body = '';
      res.on('data', chunk => body += chunk);
      res.on('end', () => {
        const parsed = JSON.parse(body);
        if (parsed.cod !== 200 && parsed.cod !== '200') {
          reject(new Error(parsed.message || 'API request failed'));
        } else {
          resolve(parsed);
        }
      });
    }).on('error', reject);
  });
},

// 私有方法:將 3 小時資料聚合為每日摘要
_aggregateDaily(list, days) {
  const dailyMap = {};
  list.forEach(item => {
    const date = item.dt_txt.split(' ')[0];
    if (!dailyMap[date]) {
      dailyMap[date] = { temps: [], descriptions: [] };
    }
    dailyMap[date].temps.push(item.main.temp);
    dailyMap[date].descriptions.push(item.weather[0].description);
  });

  return Object.entries(dailyMap).slice(0, days).map(([date, info]) => ({
    date,
    temp_min: Math.min(...info.temps),
    temp_max: Math.max(...info.temps),
    description: info.descriptions[Math.floor(info.descriptions.length / 2)]
  }));
},

async cleanup() {
  this.logger.info('Weather Lookup Skill cleaned up');
}
};

3.4 測試與安裝

開發完成後,使用 OpenClaw CLI 進行本地測試與安裝:

# 在 Skill 目錄中執行驗證
cd weather-lookup
openclaw skills validate .

# 預期輸出
# ✓ manifest.json is valid
# ✓ Entry point found: index.js
# ✓ All capabilities have matching exports
# ✓ Config schema is valid
# ✓ Permissions declared: network

# 本地安裝(開發模式,symlink)
openclaw skills install --dev .

# 或正式安裝(複製到 skills 目錄)
openclaw skills install .

# 驗證安裝成功
openclaw skills list

# 預期輸出會包含
# weather-lookup  1.0.0  ready  2 capabilities

安裝後,還需要在 openclaw.json 中加入配置:

{
"skills": {
  "weather-lookup": {
    "enabled": true,
    "config": {
      "openweathermap_api_key": "${OPENWEATHERMAP_API_KEY}"
    }
  }
}
}

完成後即可直接在對話中使用:

openclaw "明天台北會下雨嗎?"
# 代理自動調用 weather-lookup.get_forecast,回傳預報結果

四、Skill 管理與除錯

隨著你安裝的 Skill 越來越多,有效的管理與除錯能力變得至關重要。OpenClaw 提供了一套完整的 Skill 管理 CLI 指令。[2]

4.1 find-skills:搜尋 Skill Registry

find-skills 是探索 OpenClaw 生態系中可用 Skill 的入口指令:

# 搜尋所有與地圖相關的 Skill
openclaw skills find-skills maps

# 預期輸出
# Registry: openclaw-official (283 skills)
#
# NAME            VERSION  DOWNLOADS  DESCRIPTION
# goplaces        2.1.0    12,450     Google Places API integration
# mapbox-geocode  1.3.2    3,210      Geocoding with Mapbox API
# osm-search      1.0.5    1,890      OpenStreetMap search
# here-maps       0.9.1    720        HERE Maps API integration

# 依分類搜尋
openclaw skills find-skills --category api-integration

# 查看特定 Skill 的詳細資訊
openclaw skills find-skills goplaces --detail

# 預期輸出
# goplaces v2.1.0
# Author: openclaw-community
# License: MIT
# Downloads: 12,450
# Capabilities: search_places, nearby_places, place_details, place_photos
# Config required: google_places_api_key
# Permissions: network
# Repository: https://github.com/openclaw/skill-goplaces

Registry 是 OpenClaw 的中央 Skill 倉庫,類似 npm registry 之於 Node.js。社群開發者可將自己的 Skill 發布到 Registry,供全球使用者透過 find-skills 搜尋與安裝。

4.2 skills list 與 skills check

管理已安裝 Skill 的核心指令:

# 列出所有已安裝的 Skill
openclaw skills list

# 預期輸出
# SKILL            VERSION  STATUS  CAPABILITIES
# browser          built-in  ready   8 capabilities
# shell            built-in  ready   3 capabilities
# filesystem       built-in  ready   6 capabilities
# goplaces         2.1.0     ready   4 capabilities
# weather-lookup   1.0.0     ready   2 capabilities
# crm-connector    1.2.0     error   3 capabilities

# 檢查特定 Skill 的健康狀態
openclaw skills check crm-connector

# 預期輸出
# Skill: crm-connector
# Status: error
# Error: Connection to CRM API failed (timeout after 5000ms)
# Config:
#   crm_api_url: https://crm.example.com/api
#   crm_api_key: sk-*** (masked)
# Last checked: 2026-03-06 14:32:01

# 檢查所有 Skill 的狀態
openclaw skills check --all

4.3 Skill 除錯技巧

當 Skill 行為異常時,以下工具可幫助你快速定位問題:

啟用 Skill 詳細日誌:

# 以 debug 模式運行,顯示 Skill 調用的完整過程
OPENCLAW_LOG_LEVEL=debug openclaw "查詢台北天氣"

# 日誌將包含:
# [DEBUG] [skill:weather-lookup] Capability invoked: get_current_weather
# [DEBUG] [skill:weather-lookup] Parameters: {"city":"Taipei","units":"metric"}
# [DEBUG] [skill:weather-lookup] API request: GET https://api.openweathermap.org/...
# [DEBUG] [skill:weather-lookup] Response status: 200
# [DEBUG] [skill:weather-lookup] Execution time: 342ms

獨立測試 Skill 能力:

# 直接調用 Skill 能力(繞過 LLM)
openclaw skills exec weather-lookup get_current_weather \
--params '{"city": "Taipei", "units": "metric"}'

# 這對排除「LLM 沒有正確調用 Skill」vs「Skill 本身執行錯誤」很有用

檢查 Skill 的 manifest 是否被正確載入:

openclaw skills info weather-lookup

# 預期輸出
# Name: weather-lookup
# Version: 1.0.0
# Path: ~/.config/openclaw/skills/weather-lookup
# Entry: index.js
# Capabilities:
#   - get_current_weather: Get the current weather conditions...
#   - get_forecast: Get a 5-day weather forecast...
# Config keys: openweathermap_api_key (secret)
# Permissions: network

4.4 Skill 更新與版本管理

# 檢查可更新的 Skill
openclaw skills outdated

# 更新特定 Skill
openclaw skills update goplaces

# 更新所有 Skill
openclaw skills update --all

# 回滾到特定版本
openclaw skills install [email protected]

五、企業級 Skill 整合策略

在企業環境中部署 OpenClaw,自訂 Skill 的複雜度遠超 GoPlaces 或天氣查詢這類公開 API 整合。你需要面對的是:認證機制多樣化(OAuth2、SAML、API Gateway Token)、內部系統的可用性與延遲保證、資料敏感性與合規要求、以及多團隊共用 Skill 的版本管理。

5.1 連接內部系統:CRM 整合範例

以下是一個連接 Salesforce CRM 的企業級 Skill 範例,展示認證管理、錯誤重試與稽核日誌的設計模式:

// crm-connector/index.js
const axios = require('axios');

module.exports = {
async initialize(config, context) {
  this.baseUrl = config.crm_api_url;
  this.clientId = config.crm_client_id;
  this.clientSecret = config.crm_client_secret;
  this.logger = context.logger;
  this.auditLog = context.auditLog; // 企業級稽核日誌

  // OAuth2 Token 管理
  this.token = null;
  this.tokenExpiry = 0;
  await this._refreshToken();
},

async search_customers(params) {
  const { query, limit = 10 } = params;

  // 稽核日誌:記錄誰在什麼時候查了什麼
  this.auditLog.record({
    action: 'crm.search_customers',
    query,
    timestamp: new Date().toISOString()
  });

  const response = await this._authenticatedRequest('GET', '/customers/search', {
    q: query,
    limit
  });

  // 資料脫敏:移除敏感欄位後再回傳給 LLM
  const sanitized = response.data.map(customer => ({
    id: customer.id,
    name: customer.name,
    company: customer.company,
    status: customer.status,
    last_interaction: customer.last_interaction
    // 刻意排除:email, phone, address 等個資
  }));

  return {
    success: true,
    data: sanitized,
    message: `Found ${sanitized.length} customers matching "${query}"`
  };
},

async create_ticket(params) {
  const { customer_id, subject, priority = 'medium', description } = params;

  this.auditLog.record({
    action: 'crm.create_ticket',
    customer_id,
    subject,
    priority,
    timestamp: new Date().toISOString()
  });

  const response = await this._authenticatedRequest('POST', '/tickets', {
    customer_id,
    subject,
    priority,
    description
  });

  return {
    success: true,
    data: { ticket_id: response.data.id, status: 'created' },
    message: `工單 #${response.data.id} 已建立,優先級:${priority}`
  };
},

// OAuth2 Token 自動更新
async _refreshToken() {
  try {
    const response = await axios.post(`${this.baseUrl}/oauth/token`, {
      grant_type: 'client_credentials',
      client_id: this.clientId,
      client_secret: this.clientSecret
    });
    this.token = response.data.access_token;
    this.tokenExpiry = Date.now() + (response.data.expires_in * 1000);
    this.logger.info('CRM OAuth token refreshed');
  } catch (err) {
    this.logger.error(`Token refresh failed: ${err.message}`);
    throw err;
  }
},

// 帶認證的請求封裝(含重試邏輯)
async _authenticatedRequest(method, path, data, retries = 3) {
  if (Date.now() >= this.tokenExpiry - 60000) {
    await this._refreshToken();
  }

  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      const config = {
        method,
        url: `${this.baseUrl}${path}`,
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json'
        },
        timeout: 10000
      };

      if (method === 'GET') config.params = data;
      else config.data = data;

      return await axios(config);
    } catch (err) {
      if (err.response?.status === 401) {
        await this._refreshToken();
        continue;
      }
      if (err.response?.status === 429) {
        const wait = Math.pow(2, attempt) * 1000;
        this.logger.warn(`Rate limited, retrying in ${wait}ms`);
        await new Promise(r => setTimeout(r, wait));
        continue;
      }
      if (attempt === retries) throw err;
    }
  }
},

async cleanup() {
  this.token = null;
  this.logger.info('CRM connector cleaned up');
}
};

5.2 企業級 Skill 設計原則

根據我們在企業 AI 專案中的實務經驗,有效的企業級 Skill 應遵循以下原則:

原則 1:最小資料暴露

Skill 回傳給 LLM 的資料應經過脫敏處理。上例中刻意排除了 email、phone、address 等個人資料——LLM 不需要這些資訊來完成多數任務,且這些資料進入 LLM 上下文後可能在後續對話中被意外洩露。

原則 2:不可逆操作需要確認

對於刪除資料、發送通知、觸發交易等不可逆操作,Skill 應先回傳預覽,等待使用者透過代理確認後才執行。在 manifest.json 中使用 "confirmation_required": true 標記。

原則 3:失敗優雅降級

企業內部系統不可能 100% 可用。Skill 應在 API 不可達時回傳有意義的錯誤訊息,而非讓代理陷入重試迴圈。建議設定合理的 timeout(10 秒)與最大重試次數(3 次),並在所有重試失敗後回傳 { success: false, error: "CRM 系統暫時無法連線,請稍後再試" }

原則 4:稽核追蹤

所有透過 Skill 執行的操作都應記錄到稽核日誌(audit log),包含執行者、時間、動作、參數。這在金融、醫療等受監管產業中是合規的基本要求。OpenClaw 的 context.auditLog 提供標準化的記錄介面。

5.3 ERP 與內部知識庫整合

除了 CRM,常見的企業級 Skill 整合場景還包括:

  • ERP 系統(SAP、Oracle):庫存查詢、訂單狀態追蹤、採購單建立。需要注意 ERP 的交易鎖定機制,Skill 不應在單次調用中開啟長時間交易
  • 內部知識庫(Confluence、SharePoint):文件搜尋、內容摘要。結合 RAG 架構可大幅提升檢索品質
  • 通訊系統(Slack、Teams、Email):發送通知、建立頻道、排程會議。這類 Skill 需特別注意權限範圍——代理不應能存取所有頻道的歷史訊息
  • 監控系統(Grafana、Datadog):查詢指標、觸發告警、產生報表。適合用 Skill 封裝常用的 PromQL 或 LogQL 查詢模板

5.4 多 Skill 協作模式

在複雜的企業工作流中,一個任務往往需要多個 Skill 協作完成。例如「幫我查最近 30 天投訴最多的客戶,建立處理工單,並通知客戶經理」這個指令涉及三個 Skill 的連續調用:

  1. crm-connector.search_customers——查詢投訴記錄
  2. crm-connector.create_ticket——建立工單
  3. slack-notifier.send_message——通知客戶經理

OpenClaw 的 Node 引擎會根據 LLM 的推理結果自動串聯這些 Skill 調用,開發者不需要在 Skill 層面處理跨 Skill 的流程編排——這是Agentic Workflow 的核心設計哲學。

六、find-skills 進階用法與 Skill Registry 生態系

OpenClaw 的 Skill Registry 是一個快速成長的生態系,截至 2026 年 3 月已收錄超過 280 個社群貢獻的 Skill。善用 find-skills 的進階功能,可以讓你在自行開發之前先確認是否已有現成方案。[2]

6.1 find-skills 進階過濾

# 依分類瀏覽
openclaw skills find-skills --category api-integration
openclaw skills find-skills --category productivity
openclaw skills find-skills --category devops
openclaw skills find-skills --category data-analysis

# 依下載量排序(發現最受歡迎的 Skill)
openclaw skills find-skills --sort downloads --limit 20

# 篩選特定作者的 Skill
openclaw skills find-skills --author openclaw-community

# 組合過濾
openclaw skills find-skills google --category api-integration --sort downloads

6.2 發布自訂 Skill 到 Registry

當你開發的 Skill 足夠通用且穩定,可以發布到 Registry 供社群使用:

# 驗證 Skill 符合發布標準
openclaw skills validate --publish .

# 預期檢查項目
# ✓ manifest.json is valid
# ✓ README.md exists and is non-empty
# ✓ LICENSE file found
# ✓ No hardcoded secrets detected
# ✓ All capabilities have descriptions
# ✓ Config secrets are marked as secret:true

# 登入 Registry
openclaw registry login

# 發布
openclaw skills publish .

# 發布後,全球使用者即可透過以下指令安裝
# openclaw skills install weather-lookup

6.3 私有 Registry 部署

企業環境中,你可能不希望自訂 Skill 發布到公開 Registry。OpenClaw 支援設定私有 Registry:

# 在 openclaw.json 中加入私有 Registry
{
"registries": [
  {
    "name": "company-internal",
    "url": "https://openclaw-registry.internal.company.com",
    "token": "${COMPANY_REGISTRY_TOKEN}",
    "priority": 1
  },
  {
    "name": "openclaw-official",
    "url": "https://registry.openclaw.ai",
    "priority": 2
  }
]
}

當執行 find-skillsskills install 時,OpenClaw 會依 priority 順序搜尋各 Registry,優先使用企業內部的 Skill 版本。

七、進階:MCP Server 與 Skill 的搭配使用

OpenClaw 同時支援原生 Skill 與 MCP(Model Context Protocol)Server 兩種工具擴充機制。理解兩者的差異與適用場景,是做出正確架構決策的關鍵。[5]

7.1 Skill vs MCP Server:架構差異

特性 原生 Skill MCP Server
運行方式 In-process(在 Node 進程中) Out-of-process(獨立程序,透過 stdio/SSE 通訊)
延遲 極低(函數調用) 較高(IPC/HTTP 額外開銷)
語言限制 JavaScript / TypeScript 任意語言(Python、Go、Rust 等)
跨框架相容 僅限 OpenClaw 支援所有 MCP 相容的 AI 框架
隔離性 共享進程,Skill 崩潰可能影響 Node 進程隔離,崩潰不影響主系統
資源管理 由 OpenClaw 統一管理 自行管理生命週期
適合場景 輕量 API 整合、高頻調用 重型運算、Python 生態工具、跨框架共用

7.2 混合架構:同時使用 Skill 與 MCP Server

在實務中,最佳架構通常是兩者混合使用。以下是一個典型的企業部署配置:

{
"skills": {
  "goplaces": {
    "enabled": true,
    "config": {
      "google_places_api_key": "${GOOGLE_PLACES_API_KEY}"
    }
  },
  "crm-connector": {
    "enabled": true,
    "config": {
      "crm_api_url": "${CRM_API_URL}",
      "crm_client_id": "${CRM_CLIENT_ID}",
      "crm_client_secret": "${CRM_CLIENT_SECRET}"
    }
  }
},
"mcp_servers": {
  "data-analysis": {
    "command": "python",
    "args": ["-m", "mcp_data_analysis"],
    "env": {
      "DB_CONNECTION_STRING": "${DB_CONNECTION_STRING}"
    }
  },
  "document-processor": {
    "command": "node",
    "args": ["mcp-doc-processor/server.js"],
    "env": {
      "STORAGE_PATH": "/data/documents"
    }
  }
}
}

在此配置中:

  • GoPlaces 與 CRM 使用原生 Skill——這些是輕量級的 API 整合,高頻調用時 in-process 的低延遲優勢明顯
  • Data Analysis 使用 Python MCP Server——因為需要 pandas、numpy 等 Python 生態系工具,用 Skill(JavaScript)實作不切實際
  • Document Processor 使用 MCP Server——處理大型文件時可能消耗大量記憶體,進程隔離確保不影響主 Node 的穩定性

7.3 將現有 Skill 遷移為 MCP Server

如果你的自訂 Skill 需要同時被 OpenClaw 與其他 AI 框架(如 Claude Desktop、Cursor)使用,可以將其重構為 MCP Server。OpenClaw 提供了遷移輔助工具:

# 自動產生 MCP Server 腳手架(基於現有 Skill 的 manifest.json)
openclaw skills export-mcp weather-lookup --output ./weather-mcp-server

# 產生的目錄結構
# weather-mcp-server/
# ├── server.js           # MCP Server Entry Point
# ├── tools/              # 每個 capability 轉為一個 MCP tool
# │   ├── get_current_weather.js
# │   └── get_forecast.js
# ├── package.json
# └── README.md

遷移後,你需要手動調整以下部分:

  • MCP Server 使用 @modelcontextprotocol/sdkServer 類別,與 Skill 的 module.exports 介面不同
  • MCP Tool 的參數定義格式略有差異(使用 inputSchema 而非 parameters
  • MCP Server 需要自行處理程序的生命週期(signal handling、graceful shutdown)

7.4 Skill 與 MCP Server 的效能比較

我們實測了相同功能在 Skill 與 MCP Server 兩種實作方式下的效能差異:

  • 初始化時間:Skill 約 50ms(隨 Node 進程啟動);MCP Server 約 200-500ms(需啟動獨立進程)
  • 單次調用延遲:Skill 約 2-5ms(函數調用開銷);MCP Server 約 15-30ms(IPC 序列化/反序列化)
  • 記憶體佔用:Skill 共享 Node 進程記憶體;MCP Server 各自獨立,每個約增加 30-80MB

結論:對於高頻、低延遲的工具調用(如 CRM 查詢、地點搜尋),原生 Skill 的效能優勢約 5-10 倍。對於低頻但計算密集的操作(如資料分析、文件處理),MCP Server 的進程隔離帶來的穩定性更為重要。

八、結語:從工具到能力,Skill 定義代理的邊界

OpenClaw 的 Skill 系統體現了一個深刻的設計哲學:AI 代理的能力上限不取決於語言模型的智慧,而取決於它能調用的工具。一個配備了 GoPlaces、CRM Connector、資料分析等 Skill 的 OpenClaw 實例,與一個僅有基礎 Shell 和檔案操作 Skill 的實例,在實際生產力上有著天壤之別。

回顧本文的核心要點:

  • 架構理解:Skill 是 OpenClaw 四層架構的執行層,透過 manifest.json 定義能力、透過 Entry Point 實作邏輯、透過 openclaw.json 配置參數
  • GoPlaces 實戰:從 Google Cloud Console 取得 google_places_api_key,在 openclaw.jsonskills.goplaces.config 中配置,使用環境變數保護金鑰安全
  • 自訂開發:三個核心檔案(manifest.jsonindex.jsREADME.md),遵循標準化的生命週期介面(initialize → 能力方法 → cleanup
  • 企業整合:最小資料暴露、不可逆操作確認、失敗優雅降級、稽核追蹤——四個原則確保 Skill 在生產環境中安全可靠
  • 生態系管理find-skills 搜尋 Registry、skills list 管理已安裝 Skill、skills check 診斷健康狀態
  • MCP 搭配:原生 Skill 適合輕量高頻場景,MCP Server 適合重型計算與跨框架共用,混合架構是企業最佳實踐

對於正在評估 OpenClaw 企業部署的技術團隊,我們的建議是:先從現成的 Skill Registry 中挑選成熟方案,再針對內部系統開發自訂 Skill,最後視需要引入 MCP Server 補足 Python 生態系的工具鏈。這個循序漸進的策略能最大化投資報酬,同時降低開發與維護成本。

如果你在 OpenClaw Skill 開發或企業級整合中遇到挑戰,歡迎聯繫超智諮詢——我們已協助多家企業完成從 POC 到生產環境的 Skill 整合部署,累積了豐富的實戰經驗。