跳转到内容

AI 对话接入架构

对话 Bot 的本质是“接收平台事件并回复”,AI 只是其中一种回复生成方式。先完成可预测的普通 API 双向对话,再把业务处理器替换为 LLM,可以明显降低平台配置、事件协议和模型问题相互干扰的概率。

本文是跨平台设计基线,核验日期为 2026-09-08。平台字段、权限和时限仍以各渠道教程及官方资料为准。

类型能否接收用户消息本手册中的定位
飞书、钉钉、企业微信、Telegram、Slack、Discord、Teams Bot可以,需配置事件、长连接或 Gateway可做普通双向 Bot,也可扩展 AI 对话
Incoming Webhook、自定义群机器人通知 URL通常不可以只用于单向投递,不能据此实现对话
Server 酱、PushPlus、WxPusher、PushDeer、Gotify、ntfy、Pushover本手册覆盖的接口是通知投递保持通知型定位,不虚构对话能力

“平台宣传有 AI 能力”不等于必须使用平台自带模型。只要平台能把消息事件交给你的服务,并允许你的服务回复,就可以接入规则引擎、业务 API、自建模型或任意第三方 LLM。

用户 / 群聊
平台事件入口(Webhook / WebSocket / Events API / Gateway)
↓ 验签、解密、快速确认
平台接入层(只处理平台协议)
↓ 标准事件
去重与路由层 ──→ 权限、配额、审计
会话层(会话键、上下文、取消与并发控制)
回复处理器 ──→ 规则 / 业务 API / generateReply(可选 LLM)
平台发送适配器(回复原消息 / 原线程 / 原会话)

每个平台适配器只承担四件事:验证来源、解析事件、快速确认、发送回复。不要在验签函数或 Webhook 路由中直接堆放提示词、知识库检索和模型调用。

建议把入站消息转换成统一结构:

interface ConversationEvent {
platform: 'feishu' | 'dingtalk' | 'wecom' | 'telegram' | 'slack' | 'discord' | 'teams';
eventId: string;
conversationId: string;
threadId?: string;
senderId: string;
text: string;
mentioned: boolean;
replyHandle: unknown;
receivedAt: number;
}

replyHandle 保存平台回复所需的最小上下文,例如消息 ID、线程时间戳、频道 ID、response_url 或 Activity 上下文;它不进入提示词,也不写入面向模型的聊天记录。

上线 AI 前先完成一个不调用模型的确定性处理器:

async function handleBusinessReply(event) {
const text = event.text.trim();
if (text === '/ping') return 'pong';
if (text === '/help') return '可用命令:/ping、/status、/ticket <编号>';
if (text.startsWith('/ticket ')) {
return await queryTicket(text.slice('/ticket '.length));
}
return '未识别该命令,请输入 /help。';
}

这条路径已经是完整的 API 双向对话:用户发消息,平台推送事件,你的服务调用业务 API,再把结果回复到同一会话。它具有响应确定、成本低、容易审计的优势,适合查询、审批、运维命令和表单流程。

将回复生成约束为厂商无关接口,平台适配器无需知道使用了哪个模型:

type ChatMessage = { role: 'system' | 'user' | 'assistant'; content: string };
interface ReplyGenerator {
generateReply(input: {
messages: ChatMessage[];
signal: AbortSignal;
metadata: { platform: string; senderId: string; conversationKey: string };
}): Promise<string>;
}
async function processEvent(event, replyGenerator) {
if (await dedupe.seen(event.eventId)) return;
const conversationKey = buildConversationKey(event);
const history = await conversations.load(conversationKey, 20);
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 20_000);
try {
const reply = await replyGenerator.generateReply({
messages: [...history, { role: 'user', content: event.text }],
signal: controller.signal,
metadata: { platform: event.platform, senderId: event.senderId, conversationKey },
});
await platform.sendReply(event.replyHandle, reply);
await conversations.append(conversationKey, event.text, reply);
} finally {
clearTimeout(timeout);
}
}

