跳至主要內容

AppleScript × AI:用最老派的 Mac 自動化,接上最新的 AI 工作流

AppleScript 是 macOS 裡存在很久、但常被低估的自動化語言。它不擅長取代完整 App 開發,卻很擅長把 Finder、Mail、Calendar、瀏覽器、剪貼簿與系統 UI 串成一段可重複執行的工作流。當 AI 能夠負責摘要、改寫、分類、生成文字與判斷下一步,AppleScript 就可以成為「把 AI 結果放回 Mac 桌面環境」的膠水層。

AppleScript AI prompt mockup


AI 很會想,但 Mac 還是需要有人按按鈕

現在很多 AI 工具都能完成摘要、翻譯、分類、改寫、產生報表等任務。問題是,日常工作通常不是只停在「得到一段文字」。我們還需要把結果貼回文件、整理到資料夾、寄出郵件、建立行事曆事件,或在某個只有圖形介面的軟體裡重複點擊。

這正是 AppleScript 重新有趣的地方。

AppleScript 不是新技術。它從 System 7.1 時代就開始存在,是 Apple 為 Mac 設計的腳本語言。根據 Apple 的說明,它可以直接控制支援腳本化的 Macintosh 應用程式,也可以控制 macOS 的部分功能;腳本的本質是一組 written instructions,用來自動化重複任務、整合多個應用功能,或建立較複雜的工作流程。

換句話說:

  • AI 負責「理解與生成」;
  • AppleScript 負責「操作 Mac 與 App」;
  • 人類 負責「設定目標、審核結果、決定是否執行」。

這三者加起來,會比單純聊天機器人更接近日常工作流。


AppleScript 適合扮演什麼角色?

Apple 官方文件把 macOS scripting 描述成一種自動化複雜、重複、耗時任務的方法。它可以和 App、process 與作業系統互動。這個定位很適合用在 AI 工作流的最後一哩路:

  • 取得上下文:讀取剪貼簿、選取文字、目前檔案、Finder 中選到的項目。
  • 呼叫外部能力:透過 shell script、CLI 工具或 HTTP API 把內容送給 AI 模型。
  • 執行結果:把 AI 回傳的文字貼回原處、建立檔案、命名資料夾、寄信、加入提醒事項。
  • 補上 UI 自動化:對於沒有完整 API 的 App,可用 System Events 模擬鍵盤、選單與部分 UI 操作。

AppleScript 本身不一定要承擔所有邏輯。實務上,較穩定的做法是分層:

  • AppleScript:控制 macOS App、剪貼簿、通知、視窗與權限互動;
  • shell / Python / Node.js:處理 API 呼叫、JSON、複雜資料轉換;
  • AI 模型:處理語意任務,例如摘要、分類、修稿與產生結構化輸出。

權限是第一個坑

macOS automation permission mockup

在開始之前,要先知道 macOS 對自動化有安全限制。當 AppleScript 要控制其他 App 時,系統可能會要求授權;當腳本需要透過 System Events 模擬按鍵、點選選單或讀取 UI 元素時,則可能需要 Accessibility 權限。

你通常會遇到兩類設定:

  • System Settings → Privacy & Security → Automation:允許某個腳本、App 或工具控制其他 App。
  • System Settings → Privacy & Security → Accessibility:允許工具模擬鍵盤、滑鼠或讀取部分 UI 元素。

這也是為什麼我不建議一開始就追求「全自動 AI Agent 操作整台電腦」。權限越大,錯誤的代價越高。比較安全的方式,是先把流程做小:取得文字、送給 AI、回填結果,必要時再逐步增加操作範圍。


一個最小可行的 AI 工作流

以下是一個實用的最小流程:使用者在任何 App 裡選取文字,執行 AppleScript,腳本複製選取內容,交給 AI 摘要,再把摘要放回剪貼簿。

set promptText to "請用繁體中文摘要以下文字,保留 3 個重點:"

-- 複製目前選取內容
tell application "System Events"
    keystroke "c" using command down
end tell

delay 0.2
set selectedText to the clipboard

if selectedText is "" then
    display dialog "剪貼簿沒有文字內容。請先選取一段文字再執行。" buttons {"OK"} default button "OK"
    return
end if

set resultText to my askAI(promptText, selectedText)
set the clipboard to resultText

display notification "摘要已放入剪貼簿" with title "AppleScript × AI"

on askAI(promptText, selectedText)
    -- 實務上不建議把 API key 寫在 AppleScript 裡。
    -- 這個範例從環境變數讀取設定:
    -- AI_API_BASE:OpenAI-compatible endpoint,例如 https://api.openai.com/v1 或 http://localhost:11434/v1
    -- AI_API_KEY:API key;本機模型若不需要可留空
    -- AI_MODEL:模型名稱,例如 gpt-4o-mini、llama3.1、qwen2.5 等
    set pythonCode to "
import json, os, sys, urllib.request

