从聊天消息到成片:Telegram AI 视频生成机器人的架构与实现 上周我把一个 Telegram AI 视频生成机器人挂上了线顺手在 HN 上发了个 Show HN。一开始只是想让群里的人能直接“发句话就出片”没想到这个简单的交互方式反而比 Web 端更容易传播。项目本质是用户在聊天窗口里输入一段文字描述后台用大模型把描述改写成适合视频生成的 prompt再交给视频模型出片最后把成品直接推回聊天。全程不需要打开网页、不需要注册新账号、不需要理解 Stable Diffusion 里的那些参数。这个定位特别适合内容创作者、社群管理员以及所有“不想为了试一个工具去折腾 GPU 环境”的人。Telegram Bot API 对富媒体的支持很完整视频、动图、文件都能直接回传对开发者来说一个 Bot 就是一个天然的产品入口。自从对话式 AI 普及之后大家已经习惯了“在对话框里完成任务”把 AI 视频生成搬到聊天里本质上不是降低功能复杂度而是换了一种更轻的交付方式。1. 聊天流式生成为什么这里值得做一个 Bot1.1 消息即指令交互模型发生了迁移如果说 Web 表单是一次性索取聊天交互就是持续的上下文。用户可以在同一个会话里连续追问、修改风格、微调 promptbot 能够通过会话状态记住上一轮的参数。我在设计时专门维护了每个 chat_id 的上下文缓存例如上一次用过的画风预设、宽高比、时长这一轮没有重新指定就沿用上一次。这种交互方式在 Web 后台需要额外做状态管理而 Telegram 天然的会话维度替我省掉了不少工作。另外一点容易被忽略聊天软件里的“视频创作”会自然变成社交行为。群里有人生成了一段小猫踩键盘的视频其他人看到立刻想试同一个 prompt。Bot 在群组里可以被唤起生成的视频又能直接作为群回复这种传播链路是独立站点很难复制的。因为用户不需要离开聊天界面产品的新手引导也接近零成本——发一条消息收到一条视频所有人都知道怎么用。1.2 适用人群和使用场景我的目标用户不是对 Stable Diffusion 参数倒背如流的玩家而是“知道自己想要什么内容、但不想碰技术”的创作者。具体来说我观察到这么几类人用得最勤社区运营者想给群友做互动小视频短视频创作者快速生成分镜参考老师把抽象概念变成视觉演示产品经理在讨论群里画动态示意图。这些场景都不需要精细控制但需要“快”和“好玩”。所以我刻意把参数层隐藏在 prompt 里而不是暴露一堆按钮。用户只需要说“一只熊猫在竹林里打太极拳背景是黄昏”其余的交给 LLM 去理解并补充成规范提示词。真正追求精细控制的用户我再提供一个/advance命令进去之后可以指定宽高比、帧率、循环次数和随机种子。这样两类用户都在同一个聊天界面里得到满足互不干扰。2. 整体架构和技术选型2.1 从消息到视频回传的完整链路整个系统的核心链路分为六个环节接收消息、解析意图、生成 prompt、调用视频模型、上传回传、更新状态。我使用 Python 的python-telegram-bot库做事件接收长耗时的生成任务不直接放在 handler 里而是丢进 Redis 队列。handler 立刻回复“任务已进入队列队列位置 #12”然后由 worker 进程从队列里取任务执行。生成完成后worker 直接调用 Bot API 的send_video方法把结果推给用户。这条链路中最容易犯的错误是“把视频生成当成普通请求同步处理”。视频模型推理通常要几十秒到几分钟HTTP 请求早就超时了。即使你用的是第三方 APIAPI 本身也会对单次请求时长做限制。所以在架构上必须把“接收消息”和“任务执行”彻底解耦Telegram 侧的线程只负责收消息、写任务、回一句“排队中”GPU 或模型 API 侧的 worker 再慢慢跑。2.2 为什么选 Redis RQ而不是动不动上 K8s先说明这里没有看不起 Celery 的意思。但个人项目最怕的是依赖太重一台 2C4G 的小服务器上既跑 Bot 又要跑 API 服务Redis RQ 足够。每个任务就是一个 JSON payload包含 chat_id、message_id、用户原始描述、解析后的参数、任务创建时间。Redis 的优势是原子操作和原生支持阻塞弹队列用来做状态存储也不需要额外建数据库。任务状态我直接存在一个status:hash里pending / running / success / failed前端查询时读 Redis 就行。有些读者可能会问为什么不用 RabbitMQ 或者数据库轮询因为对于日均几百个任务的小工具引入重型 MQ 是错误的复杂度。真正需要扩展时把 worker 从 1 个扩到 5 个也只需要多启动几个进程队列依然是同一个 Redis。我实测在 2 个 worker 的情况下单个任务端到端延迟主要由视频生成时间决定队列本身几乎是零开销。瓶颈永远在 GPU 或模型 API 额度不在队列。2.3 任务状态与失败补偿用户等待视频期间最怕的是等了五分钟然后什么都没有。所以我在每个关键节点都要回调一次状态消息入队、开始生成、生成完成、开始上传。如果失败会带上失败原因而不是一句“出错啦”。具体做法是每个任务维护一个状态机worker 在处理到某一步时用editMessageText更新原始状态消息。为了解决“模型 API 临时挂掉”我给 worker 加了重试机制。重试分三种第一种是普通网络抖动3 秒后重试第二种是模型 API 返回 429/503等待retry-after或按指数退避第三种是“非法输入”这类错误重试十次也没用直接标记失败并通知用户修改描述。把错误类型分类而不是一刀切重试是我上线初期踩过的最深的坑之一。3. 核心实现里的关键工程点3.1 Bot 创建、Token 与消息接收方式Telegram 这边要先从 BotFather 拿到一个 token这个没有太多可说的。真正要决定的是用 polling 还是 webhook。本地调试时我用 polling部署到生产环境后我改用 webhook因为服务器本来就有 HTTPS 域名Telegram 会把更新直接 POST 到我的接口不需要 Bot 进程主动长轮询延迟也低。切换时最容易踩的坑是之前用 polling 测过后来设置了 webhook进程重启后一直接不到消息原因是服务器上还有残留的 polling 循环在抢 update。用python-telegram-bot的话两种方式切换非常简单application Application.builder().token(TOKEN).build() application.add_handler(CommandHandler(start, start)) application.add_handler(MessageHandler(filters.TEXT, handle_message)) if config.WEBHOOK: application.run_webhook( listen0.0.0.0, portconfig.PORT, url_pathTOKEN, webhook_urlfhttps://example.com/{TOKEN} ) else: application.run_polling()注意 webhook 的url_path最好直接用 token这个路径同时充当密钥外部猜不到具体路径。如果用/webhook这种通用路径谁都可以往你的 Bot 推送假更新轻则浪费消息额度重则触发频率限制。3.2 用 LLM 把粗糙想法变成视频模型 prompt这是我觉得最有价值的一层。视频模型对提示词的要求比图片模型更苛刻需要描述主体、动作、镜头、光照、氛围和画风。如果直接把用户输入扔给视频模型生成结果通常像一段随机噪声。所以我接了一个“prompt 改写层”本质上就是一个 LLM 的 system prompt要求输出结构化 JSON{ prompt: A giant panda is performing Tai Chi in a bamboo forest at dusk, warm sunlight filtering through leaves, subtle camera zoom, cinematic lighting, highly detailed, negative_prompt: blurry, distorted limbs, low quality, watermark, flickering, width: 1280, height: 720, duration: 4, fps: 24, seed: 42 }用户只需要说“熊猫在竹林里打太极”LLM 会补全镜头语言、光照和画风。在调用层我强制用 function calling 或 JSON mode不要让它自由发挥文本格式否则解析稳定性会很差。结构化输出还有一个额外好处如果某次解析失败我可以把那次 prompt 记录下来后续迭代改写层时作为测试样本这比零散地看日志高效多了。3.3 视频文件回传压缩、转码与大小限制Telegram Bot API 对上传文件有限制视频不能超过 50MB文档上传也有类似限制具体取决于接口方法。视频模型直接输出的 MP4 经常超过这个值尤其是高分辨率长视频。我在上传前统一走一遍 FFmpeg如果文件大于 40MB就把编码器换成 H.264、降低码率必要时缩小到 720p。转码参数我用了一个比较保守的预设ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset medium -movflags faststart -c:a aac -b:a 128k output.mp4-movflags faststart很关键它让 moov atom 移到文件头部Telegram 播放视频时不用等完整文件下载才能开始。在聊天场景下用户等待体验和视频能否秒开直接相关。如果你不写这一行生成的视频在消息里可能转圈很久体验瞬间掉一个等级。3.4 并发控制和额度管理个人项目最容易被打爆尤其是免费开放的时候。我给系统加了一层很简单的限流同一个用户同一时刻最多只能有一个任务在跑达到上限时直接提示/queue命令能看到自己的排队位置。全局并发也设了上限我是基于 GPU 显存来算的当前视频模型一次只能跑一个任务所以 worker 进程数设为 2多余任务留在队列。如果用的是第三方 API则根据套餐每分钟请求数设置令牌桶限流。实现上我用 Redis 的原子自增做计数入队时incr(user_running: user_id)任务结束时decr。如果你的并发超过 10建议换成令牌桶或信号量库避免自己造分布式锁。额度管理是后期才意识到的即使每天只有 100 个人玩视频生成 API 的费用也比想象的贵。目前每个用户默认只能免费用 3 次之后再想用就需要用兑换码。我宁愿先收窄供给也不愿意月底收到账单后慌忙砍服务。4. 安全合规与内容治理不是可选项4.1 输入侧和输出侧的过滤聊天里直接生成视频意味着产品面向的是所有年龄和背景的用户。AI 视频模型并不是天然就懂什么内容不能生成很多开源模型的“安全阀”很薄。因此在输入侧我会同时做两件事一张关键词黑名单做第一层粗筛再调一次模型内容审核接口做第二层分类。一些号称零审核、零限制的工具本质上是在绕过模型审核作为需要长期维护的项目我不会碰也建议你不要碰。输出侧同样重要。部分模型直接输出的帧里可能出现边缘情况需要设置安全审核回调发现置信度高的违规类别就直接丢弃结果并给用户回一句“生成内容未通过安全审核”。不要尝试绕过模型本身的审核机制一旦被举报Telegram 会直接封禁整个 Bot前面积累的用户量和口碑全部清零。这比任何技术风险都致命。4.2 用户限流与防滥用开放 Bot 之后我最大的教训是必须有白名单和黑名单两套机制。白名单适合早期验证阶段只允许好友和少数测试群使用黑名单用来处理反复生成违规内容或者恶意刷接口的用户。被封禁的用户连消息都不应该进队列只返回一条“你已被禁止使用本服务”。防滥用还有一个细节同一个用户如果注销后重新注册user_id 会变化如果你只封 user_id对方换一个新账号就能进来。所以我用“业务指纹”来加强判断比如该 user_id 绑定的常用 chat_id 和群组关系。不过也要注意隐私不要过度存储只保留防止重复进黑名单所需的最小字段。4.3 隐私和数据保留策略聊天内容本身就属于敏感数据尤其是视频生成会涉及用户输入的描述。我的策略是Redis 里的任务数据只保留 24 小时启动一个定时任务每天清理生成的视频原文件存 7 天用于失败排查超过就删除。用户任何时候发/delete_my_data就把该用户相关的任务记录和文件全部移除。这不是营销噱头是长期项目的基本底线。我还对日志做了脱敏处理。记录 prompt 时会把里面的人名、手机号、邮箱等实体替换成PII占位符。这样排查问题时不需要为了定位 bug 就把用户隐私原样带进日志。Telegram 对 Bot 的隐私要求很高用户很容易举报 Bot 不当存储聊天内容提前把数据生命周期设计好能省掉至少一次封禁风险。5. 踩坑实录与问题排查手册5.1 Bot 收不到消息、API 报错的常规排查开发期最常见的三个问题token 写错或者带上了多余前缀运行了多个 Bot 进程polling 和 webhook 同时抢更新服务器时区不是 UTC导致更新处理逻辑里的时间判断错乱。如果 Bot 完全没响应第一时间先看/getMe能不能返回 user 信息能返回说明 token 没问题。然后看进程输出里有没有收到 update如果进程没有输出基本就是 webhook 没有删干净。删 webhook 也有一个低级错误用 SDK 时是delete_webhook()用 HTTP 请求时是deleteWebhook大小写和下划线不一致就会接口 404。申请 Bot 时如果遇到error先别急着重开项目检查是不是 token 复制了完整 URL 而不是纯字符串这种错误几乎每天都有。5.2 模型接口的 unexpected endpoint or method 是怎么来的有一段时间我的日志里频繁出现类似“unexpected endpoint or method”的报错而且明确标记着 POST /chat/completions。排查下来不是模型的问题而是我在封装基础地址时把 URL 多拼或少拼了一段导致请求打到了一个不存在的 path。比如基础地址已经带了/v1我拼接时又写了一遍/v1/chat/completions自然就撞上了 endpoint 错误。另外一个低级错误是 HTTP method 用错GET 打到了只允许 POST 的接口。很多 AI 服务商对这类错误返回一个让人看不懂的响应看起来像网络故障。建议把所有模型调用的完整 URL 打印到日志里用 curl 手动复现一遍报错瞬间就明白了。这比猜测“是不是参数格式不对”高效得多。5.3 视频生成的常见质量问题生成视频的观感问题远多于功能问题。用户最常见的抱怨是“动物有五条腿”“镜头忽然闪了一下”“动作太快不像真实物理”。我的经验是让 LLM 在 prompt 里显式加入负向提示词并在参数层固定seed。同一段描述固定 seed 可以让用户反复生成时看到更稳定的构图而不是每次换一个完全不同的版本。如果用户描述里包含抽象名词比如“孤独”“回忆的温度”视频模型的输出会非常不可控。我在改写层里加了一条规则遇到抽象描述时先让 LLM 把抽象概念转成具象镜头例如“孤独”变成“一个人坐在窗边雨滴划过玻璃冷色调”“回忆的温度”变成“暖黄灯光下的旧书桌咖啡冒着热气粒子在光中漂浮”。这一步转化质量直接决定了用户是否会留下来用第二次。5.4 常见问题速查表现象原因快速处理Bot 不回消息webhook/polling 冲突调用 getWebhookInfo 并删除残留 webhook生成任务一直 pendingRedis 连接断开或 worker 没启动检查 worker 进程日志视频上传失败文件超过 Telegram 限制重新压缩到 40MB 以内模型接口 429限流触发按 retry-after 等待并指数退避画面花屏/闪烁视频模型参数太激进降低 fps适当提高 CFG固定 seed用户用完次数无法再试额度判断逻辑写在 handler 前检查 Redis 计数键是否未清理6. 扩展方向与个人体会6.1 把模板和配方做成多人协作的内容库目前最实用的扩展是预设若干“视频配方”复古胶片、3D 卡通、水墨风、定格动画。每个配方不是简单的几个标签而是一整套 prompt、负向提示词和参数模板。普通用户不需要理解配方内部结构只需要说“给我来一个水墨风的”系统就会从配方库里匹配。我把这些配方放在一个 JSON 文件里任何人都可以提 PR 扩展慢慢变成了一个小型协作库。这比让每个用户自己描述风格要高效得多。视频生成不像文字生成风格之间的边际差异很大而绝大多数用户并不能准确描述“赛博朋克”和“废土风”的区别。配方库的实质是把专业 prompt 工程师的经验沉淀下来用聊天里的自然语言作为入口这是很多纯 Web 工具做不到的。6.2 从单次生成走向多 AI 协作 Agent单个视频只能叫生成连续的视频故事才算内容。下一步我打算把 Bot 从“生成器”升级成“导演”收到一个故事主题后由编排层的大模型规划分镜每个分镜生成好几段视频再用 FFmpeg 拼接甚至接入 TTS 给它配旁白。这就引入了多个 AI 模型的协作一个做导演、一个做分镜、一个做文本转语音最后合成。这套东西听起来很“Agent”但本质上就是把每个模型封装成 Tool由一个编排器按剧本调用。我在实验里已经做到了一个很粗糙的版本用户说“这是我爷爷教我的菜拍个 15 秒食谱视频”bot 会先输出分镜列表然后逐段生成最后串起来。效果还不够稳定但在聊天框里看到它主动汇报“分镜 2/3 完成”的时候确实有眼前一亮的感觉。6.3 回头看的一些个人体会上线这个项目两个月我最深的感受是聊天交互会把用户预期拉得很高。用户不会管你有没有 GPU、API 配额够不够他们只想知道“为什么还没好”。所以我后来在排队状态里加了一个进度式文案每 10 秒更新一次比如“正在补帧…”“正在渲染光影…”其实后台不一定真的分步骤但用户等待时需要一个进度锚点。另一个体会是日志比功能更重要。所有任务的关键节点都打点包括耗时、失败原因、队列深度。没有这套日志出问题时连排查方向都没有。我甚至把关键指标接到了一个简单的 Grafana 看板上虽然有点过度搭建但看到队列积压曲线的那一刻你会觉得一切都值了。最后再说一点如果你也想做一个 Telegram AI 生成类 Bot不要一开始就堆算力。用小模型或者第三方 API 验证交互确认用户真的愿意在聊天框里输入描述再逐步加大投入。技术做得再快如果交互不成立投入的算力也只会让钱烧得更快。