Skip to content

添加平台适配器

本指南介绍如何向 Hermes 网关添加新的消息平台。平台适配器将 Hermes 连接到外部消息服务(Telegram、Discord、企业微信等),以便用户可以通过该服务与智能体交互。

提示

添加平台适配器涉及代码、配置和文档中的 20 多个文件。将此指南作为清单使用 —— 适配器文件本身通常只占工作的 40%。

架构概述

用户 ↔ 消息平台 ↔ 平台适配器 ↔ 网关运行器 ↔ AIAgent

每个适配器都扩展自 gateway/platforms/base.pyBasePlatformAdapter 并实现:

  • connect() —— 建立连接(WebSocket、长轮询、HTTP 服务器等)
  • disconnect() —— 干净关闭
  • send() —— 向聊天发送文本消息
  • send_typing() —— 显示正在输入指示器(可选)
  • get_chat_info() —— 返回聊天元数据

入站消息由适配器接收并通过 self.handle_message(event) 转发,基类将其路由到网关运行器。

分步清单

1. 平台枚举

将你的平台添加到 gateway/config.py 中的 Platform 枚举:

python
class Platform(str, Enum):
    # ... 现有平台 ...
    NEWPLAT = "newplat"

2. 适配器文件

创建 gateway/platforms/newplat.py

python
from gateway.config import Platform, PlatformConfig
from gateway.platforms.base import (
    BasePlatformAdapter, MessageEvent, MessageType, SendResult,
)

def check_newplat_requirements() -> bool:
    """如果依赖项可用则返回 True。"""
    return SOME_SDK_AVAILABLE

class NewPlatAdapter(BasePlatformAdapter):
    def __init__(self, config: PlatformConfig):
        super().__init__(config, Platform.NEWPLAT)
        # 从 config.extra 字典读取配置
        extra = config.extra or {}
        self._api_key = extra.get("api_key") or os.getenv("NEWPLAT_API_KEY", "")

    async def connect(self) -> bool:
        # 设置连接,开始轮询/ webhook
        self._mark_connected()
        return True

    async def disconnect(self) -> None:
        self._running = False
        self._mark_disconnected()

    async def send(self, chat_id, content, reply_to=None, metadata=None):
        # 通过平台 API 发送消息
        return SendResult(success=True, message_id="...")

    async def get_chat_info(self, chat_id):
        return {"name": chat_id, "type": "dm"}

对于入站消息,构建一个 MessageEvent 并调用 self.handle_message(event)

python
source = self.build_source(
    chat_id=chat_id,
    chat_name=name,
    chat_type="dm",  # 或 "group"
    user_id=user_id,
    user_name=user_name,
)
event = MessageEvent(
    text=content,
    message_type=MessageType.TEXT,
    source=source,
    message_id=msg_id,
)
await self.handle_message(event)