会话键决定哪些消息共享上下文。推荐至少包含租户和平台,避免跨企业串话:

私聊:{tenant}:{platform}:dm:{conversationId}:{senderId}
群聊:{tenant}:{platform}:group:{conversationId}:{threadId-or-root}

群聊默认按线程隔离;平台没有线程时,再按群聊隔离。不要只用 senderId,同一个人在不同企业、群聊或主题中的内容不应自动混合。

  • 只保存完成的用户/助手消息,不把原始平台事件整体写入模型上下文。
  • 同时设置消息条数、Token 数和时间窗口上限。
  • 长会话先摘要再截断,并保留最近几轮原文。
  • 提供“清空上下文”命令和明确的数据保留期。
  • 多实例部署使用共享存储;内存 Map 只适合本地验证。

平台可能因超时或网络错误重试同一事件。以官方事件 ID 作为首选幂等键;没有稳定 ID 时,对“平台 + 会话 + 消息 ID + 事件类型”做哈希。去重记录的过期时间应覆盖平台最大重试窗口。

同一会话的两条消息还可能并行到达。可按会话键加短租约锁,或把事件投递到按会话分区的队列。新的用户消息到达时,可以取消上一轮仍在生成的低优先级回答,避免回复顺序颠倒。

Webhook 的确认时限通常短于一次模型调用。通用处理顺序是:

  1. 验签、解析并写入队列。
  2. 在平台规定时限内返回成功或 defer。
  3. 后台调用业务 API 或 LLM。
  4. 使用平台允许的回复 API、线程消息或后续 Webhook 返回结果。

只有平台明确支持时才流式更新。否则先回复“已收到,正在处理”可能产生噪声;更稳妥的做法是使用平台的 defer、占位消息或 typing 能力,并设置总超时和失败提示。

  • 群聊默认只响应 @机器人、斜杠命令或显式回复,避免监听所有对话。
  • 在服务端再次校验租户、群聊、用户和命令权限,不能只依赖客户端按钮是否可见。
  • 高风险动作使用二次确认或审批,不让模型直接执行转账、删除、发布等不可逆操作。
  • 普通查询与 AI 对话可以共用入口,但命令路由应优先于自由文本模型处理。

把用户消息、检索文档和工具返回值都视为不可信输入。系统指令和工具权限不能由消息正文覆盖;工具调用应通过结构化参数、白名单和服务端鉴权执行。

  • 发送到模型前移除 Token、手机号、证件号和业务密钥等敏感数据。
  • 明确数据跨境、模型训练、保留期和删除能力是否满足组织要求。
  • 日志不记录完整聊天正文和平台凭据;必要时按字段脱敏并限制访问。
  • 给用户清晰的 AI 身份提示,重要结论提供来源或要求人工确认。
  • 限制单次输入、输出和附件大小,防止成本失控。
  • 对 Markdown、HTML、提及和链接按平台规则转义。
  • 对工具执行结果做独立验证,不把模型生成的“成功”当成真实执行结果。
  • 模型不可用时降级到帮助菜单、工单或人工服务,而不是无限重试。

每次处理至少记录脱敏后的 eventId、会话键哈希、平台、处理阶段、耗时、回复消息 ID、模型用量和错误类型。建议分别统计:入站验签失败、重复事件、队列延迟、生成耗时、平台限流和回复失败。

上线前按顺序验收:

  1. 确定性 /ping 能在私聊或测试群完成一问一答。
  2. 同一事件重复投递只回复一次。
  3. 模型超时、平台 429、进程重启都有明确降级。
  4. 两个租户、两个群聊和两个线程之间不会共享上下文。
  5. 提示词注入测试不能越过工具权限或泄露系统配置。
  6. Token 轮换后旧凭据失效,日志中不存在完整密钥。

跨平台不存在统一的官方对话协议。请以各平台教程末尾列出的官方文档为准;LLM 接口由实际选用的模型服务提供方定义。本页刻意不绑定任何模型厂商或现有通知网关实现。