Google Chat 設置
將 Hermes Agent 作為機器人連接到 Google Chat。該集成使用 Cloud Pub/Sub 拉取訂閱(pull subscriptions)處理入站事件,並使用 Chat REST API 發送出站消息。其易用性與 Slack Socket Mode 或 Telegram 長輪詢相當:你的 Hermes 進程不需要公共 URL、隧道或 TLS 證書。它通過連接、認證並監聽訂閱來工作——這與 Telegram 機器人監聽令牌的方式相同。
運行
hermes gateway setup並選擇 Google Chat 以獲取引導式 walkthrough。
Google Chat 是 Google Workspace 的一部分。你可以使用個人 Workspace(通過 Google 註冊的 @yourdomain.com)或你擁有發佈應用管理員權限的工作 Workspace 進行此集成。僅限 Gmail 的賬戶無法託管 Chat 應用。
概覽
| 組件 | 值 |
|---|---|
| 庫 | google-cloud-pubsub, google-api-python-client, google-auth |
| 入站傳輸 | Cloud Pub/Sub 拉取訂閱(無公共端點) |
| 出站傳輸 | Chat REST API (chat.googleapis.com) |
| 身份驗證 | 服務賬號 JSON,在訂閱上具有 roles/pubsub.subscriber 角色 |
| 用戶標識 | Chat 資源名稱 (users/{id}) + 電子郵件 |
步驟 1:創建或選擇一個 GCP 項目
你需要一個 Google Cloud 項目來託管 Pub/Sub 主題。如果你還沒有項目,請在 console.cloud.google.com 創建一個——個人賬戶獲得的免費層級足以覆蓋機器人流量。
記下項目 ID(例如 my-chat-bot-123)。你在後續的每個步驟中都會用到它。
步驟 2:啟用兩個 API
在控制檯中,前往 APIs & Services → Library 並啟用:
- Google Chat API
- Cloud Pub/Sub API
對於個人機器人產生的流量,這兩者都是免費的。
步驟 3:創建服務賬號
IAM & Admin → Service Accounts → Create Service Account。
- 名稱:
hermes-chat-bot - 跳過“授予此服務賬號訪問項目的權限”步驟。你只需要特定訂閱上的 IAM 權限——不要授予項目級別的 Pub/Sub 角色。
創建後,打開該服務賬號,前往 Keys → Add Key → Create new key → JSON 並下載文件。將其保存在只有 Hermes 可以讀取的位置(例如 ~/.hermes/google-chat-sa.json,執行 chmod 600)。
一個常見的錯誤是搜索特定的 Chat IAM 角色並在項目級別授予它。該角色並不存在。Chat 機器人的權限來自於安裝在空間(space)中,而非來自 IAM。你的服務賬號只需要在下一步創建的訂閱上擁有 Pub/Sub 訂閱者權限。
步驟 4:創建 Pub/Sub 主題和訂閱
Pub/Sub → Topics → Create topic.
- 主題 ID:
hermes-chat-events - 其他所有選項保留默認值。
創建後,在主題的詳情頁面有一個 Subscriptions 標籤頁。創建一個訂閱:
- 訂閱 ID:
hermes-chat-events-sub - 交付類型:Pull
- 消息保留:7 days(以便積壓消息在 hermes 重啟後仍然存在)
- 其餘保留默認值。
步驟 5:主題上的 IAM 綁定(關鍵)
在主題(而非訂閱)上,添加一個 IAM 主體:
- 主體:
chat-api-push@system.gserviceaccount.com - 角色:
Pub/Sub Publisher
如果沒有這一步,Google Chat 無法向你的主題發佈事件,你的機器人將永遠收不到任何消息。
步驟 6:訂閱上的 IAM 綁定
在訂閱上,將你自己的服務賬號添加為主體:
- 主體:
hermes-chat-bot@<your-project>.iam.gserviceaccount.com - 角色:
Pub/Sub Subscriber
同時在該訂閱上授予 Pub/Sub Viewer 權限——Hermes 在啟動時會調用 subscription.get() 作為可達性檢查。
步驟 7:配置 Chat 應用
前往 APIs & Services → Google Chat API → Configuration。
- App name:你希望用戶看到的名稱(“Hermes”是合理的選擇)。
- Avatar URL:任何公開的 PNG 圖片(Google 有一些默認圖片)。
- Description:在應用目錄中顯示的一句簡短描述。
- Functionality:啟用 Receive 1:1 messages 和 Join spaces and group conversations。
- Connection settings:選擇 Cloud Pub/Sub,輸入主題名稱
projects/<your-project>/topics/hermes-chat-events。 - Visibility:限制為你的工作區(或特定用戶)——在測試期間不要發佈給所有人。
保存。
步驟 8:在測試空間中安裝機器人
在瀏覽器中打開 Google Chat。通過在 + New Chat 菜單中搜索應用名稱,開始與你的應用進行私聊(DM)。第一次向其發送消息時,Google 會發送一個 ADDED_TO_SPACE 事件,Hermes 利用該事件緩存機器人自身的 users/{id} 以用於自我消息過濾。
步驟 9:配置 Hermes
將 Google Chat 部分添加到 ~/.hermes/.env:
# Required
GOOGLE_CHAT_PROJECT_ID=my-chat-bot-123
GOOGLE_CHAT_SUBSCRIPTION_NAME=projects/my-chat-bot-123/subscriptions/hermes-chat-events-sub
GOOGLE_CHAT_SERVICE_ACCOUNT_JSON=/home/you/.hermes/google-chat-sa.json
# Authorization — paste the emails of people allowed to talk to the bot
GOOGLE_CHAT_ALLOWED_USERS=you@yourdomain.com,coworker@yourdomain.com
# Optional
GOOGLE_CHAT_HOME_CHANNEL=spaces/AAAA... # default delivery destination for cron jobs
GOOGLE_CHAT_MAX_MESSAGES=1 # Pub/Sub FlowControl; 1 serializes commands per session
GOOGLE_CHAT_MAX_BYTES=16777216 # 16 MiB — cap on in-flight message bytes
項目 ID 也可以回退到 GOOGLE_CLOUD_PROJECT,服務賬號路徑可以回退到 GOOGLE_APPLICATION_CREDENTIALS——使用你喜歡的約定即可。
安裝 Google Chat 適配器所需的依賴項(目前尚未發佈 Hermes extra——直接安裝它們):
pip install google-cloud-pubsub google-api-python-client google-auth google-auth-oauthlib
啟動網關:
hermes gateway
你應該會看到類似如下的日誌行:
[GoogleChat] Connected; project=my-chat-bot-123, subscription=<redacted>,
bot_user_id=users/XXXX, flow_control(msgs=1, bytes=16777216)
在測試私聊(DM)中發送“hola”。機器人會先發佈一個“Hermes is thinking…”標記,然後就地編輯該消息,替換為實際響應——不會出現“消息已刪除”的佔位符。
格式與功能
Google Chat 僅支持有限的 Markdown 子集:
| 支持 | 不支持 |
|---|---|
*bold*、_italic_、~strike~、`code` | 標題、列表 |
| 通過 URL 嵌入圖片 | 交互式 Card v2 按鈕(本網關的 v1 版本) |
原生文件附件(在執行 /setup-files 後——參見步驟 10) | 原生語音筆記 / 圓形視頻筆記 |
代理的系統提示中包含針對 Google Chat 的特定提示,使其瞭解這些限制並避免使用無法渲染的格式。
消息大小限制:每條消息 4000 個字符。較長的代理響應會自動拆分為多條消息。
線程支持:當用戶在線程內回覆時,Hermes 會檢測 thread.name 並在同一線程中發佈回覆,因此每個線程擁有獨立的 Hermes 會話。
步驟 10:原生附件交付(可選)
默認情況下,機器人可以發佈文本、通過 URL 嵌入圖片,以及用於音頻/視頻/文檔的下載卡片。要交付原生 Chat 附件(即人類拖放文件時出現的相同文件小部件),每位用戶需通過每用戶 OAuth 流程對機器人進行一次授權。
為何需要單獨的流程
Google Chat 的 media.upload 端點明確拒絕服務賬號認證:
此方法不支持使用服務賬號進行應用認證。請使用用戶賬號進行認證。
沒有任何 IAM 角色或範圍可以解決此問題。該端點僅接受用戶憑據。因此,機器人在上傳文件時必須以用戶身份行事——具體而言,是以請求文件的用戶身份。
一次性設置(每個配置文件)
- 在同一 GCP 項目中,前往 APIs & Services → Credentials。
- Create credentials → OAuth client ID → Desktop app。
- 下載 JSON 文件。將其移動到運行 Hermes 的主機上。
- 向 Hermes 註冊客戶端(在希望限定範圍的配置文件下運行):
# Default profile:
python -m plugins.platforms.google_chat.oauth \
--client-secret /path/to/client_secret.json
# A named profile gets its own separate registration:
hermes -p <profile> python -m plugins.platforms.google_chat.oauth \
--client-secret /path/to/client_secret.json
這會將客戶端密鑰寫入活動配置文件的 Hermes 主目錄(例如,默認配置文件為 ~/.hermes/google_chat_user_client_secret.json)。客戶端密鑰是配置文件範圍的,不在配置文件間共享——每個配置文件註冊自己的密鑰。這是有意為之:配置文件是隔離的認證邊界,因此兩個配置文件可以指向不同的 Google OAuth 應用/賬號。僅為需要 Google Chat 附件交付的每個配置文件註冊一次。
每用戶授權(在聊天中)
每位用戶在其與機器人的私聊(DM)中運行一次該流程:
- 他們向機器人發送
/setup-files。機器人回覆狀態和下一步操作。 - 他們發送
/setup-files start。機器人回覆一個 OAuth URL。 - 他們打開該 URL,點擊 Allow,並觀察瀏覽器無法加載
http://localhost:1/?...&code=...。這種失敗是預期的——認證代碼位於 URL 欄中。 - 他們複製失敗的 URL(或僅複製
code=...值)並將其粘貼回聊天中,作為/setup-files <PASTED_URL>。機器人將其交換為刷新令牌。
令牌存儲在 ~/.hermes/google_chat_user_tokens/<sanitized_email>.json。該用戶後續在私聊中的文件請求將使用其令牌,因此機器人以其身份上傳,消息出現在其空間中。
如需稍後撤銷:/setup-files revoke 僅刪除該用戶的令牌。其他用戶的令牌不受影響。
範圍
該流程僅請求一個範圍:chat.messages.create。這涵蓋了 media.upload 和引用已上傳 attachmentDataRef 的 messages.create。不包含 Drive,也不包含更廣泛的 Chat 範圍——這是有意遵循最小權限原則。
多用戶行為
當提問者尚無每用戶令牌時,機器人會回退到遺留的單用戶令牌 ~/.hermes/google_chat_user_token.json(如果存在來自預多用戶安裝的令牌)。如果兩者均不可用,機器人會發布明確的文本通知,告知提問者運行 /setup-files。
用戶撤銷僅清除其自己的槽位。來自某用戶令牌的 401/403 錯誤僅驅逐該用戶的緩存。用戶之間不會相互干擾。
故障排除
發送“hola”後機器人保持沉默。
- 在控制檯中檢查 Pub/Sub 訂閱是否有未投遞的消息。如果有,說明 Hermes 未通過認證——驗證
GOOGLE_CHAT_SERVICE_ACCOUNT_JSON並確保服務賬號在訂閱中被列為Pub/Sub Subscriber。 - 如果訂閱中沒有消息,說明 Google Chat 未發佈消息。仔細檢查主題上的 IAM 綁定:
chat-api-push@system.gserviceaccount.com必須具有Pub/Sub Publisher角色。 - 檢查
hermes gateway日誌中是否有[GoogleChat] Connected。如果看到[GoogleChat] Config validation failed,錯誤消息會告訴你需要修復哪個環境變量。
機器人回覆了,但顯示的是錯誤消息而非代理的答案。
檢查日誌中是否有 [GoogleChat] Pub/Sub stream died——如果反覆出現,你的服務賬號憑據可能已被輪換或訂閱已被刪除。嘗試 10 次後,適配器會將自身標記為致命錯誤。
每條出站消息都出現“403 Forbidden”。
機器人已從空間中移除,或者你在 Chat API 控制檯中撤消了它。
在空間中重新安裝它(下一個 ADDED_TO_SPACE 事件將自動重新啟用消息傳遞)。
“Rate limit hit”警告過多。
Chat API 的默認配額允許每個空間每分鐘發送 60 條消息。如果你的代理生成了超過該限制的長流式響應,適配器會使用指數退避進行重試——但你仍然會看到用戶可見的延遲。請考慮使用更簡潔的響應或在 GCP 控制檯中提高配額。
機器人持續發佈“/setup-files”通知而不是文件。
提問者沒有每用戶 OAuth 令牌,且沒有舊版回退機制。在他們的私聊(DM)中運行 /setup-files 並按照步驟 10 操作。交換完成後,下一次文件請求將原生上傳,無需重啟網關。
/setup-files start 顯示“No client credentials stored.”
尚未為此配置文件執行一次性設置(客戶端密鑰是配置文件範圍的,因此在一個配置文件下注冊的密鑰不會在另一個配置文件中可見)。從終端中,在網關使用的配置文件下運行它:
# Default profile:
python -m plugins.platforms.google_chat.oauth \
--client-secret /path/to/client_secret.json
# Named profile:
hermes -p <profile> python -m plugins.platforms.google_chat.oauth \
--client-secret /path/to/client_secret.json
然後再次發送 /setup-files start。
/setup-files <PASTED_URL> 顯示“Token exchange failed.”
授權代碼是一次性且短效的(通常只有幾分鐘)。發送 /setup-files start 以獲取新的 URL 並重試。
安全說明
- 服務賬號範圍:適配器請求
chat.bot和pubsub範圍。IAM 應是實際的執行機制——授予你的服務賬號最小權限(訂閱上的roles/pubsub.subscriber+roles/pubsub.viewer),而不是項目級或組織級的 Pub/Sub 角色。 - 附件下載保護:Hermes 僅將服務賬號持有者令牌附加到主機與 Google 自有域名的簡短允許列表匹配 URL(
googleapis.com、drive.google.com、lh[3-6].googleusercontent.com以及其他幾個域名)。任何其他主機都會在 HTTP 請求之前被拒絕,以防止 SSRF 場景,即精心構造的事件可能將持有者令牌重定向到 GCE 元數據服務。 - 脫敏:服務賬號電子郵件、訂閱路徑和主題路徑會通過
agent/redact.py從日誌輸出中剝離。調試信封轉儲(GOOGLE_CHAT_DEBUG_RAW=1)通過相同的脫敏過濾器路由,並以 DEBUG 級別記錄。 - 合規性:如果你計劃將此機器人連接到受監管的工作區(任何具有數據駐留或 AI 治理策略的工作區),請在首次安裝前獲得批准。
- 用戶 OAuth 範圍:每用戶附件流僅請求
chat.messages.create——這是涵蓋media.upload以及後續messages.create的最小範圍。令牌以純 JSON 形式持久存儲在~/.hermes/google_chat_user_tokens/<sanitized_email>.json(文件系統權限是保護機制——與服務賬號密鑰文件的模型相同)。每個令牌僅由一個用戶擁有;撤消範圍僅限於該用戶。