3. 网关配置(gateway/config.py

三个接触点:

  1. get_connected_platforms() —— 添加对你的平台所需凭证的检查
  2. load_gateway_config() —— 添加令牌环境映射条目:Platform.NEWPLAT: "NEWPLAT_TOKEN"
  3. _apply_env_overrides() —— 将所有 NEWPLAT_* 环境变量映射到配置

4. 网关运行器(gateway/run.py

五个接触点:

  1. _create_adapter() —— 添加一个 elif platform == Platform.NEWPLAT: 分支
  2. _is_user_authorized() allowed_users 映射 —— Platform.NEWPLAT: "NEWPLAT_ALLOWED_USERS"
  3. _is_user_authorized() allow_all 映射 —— Platform.NEWPLAT: "NEWPLAT_ALLOW_ALL_USERS"
  4. 早期环境检查 _any_allowlist 元组 —— 添加 "NEWPLAT_ALLOWED_USERS"
  5. 早期环境检查 _allow_all 元组 —— 添加 "NEWPLAT_ALLOW_ALL_USERS"
  6. _UPDATE_ALLOWED_PLATFORMS frozenset —— 添加 Platform.NEWPLAT

5. 跨平台传递

  1. gateway/platforms/webhook.py —— 将 "newplat" 添加到传递类型元组
  2. cron/scheduler.py —— 添加到 _KNOWN_DELIVERY_PLATFORMS frozenset 和 _deliver_result() 平台映射

6. CLI 集成

  1. hermes_cli/config.py —— 将所有 NEWPLAT_* 变量添加到 _EXTRA_ENV_KEYS
  2. hermes_cli/gateway.py —— 添加 _PLATFORMS 列表条目,包含 key、label、emoji、token_var、setup_instructions 和 vars
  3. hermes_cli/platforms.py —— 添加 PlatformInfo 条目,包含 label 和 default_toolset(由 skills_configtools_config TUIs 使用)
  4. hermes_cli/setup.py —— 添加 _setup_newplat() 函数(可以委托给 gateway.py)并添加元组到消息平台列表
  5. hermes_cli/status.py —— 添加平台检测条目:"NewPlat": ("NEWPLAT_TOKEN", "NEWPLAT_HOME_CHANNEL")
  6. hermes_cli/dump.py —— 添加 "newplat": "NEWPLAT_TOKEN" 到平台检测字典

7. 工具

  1. tools/send_message_tool.py —— 添加 "newplat": Platform.NEWPLAT 到平台映射
  2. tools/cronjob_tools.py —— 添加 newplat 到传递目标描述字符串

8. 工具集

  1. toolsets.py —— 添加 "hermes-newplat" 工具集定义与 _HERMES_CORE_TOOLS
  2. toolsets.py —— 添加 "hermes-newplat""hermes-gateway" 包含列表

9. 可选:平台提示

agent/prompt_builder.py —— 如果你的平台有特定的渲染限制(无 markdown、消息长度限制等),添加条目到 _PLATFORM_HINTS 字典。这会将平台特定的指导注入系统提示:

python
_PLATFORM_HINTS = {
    # ...
    "newplat": (
        "你正在通过 NewPlat 聊天。它支持 markdown 格式化"
        "但有 4000 字符的消息长度限制。"
    ),
}

不是所有平台都需要提示 —— 只有智能体行为应该不同的平台才需要添加。

10. 测试

创建 tests/gateway/test_newplat.py 覆盖:

  • 从配置构造适配器
  • 消息事件构建
  • 发送方法(模拟外部 API)
  • 平台特定功能(加密、路由等)

11. 文档

文件要添加的内容
website/docs/user-guide/messaging/newplat.md完整的平台设置页面
website/docs/user-guide/messaging/index.md平台对比表、架构图、工具集表、安全部分、下一步链接
website/docs/reference/environment-variables.md所有 NEWPLAT_* 环境变量
website/docs/reference/toolsets-reference.mdhermes-newplat 工具集
website/docs/integrations/index.md平台链接
website/sidebars.ts文档页面的侧边栏条目
website/docs/developer-guide/architecture.md适配器计数 + 列表
website/docs/developer-guide/gateway-internals.md适配器文件列表

一致性审计

在将新平台 PR 标记为完成之前,针对已建立的平台运行一致性审计:

bash
# 查找提到参考平台的每个 .py 文件
search_files "bluebubbles" output_mode="files_only" file_glob="*.py"

# 查找提到新平台的每个 .py 文件
search_files "newplat" output_mode="files_only" file_glob="*.py"

# 第一个集合中但不在第二个集合中的任何文件都是潜在的缺口

.md.ts 文件重复。调查每个缺口 —— 它是平台枚举(需要更新)还是平台特定引用(跳过)?

常见模式

长轮询适配器

如果你的适配器使用长轮询(如 Telegram 或微信),使用轮询循环任务:

python
async def connect(self):
    self._poll_task = asyncio.create_task(self._poll_loop())
    self._mark_connected()

async def _poll_loop(self):
    while self._running:
        messages = await self._fetch_updates()
        for msg in messages:
            await self.handle_message(self._build_event(msg))

回调/Webhook 适配器

如果平台将消息推送到你的端点(如企业微信回调),运行 HTTP 服务器:

python
async def connect(self):
    self._app = web.Application()
    self._app.router.add_post("/callback", self._handle_callback)
    # ... 启动 aiohttp 服务器
    self._mark_connected()

async def _handle_callback(self, request):
    event = self._build_event(await request.text())
    await self._message_queue.put(event)
    return web.Response(text="success")  # 立即确认

对于具有严格响应期限的平台(例如企业微信的 5 秒限制),始终立即确认并稍后通过 API 主动传递智能体的回复。智能体会话运行 3–30 分钟——回调响应窗口内的内联回复是不可行的。

令牌锁

如果适配器使用唯一凭证持有持久连接,添加作用域锁以防止两个配置文件使用相同的凭证:

python
from gateway.status import acquire_scoped_lock, release_scoped_lock

async def connect(self):
    if not acquire_scoped_lock("newplat", self._token):
        logger.error("令牌已被另一个配置文件使用")
        return False
    # ... 连接

async def disconnect(self):
    release_scoped_lock("newplat", self._token)

参考实现

适配器模式复杂度适合参考
bluebubbles.pyREST + webhook中等简单的 REST API 集成
weixin.py长轮询 + CDN媒体处理、加密
wecom_callback.py回调/webhook中等HTTP 服务器、AES 加密、多应用
telegram.py长轮询 + Bot API功能完整的适配器,支持群组、话题