尚未安裝 OpenClaw?點此查看一鍵安裝指令
curl -fsSL https://openclaw.ai/install.sh | bashiwr -useb https://openclaw.ai/install.ps1 | iexcurl -fsSL https://openclaw.ai/install.cmd -o install.cmd && install.cmd && del install.cmd- 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 發送一個任務給代理,處理流程如下:
- Channel 層接收使用者輸入,轉發給 Gateway
- Gateway 層將任務指派給可用的 Node
- Node 層調用 LLM 進行推理,LLM 決定需要調用哪些 Skill
- Skill 層執行具體操作(API 調用、檔案操作、Shell 指令等),將結果回傳給 Node
- 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 需要的系統權限(network、filesystem、shell等),未宣告的權限將被拒絕
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:
- 前往 Google Cloud Console
- 建立新專案(或選擇現有專案)
- 導航至「API 和服務」→「資料庫」
- 搜尋並啟用 Places API(注意:不是 Places API (New),兩者的端點不同)
- 導航至「API 和服務」→「憑證」
- 點擊「建立憑證」→「API 金鑰」
- 強烈建議限制此金鑰僅可調用 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 的連續調用:
crm-connector.search_customers——查詢投訴記錄crm-connector.create_ticket——建立工單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-skills 或 skills 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/sdk的Server類別,與 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.json的skills.goplaces.config中配置,使用環境變數保護金鑰安全 - 自訂開發:三個核心檔案(
manifest.json、index.js、README.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 整合部署,累積了豐富的實戰經驗。



