Cursus
La plupart des démos d’IA ressemblent encore à des chatbots : vous posez une question, le modèle répond, et l’échange s’arrête là. Or, la vraie productivité ne tient pas en une seule étape. Un assistant utile doit savoir découper une demande floue, réunir du contexte, comparer des options, produire un livrable exploitable, puis vérifier son propre travail avant de le remettre.
Qwen 3.7 Max est un modèle « agentic » conçu par l’équipe Qwen pour les charges centrées agent, incluant le code, les tâches bureautiques et les exécutions de longue haleine. C’est un modèle pensé d’abord pour l’agent : non pas simplement pour bien répondre à une invite, mais pour rester cohérent tout au long d’un flux impliquant planification, utilisation d’outils, rédaction et auto-correction.
Dans ce tutoriel, nous allons créer un agent de productivité compact avec Qwen 3.7 Max et Streamlit. L’application prend une demande métier floue, comme préparer une analyse concurrentielle des bases de données vectorielles, et la transforme en un fichier competitive_analysis.md abouti.
À la fin de ce tutoriel, vous saurez :
-
Construire un workflow d’agent en cinq tours figés
-
Utiliser
enable_thinking=Trueetpreserve_thinking=True -
Ajouter une recherche parallèle légère
-
Rédiger et corriger un livrable en Markdown
-
Créer une interface Streamlit simple autour du workflow
Le code complet est disponible dans le dépôt GitHub.
Le projet est volontairement compact, avec la logique principale répartie entre agent.py pour l’app Streamlit et thinking_agent.py pour le workflow backend.
Si vous débutez avec les agents IA, nous vous recommandons notre parcours de compétences AI Agent Fundamentals.
Qu’est-ce que Qwen 3.7 Max ?
Qwen 3.7 Max est le nouveau modèle phare d’Alibaba, publié le 20 mai 2026. Il est conçu pour des workflows « agentic ». Autrement dit, plutôt que d’être optimisé pour un échange unique, il l’est pour des tâches nécessitant planification, usage d’outils, code, automatisation bureautique, raisonnement sur long contexte et exécution multi-étapes.
L’équipe Qwen le présente comme un modèle pour « l’ère des agents », efficace pour les agents de codage, assistants de productivité, workflows basés sur MCP, et tâches autonomes de longue durée.
L’intérêt majeur ne tient pas seulement à ses scores bruts, mais à sa capacité à rester cohérent sur une tâche en plusieurs tours, où chaque tour a un objectif distinct, notamment :
- planification
- synthèse d’éléments probants
- rédaction longue
- auto-critique
- révision
Sur X, des utilisateurs ont constaté que le modèle est au niveau d’Opus 4.7 et GPT 5.5 pour des tâches de codage de longue haleine.

Forces de Qwen 3.7 Max et performances aux benchmarks
Qwen 3.7 Max obtient de très bons résultats sur les benchmarks d’agents et de raisonnement. En évaluation d’agents de codage, il atteint
- 69,7 sur Terminal-Bench 2.0-Terminus
- 60,6 sur SWE-bench Pro
- 78,3 sur SWE-bench Multilingual
- 47,2 sur NL2Repo
- 53,5 sur SciCode
Sur les benchmarks d’agent général, il atteint
- 60,8 sur MCP-Mark
- 76,4 sur MCP-Atlas
- 67,2 sur CoWorkBench
- 87,0 sur SpreadSheetBench-v1

Source : blog des développeurs Qwen
Pour situer ces résultats : ils dépassent tous ceux de DeepSeek V4 Pro ; pour la plupart légèrement, mais en codage longue portée, l’écart est notable (47,2 contre 35,5 sur NL2Repo).
Ce qui nous amène à un exemple marquant de la sortie : l’optimisation de kernel sur longue durée par Qwen 3.7 Max. Le modèle aurait tourné environ 35 heures, effectué 1 158 appels d’outils, mené 432 évaluations de kernels et produit une accélération géométrique moyenne de 10,0× par rapport à une implémentation de référence Triton.
C’est important car cela évalue le modèle sur une amélioration itérative par outils, et non sur des questions statiques de benchmark.
En bref, Qwen 3.7 Max convient parfaitement à cette démo car il est conçu pour des workflows où le modèle doit raisonner, utiliser des outils, préserver le contexte et améliorer un livrable sur plusieurs tours.
Créer un agent de productivité qui préserve sa réflexion avec Qwen 3.7 Max
Dans ce projet, nous allons illustrer trois idées pratiques :
- Une demande floue peut être convertie en workflow structuré multi-étapes.
- Les sorties d’outils peuvent être réinjectées dans le raisonnement au lieu d’être déversées dans une seule invite interminable.
- Un modèle peut relire et améliorer sa propre sortie via le chain-of-thought prompting avant de remettre le livrable final.
Aperçu du projet
Nous allons construire une application simple avec une zone de saisie et un bouton. L’utilisateur saisit une demande floue comme :
I need to prepare a competitive analysis of the top 3 vector databases
for a team presentation next week. I have no idea where to start.

