Google Chat 设置

将 Hermes Agent 作为机器人连接到 Google Chat。该集成使用 Cloud Pub/Sub 拉取订阅处理入站事件,使用 Chat REST API 处理出站消息。 与 Slack Socket Mode 或 Telegram 长轮询等效:您的 Hermes 进程不需要公共 URL、隧道或 TLS 证书。它连接、 认证并在订阅上监听——就像 Telegram 机器人在令牌上监听一样。

:::note Workspace 版本 Google Chat 是 Google Workspace 的一部分。您可以使用此集成与 个人 Workspace(通过 Google 注册的 @yourdomain.com)或工作 Workspace(您拥有发布应用的管理员权限)。仅 Gmail 的账户 无法托管 Chat 应用。 :::

概述

组件
google-cloud-pubsubgoogle-api-python-clientgoogle-auth
入站传输Cloud Pub/Sub 拉取订阅(无需公共端点)
出站传输Chat REST API(chat.googleapis.com
认证具有订阅 roles/pubsub.subscriber 权限的服务账号 JSON
用户标识Chat 资源名称(users/{id})+ 邮箱

第一步:创建或选择 GCP 项目

您需要一个 Google Cloud 项目来托管 Pub/Sub 主题。如果没有, 请在 console.cloud.google.com 创建—— 个人账号的免费层足以覆盖机器人流量。

记下项目 ID(例如 my-chat-bot-123)。您将在后续每个步骤中使用它。


第二步:启用两个 API

在控制台中,进入 APIs & Services → Library 并启用:

  • Google Chat API
  • Cloud Pub/Sub API

两者对于个人机器人产生的流量都是免费的。


第三步:创建服务账号

IAM & Admin → Service Accounts → Create Service Account。

  • 名称:hermes-chat-bot
  • 跳过”Grant this service account access to project”步骤。IAM 只需 设置在特定的订阅上——不要授予项目级别的 Pub/Sub 角色。

创建后,打开服务账号,进入 Keys → Add Key → Create new key → JSON 并 下载文件。将其保存在只有 Hermes 能读取的位置(例如 ~/.hermes/google-chat-sa.jsonchmod 600)。

:::caution 没有”Chat Bot Caller”角色 一个常见的错误是搜索 Chat 特定的 IAM 角色并在项目级别授予它。 这个角色不存在。Chat 机器人的权限来自于安装在空间中,而非 IAM。 您的服务账号只需要对下一步创建的订阅具有 Pub/Sub 订阅者权限。 :::


第四步:创建 Pub/Sub 主题和订阅

Pub/Sub → Topics → Create topic。

  • 主题 ID:hermes-chat-events
  • 其他保持默认。

创建后,主题详情页面有一个 Subscriptions 标签。创建一个:

  • 订阅 ID:hermes-chat-events-sub
  • 投递类型:Pull
  • 消息保留期:7 天(以便 backlog 在 hermes 重启后仍然存在)
  • 其他保持默认。

第五步:主题的 IAM 绑定(关键)

主题(而非订阅)上,添加一个 IAM 主体:

  • 主体:chat-api-push@system.gserviceaccount.com
  • 角色:Pub/Sub Publisher

没有这个,Google Chat 无法将事件发布到您的主题,您的机器人将 永远收不到任何消息。


第六步:订阅的 IAM 绑定

订阅上,将您自己的服务账号添加为主体:

  • 主体:hermes-chat-bot@<your-project>.iam.gserviceaccount.com
  • 角色:Pub/Sub Subscriber

同时在同一个订阅上授予 Pub/Sub Viewer——Hermes 在启动时 调用 subscription.get() 作为可达性检查。


第七步:配置 Chat 应用

进入 APIs & Services → Google Chat API → Configuration

  • App name:您希望用户看到的名称(“Hermes”即可)。
  • Avatar URL:任何公共 PNG 图片(Google 有一些默认选项)。
  • Description:在应用目录中显示的简短描述。
  • Functionality:启用 Receive 1:1 messagesJoin spaces and group conversations
  • Connection settings:选择 Cloud Pub/Sub,输入主题名称 projects/<your-project>/topics/hermes-chat-events
  • Visibility:限制到您的工作区(或特定用户)——测试期间不要 发布给所有人。

保存。


第八步:在测试空间中安装机器人

在浏览器中打开 Google Chat。在 + New Chat 菜单中搜索您的应用名称, 开始与应用的私聊。第一次发送消息时,Google 会发送 ADDED_TO_SPACE 事件,Hermes 用该事件缓存机器人的 users/{id}, 用于自消息过滤。


第九步:配置 Hermes

将 Google Chat 部分添加到 ~/.hermes/.env

# 必填
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
 
# 授权——粘贴允许与机器人对话的人的邮箱
GOOGLE_CHAT_ALLOWED_USERS=you@yourdomain.com,coworker@yourdomain.com
 
# 可选
GOOGLE_CHAT_HOME_CHANNEL=spaces/AAAA...         # 定时任务的默认投递目标
GOOGLE_CHAT_MAX_MESSAGES=1                      # Pub/Sub FlowControl;1 使命令按会话串行化
GOOGLE_CHAT_MAX_BYTES=16777216                  # 16 MiB — 传输中消息字节数上限

项目 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)

