在上一篇中,我们全面了解了 Hermes Agent 的 Gateway 多平台架构。架构是骨架,但真正的"血肉"在于与各个平台的具体集成。

微信 Telegram Discord 平台集成实战 —— 平台认证、Intent 配置、常见问题排查、消息收发

简介

在上一篇中,我们全面了解了 Hermes Agent 的 Gateway 多平台架构。架构是骨架,但真正的"血肉"在于与各个平台的具体集成。

今天,我们将进入实战环节,手把手教你将 Hermes Agent 接入三个最主流的消息平台:

  • 微信(WeChat) —— 中文用户最多的即时通讯平台
  • Telegram —— 全球流行的加密通讯平台,Bot API 极其成熟
  • Discord —— 开发者和游戏社区首选的协作平台

每个平台都有其独特的认证方式、消息格式、权限模型和限制条件。本文将带你:

  1. 完成平台认证:从零开始创建 Bot、获取 Token、配置权限
  2. 配置 Intent(意图):精确控制 Agent 在什么场景下响应什么消息
  3. 排查常见问题:连接失败、消息丢失、权限不足、限流退避
  4. 实现消息收发:从简单文本到富媒体交互的完整代码示例

目标:读完本文后,你能独立完成三大平台的接入,并具备排查和解决问题的能力。

目录

微信(WeChat)平台集成

1.1 平台认证配置

微信平台的接入方式有几种,我们主要介绍最常用的 个人号 Bot 方案(基于 itchat/ComWeChatBot 协议):

yaml
# ~/.hermes/adapters/wechat/config.yaml
adapter:
  name: "wechat"
  version: "2.3.0"

# 认证配置
auth:
  # 方式一:扫码登录(个人号)
  login_method: "qr_scan"
  qr_callback: "console"     # console | webhook | file

  # 方式二:企业微信应用(推荐生产环境)
  # login_method: "enterprise"
  # corp_id: "ww1234567890"
  # agent_id: "1000002"
  # corp_secret: "${WECHAT_CORP_SECRET}"

  # 方式三:微信公众号
  # login_method: "official"
  # app_id: "wx1234567890"
  # app_secret: "${WECHAT_APP_SECRET}"
  # token: "${WECHAT_VERIFY_TOKEN}"

# 功能配置
features:
  text: true
  image: true
  voice: true
  video: false              # 个人号暂不支持
  file: true
  sticker: true
  red_packet: false         # 红包不支持

# 安全配置
security:
  # 白名单模式:只有这些用户/群才能与 Agent 交互
  whitelist:
    users:
      - "wxid_abc123"
      - "wxid_def456"
    groups:
      - "room_xyz789"

  # 黑名单模式
  blacklist:
    users: []
    groups: []

  # 敏感词过滤
  blocked_keywords:
    - "密码"
    - "token"
    - "密钥"

启动与扫码

bash
# 启动微信适配器
hermes gateway adapters start wechat

# 输出:
# ═══════════════════════════════════════════════
#  WeChat Adapter Starting
# ═══════════════════════════════════════════════
#
#  [1/3] 初始化连接...
#  ✓ WebSocket 已连接
#
#  [2/3] 等待登录...
#  请使用微信扫描下方二维码登录:
#
#  ┌──────────────────────────┐
#  │                          │
#  │    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓    │
#  │    ▓▓            ▓▓    │
#  │    ▓▓  ▓▓▓▓▓▓  ▓▓    │
#  │    ▓▓  ▓▓  ▓▓  ▓▓    │
#  │    ▓▓  ▓▓▓▓▓▓  ▓▓    │
#  │    ▓▓            ▓▓    │
#  │    ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓    │
#  │                          │
#  └──────────────────────────┘
#
#  或使用手机打开: https://hermes.agent/wx/login/abc123
#
#  [3/3] 登录成功!
#  ✓ 昵称: Hermes Bot
#  ✓ 微信号: hermes_bot_001
#  ✓ 好友数: 156
#  ✓ 群聊数: 23
#
#  ✅ WeChat Adapter 就绪

1.2 微信消息收发

