在現代工作環境中,團隊經常需要在不同平台之間反覆切換:例如查詢 Jira 上的專案進度、查看資料庫中的訂單狀態,或是在 Azure 系統中監控錯誤報告。這些手動查詢的過程雖然看似不複雜,卻往往打斷專注,降低工作效率。當資訊分散在多個平台時,即時掌握整體情況變得更加困難。
Slack 作為一個強大的協作工具,能夠通過 Slack 機器人 應用程式將來自不同系統的數據與通知無縫整合,無需離開 Slack 視窗,團隊成員可以即時獲取關鍵資訊,大幅提升工作效率。
本文將帶你從零開始,學習如何建立一個 Slack 機器人 應用程式,並透過 韜睿軟體 AI OCR API 整合到 Slack 工作空間中,達到更高的自動化和效率作為示範.
一、前置作業
Slack Bot 的核心是透過 Slack API 接收事件(如訊息、指令)並回應。你會需要:
- Django 作為 Web Server(處理 Slack 的 webhook)
- Slack App(在 Slack Developer Portal 註冊)
- Slack API Token(用於呼叫 Slack API)
- ngrok 或雲端部署(讓 Slack 能夠存取你的 webhook)
1. 在 Slack API 建立一個新的 APP

這邊有兩個建立方式可以選擇:manifest
可以讓YMAL 或 JSON 的設定檔,明確定義權限與功能,且如果需要建立新環境,在重復使用上很方便。
display_information:
name: My Slack Bot
features:
bot_user:
display_name: MyBot
always_online: true
oauth_config:
scopes:
bot:
- chat:write
- app_mentions:read
settings:
event_subscriptions:
request_url: https://yourdomain.com/slack/events
bot_events:
- app_mention
熟悉 YAML/JSON 的開發者,或是有想要自動化部署或 CI/CD,以及有多個 App 或 workspace 要管理的需求,推薦使用 manifest。
scratch
則是 Slack 提供的 UI 步驟,適合初學者,可以邊設定邊測試 webhook、OAuth 等功能。適合第一次開發 Slack App,想快速測試功能,或是還不熟悉 YAML/JSON 或沒有版本化設定需求的用戶。
1. 這邊我們選擇用 scratch,輸入 App 名稱和要建置的工作環境後,就會看到 App 的設定頁面

在 Event Subscription 的選項,完成以下動作:
- 打開 “Enable Events”,並輸入你的 Webhook 路徑 ( Slack 會立刻發送請求去驗證這個 URL 是否有效 )。
- 在 “Subscribe to bot events” 加入三個事件:
app_mention
(被提及)message.channels
(公開頻道訊息)message.im
(私訊)

2. 在 OAuth & Permission 選項,點選 “Install to <工作空間>” 的按鈕取得 OAuth Token。

3. 然後在 “Bot Token Scopes” 加入一個 Token:
chat:write
:允許你的 bot 發送訊息到頻道、私訊、thread 等
4. Slack 會自動幫你在「應用程式 (Apps)」建立一個私訊對話 (Direct Message),通稱 App DM。