prompt = sys.argv[1]
text = sys.argv[2]
base = os.environ.get('AI_API_BASE', 'http://localhost:11434/v1').rstrip('/')
model = os.environ.get('AI_MODEL', 'llama3.1')
api_key = os.environ.get('AI_API_KEY', '')

payload = {
    'model': model,
    'messages': [
        {'role': 'system', 'content': '你是謹慎的工作助理。請使用繁體中文,輸出清楚、可直接貼上的內容。'},
        {'role': 'user', 'content': prompt + '\n\n' + text}
    ],
    'temperature': 0.2
}

req = urllib.request.Request(
    base + '/chat/completions',
    data=json.dumps(payload).encode('utf-8'),
    headers={'Content-Type': 'application/json'},
    method='POST'
)
if api_key:
    req.add_header('Authorization', 'Bearer ' + api_key)

try:
    with urllib.request.urlopen(req, timeout=60) as res:
        data = json.loads(res.read().decode('utf-8'))
    print(data['choices'][0]['message']['content'])
except Exception as exc:
    print('AI 呼叫失敗:' + str(exc))
    sys.exit(1)
"

    set shellCommand to "AI_API_BASE=${AI_API_BASE:-http://localhost:11434/v1} AI_MODEL=${AI_MODEL:-llama3.1} AI_API_KEY=${AI_API_KEY:-} /usr/bin/python3 -c " & quoted form of pythonCode & " " & quoted form of promptText & " " & quoted form of selectedText
    return do shell script shellCommand
end askAI

這段範例刻意使用 OpenAI-compatible API 格式,但不綁定單一供應商。你可以把 AI_API_BASE 指向雲端服務、公司內部 gateway,或本機模型服務,例如 Ollama / LM Studio 提供的相容端點。

要注意:從 Script Editor 執行 AppleScript 時,不一定會讀到你在 Terminal 裡 export 的環境變數。若要讓 GUI App 也讀得到,可用 launchctl setenv 設定;若只是從 Terminal 透過 osascript 執行,則可用一般 export

範例設定方式如下:

# 本機模型範例:通常不需要 API key
launchctl setenv AI_API_BASE "http://localhost:11434/v1"
launchctl setenv AI_MODEL "llama3.1"

# 雲端 API 範例
launchctl setenv AI_API_BASE "https://api.openai.com/v1"
launchctl setenv AI_API_KEY "你的 API key"
launchctl setenv AI_MODEL "gpt-4o-mini"

如果要長期使用,建議把 API 呼叫抽成獨立的 ask-ai CLI,再讓 AppleScript 只負責:取得文字、呼叫 CLI、貼回結果。這樣比較好測試,也比較不容易把複雜邏輯塞進 AppleScript。


推薦架構:讓 AI 輸出結構化結果,而不是直接操作電腦

AI automation workflow mockup

如果只是摘要文字,回傳純文字就夠了。但只要牽涉到「下一步要做什麼」,我會建議讓 AI 回傳 JSON,而不是讓它自由發揮。

例如要求 AI 回傳:

{
  "action": "create_note",
  "title": "會議重點摘要",
  "content": "...",
  "confidence": 0.86,
  "needs_confirmation": true
}

AppleScript 或後端程式接到這份 JSON 後,只接受白名單裡的 action。如果 actioncreate_note,就建立筆記;如果是 rename_files,就先顯示預覽;如果是 send_emaildelete_files,就強制要求人工確認。

重點不是讓 AI 任意產生 AppleScript 後直接執行。比較安全的模式是:

  • 人類定義允許的 action;
  • AI 只負責在 action 之間選擇,並產生必要欄位;
  • AppleScript 只執行已知、可審核、可回滾的操作;
  • 高風險動作永遠保留人工確認。

為什麼不是全部交給 AI Agent?

如果 AI Agent 已經能看螢幕、點按鈕、操作瀏覽器,為什麼還需要 AppleScript?

我的看法是:AppleScript 的價值在於「可預期」。

AI Agent 擅長處理模糊任務,但它的每一步可能受到畫面狀態、文字理解、模型輸出影響。AppleScript 則比較像固定軌道:如果條件一致,它會用同樣方式執行同樣流程。對於每天都要做的任務,這種可重複性很重要。

因此,比較務實的分工不是二選一,而是:

  • 讓 AI 產出內容或判斷分類;
  • 讓 AppleScript 執行固定、安全、可追蹤的操作;
  • 在關鍵節點讓人確認,例如寄信前、刪檔前、批次改名之前。

Automator、Shortcuts、AppleScript、shell 該怎麼選?

macOS 自動化工具很多,不一定每件事都要用 AppleScript。可以用下面的方式判斷:

工具適合情境不適合情境
Shortcuts快速串接系統動作、分享選單、行動裝置與 Mac 共用流程需要細緻控制舊式 Mac App、複雜錯誤處理或大量文字處理
Automator既有 Automator workflow、批次處理 Finder 檔案、服務選單新專案通常可優先考慮 Shortcuts 或腳本化方式
AppleScript控制支援腳本化的 Mac App、操作選單、視窗、剪貼簿與 UI複雜資料處理、網路 API、JSON 解析、大型程式邏輯
shell / Python / Node.js呼叫 API、處理 JSON、整理檔案、串接 CLI、做可測試邏輯需要直接控制 GUI App 或 macOS App 物件模型

