返回首页

将 Gemini API 集成到 Telegram bot:开发者指南

使用 aiogram 3.x 将 Google Gemini API 集成到异步 Telegram bot 的详细指南。架构分析、代码示例、绕过速率限制和实现函数调用。

如何在不出现 429 错误的情况下将 Gemini API 连接到 Telegram bot
Advertisement 728x90

使用 aiogram 3.x 将 Gemini API 异步集成到 Telegram 机器人:实用指南

当你的 Telegram 机器人突然因为 Gemini API 的 429 错误而停止响应时,这不仅仅是个 bug——这是技术债。本文将一步步拆解:如何正确地将 Gemini 集成到基于 aiogram 3.x 的异步机器人中,避免阻塞事件循环,绕过 RPM/TPM 限制,并实现函数调用而不牺牲性能。

架构:从简单处理器到生产级解决方案

通过 Gemini 的基本用户-机器人交互流程看起来很简单:请求 → 处理 → 响应。但现实场景需要额外的层。不正确包装就异步调用同步 API,会冻结 aiogram 事件循环,尤其在高负载下。因此关键组件是:

  • Asyncio Queue — 用于缓冲传入请求
  • Rate Limiter — 遵守 Gemini 限制(5–60 RPM)
  • Response Cache — 为重复请求节省令牌
  • Streaming Handler — 绕过 Telegram 超时(10 秒)

即使付费计划,Gemini API 也强制执行严格限制:最大响应延迟可达 15 秒,免费层仅限 5 请求/分钟。没有队列和缓存,你的用户体验将彻底崩坏。

Google AdInline article slot

客户端设置:在异步环境中使用同步 SDK

Google GenAI SDK 尽管社区满怀期望,仍是同步的。这意味着在 aiogram 处理器中直接调用 generate_content() 会阻塞整个事件循环。解决方案:用 asyncio.to_thread 包装调用,或使用 run_in_executor

import asyncio
from google import genai

class AsyncGeminiClient:
    def __init__(self, model: str = "gemini-3-flash-preview"):
        self.client = genai.Client()
        self.model = model
    
    async def generate(self, prompt: str) -> str:
        loop = asyncio.get_event_loop()
        response = await loop.run_in_executor(
            None,
            self._sync_generate,
            prompt
        )
        return response
    
    def _sync_generate(self, prompt: str) -> str:
        response = self.client.models.generate_content(
            model=self.model,
            contents=prompt
        )
        return response.text

这是一个最小化可工作的包装器。生产环境中,添加异常处理和执行指标。

与 aiogram 集成:从 /start 到流式响应

基本处理器需要做的不仅仅是接受消息:还要管理状态显示“typing”、拆分长响应,并缓存结果。Telegram 消息长度上限为 4096 字符——忽略这一点会导致截断。

Google AdInline article slot
@router.message()
async def handle_message(message: types.Message):
    await message.bot.send_chat_action(chat_id=message.chat.id, action="typing")
    
    try:
        response = await gemini.generate(message.text)
        if len(response) > 4000:
            for i in range(0, len(response), 4000):
                await message.answer(response[i:i+4000])
        else:
            await message.answer(response)
    except Exception as e:
        logging.error(f"Gemini error: {e}")
        await message.answer("Chto-then poshlo not so. Poprobuyte pozzhe.")

对于长时间运行的请求,使用流式处理——随着文本生成更新单条消息。这能规避超时并提升用户体验。

函数调用:Gemini 变身智能代理

函数调用让模型基于请求上下文调用外部 API。例如,用户说“明天上午 3 点预约会议”,Gemini 可以解析参数并调用你的 schedule_meeting 函数。

关键步骤:

Google AdInline article slot
  • 用 JSON Schema 格式描述函数——让模型理解其签名。
  • GenerateContentConfig 中作为 tools 传递描述。
  • 在响应中处理 function_call 并执行实际调用。
  • 将结果反馈回对话作为对话的一部分。

示例函数声明:

schedule_meeting_function = {
    "name": "schedule_meeting",
    "description": "Withzdayot meetingsu with ukazannymi uchastnikami",
    "parameters": {
        "type": "object",
        "properties": {
            "attendees": {"type": "array", "items": {"type": "string"}},
            "date": {"type": "string"},
            "time": {"type": "string"},
            "topic": {"type": "string"}
        },
        "required": ["attendees", "date", "time", "topic"]
    }
}

这将静态机器人转变为能与外部系统交互的动态助手。

缓存和限流:防止破产和封禁

Gemini 按令牌计费。没有缓存,你会为每个重复问题付费。用提示的 MD5 哈希加 TTL 的简单内存缓存就能解决:

class SimpleCache:
    def __init__(self, ttl_seconds: int = 3600):
        self._cache = {}
        self._ttl = ttl_seconds
    
    def get(self, key: str) -> Optional[str]:
        # check TTL and vozvrat values
    
    def set(self, key: str, value: str):
        self._cache[key] = (value, datetime.now())
    
    @staticmethod
    def hash_prompt(prompt: str) -> str:
        return hashlib.md5(prompt.lower().strip().encode()).hexdigest()

即使付费层,限流也必不可少。以异步上下文管理器或中间件实现:

class AsyncRateLimiter:
    def __init__(self, max_requests: int, time_window: int = 60):
        self.max_requests = max_requests
        self.time_window = time_window
        self.requests = []
        self._lock = asyncio.Lock()
    
    async def acquire(self):
        async with self._lock:
            now = time.time()
            self.requests = [t for t in self.requests if now - t < self.time_window]
            if len(self.requests) >= self.max_requests:
                sleep_time = self.time_window - (now - self.requests[0])
                await asyncio.sleep(sleep_time + 0.1)
                return await self.acquire()
            self.requests.append(now)

常见错误及规避方法

每个人都会踩的三大经典坑:

  • 错误 429 (RESOURCE_EXHAUSTED) — 因超过 RPM、TPM 或 RPD 触发。解决:本地限流器 + 指数退避。
  • Telegram 超时 — 服务器等待响应 10 秒。如果 Gemini 慢,用流式或发送中间消息。
  • 过时模型 — Google 定期停用旧版本。2026 年 3 月,Pro 模型转为仅订阅。部署前始终验证模型可用性。

关键要点:

  • 同步 Gemini SDK 需要 run_in_executor 包装——否则会阻塞事件循环。
  • 在机器人端实现限流,不要依赖 API。
  • 流式是绕过 Telegram 10 秒超时的唯一方法,用于长响应。
  • 缓存能省钱并降低重复请求延迟。
  • 函数调用让你的机器人从文本生成器进化为完整代理。

采用这些实践能减少生产事故,并随着负载增长保持稳定。在架构上别偷懒——在令牌上省钱吧。

— Editorial Team

Advertisement 728x90

继续阅读