javascript
// 微信适配器消息处理示例
const wechatAdapter = {
  // 接收消息
  onMessage(async (msg) => {
    // msg 结构
    /*
    {
      type: "text" | "image" | "voice" | "video" | "file" | "sticker",
      from: "wxid_abc123",
      to: "hermes_bot_001",
      chat: "wxid_abc123",          // 私聊 = from, 群聊 = room_id
      isGroup: false,
      content: "帮我写一个冒泡排序",
      timestamp: 1716393600,
      // 图片/文件特有字段
      mediaUrl: "https://...",
      fileSize: 102400,
    }
    */

    // 处理文本消息
    if (msg.type === "text") {
      // 发送给 Agent 处理
      const reply = await agent.process({
        platform: "wechat",
        userId: msg.from,
        chatId: msg.chat,
        content: msg.content,
        isGroup: msg.isGroup
      });

      // 发送回复
      await this.sendReply(msg.chat, reply);
    }

    // 处理图片消息(OCR 或图像分析)
    if (msg.type === "image") {
      const analysis = await agent.analyzeImage(msg.mediaUrl);
      await this.sendText(msg.chat, analysis.description);
    }
  }),

  // 发送回复
  async sendReply(chatId, reply) {
    // 微信不支持 Markdown,需要格式化
    const formattedText = this.formatForWechat(reply.content);

    if (formattedText.length > 2000) {
      // 超长消息拆分发送
      const chunks = this.splitMessage(formattedText, 2000);
      for (const chunk of chunks) {
        await this.sendText(chatId, chunk);
        await this.delay(500);  // 避免发送过快
      }
    } else {
      await this.sendText(chatId, formattedText);
    }

    // 如果有代码,转为图片发送
    if (reply.hasCode) {
      const codeImage = await this.codeToImage(reply.code);
      await this.sendImage(chatId, codeImage);
    }

    // 如果有文件
    if (reply.files) {
      for (const file of reply.files) {
        await this.sendFile(chatId, file);
      }
    }
  },

  // 微信格式转换
  formatForWechat(text) {
    return text
      .replace(/\*\*(.+?)\*\*/g, '【$1】')    // **bold** → 【bold】
      .replace(/\*(.+?)\*/g, '$1')             // *italic* → italic
      .replace(/`(.+?)`/g, '「$1」')           // `code` → 「code」
      .replace(/^#\s+(.+)$/gm, '=== $1 ===')   // # heading → === heading ===
      .replace(/^##\s+(.+)$/gm, '-- $1 --')    // ## heading → -- heading --
      .replace(/^###\s+(.+)$/gm, '· $1 ·');    // ### heading → · heading ·
  }
};

Telegram 平台集成

2.1 创建 Telegram Bot

步骤一:通过 BotFather 创建 Bot

text
1. 在 Telegram 中搜索 @BotFather
2. 发送 /newbot
3. 按提示输入 Bot 名称和用户名(必须以 bot 结尾)
4. 获取 Bot Token(格式:123456789:ABCdefGHIjklMNOpqrsTUVwxyz)
5. 保存 Token,后续配置需要用到

步骤二:配置 Bot 权限

text
# 通过 BotFather 设置
/setdescription - 设置 Bot 描述
/setabouttext - 设置 About 信息
/setuserpic - 设置 Bot 头像
/setcommands - 设置 Bot 命令列表

# 推荐命令列表:
start - 开始对话
help - 查看帮助
status - 查看 Agent 状态
clear - 清空当前对话上下文
skills - 查看已加载的技能

步骤三:配置 Hermes

yaml
# ~/.hermes/adapters/telegram/config.yaml
adapter:
  name: "telegram"
  version: "2.1.0"

# 认证配置
auth:
  bot_token: "${TELEGRAM_BOT_TOKEN}"
  # 或使用环境变量
  # bot_token_env: "TELEGRAM_BOT_TOKEN"

# 连接方式
connection:
  method: "webhook"      # webhook | long_polling
  # Webhook 配置(推荐生产环境)
  webhook:
    url: "https://your-domain.com/hermes/telegram/webhook"
    secret_token: "${TELEGRAM_WEBHOOK_SECRET}"
    max_connections: 40
  # Long Polling 配置(适合开发/内网)
  long_polling:
    timeout: 30          # 秒
    allowed_updates:
      - "message"
      - "edited_message"
      - "callback_query"

# 功能配置
features:
  text: true
  image: true
  voice: true           # 语音转文字
  video: true
  file: true
  sticker: true
  location: true
  contact: true
  poll: true
  inline_keyboard: true # 内联按钮

# Markdown 支持
formatting:
  parse_mode: "MarkdownV2"  # Markdown | MarkdownV2 | HTML
  # MarkdownV2 需要转义的字符
  escape_chars: "_*[]()~`>#+-=|{}.!"

# Bot 行为
bot:
  # 只响应 @提及的消息
  mention_only_in_groups: true

  # 自动删除 Bot 消息(减少刷屏)
  auto_delete:
    enabled: false
    delay: 60  # 秒

  # 打字指示器
  typing_indicator: true

  # 消息长度限制
  max_message_length: 4096

2.2 Telegram 消息收发

javascript
// Telegram 适配器消息处理
const telegramAdapter = {
  async onMessage(msg) {
    /*
    Telegram 消息结构:
    {
      message_id: 123,
      from: { id: 12345, username: "alice", first_name: "Alice" },
      chat: { id: -100987654, type: "supergroup", title: "Dev Group" },
      date: 1716393600,
      text: "@hermes_bot 帮我写一个冒泡排序",
      entities: [
        { type: "mention", offset: 0, length: 12 }
      ],
      reply_to_message: { ... },  // 如果是回复消息
    }
    */

    // 检查是否被 @提及(群聊)
    if (msg.chat.type !== "private") {
      const mentions = msg.entities?.filter(e => e.type === "mention") || [];
      const isMentioned = mentions.some(m =>
        msg.text.substring(m.offset, m.offset + m.length) === "@hermes_bot"
      );

      if (!isMentioned && !msg.reply_to_message?.from?.is_bot) {
        return;  // 未被 @提及且不回复 Bot,忽略
      }
    }

    // 处理消息
    const cleanContent = this.cleanContent(msg.text, msg.entities);
    const reply = await agent.process({
      platform: "telegram",
      userId: String(msg.from.id),
      userName: msg.from.username || msg.from.first_name,
      chatId: String(msg.chat.id),
      chatName: msg.chat.title,
      isGroup: msg.chat.type !== "private",
      content: cleanContent
    });

    // 发送回复(支持 MarkdownV2)
    await this.sendMarkdown(msg.chat.id, reply.content);

    // 如果有代码
    if (reply.hasCode) {
      await this.sendCode(msg.chat.id, reply.code, reply.language);
    }
  },

  // 清理提及后的内容
  cleanContent(text, entities) {
    let clean = text;
    const mentions = entities?.filter(e => e.type === "mention") || [];
    for (const m of mentions) {
      clean = clean.replace(text.substring(m.offset, m.offset + m.length), '').trim();
    }
    return clean || text;
  },

  // 发送 Markdown 消息
  async sendMarkdown(chatId, text) {
    // 转义 MarkdownV2 特殊字符
    const escaped = this.escapeMarkdownV2(text);

    await fetch(`https://api.telegram.org/bot${TOKEN}/sendMessage`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        chat_id: chatId,
        text: escaped,
        parse_mode: 'MarkdownV2',
        disable_web_page_preview: true
      })
    });
  },

  // 发送代码块
  async sendCode(chatId, code, language = '') {
    const text = `\`\`\`${language}\n${code}\n\`\`\``;
    const escaped = this.escapeMarkdownV2(text);

    await fetch(`https://api.telegram.org/bot${TOKEN}/sendMessage`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        chat_id: chatId,
        text: escaped,
        parse_mode: 'MarkdownV2'
      })
    });
  },

  // MarkdownV2 转义
  escapeMarkdownV2(text) {
    return text.replace(/([_*\[\]()~`>#+\-=|{}.!])/g, '\\$1');
  },

  // 发送内联按钮
  async sendWithButtons(chatId, text, buttons) {
    /*
    buttons = [
      [
        { text: "确认", callback_data: "confirm" },
        { text: "取消", callback_data: "cancel" }
      ]
    ]
    */
    await fetch(`https://api.telegram.org/bot${TOKEN}/sendMessage`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        chat_id: chatId,
        text: this.escapeMarkdownV2(text),
        parse_mode: 'MarkdownV2',
        reply_markup: {
          inline_keyboard: buttons
        }
      })
    });
  }
};

