QQ 公式 Bot
Ed25519 webhook イベントを使った QQ Official Bot v2 メッセージング。アクティブメッセージは Bot ごとに月 4 件までに制限されるため、受動返信を主体に設計してください。
⚠️ プッシュではなく受動返信を使用してください。 QQ のアクティブメッセージは Bot ごとに月 4 件までです。1 日あたりの上限: アクティブ DM は 200 件、チャネルごとのサブチャネルへのアクティブメッセージは 20 件。本番環境でのやりとりは、ユーザーからの受信メッセージへの返信(Bot の応答は 5 秒以内、無料枠)を基本とし、アクティブなプッシュは重要なアラートのみに限定してください。
利用できる機能
- 4 種類の送信サーフェス。
channelプレフィックスによってルーティングされます。c2c:<openid>→/v2/users/{openid}/messages(C2C DM)group:<openid>→/v2/groups/{openid}/messages(グループ)channel:<id>(デフォルト) →/channels/{channel_id}/messages(パブリックギルドチャネル)dm:<guild_id>→/dms/{guild_id}/messages(プライベートギルド DM)
/webhooks/qqへの受信 webhook(Ed25519 署名付き)。access_tokenのキャッシュは 7200 秒で、自動更新に対応。- テキストのみ対応。 リッチメディアメッセージ(画像、ファイル、ARK カード)は将来の機能拡張で対応予定。
- テキスト上限は 4000 文字。
セットアップ
1. Bot を登録する
- QQ オープンプラットフォーム Bot コンソールにサインイン
- Bot を作成し、Bot 詳細ページの AppID と AppSecret を控える
- 「Develop Settings」→「Webhook」から URL を
https://<your-host>/webhooks/qqに設定し、「Webhook Mode」を選択 - プラットフォームから op=13 のバリデーションハンドシェイクが送信される。Minara は署名済みの plain_token を自動的に返答する。
2. デフォルトの送信先を決める
最もよく使う送信先を選び、プレフィックスを付けてエンコードしてください。
| シナリオ | QQ_BOT_DEFAULT_CHANNEL_ID |
|---|---|
| パブリックギルドの DM に返信する | channel:<channel id> |
| グループへプッシュする | group:<group openid> |
| 特定ユーザーへプッシュする | c2c:<user openid> |
| プライベートギルド DM に返信する | dm:<guild id> |
パブリックギルドチャネルの場合(最も一般的)はプレフィックスを省略できます。
QQ_BOT_DEFAULT_CHANNEL_ID=1234567890channel:1234567890 と同等です。
3. Minara を設定する
minara auth messaging add
# `qq` を選択し、AppID・AppSecret・デフォルト送信先を貼り付ける。または環境変数で設定します。
QQ_BOT_APP_ID=12345678
QQ_BOT_APP_SECRET=<opaque secret>
QQ_BOT_TOKEN=<bot token>
QQ_BOT_DEFAULT_CHANNEL_ID=channel:12345678904. テストする
minara auth messaging test qq月間アクティブメッセージの枠を消費します。 計画的に使用してください。
受信 webhook
QQ は受信ボディに対して <timestamp><raw_body> を Ed25519 で署名します。
公開鍵はプラットフォームから公開されておらず、Bot シークレットから導出されます。
QQ_BOT_APP_SECRETの UTF-8 バイト列を取得する- バッファが 32 バイトに達するまで繰り返す
- これを Ed25519 シードとして使用し、鍵ペアを導出する
Minara はこのシード導出による鍵ペアを内部で処理します。リプレイウィンドウは 5 分間で、Discord や Slack と同じ規約に準拠しています。
バリデーションハンドシェイク: プラットフォームから {op: 13, d: {plain_token, event_ts}} が送られた場合、Minara は導出した秘密鍵で event_ts + plain_token に署名し、署名済みの hex を返答します。これによりプラットフォームは、エンドポイントがシークレットを保持していることを確認します。
受け付ける受信イベントの種類:
AT_MESSAGE_CREATE: パブリックギルドチャネルで Bot が @メンションされたGROUP_AT_MESSAGE_CREATE: グループで Bot が @メンションされたC2C_MESSAGE_CREATE: ユーザーからの DM
その他の op=0 ディスパッチイベント(チャネル更新、リアクションなど)は無視されます。
制限と注意事項
- アクティブメッセージの枠制限。 月 4 件、DM は 1 日 200 件、サブチャネルごとに 1 日 20 件。枠を超えるとエラーコード 130_001 が返ります。ある程度のボリュームでプッシュする場合は、このエラーを想定内として扱ってください。
- 受動返信パターンが想定される利用方法です。 ユーザーが Bot を @メンションし、Bot が 5 秒以内に返信する形式です。この返信はアクティブ枠に含まれません。
- 新規 Bot は webhook が必須です。 WebSocket のサンドボックスモードは v2 では非推奨となっています。
トラブルシューティング
「テストメッセージで errcode 130001 が返る」
- 月間アクティブメッセージの枠が消費されています。受動返信を使用してください。
「受信 webhook が 401 を返す」
- 最もよくある原因: ホストのクロックスキュー。5 分間のリプレイウィンドウは厳格に適用されます。
- まれな原因: App Secret の一部しか貼り付けていない。短いシークレットはシード導出時に繰り返されますが、誤ったシークレットを使うと誤った公開鍵が生成されます。
「バリデーションハンドシェイク(op=13)が失敗する」
- 起動時に
QQ_BOT_APP_SECRETが設定されていません。設定がないとシード導出が失敗し、プラットフォームのバインドが完了しません。
リファレンス
- 環境変数:
QQ_BOT_* - 送信:
apps/agent/src/messaging/qq.ts - 受信仕様:
apps/agent/src/messaging/inbound/specs/qq.ts - QQ Bot v2 API: bot.q.qq.com / wiki
- 署名の実装方法: Authentication / Sign