在测试私聊中发送”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 会话。


第十步:原生附件投递(可选)

开箱即用,机器人可以发布文本、通过 URL 的内联图片以及音频/视频/文档的 下载卡片。要投递原生 Chat 附件——即 用户拖放文件时得到的相同文件小部件——每个用户需要通过 每用户 OAuth 流程授权机器人一次。

为什么需要单独的流程

Google Chat 的 media.upload 端点硬性拒绝服务账号认证:

此方法不支持使用服务账号的应用认证。 请使用用户账号进行认证。

没有 IAM 角色或权限范围可以解决这个问题。该端点只接受用户 凭证。因此机器人每次上传文件时必须以用户身份操作—— 具体来说,是请求该文件的用户的身份。

一次性主机设置

  1. 在同一个 GCP 项目中进入 APIs & Services → Credentials
  2. Create credentials → OAuth client ID → Desktop app
  3. 下载 JSON。将其移动到运行 Hermes 的主机上。
  4. 在主机上,向 Hermes 注册客户端:
python -m gateway.platforms.google_chat_user_oauth \
    --client-secret /path/to/client_secret.json

这会写入 ~/.hermes/google_chat_user_client_secret.json。这是共享的 基础设施——它标识的是 OAuth 应用,而非任何单个用户。每台主机 一个文件就足够了,无论之后有多少用户授权。

每用户授权(在聊天中)

每个用户在机器人私聊中运行一次流程:

  1. 向机器人发送 /setup-files。它会回复状态和下一步 操作。
  2. 发送 /setup-files start。机器人回复一个 OAuth URL。
  3. 打开 URL,点击 Allow,然后看到浏览器无法加载 http://localhost:1/?...&code=*** 的失败页面——这是预期的。认证码 就在 URL 栏中。
  4. 复制失败的 URL(或仅 code=... 值)并粘贴回聊天 作为 /setup-files <PASTED_URL>。机器人将其换为 refresh token。

令牌会保存到 ~/.hermes/google_chat_user_tokens/<sanitized_email>.json。 该用户私聊中的后续文件请求使用他们的令牌,因此机器人 以他们的身份上传,消息会出现在他们的空间中。

要稍后撤销:/setup-files revoke 仅删除该用户的令牌。其他 用户的令牌不受影响。

权限范围

该流程只请求一个权限范围:chat.messages.create。这涵盖了 media.upload 和引用已上传 attachmentDataRefmessages.create。没有 Drive,没有更广泛的 Chat 范围——这是故意设计的最小权限。

多用户行为

当请求者还没有每用户令牌时,机器人回退到旧版 单用户令牌 ~/.hermes/google_chat_user_token.json(如果从 预多用户安装存在)。当两者都不可用时,机器人发布一条清晰的 文本通知,告诉请求者运行 /setup-files

用户撤销只清除自己的槽位。某个用户的令牌出现 401/403 只驱逐该用户的缓存。用户之间互不干扰。


故障排查

发送”hola”后机器人保持沉默。

  1. 检查 Pub/Sub 订阅在控制台中是否有未投递的消息。 如果有,表示 Hermes 未通过认证——验证 GOOGLE_CHAT_SERVICE_ACCOUNT_JSON 以及服务账号是否在订阅上列为 Pub/Sub Subscriber
  2. 如果订阅有零条消息,表示 Google Chat 没有发布。 仔细检查主题上的 IAM 绑定: chat-api-push@system.gserviceaccount.com 必须有 Pub/Sub Publisher
  3. 检查 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 令牌,也没有旧版回退。在其私聊中运行 /setup-files 并遵循第 10 步。交换完成后, 下一个文件请求无需网关重启即可原生上传。

/setup-files start 提示”主机上未存储客户端凭证。”

未完成一次性主机设置。在运行 Hermes 的主机的终端上:

python -m gateway.platforms.google_chat_user_oauth \
    --client-secret /path/to/client_secret.json

然后重新发送 /setup-files start

/setup-files <PASTED_URL> 提示”令牌交换失败。”

认证码是单次使用的且有效期很短(通常几分钟)。发送 /setup-files start 获取新的 URL 并重试。


安全说明

  • 服务账号范围:适配器请求 chat.botpubsub 范围。 IAM 应该是实际的强制执行手段——授予您的服务账号最小权限 (订阅上的 roles/pubsub.subscriber + roles/pubsub.viewer),而不是 项目级或组织级的 Pub/Sub 角色。
  • 附件下载保护:Hermes 只将服务账号承载令牌附加到 主机名与 Google 拥有的域名短名单(googleapis.comdrive.google.comlh[3-6].googleusercontent.com 等)匹配的 URL。 其他任何主机都在 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(文件系统 权限是保护手段——与服务账号密钥文件一样的模型)。每个 令牌属于唯一一个用户;撤销限于该用户。