Discord 平台集成

3.1 创建 Discord Bot

步骤一:创建应用和 Bot

text
1. 访问 https://discord.com/developers/applications
2. 点击 "New Application",输入名称
3. 进入 "Bot" 标签页
4. 点击 "Add Bot"
5. 复制 Token(只显示一次!)
6. 配置 Privileged Gateway Intents:
   ✅ MESSAGE CONTENT INTENT
   ✅ SERVER MEMBERS INTENT(可选)
   ✅ PRESENCE INTENT(可选)

步骤二:邀请 Bot 到服务器

text
1. 进入 "OAuth2""URL Generator"
2. 选择 Scopes:botapplications.commands(斜杠命令)
3. 选择 Bot Permissions:Send MessagesEmbed LinksAttach FilesRead Message HistoryAdd ReactionsManage Messages(可选)
   ✅ Use External Emojis
4. 复制生成的 URL,在浏览器中打开
5. 选择要添加的服务器

步骤三:配置 Hermes

yaml
# ~/.hermes/adapters/discord/config.yaml
adapter:
  name: "discord"
  version: "2.0.0"

# 认证配置
auth:
  bot_token: "${DISCORD_BOT_TOKEN}"
  client_id: "${DISCORD_CLIENT_ID}"

# Gateway Intents(必须与 Dev Portal 中启用的一致)
intents:
  - "Guilds"              # 基本服务器事件
  - "GuildMessages"       # 消息事件
  - "MessageContent"      # 消息内容(需要 Privileged Intent)
  - "GuildMembers"        # 成员事件(可选)

