Le sous-agent de recherche
Installer
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt # google-adk==2.10.0, python-dotenv, pytest
cp .env.example .env # collez votre clé d'API GeminiÉtape 1 : la version naïve (et pourquoi elle échoue)
Premier réflexe : un seul agent avec tous les outils.
agent = Agent(name="mix", model="gemini-3.5-flash",
instruction="Utilise date_du_jour puis cherche.",
tools=[google_search, date_du_jour])Lancé le 2026-10-15 avec ADK 2.10 et une clé d'API, l'appel au modèle est refusé :
google.genai.errors.ClientError: 400 INVALID_ARGUMENT. {'error': {'code': 400,
'message': 'Please enable tool_config.include_server_side_tool_invocations to use
Built-in tools with Function calling.', 'status': 'INVALID_ARGUMENT'}}Le message montre que l'API traite à part les outils intégrés exécutés côté serveur. Plutôt que de dépendre d'une option de bas niveau (non exposée par Agent), on suit le schéma documenté par ADK : séparer les agents.
Que signifie l'erreur 400 obtenue avec tools=[google_search, date_du_jour] ?
Une clé invalide donnerait une erreur 400/403 différente, un quota une erreur 429. Ici le message parle explicitement des outils intégrés combinés au function calling.
Étape 2 : le chercheur, avec un seul outil
chercheur = Agent(
name="chercheur_web",
model=MODEL,
description="Cherche sur le web (Google Search) et renvoie des faits datés et sourcés sur UNE question précise.",
instruction=("Tu fais une recherche Google sur la question reçue et tu réponds en français par 3 à 6 faits "
"précis, chacun avec sa date ou sa période. Pas d'opinion, pas de remplissage."),
tools=[google_search], # seul outil de cet agent : c'est la règle
after_model_callback=memoriser_sources,
)La description compte : c'est elle que l'agent principal lit pour savoir quand appeler ce chercheur. Le callback memoriser_sources est détaillé dans la leçon suivante.
Étape 3 : l'agent principal
root_agent = Agent(
name="analyste_recherche",
model=MODEL,
description="Rapport de veille structuré et sourcé à partir de recherches web.",
instruction=INSTRUCTION,
tools=[date_du_jour, AgentTool(agent=chercheur)],
)AgentTool(agent=chercheur) crée un outil nommé chercheur_web avec un paramètre request (le texte de la sous-question). À chaque appel, ADK lance le chercheur dans une session à part, puis renvoie son texte final comme résultat d'outil. Les modifications d'état du chercheur (state_delta) remontent dans la session principale.
sequenceDiagram
participant P as analyste_recherche
participant AT as AgentTool
participant C as chercheur_web
participant G as Gemini + Google Search
P->>AT: chercheur_web(request="sous-question 1")
AT->>C: nouvelle session (copie de l'état)
C->>G: requête avec l'outil google_search seul
G-->>C: texte + grounding_metadata
C-->>AT: texte final + state_delta (sources)
AT-->>P: {"result": "faits... Sources : [1] ... [2] ..."}
| Approche | Avantages | Limites |
|---|---|---|
AgentTool(chercheur) (ce lab) | l'agent principal garde la main, peut appeler plusieurs recherches puis synthétiser | un appel de modèle de plus par recherche |
sub_agents=[chercheur] (transfert) | le chercheur parle directement à l'utilisateur | l'agent principal perd la main ; ADK refuse aussi un parent avec google_search et des sous-agents sans option dédiée |
GoogleSearchTool(bypass_multi_tools_limit=True) | une ligne : ADK 2.10 crée lui-même un sous-agent de recherche en coulisses | moins de contrôle (pas de callback de sources à vous) |
Quel paramètre l'agent principal passe-t-il à l'outil chercheur_web créé par AgentTool ?
AgentTool expose un paramètre unique « request » quand l'agent emballé n'a pas de schéma d'entrée. On le voit dans le run réel : chercheur_web({'request': '...'}).
Exercice : un deuxième chercheur spécialisé
Ajoutez un sous-agent chercheur_chiffres qui ne cherche que des données chiffrées (montants, pourcentages, dates de version) et rendez-le disponible à l'agent principal. Quelles lignes ajoutez-vous ?
Voir la solution
chercheur_chiffres = Agent(
name="chercheur_chiffres", model=MODEL,
description="Cherche uniquement des données chiffrées et datées sur une question.",
instruction="Recherche Google, puis liste uniquement des chiffres avec leur date et leur contexte.",
tools=[google_search],
after_model_callback=memoriser_sources, # même numérotation partagée via l'état
)
root_agent = Agent(..., tools=[date_du_jour, AgentTool(agent=chercheur),
AgentTool(agent=chercheur_chiffres)])Chaque sous-agent a un seul outil intégré. Comme les deux écrivent dans state["sources"], les numéros restent cohérents. Précisez dans l'instruction principale quand utiliser l'un ou l'autre.
Résultat obtenu
Les deux comportements, observés le 2026-10-15 :
# tools=[google_search, date_du_jour] dans un seul agent
ERR ClientError 400 INVALID_ARGUMENT. {'error': {'code': 400, 'message': 'Please enable
tool_config.include_server_side_tool_invocations to use Built-in tools with Function calling.'}}
# architecture agent principal + AgentTool(chercheur_web)
[outil] date_du_jour({})
[outil] chercheur_web({'request': 'Google Agent Development Kit ADK dernieres nouveautes annonces fonctionnalités'})
[outil] chercheur_web({'request': 'Google Agent Developer Kit ADK features updates Vertex AI Firebase'})
[outil] chercheur_web({'request': 'Google ADK Agent Development Kit documentation framework release notes'})Je sais faire
- Reconnaître l'erreur due au mélange outil intégré + fonction
- Isoler
google_searchdans un sous-agent - Exposer un agent comme outil avec
AgentTool - Choisir entre
AgentTool,sub_agentsetbypass_multi_tools_limit