Ensuite, l’agent exécute un workflow fixe en cinq tours :
User prompt
Turn 1: Plan the work
Parallel research for Pinecone, Weaviate, and Qdrant
Turn 2: Summarize research
Turn 3: Build comparison matrix
Turn 4: Write competitive_analysis.md
Turn 5: Self-review and patch the markdown file
Streamlit file preview
L’interface affiche chaque étape sous forme de carte de progression. À mesure que le workflow avance, les cartes passent de « en attente » à « terminé ». À la fin, l’utilisateur peut consulter chaque étape : planification, recherche, synthèse, brouillon, auto-relecture et aperçu du fichier final.
Le workflow de l’agent est ainsi rendu visible, plutôt que caché derrière une seule réponse de chat.
Le dépôt est volontairement réduit. Les éléments principaux sont :
-
thinking_agent.py: contient la logique backend de l’agent : appels au modèle, prompts, préservation de la réflexion, recherche, relances, écriture de fichier et auto-relecture. -
agent.py: contient l’interface Streamlit : mise en page, zone de prompt, barre de progression, cartes d’étapes, sélecteur de résultats, aperçu Markdown et bouton de téléchargement. -
requirements.txt: dépendances d’exécution requises pour la démo
Le backend s’articule autour d’une classe ThinkingAgent qui exécute une séquence fixe en cinq tours et renvoie des enregistrements structurés. L’UI n’a pas besoin de savoir comment fonctionnent les appels modèle, les relances ou la recherche en éventail. Elle n’a qu’à afficher chaque tour à son arrivée.
Le code complet de ce tutoriel est disponible sur GitHub.
Remarque : j’ai utilisé OpenRouter pour accéder à Qwen 3.7 Max, mais vous pouvez également utiliser le modèle via la plateforme API Qwen officielle.
Étape 1 : préparation de l’environnement
Avant de créer l’agent de productivité Qwen 3.7 Max, nous devons configurer un mini-environnement Python avec Streamlit, le client compatible OpenAI et httpx pour une recherche web légère.
Dans ce tutoriel, nous utiliserons OpenRouter comme passerelle de modèle, mais le backend est écrit selon le format d’API compatible OpenAI. Vous pourrez donc adapter la même structure à Alibaba Cloud Model Studio ou tout autre fournisseur compatible.
Dans cette étape, nous allons :
-
Créer un environnement virtuel
-
Installer les dépendances requises
-
Définir la variable
OPENROUTER_API_KEYouQWEN_API_KEY -
Vérifier que l’app se lance avec Streamlit
Créez et activez un environnement virtuel :
python3 -m venv .venv
source .venv/bin/activate
Installez les dépendances du projet :
pip install -r requirements.txt
Le fichier requirements.txt est volontairement minimal :
httpx>=0.23.0
openai>=1.30.0
streamlit>=1.45.0
Nous utilisons streamlit pour l’interface web interactive, openai pour appeler Qwen 3.7 Max via une API compatible OpenAI, et httpx pour récupérer des résultats de recherche légers et récents à l’étape de recherche.
Étape 2 : configurer le client Qwen 3.7 Max
Le backend utilise le SDK Python OpenAI car OpenRouter expose un endpoint compatible OpenAI. Le fichier thinking_agent.py définit quelques valeurs par défaut :
from openai import OpenAI
DEFAULT_MODEL = "qwen/qwen3.7-max"
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1"
DEFAULT_REFERER = "https://qwen.ai"
DEFAULT_TITLE = "Qwen3.7-Max Productivity Agent"
Puis nous créons un client :
def build_client(
api_key: str | None = None,
base_url: str | None = None,
referer: str = DEFAULT_REFERER,
title: str = DEFAULT_TITLE,
) -> OpenAI:
return OpenAI(
base_url=base_url or DEFAULT_BASE_URL,
api_key=api_key,
default_headers={
"HTTP-Referer": referer,
"X-Title": title,
},
)
La fonction build_client() centralise toute la configuration spécifique au fournisseur. Le reste de l’app n’a pas besoin de savoir si la requête passe par OpenRouter, Alibaba Cloud Model Studio, ou un autre endpoint compatible.
Une fois le client configuré, le backend peut appeler Qwen 3.7 Max via le format standard des chat completions.
Nous allons maintenant créer le workflow cœur de ThinkingAgent.
Étape 3 : workflow d’agent en cinq tours
Une fois le client modèle configuré, nous pouvons définir le workflow backend. Plutôt que de demander à Qwen 3.7 Max de générer un rapport complet en une seule fois, nous découpons la tâche en cinq étapes contrôlées.
-
Planification : transforme l’invite floue en plan d’action structuré.
-
Recherche : collecte et résume des preuves à partir d’extraits externes.
-
Synthèse : construit une matrice de comparaison à partir de la recherche.
-
Brouillon : rédige le premier rapport
competitive_analysis.md. -
Auto-relecture : relit et corrige le rapport avant de fournir le fichier final.
class ThinkingAgent:
def run(
self,
goal: str,
preserve_thinking: bool = True,
data_mode: str = "live",
on_turn: Callable[[TurnRecord], None] | None = None,
) -> ThinkingRunResult:
history = [{"role": "system", "content": SYSTEM_PROMPT}]
turns = []
backend = self._build_search_backend(data_mode)
turn1 = self._run_turn(
history=history,
turn_index=1,
phase="planning",
user_prompt=_planning_prompt(goal),
preserve_thinking=preserve_thinking,
)
search_results = self._run_research(backend)
turn2 = self._run_turn(
history=history,
turn_index=2,
phase="research",
user_prompt=_research_prompt(goal, search_results),
preserve_thinking=preserve_thinking,
)
turn3 = self._run_turn(
history=history,
turn_index=3,
phase="synthesis",
user_prompt=_synthesis_prompt(),
preserve_thinking=preserve_thinking,
)
turn4 = self._run_turn(
history=history,
turn_index=4,
phase="draft",
user_prompt=_draft_prompt(goal),
preserve_thinking=preserve_thinking,
)
turn5 = self._run_turn(
history=history,
turn_index=5,
phase="self_review",
user_prompt=_self_review_prompt(draft_markdown),
preserve_thinking=preserve_thinking,
)
La méthode run() est la boucle d’orchestration principale. Elle démarre avec un prompt système, crée un historique de conversation, construit un backend de recherche puis exécute les cinq tours, l’un après l’autre.
Chaque appel à _run_turn() correspond à une phase précise. Cela facilite le débogage : chaque appel a une responsabilité claire. La planification… planifie. La recherche interprète des extraits externes. La synthèse construit la structure. Le brouillon rédige. L’auto-relecture améliore la sortie.
La recherche est placée entre le tour 1 et le tour 2, car le modèle doit d’abord comprendre la tâche avant d’intégrer l’information externe au workflow.
À l’étape suivante, nous allons ajouter la logique Qwen de préservation de la réflexion, qui aide le modèle à maintenir la continuité d’un tour à l’autre.
Étape 4 : préserver la réflexion entre les tours
Nous utilisons Qwen 3.7 Max ici pour sa prise en charge des workflows qui préservent la réflexion. L’agent ne traite pas chaque appel modèle comme une invite isolée : il peut conserver le raisonnement des tours précédents et le transmettre aux tours suivants.
Dans cette étape, nous allons :
- Activer le mode « thinking » du modèle.
- Préserver le raisonnement entre les tours.
- Réinjecter les sorties de l’assistant dans l’historique partagé.
response = self.client.chat.completions.create(
model=self.config.model,
messages=request_messages,
extra_body={
"enable_thinking": True,
"preserve_thinking": preserve_thinking,
},
)
Le drapeau enable_thinking=True permet à Qwen 3.7 Max de produire du contenu de raisonnement pendant la réponse. Le drapeau preserve_thinking contrôle s’il faut conserver ce raisonnement pour les tours ultérieurs.
Après la réponse du modèle, le backend extrait à la fois la réponse visible et le contenu de raisonnement :
message = response.choices[0].message
assistant_content = _normalize_text(getattr(message, "content", ""))
reasoning_content = _extract_reasoning_content(message)
The visible answer is what the app can show to the user. The reasoning content is used internally to help the next turn stay aligned with the earlier plan.
Then the backend appends the assistant message back into the conversation history:
```python
assistant_message = {
"role": "assistant",
"content": assistant_content,
}
if preserve_thinking and reasoning_content:
assistant_message["reasoning_content"] = reasoning_content
history.append(assistant_message)
Si la phase de planification décide que le rapport final doit comparer les bases vectorielles selon le modèle de déploiement, la scalabilité, l’expérience développeur, la recherche hybride et la capacité « enterprise », les tours suivants pourront continuer d’utiliser ces critères. Sans cela, chaque tour peut dériver : la synthèse pourrait choisir d’autres critères que la planification, ou l’auto-relecture évaluer le rapport selon un objectif différent.
Passons maintenant à la couche de recherche, qui fournit à l’agent un contexte externe avant la rédaction.
Étape 5 : ajouter une recherche parallèle avec repli
Avant de rédiger une analyse concurrentielle, le modèle a besoin de contexte externe. Dans cette démo, nous limitons volontairement le périmètre à trois bases de données vectorielles : Pinecone, Weaviate et Qdrant.
Dans cette étape, nous allons :
- Définir les bases cibles.
- Lancer les recherches en parallèle.
- Basculer sur des données de test déterministes si la recherche live échoue.
DATABASES = ("Pinecone", "Weaviate", "Qdrant")
La liste cible est volontairement fixe. La démo reste ainsi stable et plus simple à expliquer. Vous pourrez ensuite étendre le projet pour que le modèle choisisse dynamiquement les cibles de comparaison.
Le backend lance ensuite les recherches en parallèle :
from concurrent.futures import ThreadPoolExecutor, as_completed
with ThreadPoolExecutor(max_workers=3) as executor:
future_map = {
executor.submit(backend.search, database, query): database
for database, query in queries.items()
}
for future in as_completed(future_map):
database = future_map[future]
results[database] = future.result()
Le ThreadPoolExecutor lance une recherche par base. C’est plus rapide que séquentiel, car les recherches sur Pinecone, Weaviate et Qdrant s’exécutent en parallèle.
try:
results[database] = future.result()
except Exception as exc:
fallback = FixtureSearchBackend().search(database, queries[database])
fallback.warning = (
f"Live search failed for {database} ({exc}). "
"Fallback demo research was used."
)
results[database] = fallback
Si la recherche live aboutit, l’agent utilise des extraits frais. En cas d’échec, l’application termine quand même le workflow en s’appuyant sur des extraits déterministes intégrés. Le principe clé est la dégradation maîtrisée : l’agent ne doit pas échouer parce qu’une dépendance externe tombe.
À l’étape suivante, nous transmettrons ces résultats à Qwen 3.7 Max pour générer une matrice de comparaison.
Étape 6 : générer la synthèse et la matrice de comparaison
Une fois les extraits de recherche réunis, place à la synthèse. Cette étape convertit des informations éparses en une comparaison structurée, base du rapport final.
Dans cette étape, nous allons :
- Renvoyer le contexte de recherche à Qwen 3.7 Max.
- Demander au modèle de créer une comparaison structurée.
- Afficher ensuite cette sortie dans l’interface Streamlit.
turn3 = self._run_turn(
history=history,
turn_index=3,
phase="synthesis",
user_prompt=_synthesis_prompt(),
preserve_thinking=preserve_thinking,
)
À ce stade, l’historique contient déjà la demande initiale, la planification, les résumés de recherche et, éventuellement, la réflexion préservée des tours précédents.
Le prompt de synthèse n’a donc pas besoin de tout réexpliquer. Il se concentre sur un objectif : convertir la recherche en une matrice d’aide à la décision.
Une bonne synthèse doit comparer les options selon des dimensions telles que :
- modèle de déploiement
- scalabilité
- expérience développeur
- prise en charge de la recherche hybride
- préparation « enterprise »
- cas d’usage idéal
Nous utiliserons ensuite cette structure pour rédiger le premier rapport Markdown.
Étape 7 : rédiger le rapport Markdown
Après la planification, la recherche et la synthèse, l’agent dispose d’assez de contexte pour rédiger un premier livrable complet. Dans cette démo, il s’agit d’un fichier Markdown nommé competitive_analysis.md.
Dans cette étape, nous allons :
- Demander à Qwen 3.7 Max d’écrire le premier brouillon.
- Retirer les balises de code Markdown inutiles.
- Enregistrer le brouillon sur disque.
- Enregistrer l’écriture de fichier comme un événement d’outil.
turn4 = self._run_turn(
history=history,
turn_index=4,
phase="draft",
user_prompt=_draft_prompt(goal),
preserve_thinking=preserve_thinking,
)
Le tour « brouillon » exploite tout le contexte accumulé : objectif initial, plan, recherche et matrice de synthèse.
La réponse du modèle est ensuite nettoyée et écrite sur disque :
draft_markdown = _strip_markdown_fences(turn4.assistant_content)
report_path = run_output_dir / "competitive_analysis.md"
report_path.write_text(draft_markdown)
Le helper _strip_markdown_fences() est utile car les modèles encapsulent souvent le Markdown entre des triples backticks : tolérable dans un chat, moins dans un fichier .md.
Le backend journalise aussi l’écriture :
turn4.tool_events.append(
ToolEvent(
name="write_file",
status="completed",
input_payload={"path": str(report_path)},
output_payload={
"description": "Initial draft written to disk.",
},
)
)
Cet événement permet à l’UI d’indiquer qu’un vrai fichier a été créé, pas seulement une réponse texte. À ce stade, l’app dispose déjà d’un rapport exploitable. Nous ajoutons toutefois un dernier tour pour améliorer la qualité avant l’aperçu final.
À l’étape suivante, nous demanderons à Qwen 3.7 Max de relire et corriger son propre brouillon.
Étape 8 : auto-relecture et correctif du rapport
Le dernier tour est une auto-relecture. Plutôt que de livrer immédiatement le premier jet, l’agent relit le rapport, le confronte à l’objectif initial et produit une version améliorée.
Dans cette étape, nous allons :
- Renvoyer le Markdown du brouillon au modèle.
- Identifier les faiblesses.
- Générer une version révisée.
- Écraser le rapport avec la version finale améliorée.
turn5 = self._run_turn(
history=history,
turn_index=5,
phase="self_review",
user_prompt=_self_review_prompt(draft_markdown),
preserve_thinking=preserve_thinking,
)
Le prompt d’auto-relecture vérifie des points pratiques : clarté de la recommandation, cohérence des critères de comparaison, utilité pour une présentation d’équipe.
La sortie révisée est écrite au même emplacement :
final_markdown = _strip_markdown_fences(turn5.assistant_content)
report_path.write_text(final_markdown)
L’agent enregistre aussi l’événement d’écriture final :
turn5.tool_events.append(
ToolEvent(
name="write_file",
status="completed",
input_payload={"path": str(report_path)},
output_payload={
"description": "Self-reviewed final report written to disk.",
},
)
)
Cette étape transforme l’app d’un simple générateur en un petit workflow éditorial. Ce que voit l’utilisateur n’est pas le premier jet, mais une version relue et corrigée.
Ensuite, nous relierons ce backend à l’app Streamlit.
Étape 9 : construire l’interface de progression Streamlit
Passons de la logique backend à l’interface. L’app Streamlit doit permettre de saisir un prompt, lancer le workflow et visualiser l’avancement de chaque étape.
Remarque : ce code vit dans agent.py, car il régit ce que l’utilisateur voit et clique.
Dans cette étape, nous allons :
-
Configurer la page Streamlit.
-
Créer la zone de prompt.
-
Ajouter un bouton d’exécution.
-
Appeler la fonction
ThinkingAgent.run(). -
Mettre à jour l’UI au fil des tours.
def render_streamlit_app() -> None:
st.set_page_config(
page_title="Qwen3.7-Max Demo Agent",
page_icon=":material/psychology:",
layout="wide",
initial_sidebar_state="collapsed",
)
L’app utilise une mise en page large, car l’UI comporte des cartes d’étapes, des indicateurs de progression et des panneaux de résultats.
La zone de saisie est simple :
goal = st.text_area(
"Prompt",
value=DEFAULT_GOAL,
height=120,
label_visibility="collapsed",
)
run_clicked = st.button("Run Demo", use_container_width=True)
L’utilisateur n’indique que la tâche. L’app ne lui demande pas de paramétrer température, mode de recherche, ID de modèle ou réglages de raisonnement : ces détails sont gérés côté backend.
Au clic sur le bouton, agent.py instancie l’agent backend et l’exécute :
agent = ThinkingAgent(config=config)
result = agent.run(
goal=goal,
preserve_thinking=True,
data_mode="live",
on_turn=on_turn,
)
C’est le point de jonction entre les deux fichiers. agent.py déclenche le workflow, mais thinking_agent.py pilote le comportement de l’agent. Le callback UI met la page à jour après chaque tour :
def on_turn(turn: TurnRecord) -> None:
partial_turns.append(turn)
progress_placeholder.progress(
len(partial_turns) / len(phase_order),
text=f"Completed {_phase_label(turn.phase)}",
)
with steps_placeholder.container():
_render_step_cards(partial_turns, result_ready=False)
Le callback reçoit un TurnRecord complété et rafraîchit la barre de progression et les cartes d’étapes. En cours d’exécution, les cartes servent d’indicateurs d’état. Après, elles deviennent des vues de résultats cliquables.
Nous allons maintenant afficher le rapport Markdown final et proposer son téléchargement.
Étape 10 : prévisualiser et télécharger le rapport final
Quand le backend a terminé, l’UI doit afficher le rapport final. Le fichier Markdown ayant déjà été créé, agent.py n’a plus qu’à le lire, le rendre et proposer un bouton de téléchargement.
Dans cette étape, nous allons :
- Vérifier l’existence du fichier.
- Lire le contenu Markdown final.
- Afficher un bouton de téléchargement.
- Rendre le Markdown dans l’app Streamlit
def _render_file_preview(report_path: str) -> None:
path = Path(report_path)
if not path.exists():
st.info("No file was written yet.")
return
content = path.read_text()
st.caption(f"Created file: {path.name}")
st.download_button(
"Download competitive_analysis.md",
data=content,
file_name=path.name,
use_container_width=True,
)
st.markdown(content)
La fonction commence par vérifier l’existence du fichier, pour éviter un plantage si le backend a échoué avant l’écriture. Puis elle lit le contenu, crée un bouton de téléchargement et rend le Markdown directement dans la page Streamlit.
C’est une séparation des rôles claire :
-
thinking_agent.pyécrit le rapport -
agent.pyl’affiche et permet son téléchargement
Dans l’étape suivante, nous ajouterons une gestion des erreurs et des limites de débit pour rendre la démo plus robuste en cas de défaillance du fournisseur.
Étape 11 : gestion des erreurs et du rate limiting
Les fournisseurs de modèle peuvent expirer, échouer temporairement ou limiter le débit des requêtes. Si l’on expose ces erreurs brutes à l’utilisateur, l’app semble inaboutie.
Cette étape se répartit entre les deux fichiers. La logique de relance est dans thinking_agent.py (au plus près de l’appel modèle). Le message d’erreur est dans agent.py (côté présentation).
Dans cette étape, nous allons :
- Relancer les échecs temporaires côté backend.
- Détecter les erreurs de type « rate limit ».
- Afficher un message plus clair dans l’UI Streamlit
delays = (1.0, 2.0)
for attempt_index in range(len(delays) + 1):
try:
return self.client.chat.completions.create(...)
except Exception as exc:
if not _is_retryable_provider_error(exc):
raise
if attempt_index >= len(delays):
raise
time.sleep(delays[attempt_index])
Le backend tente l’appel, intercepte les échecs relançables, attend un peu et réessaie. Ces courtes pauses suffisent souvent à lisser les instabilités temporaires sans trop faire patienter l’utilisateur.
def _friendly_rate_limit_message(exc: Any) -> str:
return (
"Qwen 3.7 Max is temporarily rate-limited upstream. "
"Please wait 30 to 60 seconds and try again."
)
Ainsi, pas de JSON brut du fournisseur ni de traces d’erreur dans l’UI : l’utilisateur reçoit une explication claire et une marche à suivre.
Avec cette dernière étape, nous pouvons exécuter l’app complète et tester le workflow de bout en bout.
Étape 12 : lancer la démo
Maintenant que le backend et l’interface Streamlit sont reliés, nous pouvons lancer l’application complète.
Dans cette étape, nous allons :
- Démarrer l’app Streamlit.
- Saisir le prompt de productivité par défaut.
- Exécuter le workflow en cinq étapes.
- Prévisualiser et télécharger le rapport final en Markdown
Démarrez l’app :
streamlit run agent.py
Utilisez le prompt par défaut :
I need to prepare a competitive analysis of the top 3 vector databases
for a team presentation next week. I have no idea where to start.
En cliquant sur Run Demo, l’app parcourt le workflow complet :
-
Planification : crée un plan structuré.
-
Recherche : collecte des extraits pour Pinecone, Weaviate et Qdrant.
-
Synthèse : construit une matrice de comparaison.
-
Brouillon : rédige le premier rapport Markdown.
-
Auto-relecture : corrige le rapport.
-
Aperçu : affiche le fichier final
competitive_analysis.md.
Le rapport final est enregistré sous :
output/showcase_runs/<timestamp>/with_preserve/competitive_analysis.md
À la fin, vous devriez voir l’aperçu du rapport et un bouton de téléchargement dans l’interface Streamlit.
Conclusion
Dans ce tutoriel, nous avons construit un agent de productivité compact avec Qwen 3.7 Max exécutant un workflow fixe et interprétable : de la planification à l’auto-relecture, en passant par la recherche, la synthèse et la rédaction. Chemin faisant, nous avons montré pourquoi préserver le raisonnement entre les tours est utile pour des tâches agent longues.
La version actuelle s’appuie uniquement sur Streamlit, des appels de modèle compatibles OpenAI, une couche de recherche légère et une sortie Markdown. Cela la rend facile à étudier, modifier et réutiliser dans vos propres expérimentations.
Plusieurs extensions naturelles s’offrent à vous :
-
Laisser le modèle choisir les cibles de comparaison au lieu d’une liste fixe
-
ajouter des exécutions comparatives « avec
preserve_thinking» vs « sanspreserve_thinking» -
Exposer l’usage de tokens et une estimation des coûts dans l’UI
-
générer un plan de slides ou un graphique en plus du rapport Markdown
-
Remplacer le scraping DuckDuckGo par une API de recherche plus robuste
Si vous souhaitez aller au-delà d’un workflow figé et apprendre à construire des applications IA prêtes pour la production, du prompt engineering au RAG jusqu’aux systèmes agentic, notre parcours de compétences AI Engineering with LangChain est une excellente prochaine étape.
FAQ du tutoriel API Qwen 3.7 Max
Quand utiliser preserve_thinking=True avec Qwen 3.7 Max ?
preserve_thinking=True aide les tours suivants à rester alignés sur les décisions prises plus tôt dans les workflows multi-tours. Dans notre exemple, si la phase de planification choisit des critères de comparaison précis, les phases de synthèse et d’auto-relecture peuvent continuer à utiliser le même raisonnement au lieu de dériver.
Qwen 3.7 Max est-il uniquement destiné aux agents de codage ?
Non. Le codage est l’un de ses points forts, mais le modèle est aussi conçu pour des agents de productivité, l’automatisation bureautique, des workflows basés sur MCP, des tâches multilingues, du raisonnement sur long contexte et l’usage d’outils sur longue durée.
L’app de démo utilise-t-elle une vraie recherche web ?
Oui, le chemin par défaut tente un scraping DuckDuckGo en live. En cas d’échec, il se replie sur une recherche intégrée déterministe.
Le modèle crée-t-il des sous-agents dans notre démo ?
Non. L’app utilise une seule session modèle. La « parallélisation » se situe dans la couche de recherche, où le backend lance trois recherches web simultanées et renvoie les résultats dans la même session modèle.
Pourquoi séparer agent.py et thinking_agent.py ?
agent.py garde l’UI Streamlit lisible. thinking_agent.py contient le workflow backend, la construction des prompts, les relances et la logique de recherche, afin que le comportement de l’agent soit testable indépendamment de l’interface.
Je suis experte Google Developers en ML (Gen AI), triple experte Kaggle et ambassadrice Women Techmakers, avec plus de trois ans d’expérience dans la tech. J’ai cofondé une startup dans le domaine de la santé en 2020 et je poursuis actuellement un master en informatique à Georgia Tech, avec une spécialisation en apprentissage automatique.
