Construire un bot météo Telegram
Construisez un bot Telegram qui répond aux questions météo en français, conserve la conversation
en cours et la réinitialise lorsque l'utilisateur envoie /new. Vous testez l'agent et le bot en
local, puis déployez l'agent sur Mistral sans modifier le code du bot.
Présentation de : sessions et tours (clés d'idempotence, message envoyé pendant un tour en cours), outils, mise à disposition et déploiement d'un agent.
Exécutez (après la configuration ci-dessous), depuis le dossier de l'exemple :
uv run --frozen --env-file .env python bot.py
Fonctionnement
Telegram envoie chaque message texte à bot.py. Le bot ouvre une session pour la conversation,
transmet le message et renvoie la réponse de l'agent à Telegram. La session conserve la
conversation jusqu'à ce que l'utilisateur envoie /new ou que la session se termine : le message suivant ouvre alors
une nouvelle session.
Le bot envoie chaque message avec son identifiant de message Telegram comme clé d'idempotence. Ainsi, un même message reçu deux fois ne lance qu'un seul tour. Il ignore les messages modifiés, qui conservent leur identifiant.
Telegram chat → bot.py → session → weather agent → get_weather()L'outil get_weather() récupère la météo actuelle auprès de Open-Meteo, un service
gratuit qui ne nécessite aucune clé API : il trouve la ville, puis récupère l'état du ciel, la température et le vent.
Pendant le développement local, agents serve exécute l'agent sur votre ordinateur. Après le
déploiement, c'est Mistral qui exécute l'agent. Le code du bot ne change pas : vous ne mettez à jour
que le nom de l'agent dans .env.
Le code du bot Telegram
L'exemple comprend deux projets : l'agent dans agent/ et le bot Telegram à la racine.
| Fichier | Contenu |
|---|---|
agent/main.py | Tout l'agent : un @agents.tool typé et l'objet agent que la CLI charge |
agent/run_agent.py | Une exécution unique in-process qui importe ce même objet agent |
agent_client.py | Ouverture et fermeture d'une session, envoi d'un message et lecture de la réponse |
bot.py | Gestionnaires Telegram : un identifiant de session par conversation, conservé après les redémarrages, réinitialisation avec /new, vérification de l'utilisateur autorisé |
agent/Dockerfile | L'image que construit un déploiement géré |
Le fichier README.md de l'exemple contient la procédure complète de configuration et le script de conversation.
L'agent se compose d'un outil et d'un Agent. L'outil nécessite httpx, déclaré dans agent/pyproject.toml :
import httpx
from mistralai import agents
def sky(code: int) -> str:
"""Open-Meteo's weather code (WMO) in words."""
if code <= 3:
return ["clear sky", "mainly clear", "partly cloudy", "overcast"][code]
for below, words in [(50, "fog"), (60, "drizzle"), (70, "rain"), (80, "snow"), (95, "rain showers")]:
if code < below:
return words
return "thunderstorm"
@agents.tool
async def get_weather(city: str) -> dict[str, str | float]:
"""Return the current weather in a city: the sky, the temperature and the wind."""
async with httpx.AsyncClient(timeout=10) as http: # Open-Meteo is free and needs no key
found = await http.get("https://geocoding-api.open-meteo.com/v1/search", params={"name": city, "count": 1})
if not (places := found.json().get("results")):
raise agents.ToolError(f"No city named {city}.")
place = places[0]
forecast = await http.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": place["latitude"],
"longitude": place["longitude"],
"current": "weather_code,temperature_2m,wind_speed_10m",
},
)
now = forecast.json()["current"]
return {
"city": f"{place['name']}, {place.get('country', '')}",
"sky": sky(now["weather_code"]),
"temperature_celsius": now["temperature_2m"],
"wind_km_per_hour": now["wind_speed_10m"],
}
# Replace `alice` with a unique lowercase identifier, such as your GitHub handle,
# so the served and deployed names cannot collide with anyone else's.
agent = agents.Agent(
model="mistral-large-4",
name="french-weather-agent-alice-local",
instructions=(
"Always answer in French. "
"When the user asks about weather in a city, call get_weather first. "
"Keep the answer concise."
),
tools=[get_weather],
)Le bot ne stocke qu'un identifiant de session par conversation. ask envoie chaque message Telegram avec son identifiant de message comme
clé d'idempotence. Lorsqu'un message arrive pendant un tour en cours, send_message réoriente ce tour
(turn.started vaut False), dont la réponse traite alors les deux messages :
import contextlib
from mistralai import agents
def connect(agent_name: str) -> agents.Agent:
return agents.Agent.load_from(agent_name=agent_name)
async def start_conversation(agent: agents.Agent) -> str:
"""Start a session and return its id, the only thing the bot stores."""
session = await agent.start_session()
return session.id
async def end_conversation(agent: agents.Agent, session_id: str) -> None:
# A session that already ended is left as it is; one its host no longer has needs nothing.
with contextlib.suppress(agents.SessionNotFoundError):
await agent.session(session_id).cancel()
async def ask(agent: agents.Agent, session_id: str, text: str, message_id: int) -> str | None:
"""Send one Telegram message to the conversation and return the agent's reply.
Returns None when the message steered a turn that was already running: that turn's reply
answers it.
"""
session = agent.session(session_id)
# The same Telegram message, delivered again after a restart, is sent once.
turn = await session.send_message(text, idempotency_key=f"telegram:{message_id}")
if not turn.started:
return None
match await turn.result():
case agents.Completed(text=reply) if reply:
return reply
case state:
raise RuntimeError(f"The turn did not complete with a reply: {state!r}")Prérequis
Vous avez besoin de :
- Python 3.12 et
uv. - Une clé API Mistral dont l'utilisateur possède un rôle dans l'espace de travail donnant accès à Workflows, comme Développeur : voir
Déployer.
agents serveetagents deploynécessitent tous deux cette clé. - Un compte Telegram.
- Pour déployer l'agent : un dépôt GitHub auquel vous donnez accès via le connecteur GitHub dans Mistral Studio. Vous pouvez effectuer les étapes locales sans ce dépôt.
1. Tester l'agent
Depuis le projet agent/, copiez .env.example dans .env et définissez-y MISTRAL_API_KEY. Puis
installez les dépendances et examinez ce que la CLI détecte :
cd agent
cp .env.example .env
uv sync
uv run --frozen --env-file .env agents infoagents info liste l'agent et son outil get_weather. Exécutez-le ensuite une fois depuis Python
avant d'ajouter Telegram :
uv run --frozen --env-file .env python run_agent.pyrun_agent.py importe depuis main.py le même objet agent que celui chargé par la CLI. Le script
et l'agent accessible via une API ne peuvent donc pas diverger. Il affiche une réponse courte en French avec la météo de Paris à cet
instant :
Voici la météo actuelle à **Paris** :
- ☁️ **Ciel** : couvert
- 🌡️ **Température** : 7,6 °C
- 💨 **Vent** : 7,6 km/h2. Servir l'agent
bot.py s'exécute séparément de l'agent et ne peut donc pas utiliser l'objet Agent in-process de l'étape
- Démarrez l'agent avec
agents servepour que le bot puisse ouvrir des sessions auprès de celui-ci :
uv run --frozen --env-file .env agents serveLa commande enregistre l'agent auprès de Mistral Workflows, l'exécute sur votre ordinateur et affiche des liens pour discuter avec lui ou inspecter ses exécutions. Laissez la commande active pendant que vous testez le bot Telegram.
Mistral identifie les agents servis et déployés par leur nom. L'exemple utilise alice comme placeholder :
remplacez-le par un identifiant unique en minuscules, comme votre identifiant GitHub, partout où il apparaît.
3. Exécuter le bot
Créez un bot avec le compte vérifié @BotFather de Telegram (/newbot, choisissez un nom et un nom d'utilisateur se
terminant par bot, copiez le token). Gardez le token secret : toute personne qui le possède peut contrôler votre bot.
De retour dans le répertoire telegram_weather_bot/, copiez .env.example dans .env et renseignez le
token du bot, votre clé API Mistral et le nom de l'agent. TELEGRAM_ALLOWED_USER_ID reste à 0 jusqu'à la
première exécution — la commande /id du bot vous indique votre identifiant utilisateur Telegram, et cette vérification empêche les autres
utilisateurs de communiquer avec votre agent.
uv sync
uv run --frozen --env-file .env python bot.pyDans votre conversation directe avec le bot, envoyez /id, reportez le numéro dans TELEGRAM_ALLOWED_USER_ID,
redémarrez le bot, puis :
/start
Quel temps fait-il à Paris ?
Souviens-toi que ma ville préférée est Lyon.
Quelle est ma ville préférée ?
/new
Quelle est ma ville préférée ?La réponse météo devrait être en français. L'agent devrait se souvenir de Lyon au sein de cette session.
Après /new, il ne devrait plus savoir quelle ville vous avez choisie.
4. Déployer l'agent sur Mistral
Le bot nécessite que agents serve s'exécute sur votre ordinateur. Un déploiement géré construit
l'agent à partir de Git — poussez agent/ vers un dépôt accessible au connecteur GitHub (ne faites jamais de commit de
.env), puis déployez sans le suffixe -local :
cd agent
uv run --frozen --env-file .env \
agents deploy . --name french-weather-agent-aliceL'agent servi en local et le déploiement géré partagent un espace de travail Mistral, où les noms
sont uniques. Utiliser french-weather-agent-alice-local en local et french-weather-agent-alice pour
le déploiement évite que les deux enregistrements entrent en collision.
Arrêtez agents serve, remplacez AGENT_NAME dans le .env du bot par le nom déployé, puis
redémarrez bot.py. Si le bot répond toujours, il utilise l'agent hébergé par Mistral. Seul l'agent
est déployé ; bot.py continue de s'exécuter sur votre ordinateur.
Pour mettre à jour le déploiement, poussez la modification et déployez à nouveau avec le même nom — réutiliser un nom met à jour le déploiement correspondant, un nom différent crée un déploiement séparé.
Inspecter les sessions dans Mistral Studio
Les sessions gérées par les agents démarrés avec agents serve ou agents deploy apparaissent dans
Sessions d'agent dans Mistral Studio. Ouvrez
une session pour examiner ses messages, ses appels d'outils et son statut.
Dépannage
agents serve ne peut pas enregistrer l'agentagents serve ne peut pas enregistrer l'agent
Vérifiez que MISTRAL_API_KEY est valide et que son utilisateur possède un rôle dans l'espace de travail donnant accès à Workflows
(voir Déployer pour les rôles). Une clé qui permet d'appeler un modèle peut ne pas avoir l'autorisation
d'enregistrer l'agent.
uv run --frozen ne trouve pas uv.lockuv run --frozen ne trouve pas uv.lock
Exécutez uv sync une fois dans ce projet, puis réessayez la commande.
Le bot Telegram ne répond pas
Laissez bot.py en cours d'exécution. Pendant les tests en local, laissez également agents serve actif. Envoyez des messages dans une
conversation directe, vérifiez que TELEGRAM_ALLOWED_USER_ID correspond à /id et contrôlez AGENT_NAME.
Redémarrez le bot après avoir modifié .env, puis examinez son terminal pour identifier l'erreur signalée.
Telegram signale un conflit de polling
Un seul processus bot.py peut effectuer le polling avec un token de bot. Arrêtez l'autre processus et redémarrez celui-ci.
Le déploiement géré ne peut pas lire le code source
Vérifiez que le commit a été poussé vers le dépôt auquel vous avez donné accès au connecteur GitHub et que le connecteur est activé dans Mistral Studio.
Ressources et prochaines étapes
- Sessions explique les sessions que
bot.pyconserve pour chaque conversation et leur historique de conversation. - Outils montre comment ajouter un second outil à côté de
get_weather. - Modes d'exécution compare l'exécution de l'agent dans votre processus avec son déploiement via Studio (déploiements Auto-hébergés ou gérés par Mistral) et décrit ce que la CLI charge depuis un projet.