傳送訊息被關閉是正常的。這個頁面不是頻道,也不是真正的 DM 對話,除非你有在 Slack Api 設定 Event subscriptions(例如 message.im),以及 Interactivity 或 slash commands,否則你無法在這裡輸入訊息給 bot。
※ 補充:Slack 的 DM 形式大致可以分成以下幾種:
- 人與人之間的私訊:
你可以直接點選某個人的名字,開啟一對一對話 - 多人私訊:
你可以跟兩個以上的人開啟群組私訊(但不是頻道) - App DM(Bot DM):
這是 Slack 自動幫你的 bot 建立的私訊頁面,通常在左側 sidebar 的「Apps」區塊裡
二、Django 開發
首先加上環境變數,將機器人的 OAuth Token 加進 Django 專案的 ‘settings.py’:
SLACK_BOT_TOKEN = "xoxb-345...20f"
然後新增一個 Django app,這裡我們將它命名為 ‘slack_bot’,在裡面建立 Slack 機器人的基本版型,以及配置 URL。
# bot_view.py
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import requests
import os
SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
@csrf_exempt
def slack_webhook(request):
payload = json.loads(request.body)
# Slack URL verification
if payload.get("type") == "url_verification":
return JsonResponse({"challenge": payload.get("challenge")})
# 處理訊息事件
if payload.get("type") == "event_callback":
event = payload.get("event")
if event.get("type") == "app_mention":
user = event.get("user")
channel = event.get("channel")
text = event.get("text")
reply = f"Hi <@{user}>! 你說的是:{text}"
requests.post("https://slack.com/api/chat.postMessage", headers={
"Authorization": f"Bearer {SLACK_BOT_TOKEN}",
"Content-Type": "application/json"
}, json={
"channel": channel,
"text": reply
})
return JsonResponse({"status": "ok"})
# urls.py
from django.urls import path
from app.slack_bot.views.bot_view import slack_webhook
urlpatterns = [
path("webhook/", slack_webhook),
]
# <django-project> urls.py
urlpatterns = [
...
path("api/slack/", include("app.slack_bot.urls")),
...
]
測試連線:在頻道中提及 Bot
在 Slack 我們可以先試著透過觸發標註事件 (app_mention) 去檢查 Webhook 是否有順利連線且順利運作我們設計的邏輯。
打開想讓 Bot 回應的頻道 (這邊我們新建一個頻道,叫 “bot_test”),在訊息框輸入 /invite @<機器人名稱>

機器人進入群組後就可以使用了。只要你標註機器人,訊息就會觸發 Webhook。

讓 Slack Bot 處理圖片
要接收圖片,我們要在 “Subscribe to bot events” 加入一個事件:
files:read
:讀取使用者上傳的檔案(圖片)
並在 Event Subscription 確認有加上這三個事件:
message.channels
(公開頻道)message.groups
(私密頻道)message.im
(私訊)
Slack 只會幫可以處理這三種事件的帳號處理圖片,否則 Slack 不會發送圖片訊息給你的 webhook。
加完後記得重新「Install to Workspace」更新 token 權限。
然後我們修改一下 Webhook 的邏輯,在事件處理上做出區分:
def download_slack_image(image_url):
headers = {
"Authorization": f"Bearer {SLACK_BOT_TOKEN}"
}
response = requests.get(image_url, headers=headers)
if response.status_code == 200:
filename = "downloaded_image.png"
with open(filename, "wb") as f:
f.write(response.content)
return filename
return None
...
# 處理圖片訊息(message + files)
elif event.get("type") == "message" and "files" in event:
print("收到 message 和 files 了!")
for file in event["files"]:
if file.get("mimetype", "").startswith("image/"):
image_url = file.get("url_private")
filename = download_slack_image(image_url)
if filename:
reply = f"Hi <@{user}>! 我已經收到你的圖片 `{filename}`,準備處理囉!"
send_slack_message(channel, reply)
測試時不用標註機器人,直接上傳圖片即可。

三、業務情境實作 – 串接 API
如果公司有內部的系統服務 API(如資料查詢、身分驗證等),也可以將它們串接到 Slack 機器人上,其實就是把剛才處理圖片的訊息內容改成 API 的回傳值就可以了。
這邊以串接公司票據辨識的 API 作為範例,得到的回傳結果如下:



