Premier workflow : naviguer et interagir
Mis à jour le 29 juillet 2026
Assembler les briques
Vous avez la boucle en tête et l’environnement configuré. Reste à les réunir en un programme qui tourne vraiment : un agent qui ouvre un moteur de recherche, tape une requête, clique sur le premier résultat et vous rapporte le titre de la page atteinte. Le scénario paraît modeste, mais il mobilise les quatre gestes fondamentaux — navigation, frappe, clic, extraction d’information — et tout ce que vous construirez ensuite n’en sera qu’une variation plus longue.
L’exécuteur d’actions
Le modèle décide, mais il n’exécute rien lui-même : il vous renvoie une action structurée et c’est votre code qui la traduit en gestes Playwright. Cette fonction de traduction est le pont entre les deux mondes.
import time
def execute_action(page, action: dict):
"""Exécute une action Computer Use sur le navigateur."""
action_type = action.get("action")
if action_type == "click":
x, y = action["coordinate"]
page.mouse.click(x, y)
time.sleep(0.5) # Attendre la réaction de l'UI
elif action_type == "type":
page.keyboard.type(action["text"], delay=50)
elif action_type == "key":
page.keyboard.press(action["key"])
elif action_type == "scroll":
x, y = action["coordinate"]
direction = action.get("direction", "down")
amount = action.get("amount", 3)
delta = -amount * 100 if direction == "up" else amount * 100
page.mouse.wheel(0, delta)
time.sleep(0.3)
elif action_type == "screenshot":
pass # Le screenshot sera pris au prochain tour de boucle
else:
print(f"Action inconnue : {action_type}")
Les time.sleep() ne relèvent pas de la superstition. Un clic sur un menu déclenche une animation d’ouverture de quelques centaines de millisecondes ; si vous capturez l’écran dans la foulée, le modèle reçoit l’image d’un menu à moitié déplié et en conclut que son clic a échoué — il reclique, le menu se referme, et vous voilà parti pour un aller-retour sans fin. Cette demi-seconde laisse l’interface se stabiliser avant la prochaine observation.
La boucle complète
L’agent orchestre ensuite le cycle : capture, envoi, décision, exécution. Le point délicat est la construction du message. Au premier tour, vous envoyez l’image accompagnée de la tâche ; aux tours suivants, le nouveau screenshot doit être présenté comme le résultat de l’outil que le modèle vient d’appeler, référencé par son tool_use_id. C’est ce chaînage qui permet au modèle de relier son action à sa conséquence.
import anthropic
import base64
from playwright.sync_api import sync_playwright
client = anthropic.Anthropic()
DISPLAY_WIDTH = 1280
DISPLAY_HEIGHT = 720
MAX_ITERATIONS = 15
def run_agent(task: str, start_url: str = "https://www.google.com"):
"""Lance un agent Computer Use sur une tâche donnée."""
pw = sync_playwright().start()
browser = pw.chromium.launch(headless=False) # False pour observer
page = browser.new_page(viewport={
"width": DISPLAY_WIDTH, "height": DISPLAY_HEIGHT
})
page.goto(start_url)
messages = []
tools = [{
"type": "computer_20241022",
"name": "computer",
"display_width_px": DISPLAY_WIDTH,
"display_height_px": DISPLAY_HEIGHT,
}]
for i in range(MAX_ITERATIONS):
# Capturer l'écran
screenshot_bytes = page.screenshot()
screenshot_b64 = base64.b64encode(screenshot_bytes).decode("utf-8")
# Construire le message
if i == 0:
content = [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": screenshot_b64,
}
},
{"type": "text", "text": task}
]
else:
content = [
{
"type": "tool_result",
"tool_use_id": last_tool_use_id,
"content": [{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": screenshot_b64,
}
}]
}
]
messages.append({"role": "user", "content": content})
# Appeler le modèle
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
# Ajouter la réponse à l'historique
messages.append({"role": "assistant", "content": response.content})
# Vérifier si la tâche est terminée
if response.stop_reason == "end_turn":
final_text = ""
for block in response.content:
if hasattr(block, "text"):
final_text += block.text
print(f"Tâche terminée : {final_text}")
break
# Exécuter les actions
for block in response.content:
if block.type == "tool_use":
last_tool_use_id = block.id
print(f" Action : {block.input.get('action')} "
f"— {block.input}")
execute_action(page, block.input)
browser.close()
pw.stop()
Deux garde-fous sont déjà en place dans ce code. MAX_ITERATIONS = 15 borne le nombre de tours : sans cette limite, un agent désorienté consommerait votre budget API jusqu’à épuisement, et une nuit suffit à faire des dégâts. Le stop_reason == "end_turn" marque quant à lui la fin normale, celle où le modèle a cessé d’agir et se contente de vous répondre — c’est dans ce bloc de texte que vous récupérerez le titre de la page.
Lancer le workflow
if __name__ == "__main__":
run_agent(
task=(
"Recherche Computer Use Anthropic sur Google, "
"puis clique sur le premier résultat. "
"Dis-moi le titre de la page."
)
)
Avec headless=False, le spectacle est instructif : la fenêtre s’ouvre, le curseur va se poser dans le champ de recherche, les caractères s’affichent un par un, le clic part vers le premier lien et le titre remonte dans votre console. Regardez-le tourner deux ou trois fois avant de passer à des tâches plus ambitieuses ; vous y verrez précisément où l’agent hésite et sur quoi porter vos consignes.
Trois pannes que vous rencontrerez
L’agent clique systématiquement à côté de sa cible ? Le coupable est presque toujours un désaccord entre display_width_px / display_height_px et le viewport réel de Playwright. Le modèle raisonne dans le repère qu’on lui a déclaré ; un écart de quelques pixels décale toutes ses coordonnées, et rien dans les logs ne le signalera.
L’agent tourne en rond et refait le même geste indéfiniment ? La borne d’itérations finira par le stopper, mais mieux vaut détecter la boucle plus tôt : si le même screenshot revient trois fois de suite, l’agent n’avance plus, et l’interrompre vous épargne douze appels API inutiles.
L’agent agit sur une page encore vide ? Sur un site lourd, page.goto() rend la main avant la fin du rendu, et la première capture ne montre qu’un fond blanc. Attendez l’inactivité réseau avant de photographier :
page.goto(url)
page.wait_for_load_state("networkidle")
Points clés à retenir
- Un agent Computer Use combine un exécuteur d’actions, une boucle de contrôle et un historique de messages
- Le premier message contient le screenshot initial et la tâche ; les suivants contiennent les résultats des outils
- Limitez toujours le nombre d’itérations pour éviter les boucles infinies
- Utilisez
headless=Falsependant le développement pour observer le comportement de l’agent