Skip to content

Latest commit

 

History

History
46 lines (42 loc) · 5.06 KB

File metadata and controls

46 lines (42 loc) · 5.06 KB

QQ Bot Worker 项目规则

环境与凭据

  • 平台:Cloudflare Workers + D1 + KV
  • 域名:https://bot.astroptis.dpdns.org(自定义域名,QQ 平台拒绝 .workers.dev 域名)
  • Webhook URL:https://bot.astroptis.dpdns.org/api/webhook
  • QQ AppID:1905493443
  • AppSecret 存于 KV config:qq_credentials(会变动,通过管理面板设置,不要硬编码)
  • 管理面板密码:tianlu4.5(首次登录设置)
  • AI 后端:b.ai,endpoint https://api.b.ai,模型 deepseek-v4-flash(KV 中配置)
  • 联网搜索:AnySearch REST API https://api.anysearch.com/v1/search(免费 1000次/天,无需 key,匿名可用)。请求 POST {"query":"...","max_results":N},返回 code:0 + data.results[](title/url/snippet/content)
  • 搜索触发:needsSearch() 启发式关键词检测(天气/新闻/最新/股价/汇率/搜索等),命中后自动调用 AnySearch 并把结果注入 AI system prompt 上下文

关键 API 要点

  • QQ access_token 端点:https://api.bot.qq.com/app/getAppAccessToken(不是 bots.qq.com,那是错的)
  • access_token 成功响应:{"access_token":"...","expires_in":3815} — 无 code 字段;失败才是 {"code":100002,"message":"internal err"}。判断成功用 data.access_token 是否存在,不要用 code !== 0(成功时 code 是 undefined)
  • 发送消息 API:https://api.bot.qq.com/v2/users/{openid}/messages,Authorization 头 QQBot {token}
  • webhook 事件字段:事件类型用 t(不是 type),数据在 d(不是 raw)
    • d.content 消息文本,d.author.user_openid 发送者,d.id 消息ID(ROBOT1.0_...)
    • 顶层 id 是 C2C_MESSAGE_CREATE:...,不能作为 msg_id 发送
  • Webhook 回调验证:请求 {"d":{"plain_token":"...","event_ts":"..."},"op":13},返回 {"plain_token":"...","signature":"..."}
  • Ed25519 签名:secret 重复填充到 32 字节作为种子,签名 event_ts + plain_token。必须用 tweetnacl(Web Crypto 的 Ed25519 与 Go 签名不一致);Go 参考 ed25519.GenerateKey(strings.NewReader(seed)) + ed25519.Sign,tweetnacl 输出与 Go 完全一致

Cloudflare Workers 注意事项

  • 免费计划有冷启动:低活跃时首个请求慢 ~5s,cron */1 * * * * 保活可缓解(已配置)
  • wrangler kv key get / wrangler tail 在本机 Windows 会崩溃(access violation),用管理面板 API 代替
  • PowerShell 不支持 &&,用 ;
  • 查询/删除 D1 远程库:wrangler d1 execute qq-bot-db --remote --command "SQL"(单条语句,不能多条)
  • Windows curl 发送 JSON 到 QQ token 接口会报 100002,用 Node.js 或 Worker fetch 测试
  • webhook 必须用 ctx.waitUntil() 异步处理消息:如果同步等待 AI fetch(3-5秒+偶发挂起)再返回,Cloudflare 会强制终止 Worker 导致 AI 请求中断、消息丢失。先返回 OK 再 ctx.waitUntil(processAsync()) 已解决
  • 不要用 AbortController + fetch:Cloudflare Workers 存在兼容问题会导致请求挂起;改用 Promise.race([fetch, timeout]) 实现超时
  • 给 AI 调用加超时 + 重试:api.b.ai 对 Cloudflare Worker 偶发不响应,fetchWithTimeout(15000) + 二次重试提高可靠性
  • AppSecret 重置后需等待几分钟:QQ 平台 secret 缓存有延迟,重置后立即保存 webhook 会报签名错误,等 5 分钟再试
  • AppSecret 一致性:用户多次重置,每次重置后必须同步更新 KV config:qq_credentials,否则签名验证失败
  • deepseek-v4-flash 不支持稳定 function calling:b.ai 上它有时返回 tool_calls、有时只输出文字"我去查一下"(不稳定)。b.ai 的 mimo-v2.5 用非标准文本式 <tool_call> 标记也不稳定。OpenCode Zen mimo-v2.5-free 支持标准 tool_calls 但免费限流极严(连续第1次就 429),不可用
  • 实现"AI 主动搜索"用两阶段标记方案:第一次调用让 AI 只输出 SEARCH/NO(max_tokens=100,推理模型 max_tokens 太小会被截断在 reasoning 阶段导致 content 为空),若 SEARCH 则执行搜索并把结果注入 system prompt 再第二次调用生成回复
  • 决策判断检查 content:deepseek 推理模型把思考放 reasoning_content,content 可能为空,需 json() 解析后读 choices[0].message.content
  • AI 请求超时:用 Promise.race 自定义超时(AbortController 在 CF Workers 有兼容问题)
  • CF→api.b.ai 网络偶发挂起:Worker 到 b.ai 的 fetch 偶发无响应(非代码问题),用超时+重试兜底
  • b.ai 模型列表:deepseek-v4-flash(免费,可用)、mimo-v2.5、mimo-v2.5-pro、deepseek-v4-pro(付费,access_denied)、gpt-5.2等付费模型需充值

部署与仓库

  • 部署:wrangler deploy(项目目录 C:\Users\wang\qq-bot-worker)
  • GitHub 仓库:Astroptis/WorkerBot
  • 管理面板:https://bot.astroptis.dpdns.org/
  • 测试消息:POST 到 /api/webhook,body 用 t/d 字段格式,openid 用 46BD04B2B0B12C2485CCDB9FCF5F6394(真实用户,能触发真回复)