(車票與發票皆為網路搜尋的範本,敏感資訊已有額外處理。)
補充:訊息事件的去重處理
要注意的是,通常在 Slack 串接 API 可能會需要去重 (去除重複呼叫) 的設計。因為如果伺服器回應太慢,Slack 就會重複發送請求。
在 View 裡面我們要做兩個處理:一個是在 Webhook 開頭直接先確認標頭,看是不是 Slack 重送的訊息,是的話就直接忽略。
@csrf_exempt
def slack_webhook(request):
# Slack retry 重送直接忽略
if request.headers.get("X-Slack-Retry-Num"):
return JsonResponse({"status": "ignored"})
...
另一個是要在處理圖片事件 (message + file_share) 時,檢查是否有重複發送的事件。
可以用 set 去接住事件 id,但 Slack 不是每種情境都有 client_msg_id (像手機傳圖、桌機拖圖、或直接用第三方應用傳圖就會回傳 None)。
所以去重的 key 可以再加上 event_ts (事件時間戳),在 Slack 這絕對是每個訊息的唯一值。
msg_id = event.get("client_msg_id") or event.get("event_ts")
if msg_id in processed_messages:
print(f"跳過重複訊息 {msg_id}")
return
processed_messages.add(msg_id)
或是也可以用 Redis 暫存已經處理過的圖片 URL,如果在處理前的檢查發現這是重複請求的話,就會擋下來。存入、取得和刪除 URL 的方法設計如下:
class RedisUtils:
...
@staticmethod
def store_image_url(email: str, image_url: str, ttl=600):
"""將 image_url 存入 Redis,預設有效 10 分鐘"""
redis_conn = get_redis_connection("default")
redis_conn.set(f"image_url:{email}", image_url, ex=ttl)
print(f"將 image_url 存入 Redis:{image_url}")
@staticmethod
def get_stored_image_url(email: str):
redis_conn = get_redis_connection("default")
return redis_conn.get(f"image_url:{email}")
然後在處理圖片訊息前,我們也檢查一下這張圖是否已經重複檢驗過。Redis 的時間抓 30 秒就好,因為重送的訊息通常都很快。
最後整段檢驗圖片(檔案)訊息是否重複的驗證流程如下:
...
# 處理圖片訊息(message + files)
elif event.get("type") == "message" and "files" in event:
# 取用 client_msg_id 或 event_ts 當唯一 key
msg_id = event.get("client_msg_id") or event.get("event_ts")
if event.get("type") == "message" and "files" in event:
# 在 Redis 檢查這張圖是否已經處理過
if RedisUtils.get_stored_image_url(msg_id):
print(f"跳過重複訊息 {msg_id}")
return JsonResponse({"status": "duplicate"})
RedisUtils.store_image_url(msg_id, ttl=30)
...
四、儲存 Slack 用戶資訊
如果有需要紀錄用戶資料去做統計、或是身分驗證等用途,Slack 有提供相關 API 可以存取留言過的用戶資訊:
- 在 Django 安裝 slack app 的套件:
uv add django-slack-app
# settings.py
INSTALLED_APPS = ['slack_app', ...]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'slack_app.auth_backends.SlackAuthenticationBackend',
]
SLACK_CLIENT_ID = '你的 Slack App Client ID'
SLACK_CLIENT_SECRET = '你的 Slack App Secret'
SLACK_SIGNING_SECRET = '你的 Signing Secret'
- 去 Slack api 的 “Bot Token Scope” 加上
users:read
的權限。(2017 年以後,如果要查詢 email,需再加上users:read:email
的權限) - 在 Django 建立 Slack 的 Model。收到訊息並完成 OAuth 驗證後,可以得到的欄位有這些:


