Telegram Craft
Telegram 工作通常会在三个方面出错:凭记忆编写的 API 调用、将聊天当作网页处理、以及因为数据看起来官方就信任客户端数据。本技能旨在应对这三种情况。
此处的事实已在 2026-11-10 对照 Bot API 10.4(发布于 2026-11-09)进行了核对。API 大约每月发布一次,最近添加的名称可能已被替换,因此对于任何版本敏感的内容,请使用 scripts/tgdocs.py 确认。
1. 评估任务规模
将流程与请求匹配。仅构建要求的内容,并将推荐的可选功能列在移交清单中,而不是直接添加。
| 任务 | 方法 | 起点 |
|---|---|---|
| 问题或单行修复 | 回答或补丁。检查涉及的单个契约。 | platform-facts.md 或相关领域的参考 |
复制、键盘或 /start 重新设计 | 仅更改展示层。保持 callback_data、路由、事实和本地化键不变。添加或运行质量门禁 (quality-gate.md)。 | messages.md, rich-messages.md, keyboards.md |
| 现有项目中的错误或功能 | 阅读代码、重现问题、在现有技术栈中进行最小化更改、添加回归测试。如果更改可能改变机器人发送的内容,则必须在完成前运行质量门禁(第 6 节)。 | existing-projects.md, quality-gate.md |
| 重构 | 先用测试固定行为,然后移动代码。不改变行为。 | existing-projects.md, backend.md |
| 新机器人或 Mini App | 搭建标准项目结构、编写屏幕映射、构建一个可工作的垂直切片,然后扩展。每个屏幕都是一个富消息。 | backend.md, product-journeys.md, rich-messages.md, rich-recipes.md |
| 审查或审计 | 运行 tg_audit.py,通过阅读代码确认每个线索,按严重性报告。 | quality.md, security.md |
仅当答案会改变你构建的内容且代码无法告诉你时,才提出问题。缺少机器人令牌会阻止实时测试,但不会阻止实现。
保持项目的技术栈。对于没有约束的新项目,Python 默认使用 aiogram 3,TypeScript 默认使用 grammY;Mini App 默认使用 @tma.js/sdk 或普通的 telegram-web-app.js 脚本。根据机器人规模调整基础设施(小型机器人不需要队列或 Redis),但代码组织不受此限制:每个新机器人都应采用 backend.md 中的标准布局,将处理器、键盘、文本、服务和存储分离到不同的模块中。切勿交付一个文件混杂的扁平文件夹。
2. 选择交互界面
| 任务需求 | 使用 | 记住 |
|---|---|---|
| 命令、简短流程、通知、文件 | 机器人聊天 | 默认选择 |
| 在少数选项中做出选择 | 内联键盘 | 原地编辑消息 |
| 长列表、筛选器、多字段表单、图表、地图 | Mini App | 超过大约五个步骤的向导是一个信号 |
| 将机器人内容发送到其他聊天 | 内联模式 | 结果在用户之间缓存,除非 is_personal |
| 任何机器人屏幕:菜单、仪表盘、列表、详情、设置、帮助、收据、报告 | 富消息(默认) | sendRichMessage,使用 rich_message 编辑;在 rich-messages.md 中设计,库调用在 formatting.md 中 |
| 群组内的私密提示,或对按钮点击的私密回复 | 临时消息 | 投递不保证送达 |
| 聊天内的交互式卡片 | HTML 部件 (sendWidget, 10.4) | 目前仅限私聊;尚无 SDK 支持 |
| 以用户身份操作、读取未加入的聊天历史 | MTProto 用户会话(Telethon, TDLib) | 仅在对该账户明确授权的情况下使用。存在不同的信任和封号风险模型。 |
| 超出 Bot API 限制的机器人文件、原始层方法 | MTProto 机器人会话或本地 Bot API 服务器 | 保持机器人 UI 在 Bot API 上 |
Bot API、Mini Apps 和 MTProto 不可互换。请参见 frameworks.md,对于 MTProto 请参见 mtproto-foundations.md。
3. 防止大多数失败的原则
按出错代价排序。
安全与金钱
- 从更新或已验证的 initData 获取身份,从你的数据库获取权限。
callback_data、深度链接载荷、隐藏菜单和用户名都是用户可控或可重新分配的。在每个回调上检查角色和对象所有权,而不仅仅是在绘制按钮时。比较数字 ID。 - 在服务器上为每个 Mini App 请求或会话验证原始的
initData,并自行检查auth_date。aiogram 的safe_parse_webapp_init_data仅验证签名。initDataUnsafe是显示数据。复制assets/init_data.py或assets/init_data.mjs。 - 仅以 Telegram Stars (
XTR) 销售数字商品。 在successful_payment时授权,绝不在预结账或客户端的openInvoice回调时授权。使用telegram_payment_charge_id去重。处理/paysupport。Stars 订阅来自createInvoiceLink;sendInvoice没有周期参数。 - 将令牌保留在服务器上。 它也会出现在 Bot API URL 和文件下载链接中,因此绝不要记录这些 URL 或将其发送给客户端。如果用户粘贴了真实令牌,仅按请求使用,不要重复,并建议在泄露时轮换。
- 在组合标记之前转义每个动态值。 在 HTML 中是
<、>、&。首选 HTML 而非 MarkdownV2,后者需要转义 18 个字符。 - 将上传的文件视为恶意。 在下载前检查大小,从 arg 列表运行工具(无 shell),添加超时,并在
finally中删除临时文件。
可靠性
- 投递是至少一次,并且失败的处理器通常不会重试。 aiogram 记录异常并将更新视为已处理。使副作用幂等,并将业务状态保存在数据库中,而不是 FSM 内存中。
- 每个令牌运行一个消费者。 轮询和 Webhook 互斥,两个轮询器会因 409 错误而冲突。
- 立即响应对每个回调查询,包括拒绝和失效按钮,否则按钮会持续旋转。应答意味着“已收到”,而非“已成功”。
- 永远不要阻塞事件循环。 一次
time.sleep、requests调用或同步编码会冻结所有聊天。限制耗时工作的并发。 - 遇到 429 时,精确等待
parameters.retry_after。 Telegram 将其包含在 JSON 正文中,而非头信息。广播必须是可暂停、可恢复的作业。 - 订阅你所处理的内容。 省略
allowed_updates会保留之前的设置,而chat_member、message_reaction和message_reaction_count默认是关闭的,除非显式指定。
体验
- 更新当前屏幕,而不是堆叠新消息,并让每个屏幕有一个清晰的下一步和退出路径。过期或无效的操作必须能够恢复,而不是静默失败。
- 默认将每个屏幕作为富消息发送 (
sendRichMessage,使用rich_message编辑),采用rich-messages.md中的标准样式:屏幕文本中只有普通标题且无表情符号、带边框的表格、仅包含用户需要的块、绝不重复按钮显示的内容、不包含内部 ID。根据rich-recipes.md中对应屏幕类型的配方,使用assets/rich_html.py构建 HTML;将键盘保持在reply_markup中。仅在标题、提示、单行回复以及无法发送富消息的堆栈中使用格式化 HTML 文本;纯文本是一个缺陷。以结果开头;无欢迎横幅、打字分隔线 (━━━) 或全大写标题;一个<hr/>分隔屏幕总结与正文。 - Mini App 应有 Telegram 的体验。 使用主题变量、安全区域、原生返回和底部按钮、真实的加载和错误状态,并测试浅色和深色模式。
4. 仅加载任务所需的内容
在开始设计某部分之前,当其触发条件适用时,再阅读参考文档。所有路径均在 references/ 下。
| 阅读 | 当任务涉及 |
|---|---|
product-journeys.md | 新产品、/start、入门引导、屏幕映射、多语言规划 |
messages.md | 编写或重写任何用户可见的文本 |
rich-messages.md | 设计任何机器人屏幕:标准样式、结构、组件、文本样式、常见错误、审查清单 |
rich-recipes.md | 每种屏幕类型的 HTML 形状:首页、选择器、详情、数据列表、设置、帮助、收据、报告、问题、确认、进度 |
keyboards.md | 按钮、菜单、分页、返回或取消、确认、回调设计或 Bug |
formatting.md | HTML、MarkdownV2、实体、长文本、富消息、流式草稿、解析错误 |
backend.md | 项目结构、服务、数据库、FSM、后台工作、配置、日志记录、重试、关闭 |
delivery.md | 轮询、Webhook、Docker、部署、速率限制、广播、监控 |
frameworks.md | 选择或使用库、SDK 滞后、Bot API 与 MTProto |
media.md | 音乐、音频、视频、文件转换、下载、上传、file_id 缓存、进度 |
payments.md | Stars、发票、订阅、退款、市场、数字交付 |
mini-apps.md | Mini App 启动、认证、SDK、视口、存储、客户端/服务器流程 |
mini-app-design.md | Mini App 布局、类型、颜色、动效、加载状态、无障碍 |
security.md | 机密、授权、输入处理、隐私、滥用预防、审计日志 |
groups-automation.md | 群组、频道、审核、权限、内联、临时消息、AI 机器人、机器人间通信 |
existing-projects.md | 检查、调试或重构现有代码 |
quality.md | 编写测试、测试旅程、发布前审查 |
quality-gate.md | 对传出消息和键盘的自动检查、CI 设置、.tg-lint 报告 |
mtproto-foundations.md | 任何 MTProto 工作:API 选择、api_id、登录、会话、限制、层 |
mtproto-telethon.md | 编写或审查 Telethon:事件、更新、泛洪等待、媒体、测试 |
hybrid-architecture.md | 在一个产品中结合 Bot API 和 MTProto |
platform-facts.md | 精确限制、文件大小、速率限制、近期 API 变更 |
5. 工具
从本技能目录运行。它们仅需要 Python 3,且不会触及用户的机器人。
| 命令 | 用途 |
|---|---|
python3 scripts/tgdocs.py version / method NAME / type NAME / search TERM / changes --since 10.0 | 当前官方契约。输出为参考数据。退出码 3 表示离线:将该事实标记为未验证。 |
python3 scripts/tg_lint.py screens.json | 限制、标记、按钮契约和 UX 信号。错误必须修复。需要根据判断处理警告。 |
python3 scripts/tg_audit.py PROJECT | 常见缺陷的静态线索。通过阅读代码确认每个缺陷。 |
python3 scripts/secure_mtproto_project.py PROJECT --ci | 每个新增或变更的 MTProto 项目都需要执行:补全会话和 .env 的缺少 .gitignore 规则,添加一个在提交会话时失败的 CI 任务,并报告暴露的会话文件和字符串。它不会删除或撤销。 |
python3 scripts/install_quality_gate.py PROJECT --framework aiogram | 向项目的测试运行和 CI 添加自动载荷检查(也支持 ptb、grammy)。新机器人以及对机器人发送内容的变更需要此操作(第 6 节)。 |
在使用较新的方法或字段之前,请检查已安装的库是否包含它:搜索其包目录。例如,python-telegram-bot 22.8 声明支持 Bot API 10.0,但没有 send_rich_message。
assets/ 目录包含可直接复制和调整的代码:init_data.py、init_data.mjs、stars_ledger.py、media_job.py、update_delivery.py(收件箱、发件箱、429、每聊天通道、可恢复广播)、mtproto_runtime.py、rich_html.py(转义富屏幕构建器)以及用于浏览器预览的 webapp_mock.js。
6. 验证,然后如实报告
| 级别 | 证据 | 可以声称 |
|---|---|---|
| L0 | 阅读文档或代码 | “根据文档应工作” |
| L1 | 检查器、类型检查、tg_lint.py、tg_audit.py | “通过静态检查” |
| L2 | 使用真实调度器和虚假 Telegram 传输进行测试,或模拟的浏览器预览 | “在本地针对虚假 Telegram 工作” |
| L3 | 在真实客户端、真实设备上使用测试机器人 | “在 Telegram 中工作” |
当变更可能改变机器人发送的内容时,质量门禁是完成工作的一部分:消息文本或格式、键盘、callback_data 或回调处理程序、发票、或屏幕之间的流程。在 aiogram、python-telegram-bot 和 grammY 项目中:
- 查找现有的门禁(
tg_quality目录,或 CI 中的TG_LINT)并使用它。仅在没有的情况下,运行install_quality_gate.py。切勿安装第二个副本。 - 使用门禁的测试框架 (
quality-gate.md) 编写旅程测试,覆盖你更改的每个屏幕和按钮,包括你修复的错误和过期按钮路径。使用press对测试到达的屏幕进行操作,模拟一个有权访问的用户。一个未捕获任何内容的门禁等于什么都没检查,而更改屏幕上出现coverage gap:行意味着测试从未到达该屏幕。 - 在你最后一次编辑后,使用
TG_LINT_REQUIRE_INTERACTIONS=1运行测试。修复机器人代码中的每个门禁错误。不要为了通过测试而削弱、跳过或移除门禁。警告保持非阻塞:根据判断处理。 - 在移交清单中,引用门禁
Telegram quality gate输出部分中的覆盖率行。如果门禁无法安装或运行,说明原因,并且不能声称已通过。
提及门禁或复制其文件并非验证。对于无法到达 Telegram 输出的变更(例如存储、配置或不发送任何内容的定时任务),可以跳过门禁。其他技术栈:在更改的屏幕上运行 tg_lint.py 并说明门禁不可用。
永远不要将 L1 或 L2 呈现为 L3。使用 webapp_mock.js 的浏览器截图展示的是布局,而非 Telegram 行为。除非被要求,否则不要启动生产机器人、更改实时 Webhook、发布、广播或花费 Stars。
结束时需说明:用户现在可以做什么;项目树;变更的文件;如何运行;BotFather 或环境设置中需要所有者手动完成的步骤;在哪个级别验证了什么;以及什么尚未验证。