我的建議是:

  • 如果只是簡單串流程,先試 Shortcuts
  • 如果要控制 Finder、Mail、Calendar、Notes 等 Mac App,用 AppleScript
  • 如果要呼叫 AI API、解析 JSON、處理大量文字,用 Python / Node.js / shell
  • 如果要做穩定的長期工作流,把它們組合起來:Shortcuts 當入口,AppleScript 控制 App,Python 或 Node.js 處理 AI 與資料。

可以落地的幾個場景

1. 郵件整理與回覆草稿

流程:

  1. 選取一封郵件內容;
  2. AppleScript 複製文字並傳給 AI;
  3. AI 產生摘要與回覆草稿;
  4. AppleScript 將草稿貼到回覆視窗;
  5. 使用者檢查後手動送出。

這裡的重點是:不要讓腳本自動寄出,至少第一版應保留人工確認。

2. Finder 檔案批次命名

流程:

  1. Finder 選取多個檔案;
  2. AppleScript 取得檔名與部分內容;
  3. AI 產生命名規則或分類;
  4. AppleScript 顯示預覽清單;
  5. 使用者確認後才批次改名。

適合用在會議記錄、截圖、合約草稿、研究資料分類。

3. 瀏覽器內容摘要到 Notes

流程:

  1. 使用者在瀏覽器選取文章段落;
  2. AppleScript 複製內容;
  3. AI 摘要成條列與待辦;
  4. AppleScript 開啟 Notes 或指定筆記 App;
  5. 將結果附上來源 URL 後存入。

這類流程非常適合做成快捷鍵或 Script Menu。

4. 把會議記錄轉成待辦事項

流程:

  1. 將會議逐字稿或筆記交給 AI;
  2. AI 回傳負責人、期限、任務、風險;
  3. AppleScript 將任務放入 Reminders、Calendar 或專案管理工具;
  4. 使用者確認後再同步給團隊。

這是 AppleScript × AI 很典型的價值:AI 讀懂文字,AppleScript 把結果放到你每天使用的 Mac 工具裡。


安全原則與企業環境注意事項

在 AI 與自動化結合時,最容易出問題的不是技術,而是權限邊界。尤其在企業環境,腳本可能碰到客戶資料、內部文件、合約、郵件與權限系統,更應該先定規則再擴大使用。

建議至少遵守以下原則:

  • 不要把 API key 寫死在 AppleScript 裡:改用環境變數、Keychain、密鑰管理服務,或公司內部 proxy。腳本檔很容易被複製、同步或誤傳。
  • 不要把敏感資料送到未核准的模型服務:客戶資料、醫療資料、財務資料、合約、原始碼、內部會議內容,都應該依公司政策處理。若不確定,先使用本機模型或內部 gateway。
  • 高風險動作必須人工確認:包含寄信、刪檔、移動大量檔案、批次改名、對外送出表單、修改 CRM / ERP / 工單系統資料。
  • 讓 AI 輸出結構化資料:與其讓 AI 回傳一段自由文字,不如要求它回傳 JSON,例如:actiontargetreasonconfidenceneeds_confirmation
  • AppleScript 只執行白名單動作:不要讓模型任意產生 AppleScript 後直接執行。更安全的方式是由模型選擇預先定義好的 action。
  • 加入 dry-run 與預覽模式:批次改名、整理檔案、建立大量待辦之前,先顯示將要執行的清單,讓使用者確認。
  • 保留 log,但避免記錄完整敏感內容:至少記錄時間、操作者、action、目標摘要、AI 決策與實際執行結果。若內容敏感,可以記錄 hash、檔名或摘要,不要把全文寫進 log。
  • 定期檢查 Accessibility 與 Automation 權限:離職、換機、工具棄用或腳本不再使用時,應撤銷不必要的權限。
  • 用最小權限設計流程:能只讀剪貼簿就不要控制整個 App;能只建立草稿就不要自動送出;能只處理單一資料夾就不要掃描整個磁碟。
  • 把 AI 視為建議者,不是最終執行者:特別是牽涉金錢、法務、人事、客戶承諾與不可逆操作時,人類審核不應省略。

文章結論

AppleScript 看起來老派,但它仍然是 macOS 上非常實用的自動化膠水。AI 的出現沒有讓它過時,反而讓它多了一個新角色:把語意能力帶進 Finder、Mail、Calendar、Notes、瀏覽器與各種桌面 App。

真正值得做的不是讓 AI 失控地操作整台電腦,而是把 AI 放在適合的位置:負責理解、摘要、改寫與建議;再由 AppleScript 執行可預期、可審核、可回溯的 Mac 操作。

如果你的工作每天都在複製貼上、整理檔案、摘要內容、搬運資訊,那麼 AppleScript × AI 可能就是一個低成本、但很快能看到效果的自動化起點。


參考資料