# 功能配置
features:
  text: true
  image: true
  voice: true             # 语音频道
  file: true
  embeds: true            # 富文本嵌入
  buttons: true           # 交互按钮
  select_menus: true      # 下拉选择
  threads: true           # 线程
  slash_commands: true    # 斜杠命令

# 斜杠命令配置
slash_commands:
  - name: "hermes"
    description: "向 Hermes Agent 提问"
    options:
      - name: "question"
        type: "STRING"
        description: "你的问题"
        required: true
  - name: "status"
    description: "查看 Agent 状态"
  - name: "clear"
    description: "清空对话上下文"
  - name: "skills"
    description: "查看当前加载的技能"

# Bot 行为
bot:
  # 活动状态(显示在 Bot 名字下方)
  presence:
    status: "online"       # online | idle | dnd | invisible
    activity:
      type: "Watching"     # Playing | Streaming | Listening | Watching | Competing
      name: "your questions"

  # 频道白名单
  channel_whitelist: []    # 留空表示所有频道

  # 仅响应 @提及
  mention_only: true

  # 删除触发消息(减少刷屏)
  delete_trigger: false

3.2 Discord 消息收发

javascript
// Discord 适配器消息处理
const discordAdapter = {
  async onMessage(msg) {
    /*
    Discord 消息结构:
    {
      id: "123456789",
      channel_id: "456789",
      guild_id: "789012",
      author: { id: "345678", username: "alice", discriminator: "1234" },
      content: "@Hermes 帮我写一个冒泡排序",
      mentions: [{ id: "bot_id", username: "Hermes" }],
      attachments: [...],
      embeds: [...],
      reference: { message_id: "..." },  // 回复
    }
    */

    // 忽略 Bot 自己的消息
    if (msg.author.bot) return;

    // 检查 @提及
    if (!msg.mentions?.some(m => m.id === this.botId)) {
      return;
    }

    const cleanContent = msg.content
      .replace(/<@!?\d+>/g, '')  // 移除 @提及
      .trim();

    if (!cleanContent) return;

    const reply = await agent.process({
      platform: "discord",
      userId: msg.author.id,
      userName: msg.author.username,
      chatId: msg.channel_id,
      guildId: msg.guild_id,
      isGroup: !!msg.guild_id,
      content: cleanContent
    });

    // 发送回复
    if (reply.hasCode && reply.code) {
      await this.sendEmbedWithCode(msg.channel_id, reply.content, reply.code, reply.language);
    } else {
      await this.sendText(msg.channel_id, reply.content);
    }
  },

  // 发送 Embed 消息(富文本)
  async sendEmbedWithCode(channelId, text, code, language = '') {
    await fetch(`https://discord.com/api/v10/channels/${channelId}/messages`, {
      method: 'POST',
      headers: {
        'Authorization': `Bot ${TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        content: text,
        embeds: [{
          title: "📝 代码片段",
          color: 0x5865F2,  // Discord Blurple
          fields: [
            {
              name: `语言: ${language || 'plaintext'}`,
              value: `\`\`\`${language}\n${code.substring(0, 1000)}${code.length > 1000 ? '...' : ''}\n\`\`\``
            }
          ],
          footer: { text: `代码长度: ${code.length} 字符` },
          timestamp: new Date().toISOString()
        }]
      })
    });
  },

  // 发送带按钮的消息
  async sendWithButtons(channelId, text, buttons) {
    await fetch(`https://discord.com/api/v10/channels/${channelId}/messages`, {
      method: 'POST',
      headers: {
        'Authorization': `Bot ${TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        content: text,
        components: [{
          type: 1,  // Action Row
          components: buttons.map(btn => ({
            type: 2,  // Button
            label: btn.label,
            style: btn.style || 1,  // 1=Primary, 2=Secondary, 3=Success, 4=Danger, 5=Link
            custom_id: btn.custom_id,
            url: btn.url  // Link 按钮需要
          }))
        }]
      })
    });
  }
};

Intent 配置详解

什么是 Intent(意图)?

Intent 是 Gateway 的意图识别与响应规则系统。它决定了 Agent 在什么条件下响应消息、如何响应、响应什么内容。

Intent 层次结构

text
Intent 配置层次:
│
├── 全局 Intent(global)
│   ├── 适用于所有平台
│   └── 基础过滤规则
│
├── 平台 Intent(per-platform)
│   ├── wechat: { ... }
│   ├── telegram: { ... }
│   └── discord: { ... }
│
├── 会话 Intent(per-session)
│   ├── 基于用户偏好
│   └── 基于对话上下文
│
└── 消息 Intent(per-message)
    ├── 基于消息内容
    └── 基于消息类型

Intent 配置文件

yaml
# ~/.config/hermes/intents.yaml
intents:
  # 全局默认意图
  global:
    # 响应模式
    response_mode: "mention"    # always | mention | keyword | never

    # 关键词触发
    keywords:
      - "@hermes"
      - "hermes"
      - "问"

    # 忽略模式(正则)
    ignore_patterns:
      - "^/.*$"                 # 以 / 开头的命令
      - "^\."                   # 以 . 开头
      - "^ping$"                # ping 测试

    # 最大消息长度
    max_content_length: 2000

    # 自动回复阈值(匹配度低于此值不回复)
    confidence_threshold: 0.6

  # 微信意图
  wechat:
    # 群聊中只响应 @提及
    groups:
      response_mode: "mention"
      # 但管理员消息始终响应
      admin_whitelist:
        - "wxid_admin1"
        - "wxid_admin2"

    # 私聊始终响应
    private:
      response_mode: "always"

    # 特定群的特定规则
    group_rules:
      "room_tech_group":
        response_mode: "keyword"
        keywords: ["代码", "bug", "error", "求助"]
        prefix_required: true
        prefix: "@hermes"
      "room_random_chat":
        response_mode: "never"    # 这个群不响应

  # Telegram 意图
  telegram:
    groups:
      response_mode: "mention"
      # 回复 Bot 消息时也响应
      reply_to_bot: true

    private:
      response_mode: "always"

    # 支持斜杠命令
    slash_commands:
      "/hermes": "process"       # 正常处理
      "/clear": "clear_session"  # 清空会话
      "/status": "show_status"   # 显示状态
      "/help": "show_help"       # 显示帮助

  # Discord 意图
  discord:
    guilds:
      response_mode: "mention"
      reply_to_bot: true

    # 频道级规则
    channels:
      "channel_help":
        response_mode: "always"    # 帮助频道始终响应
      "channel_random":
        response_mode: "never"     # 灌水频道不响应
      "channel_code_review":
        response_mode: "keyword"
        keywords: ["review", "检查", "看看"]

    # 斜杠命令
    slash_commands:
      "/hermes": "process"
      "/clear": "clear_session"
      "/status": "show_status"

Intent 运行时行为

text
消息到达 → Intent 引擎处理流程:

1. 检查全局 ignore_patterns
   └── 匹配?→ 忽略消息

2. 检查平台级 response_mode
   └── never?→ 忽略
   └── always?→ 处理
   └── mention?→ 检查是否 @提及
   └── keyword?→ 检查是否包含关键词

3. 检查会话级规则(用户偏好、上下文)
   └── 用户屏蔽了?→ 忽略
   └── 用户 VIP?→ 优先处理

4. 计算置信度
   └── 低于 threshold?→ 忽略
   └── 高于 threshold?→ 处理

5. 执行动作
   └── process → 发送给 Agent
   └── clear_session → 清空上下文
   └── show_status → 返回状态
   └── show_help → 返回帮助
   └── log_only → 记录但不回复

常见问题排查手册

4.1 连接问题

问题:微信无法登录/扫码后断开

bash
# 诊断命令
hermes gateway adapters diagnose wechat

# 输出排查:
# ═══════════════════════════════════════════
#  WeChat 诊断报告
# ═══════════════════════════════════════════
#
#  [✓] 网络连接正常
#  [✓] WebSocket 端口可达
#  [✗] 登录会话已过期
#  [✓] Token 格式正确
#  [✓] 服务器响应正常
#
#  建议操作:
#  1. 清除登录缓存:hermes gateway adapters reset wechat
#  2. 重新扫码登录:hermes gateway adapters start wechat
#  3. 如果频繁断连,检查是否被微信风控

常见原因和解决方案:

问题 原因 解决方案
扫码后断连 微信安全策略 使用新号/降低频率/用企业微信
登录被拒 账号异常 检查账号状态,解除限制
心跳超时 网络不稳定 检查防火墙、代理设置
频繁掉线 协议更新 更新适配器到最新版本

问题:Telegram Webhook 设置失败

bash
# 测试 Webhook URL 是否可达
curl -f https://your-domain.com/hermes/telegram/webhook

# 检查 SSL 证书
openssl s_client -connect your-domain.com:443

# 手动设置 Webhook
curl -X POST "https://api.telegram.org/bot${TOKEN}/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.com/hermes/telegram/webhook",
    "secret_token": "your-secret",
    "max_connections": 40,
    "allowed_updates": ["message", "edited_message", "callback_query"]
  }'

# 查看当前 Webhook 信息
curl "https://api.telegram.org/bot${TOKEN}/getWebhookInfo"

问题:Discord Bot 不响应消息

bash
# 检查 Gateway Intents 是否启用
# 1. 登录 Discord Developer Portal
# 2. 进入 Bot 设置
# 3. 确认以下 Intent 已启用:
#    ✅ MESSAGE CONTENT INTENT
#    ✅ GUILD_MESSAGES

# 检查 Bot 权限
hermes gateway adapters diagnose discord

# 输出:
# [✓] Bot Token 有效
# [✓] Gateway 连接成功
# [✓] 已加入 3 个服务器
# [✗] MESSAGE CONTENT INTENT 未启用(Dev Portal)
# [✓] Bot 在目标频道有 Send Messages 权限
#
# 建议:在 Dev Portal 启用 MESSAGE CONTENT INTENT 并重新邀请 Bot

4.2 消息问题

问题:消息发送失败/超时

yaml
# 增加超时配置
gateway:
  message:
    send_timeout: 30        # 发送超时(秒)
    retry_count: 3          # 重试次数
    retry_delay: 2          # 重试间隔(秒)

  rate_limit:
    # Telegram API 限制:每秒 30 条消息
    telegram_rps: 25        # 留有余量
    # Discord 没有明确限制,但建议控制
    discord_rps: 10
    # 微信没有 API,但有风控
    wechat_rps: 5

问题:Markdown 渲染异常

javascript
// Telegram MarkdownV2 转义示例
function escapeMarkdownV2(text) {
  // 需要转义的字符:_ * [ ] ( ) ~ ` > # + - = | { } . !
  return text.replace(/([_*\[\]()~`>#+\-=|{}.!])/g, '\\$1');
}

// Discord Markdown 不需要额外转义(由 SDK 处理)
// 但代码块中的内容需要注意

// 微信纯文本转换
function toWechatText(text) {
  return text
    .replace(/\*\*(.+?)\*\*/g, '【$1】')
    .replace(/\*(.+?)\*/g, '$1')
    .replace(/`([^`]+)`/g, '「$1」')
    .replace(/^### (.+)$/gm, '· $1 ·')
    .replace(/^## (.+)$/gm, '-- $1 --')
    .replace(/^# (.+)$/gm, '=== $1 ===')
    .replace(/^[-*] (.+)$/gm, '• $1')
    .replace(/^\d+\. (.+)$/gm, '$1');
}

问题:消息内容被截断

yaml
# 各平台消息长度限制
platforms:
  wechat:
    max_length: 2000        # 单条消息最大字符数
    split_strategy: "smart" # 按段落分割
    split_delay: 500        # 分割消息之间的延迟(ms)

  telegram:
    max_length: 4096
    split_strategy: "markdown"  # 保持 Markdown 完整性分割
    split_delay: 300

  discord:
    max_length: 2000
    split_strategy: "code_block"  # 代码块优先保持完整
    split_delay: 300

4.3 权限问题

问题:Bot 无法发送消息到频道

bash
# Discord 权限检查清单
# 1. Bot 角色必须有 "Send Messages" 权限
# 2. 频道覆盖权限不能禁止 Bot 发送消息
# 3. Bot 角色必须高于 "Everyone" 的权限设置
# 4. 如果频道是 NSFW,Bot 也需要相应权限

# Telegram 权限检查
# 1. Bot 必须是群组成员
# 2. 群组管理员需要授予 Bot 发送消息权限
# 3. 如果群组开启了 "Slow Mode",Bot 也受限制

问题:Token 失效

bash
# Telegram Token 刷新
# 1. 通过 @BotFather 发送 /revoke
# 2. 获取新 Token
# 3. 更新配置:
hermes config set telegram.bot_token NEW_TOKEN_HERE

# Discord Token 刷新
# 1. Dev Portal → Bot → Reset Token
# 2. 更新配置:
hermes config set discord.bot_token NEW_TOKEN_HERE

# 微信
# 个人号:重新扫码登录
hermes gateway adapters reset wechat
hermes gateway adapters start wechat

# 企业微信:Corp Secret 需要管理员在后台查看

4.4 性能问题

问题:响应速度慢

bash
# 诊断响应链路延迟
hermes gateway benchmark

# 输出:
# ═══════════════════════════════════════════
#  响应链路延迟分析
# ═══════════════════════════════════════════
#
#  平台接收 → 路由器:     2ms
#  路由器 → 会话管理:     1ms
#  会话管理 → Agent:      5ms
#  Agent 推理:            2800ms  ← 瓶颈在这里
#  Agent → 格式化:        50ms
#  格式化 → 平台发送:     15ms
#  ─────────────────────────────
#  总延迟:                2873ms
#
#  优化建议:
#  1. 使用更快的模型(如 Groq 提供超快推理)
#  2. 启用流式输出(Stream)减少感知延迟
#  3. 使用缓存减少重复计算
yaml
# 优化配置
gateway:
  # 启用流式输出
  streaming:
    enabled: true
    chunk_size: 50        # 每块字符数
    min_chunk_interval: 100  # 最小间隔(ms)

  # 缓存配置
  cache:
    enabled: true
    ttl: 3600             # 缓存过期时间(秒)
    max_size: 1000        # 最大缓存条目数

  # 并发控制
  concurrency:
    max_active_sessions: 10
    queue_size: 50
    queue_timeout: 60     # 队列超时(秒)

消息收发实战

5.1 跨平台统一消息处理

javascript
// 统一消息处理器
class UnifiedMessageHandler {
  constructor(agent) {
    this.agent = agent;
    this.platforms = {};
  }

  // 注册平台适配器
  registerPlatform(platformName, adapter) {
    this.platforms[platformName] = adapter;
    adapter.onMessage(async (rawMsg) => {
      const msg = adapter.normalize(rawMsg);  // 标准化为 HermesMessage
      await this.handleMessage(platformName, msg);
    });
  }

  // 统一消息处理
  async handleMessage(platformName, msg) {
    console.log(`[${platformName}] 收到消息: ${msg.content.substring(0, 50)}...`);

    // 1. Intent 检查
    const intentResult = this.checkIntent(platformName, msg);
    if (!intentResult.shouldProcess) {
      console.log(`[${platformName}] 消息被过滤: ${intentResult.reason}`);
      return;
    }

    // 2. 发送给 Agent 处理
    const reply = await this.agent.process({
      platform: platformName,
      userId: msg.userId,
      userName: msg.userName,
      chatId: msg.chatId,
      content: msg.content,
      attachments: msg.attachments,
      isGroup: msg.isGroup,
    });

    // 3. 平台适配输出
    const adapter = this.platforms[platformName];
    await this.sendPlatformReply(adapter, msg, reply);
  }

  // 平台适配回复
  async sendPlatformReply(adapter, originalMsg, reply) {
    const formatted = adapter.formatReply(reply);

    // 根据平台特性发送
    if (reply.type === 'text') {
      await adapter.sendText(originalMsg.chatId, formatted.text);
    } else if (reply.type === 'text_with_code') {
      await adapter.sendText(originalMsg.chatId, formatted.text);
      if (formatted.code) {
        await adapter.sendCode(originalMsg.chatId, formatted.code, formatted.language);
      }
    } else if (reply.type === 'embed') {
      await adapter.sendEmbed(originalMsg.chatId, formatted.embed);
    }

    // 处理文件附件
    if (reply.files) {
      for (const file of reply.files) {
        await adapter.sendFile(originalMsg.chatId, file);
      }
    }
  }

  // Intent 检查
  checkIntent(platformName, msg) {
    const config = this.loadIntentConfig(platformName);

    // 黑名单检查
    if (config.blacklist?.users?.includes(msg.userId)) {
      return { shouldProcess: false, reason: '用户黑名单' };
    }

    // 白名单检查
    if (config.whitelist && !config.whitelist.users?.includes(msg.userId)) {
      return { shouldProcess: false, reason: '不在白名单中' };
    }

    // 响应模式检查
    const mode = config.response_mode || 'mention';
    if (mode === 'never') {
      return { shouldProcess: false, reason: '该频道不响应' };
    }
    if (mode === 'mention' && !msg.isMentioned) {
      return { shouldProcess: false, reason: '未被提及' };
    }
    if (mode === 'keyword') {
      const hasKeyword = config.keywords?.some(kw => msg.content.includes(kw));
      if (!hasKeyword) {
        return { shouldProcess: false, reason: '未匹配关键词' };
      }
    }

    // 忽略模式检查
    const ignoreMatch = config.ignore_patterns?.some(p => new RegExp(p).test(msg.content));
    if (ignoreMatch) {
      return { shouldProcess: false, reason: '匹配忽略模式' };
    }

    return { shouldProcess: true };
  }
}

5.2 富媒体交互示例

微信:代码转图片发送

javascript
// 微信代码图片生成
async function sendCodeAsWechatImage(chatId, code, language) {
  // 1. 使用 puppeteer 渲染代码为图片
  const html = `
    <!DOCTYPE html>
    <html>
    <head>
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
      <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
    </head>
    <body>
      <pre><code class="language-${language}">${escapeHtml(code)}</code></pre>
      <script>hljs.highlightAll();</script>
    </body>
    </html>
  `;

  // 2. 截图
  const imageBuffer = await renderHtmlToImage(html, {
    width: 800,
    height: 'auto',
    padding: 20
  });

  // 3. 发送到微信
  await wechat.sendImage(chatId, imageBuffer);
}

Telegram:内联按钮交互

javascript
// Telegram 内联按钮 - 代码审查确认
async function sendReviewButtons(chatId, review) {
  await telegram.sendWithButtons(chatId, `📋 代码审查完成

文件: ${review.file}
问题: ${review.issues} 个
评分: ⭐ ${review.score}/5

是否自动修复?`, [
    [
      { text: "✅ 自动修复", callback_data: `fix:${review.file}` },
      { text: "❌ 跳过", callback_data: `skip:${review.file}` }
    ],
    [
      { text: "📝 查看详情", url: review.detailUrl }
    ]
  ]);
}

// 处理按钮回调
telegram.onCallbackQuery(async (query) => {
  const [action, file] = query.data.split(':');

  if (action === 'fix') {
    await agent.fixFile(file);
    await telegram.answerCallbackQuery(query.id, { text: "✅ 已自动修复" });
  } else if (action === 'skip') {
    await telegram.answerCallbackQuery(query.id, { text: "⏭️ 已跳过" });
  }
});

Discord:Embed 消息展示

javascript
// Discord Embed - 任务完成报告
async function sendTaskReport(channelId, task) {
  const embed = {
    title: "🎉 任务完成",
    color: 0x00ff00,
    description: `**${task.name}** 已成功完成`,
    fields: [
      { name: "执行时间", value: task.duration, inline: true },
      { name: "修改文件", value: String(task.filesModified), inline: true },
      { name: "通过率", value: `${task.passRate}%`, inline: true },
      { name: "输出", value: task.output.substring(0, 1000) }
    ],
    thumbnail: { url: "https://..." },
    footer: { text: `由 Hermes Agent 执行 | ${new Date().toLocaleString()}` },
    timestamp: new Date().toISOString()
  };

  await discord.sendEmbed(channelId, embed);
}

总结与下篇预告

本文深入三大消息平台(微信、Telegram、Discord)与 Hermes Agent 的集成实战,涵盖了从 Bot 创建、认证配置、Intent 规则到常见问题排查的完整流程。

核心要点回顾:

  1. 认证是第一步 —— 每个平台都有独特的认证流程,务必妥善保管 Token
  2. Intent 是核心 —— 精确控制 Agent 的响应行为,避免误触发和不响应
  3. 格式要适配 —— 微信纯文本、Telegram MarkdownV2、Discord Markdown,各有讲究
  4. 限制要尊重 —— 各平台都有消息长度、频率等限制,需要妥善处理
  5. 排查有套路 —— 连接问题、消息问题、权限问题、性能问题,各有诊断方法

三大平台快速对比:

维度 微信 Telegram Discord
接入难度 ⭐⭐⭐
Bot API 成熟度 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
消息格式 纯文本 MarkdownV2 Markdown
富媒体支持
群管理 部分 完整 完整
适合场景 国内团队 国际团队 开发者社区

下篇预告

Hermes Agent 企业级部署与运维

在下一篇中,我们将转向生产环境,探讨:

  • 🏢 多实例部署架构:负载均衡、高可用、故障转移
  • 📊 监控与告警:Prometheus + Grafana 指标采集
  • 🔒 安全加固:网络隔离、权限最小化、审计日志
  • 💾 数据持久化:会话存储、技能备份、配置管理
  • 🚀 CI/CD 流水线:自动化测试、蓝绿部署、回滚策略

敬请期待!


本系列文章持续更新中,欢迎 star 和分享。如有问题,请在评论区留言。