别把 Agent 的沟通层写成一堆机器人:Caspian 如何用统一事件模型接入邮件、Slack 与 Telegram
很多团队把 Agent 的「会推理」和「能联系用户」放在同一个需求里,落地时却往往先后长出 Telegram Bot、Slack App、邮件收件器和一段 webhook 转发代码。几个月后,真正难维护的不是模型调用,而是每个平台各自的验签、重试、会话线程、消息格式和并发策略。更糟的是:同一个用户从邮件转到 Slack 后,业务代码常常把它当成了两套完全不同的对话。
Caspian 是一个面向 Agent 与人类沟通的 SDK。它不负责让多个 Agent 互相协商;它的目标是把 Slack、Discord、Telegram、邮件、WhatsApp 等渠道抽象为同一种消息处理接口。项目当前 1.0 版本将公开入口统一为 Caspian;旧版 CommClient 并不是可直接替换的 API。仓库的实际许可证文件为 AGPL-3.0,因此在将它嵌入服务前,团队应先评估网络服务场景下的许可证义务。
本文不把「多渠道」当成简单的功能清单,而是从一个更实际的问题出发:怎样让业务处理函数只关心订单、工单或审批,而不被渠道差异反复污染?
先拆开三层:传输、会话与业务决策
多渠道 Agent 常见的失败模式,是在每个 webhook 里直接调用模型:Slack handler 写一份 prompt,Telegram handler 再写一份,邮件轮询器又复制一份。这样做短期很快,长期却把渠道语义和业务规则绑死。
更稳妥的边界可分为三层:
- 传输层:接收平台原始请求、完成验签或 socket/webhook 连接,并把不同 payload 归一化。
- 会话层:确定消息属于哪个线程,处理并发消息的排队、去抖或丢弃策略,并把回复投递回正确位置。
- 业务层:读取规范化后的文本、上下文和业务数据,决定回答、转人工、创建工单还是仅记录。
Caspian 的 channels.add() 负责前两层的渠道接入;@cx.on_message(...) 注册业务处理规则;处理函数取得的 thread 和 msg 则是跨渠道的工作面。这样的抽象并不能自动解决身份合并或客服知识库,但它至少避免了业务代码到处出现 if platform == ...。
一个最小接入:先让单渠道跑通,再扩展
下面的 Python 示例采用 SDK README 中的 1.0 API。它使用自托管 Telegram webhook:平台 token 和 webhook URL 由部署者持有,SDK 在应用进程内处理入站请求。示例刻意只回显文本;生产环境应把 handle 接到明确的业务服务,而不是将未过滤内容直接送入高权限工具。
from caspian import Caspian
cx = Caspian()
cx.channels.add(
"telegram",
via="self-host",
bot_token="${TELEGRAM_BOT_TOKEN}",
webhook_url="https://agent.example.com/telegram",
)
@cx.on_message({"channel": "telegram", "overlap": "queue"})
def handle(thread, msg, ctx):
text = msg.text.strip()
if text == "/status":
thread.post("服务正常;如需人工协助,请回复 /human。")
return
thread.post(f"已收到:{text}")
这里值得注意的不是回显,而是 overlap: "queue"。当同一线程连续发来两条消息时,若第一条还在触发耗时检索或模型调用,队列策略能减少两个处理过程交叉写入同一对话的风险。Caspian 文档还列出了 debounce、drop 与 parallel 等策略;它们不是性能开关,而是产品语义:客服或审批消息通常不应随意丢弃,状态刷新类消息则可能更适合去抖。
接入第二个渠道时,核心 handler 不必复制。以自托管模式添加 email、Slack 或 Telegram 后,规则仍可围绕统一的 msg 与 thread 编写。对于 Discord 和 Slack,SDK 文档说明可以用 cx.listen("discord") 或 cx.listen("slack") 建立长连接式入站,从而避免为了接收消息额外暴露一个公共 webhook;这仍不意味着可以省掉最小权限、网络出口和平台凭据轮换。
Hosted 与 self-host:不要只按“省事”选择
Caspian 同时支持 hosted 和 via="self-host" 两种模式。前者由 Caspian gateway 接收入站事件,应用通过 cx.run() 轮询;后者由自己的进程、平台 token 与 webhook/socket 承担接入。二者可以复用相同的 handler 规则,但运维责任完全不同。
选择 hosted 时,优先确认 API key 的保存位置、事件延迟、数据保留、故障时是否可重放,以及哪些渠道需要自带平台 token。选择 self-host 时,则要把 webhook 的 TLS、来源验签、公开 URL、重试幂等性和密钥轮换纳入部署清单。不要因为 SDK 提供了统一抽象,就假定所有渠道的账号政策一致:例如 README 特别提示,X 的私信收发需要付费的 X API 订阅,免费层能力并不等价。
一个常见误区是把「self-host」理解成所有通信数据都不会经过第三方。它只能说明适配器在本进程运行;是否调用外部模型、监控平台或渠道官方 API,仍取决于你的完整架构。设计评审时应分别画出入站消息、模型请求、业务数据库和审计日志的流向。
把多渠道做成可验证的工作流
统一接口最有价值的地方,是它让测试不再按平台数量倍增。建议至少补上四类验证:
- 同一业务规则测试:构造规范化消息,确认
/status、转人工和敏感操作在不同渠道走相同授权逻辑。 - 并发与重试测试:模拟同一线程快速连发、重复 webhook 与处理超时,检查订单创建或外部写操作是否幂等。
- 验签失败测试:不能因为本地调试方便而绕过生产验签;拒绝路径应有可检索但不泄露正文的审计记录。
- 渠道降级测试:富文本按钮、流式输出或媒体发送在不同渠道的呈现不同。关键审批信息必须有纯文本的可读替代,而不能只依赖某个平台的卡片组件。
Caspian 还提供 thread.send_blocks()、thread.stream() 等能力,但使用它们前先确认业务是否真的需要。对付款、权限变更、生产发布这样的动作,最重要的交互不是漂亮的按钮,而是明确的确认文本、稳定的线程关联和可审计的授权记录。
适合什么场景,又不适合什么场景
如果你已经有一套 Agent 业务逻辑,只是需要让它在邮件、团队聊天和社区渠道之间复用,Caspian 这种通信层抽象很合适:它把适配器、线程和规则从业务代码中剥离出来。客服助手、内部 IT 支持、销售跟进、社区机器人都能从中受益。
但它不是完整的 Agent 平台。知识检索、用户身份主数据、权限系统、人工坐席、模型安全策略和业务审计仍要由应用负责;Agent-to-Agent 协作协议也不是它的主要定位。最好的接入方式不是把所有能力都塞进一个 handler,而是把 Caspian 放在边缘:接收经过验证的事件,调用具有明确权限边界的业务服务,再把可追踪的结果回复到原线程。
当团队把沟通层从「每个渠道一套机器人」收敛成统一事件模型后,新增渠道才会变成一次适配工作,而不是一次业务逻辑重写。这比多接几个 Bot 更重要:它让 Agent 能在用户选择的地方出现,同时仍保留工程团队能测试、能审计、能逐步扩展的边界。