- 串接 Slack 身分驗證的 API,就可以取得想要的用戶資訊了。
# 取得用戶資訊 (串接 Slack 提供的用戶驗證 API)
def get_slack_user_info(user_id):
url = 'https://slack.com/api/users.info'
headers = {
'Authorization': f'Bearer {SLACK_BOT_TOKEN}'
}
params = {
'user': user_id
}
response = requests.get(url, headers=headers, params=params)
data = response.json()
return data.get('user', {})
...
# 處理事件
if payload.get("type") == "event_callback":
event = payload.get("event")
team_id = payload.get('team_id')
channel = event.get("channel")
user = event.get("user")
# 呼叫 Slack API 取得使用者資訊
user_info = get_slack_user_info(user).get('profile', {})
# 儲存或更新 Model
CustomSlackUser.objects.update_or_create(
slack_user_id=user,
defaults={
'team_id': team_id,
'real_name': user_info.get('real_name'),
'display_name': user_info.get('display_name'),
'email': user_info.get('email'),
'updated_time': timezone.now()
}
)
...
本來應該這樣就完成了。
但是 django-slack-app 本身有個很大的問題:他在 PyPI 上的最新版本是 1.0.40(2020 年 3 月 27 日)——也就是說,它已經 5 年多沒有更新,還停留在 Django 2.x / Postgres JSONField 的時代,沒有針對 SQLite 或新版 Django 做過調整。
所以我們會遇到這個錯誤:
ModuleNotFoundError: No module named 'psycopg2'
這是因為在 slack-app 的 Model 有用到舊版的 JSONField:在 Django 3.1 以前,JSON 的模型欄位是引用 django.contrib.postgres.fields.JSONField
提供的方法,當時這還是 PostgreSQL 專用的欄位,所以要安裝相關套件,也就是 ‘psycopg2’。
但在 Django 3.1 以後,JSONField 已經變成跨資料庫的核心欄位,可以直接從 django.db.models
匯入,SQLite、PostgreSQL、MySQL 都能用。
一個方法是,我們可以直接修改裡面的 import 就好 (記得要連遷移檔都一起改),但這樣當我們更新或重新安裝 django-slack-app 時,就有可能被改回來。
所以另一種做法是:fork 一份 django-slack-app 到自己的 repo,把 model 和 migration 都改好,之後直接用你自己的版本安裝。
- 先解除安裝舊套件:
uv remove django-slack-app
- 到 django-slack-app 的 GitHub,點選右上角的 fork,按下 create fork 後,就會在你的 repository 建立一個相同的 django-slack-app。

3. 在專案外的資料夾將 fork 的套件 clone 到本地端。(安全起見)
cd 你的專案資料夾外面 # 先到一個安全的位置
git clone https://github.com/你的GitHub帳號/django-slack-app.git
cd django-slack-app
- 打開檔案,修改裡面所有用到
django.contrib.postgres.fields.JSONField
的地方 (包含遷移檔),改成django.db.models
。
GitHub 的版本似乎有更新過,因此只要修改遷移檔的 import,以及 29 行 JSONField 的引用路徑拿掉,就可以使用了。 - 到 setup.py 修改版本號,方便後續確認使用的是自己修改的版本。
setup(
version="1.0.0+sqlitefix", # 版本號格式可能會影響 import,請自行注意
install_requires=["slackclient", "celery"]
)
- commit 並 push 回 GitHub
- 回到原本的專案,將我們修改過的套件透過 git 網址安裝:
uv add git+https://github.com/你的GitHub帳號/django-slack-app.git@master
,在安裝的套件中有看到你版本號的 django-slack-app 就表示安裝成功了。
...
+ django-slack-app==1.0.0+sqlitefix (from git+https://github.com/你的GitHub帳號/django-slack-app.git@6b3530cbe0a121fa1c64574803f73c44484e3f25)
...
後續維護
官方更新時,你可以在 Fork 拉取更新後再 push 到 GitHub,然後用 uv sync
更新。
這樣我們在傳訊息時,就可以將用戶資訊記錄下來了。

五、總結
Slack 可以根據需求去設計流程自動化的應用程式 (機器人),若運用得當,員工甚至可以在 Slack 就完成所有的公司行政流程與業務,減少重複的工作量與時間,這正是流程自動化帶來的長遠效益。
透過韜睿軟體 Swift OCR Portal 您可以取得不同的辨識應用,加入您的Slack機器人中使用,而對 Slack 機器人有興趣,可以參考官方文件深入研究。