Skip to content
Tutorials13 min read

Regarder, mettre en pause, revenir en arrière : l'observation d'agents de coding en direct dans Potato

Tutoriel de mise en place de l'observation d'agents de coding en direct avec Ollama, l'API Anthropic ou le Claude Agent SDK. Couvre la pause, le retour arrière, le branchement et l'exportation des trajectoires.

Potato Team

Ce qui distingue l'observation en direct

L'évaluation des agents de coding se fait le plus souvent après coup : l'agent tourne, produit une trace, et les relecteurs éplucheront l'enregistrement plus tard. L'observation en direct fonctionne dans l'autre sens. L'annotateur regarde l'agent travailler en temps réel et voit chaque modification de fichier, chaque commande dans le terminal et chaque étape de raisonnement au moment où elle survient.

Cela change ce que vous pouvez faire. Si l'agent part sur une mauvaise piste, l'annotateur peut intervenir avant qu'il n'y perde du temps. Il peut mettre en pause pour lire un diff attentivement avant que l'agent ne passe à la suite, ou envoyer une instruction en langage courant pour le réorienter. La possibilité que je trouve la plus utile est le retour arrière : depuis n'importe quel point de contrôle antérieur, vous rembobinez et laissez l'agent tenter une autre approche. Ces branches sont exactement le type de données que réclame l'apprentissage de préférences.

Cela ne remplace pas l'annotation de traces statiques. C'est un mode différent qui produit un type de données différent. L'annotation statique l'emporte quand vous en voulez beaucoup à un coût prévisible. L'observation en direct l'emporte quand vous cherchez des données ciblées, que vous essayez de comprendre comment un agent échoue, ou que vous construisez des paires de préférence par branchement.

Pour la référence complète de la fonctionnalité, voir la documentation source.

L'interface d'agent de coding en direct diffuse les actions de l'agent en temps réel, en affichant les diffs de code et la sortie du terminal au fil du travail :

Interface d'agent de coding en direct montrant les diffs de code et la sortie du terminal en temps réelObservation d'un agent de coding en direct, avec rendu des diffs et sortie du terminal en temps réel

Trois backends

Potato propose trois backends pour l'observation en direct. Chacun exécute un agent de coding dans un bac à sable et diffuse ses actions vers l'interface au fur et à mesure.

Ollama (entièrement local)

Le backend Ollama tourne entièrement sur votre machine, sans clé d'API ni appel réseau. C'est le choix à faire quand la base de code est sensible, ou simplement quand vous voulez expérimenter sans faire grimper une facture d'API.

Commencez par installer Ollama et récupérer un modèle capable d'utiliser des outils :

bash
# Install Ollama
curl -fsSL https://ollama.ai/install.sh | sh
 
# Pull a coding-capable model
ollama pull qwen2.5-coder:32b
 
# Verify the model is available
ollama list

Configurez Potato pour utiliser le backend Ollama :

yaml
# config.yaml
project_name: "Live Agent Observation - Ollama"
port: 8000
 
live_coding_agent:
  enabled: true
  backend: "ollama"
  ollama:
    model: "qwen2.5-coder:32b"
    host: "http://localhost:11434"
    temperature: 0.2
    max_tokens: 4096
    num_ctx: 32768               # Context window size
  sandbox:
    type: "docker"               # "docker" or "local"
    image: "python:3.11-slim"    # Base image for sandboxed execution
    workspace: "./workspace/"    # Agent's working directory
    timeout: 600                 # Max seconds per agent session
  streaming:
    update_interval_ms: 100      # How often to push updates to the UI
    buffer_output: true          # Buffer terminal output for smoother rendering
  checkpoints:
    enabled: true
    strategy: "git"              # Git-based checkpoints
    auto_commit_on_file_change: true
    commit_message_prefix: "[potato-checkpoint]"

API Anthropic (Claude avec usage d'outils)

Le backend de l'API Anthropic se connecte aux modèles Claude avec usage d'outils. Vous gagnez en raisonnement et en génération de code par rapport à la plupart des modèles locaux, et en échange vous payez les appels d'API.

bash
# Set your API key
export ANTHROPIC_API_KEY="sk-ant-..."
yaml
# config.yaml
project_name: "Live Agent Observation - Claude"
port: 8000
 
live_coding_agent:
  enabled: true
  backend: "anthropic"
  anthropic:
    model: "claude-sonnet-4-20250514"
    api_key_env: "ANTHROPIC_API_KEY"
    max_tokens: 8192
    temperature: 0.1
    tools:
      - "file_read"
      - "file_edit"
      - "bash_command"
      - "directory_list"
      - "file_search"
    system_prompt: >
      You are a coding agent. You will be given a task description and
      access to a codebase. Use the provided tools to read files, make
      edits, and run commands to complete the task. Think step by step
      and verify your changes by running tests.
  sandbox:
    type: "docker"
    image: "python:3.11-slim"
    workspace: "./workspace/"
    timeout: 900
    allowed_commands:             # Whitelist for bash commands
      - "python"
      - "pip"
      - "pytest"
      - "git"
      - "ls"
      - "cat"
      - "find"
      - "grep"
  streaming:
    update_interval_ms: 50
    show_thinking: true           # Show Claude's thinking in real time
  checkpoints:
    enabled: true
    strategy: "git"
    auto_commit_on_file_change: true

Claude Agent SDK (toutes les capacités de Claude Code)

Le backend Claude Agent SDK est le plus capable des trois, avec l'ensemble complet des outils de Claude Code et un comportement autonome. Il nécessite le paquet claude-agent-sdk.

bash
# Install the Claude Agent SDK
pip install claude-agent-sdk
yaml
# config.yaml
project_name: "Live Agent Observation - Claude Agent SDK"
port: 8000
 
live_coding_agent:
  enabled: true
  backend: "claude_agent_sdk"
  claude_agent_sdk:
    api_key_env: "ANTHROPIC_API_KEY"
    model: "claude-sonnet-4-20250514"
    max_turns: 50                # Maximum number of agent turns
    permission_mode: "auto"      # "auto", "ask", or "restricted"
    allowed_tools:
      - "Read"
      - "Edit"
      - "Write"
      - "Bash"
      - "Glob"
      - "Grep"
    restricted_commands:          # Bash commands to block
      - "rm -rf /"
      - "sudo"
      - "curl"
      - "wget"
  sandbox:
    type: "docker"
    image: "node:20-slim"
    workspace: "./workspace/"
    timeout: 1200
    mount_volumes:
      - "./test-repo:/workspace/repo"
  streaming:
    update_interval_ms: 50
    show_thinking: true
    show_tool_inputs: true
  checkpoints:
    enabled: true
    strategy: "git"
    auto_commit_on_file_change: true
    max_checkpoints: 100

Le déroulé de l'annotation

Une fois le serveur en route, une session d'observation en direct passe par quelques étapes.

Démarrer une session

L'annotateur ouvre l'interface de Potato et voit un champ de saisie pour la description de la tâche. Il y colle ou y saisit la tâche que l'agent doit accomplir, par exemple « Corriger le test en échec dans tests/test_parser.py causé par le nouveau format de config » ou « Ajouter la pagination au point d'entrée /api/users ».

bash
# Start the server
potato start config.yaml -p 8000

L'annotateur clique sur « Start Agent » et l'agent de coding se met au travail. Chaque action apparaît en temps réel dans le panneau CodingTraceDisplay.

Regarder l'agent travailler

Pendant que l'agent tourne, chaque étape apparaît dans la visionneuse de trace :

  • Les étapes de réflexion apparaissent en blocs gris repliables qui montrent le raisonnement de l'agent.
  • Les lectures de fichiers apparaissent en blocs de code colorés, avec numéros de ligne et chemin du fichier.
  • Les modifications de fichiers apparaissent en diffs unifiés avec surlignage rouge/vert.
  • Les commandes de terminal apparaissent en blocs de terminal sombres, avec la commande, la sortie et le code de retour.
  • L'arborescence de fichiers se met à jour dans la barre latérale à mesure que les fichiers sont créés, modifiés ou lus.

Un indicateur de progression en haut affiche le numéro de l'étape courante et le temps écoulé. L'état de l'agent est affiché sous forme de « Thinking... », « Editing file... », « Running command... », etc.

Commandes de pause et d'instruction

Pendant que l'agent tourne, l'annotateur peut intervenir depuis la barre de commandes :

Pause : fige l'agent une fois son étape en cours terminée. L'agent ne passe pas à l'étape suivante tant qu'il n'a pas repris. Servez-vous-en pour examiner tranquillement un diff ou une sortie de terminal avant que l'agent ne continue.

Envoyer une instruction : pendant la pause (ou même pendant l'exécution), saisissez un message en langage naturel qui est injecté dans le contexte de l'agent. Par exemple : « Ne modifie pas le schéma de la base de données, utilise plutôt une migration » ou « Consulte le journal d'erreurs dans /var/log/app.log avant de faire des modifications ».

Reprendre : relance l'exécution de l'agent après une pause.

Arrêter : met fin à la session de l'agent. La trajectoire produite jusque-là est enregistrée.

Les annotateurs peuvent évaluer le travail de l'agent avec l'annotation PRM, à côté de l'affichage de la trace :

Annotation de récompense de processus à côté de la trace d'un agent de codingInterface d'annotation PRM pour l'étiquetage de la justesse par étape, à côté de la trace de coding

yaml
# Control bar configuration
live_coding_agent:
  controls:
    pause_enabled: true
    instruction_enabled: true
    stop_enabled: true
    rollback_enabled: true
    branch_enabled: true
    pause_keyboard_shortcut: "Space"
    instruction_keyboard_shortcut: "i"

Système de points de contrôle git

Le système de points de contrôle est ce qui fait tenir le reste. Le retour arrière, le branchement et l'exportation de trajectoires reposent tous dessus, et il fait son travail en commitant dans git après chaque modification de fichier faite par l'agent.

Fonctionnement

Au démarrage d'une session, Potato initialise un dépôt git dans l'espace de travail du bac à sable, ou reprend celui qui s'y trouve déjà. Après chaque modification de fichier, il commite automatiquement avec un message structuré :

text
[potato-checkpoint] Step 7: Edit src/parser.py
- Modified lines 45-52
- Agent reasoning: Fix the regex pattern to handle escaped quotes

On obtient un historique de commits linéaire qui correspond un pour un aux étapes de la trajectoire. Chaque point de contrôle capture l'état complet de l'espace de travail à cet instant.

bash
# You can inspect checkpoints directly with git
cd workspace/
git log --oneline
 
# Output:
# f8a2c1d [potato-checkpoint] Step 12: Edit tests/test_parser.py
# 3b7e9f0 [potato-checkpoint] Step 10: Edit src/parser.py
# a1c4d8e [potato-checkpoint] Step 8: Edit src/parser.py
# 9e2f6b3 [potato-checkpoint] Step 5: Edit src/config.py
# 7d0a3c1 [potato-checkpoint] Step 0: Initial state

Retour arrière

Cliquez sur « Rollback » et choisissez un point de contrôle antérieur dans la liste. Potato ramène l'espace de travail à cet état avec git checkout et rembobine l'affichage de la trajectoire pour qu'il corresponde ; l'agent repart de là, son contexte tronqué jusqu'à cette étape.

C'est le geste à faire quand vous voyez l'agent prendre un mauvais virage. Plutôt que de le laisser tourner et perdre du temps, vous revenez au dernier bon état et le laissez réessayer, éventuellement avec une instruction qui l'oriente ailleurs.

Trajectoires qui bifurquent

Le branchement, c'est le retour arrière qui garde les deux chemins. Quand vous revenez en arrière et que l'agent part dans une autre direction, Potato crée une branche git nommée et suit les deux trajectoires :

text
Step 0 → Step 1 → Step 2 → Step 3 → Step 4 (Branch A: original path)
                          ↘
                           Step 3' → Step 4' → Step 5' (Branch B: after rollback)

Vous pouvez bifurquer depuis n'importe quel point de contrôle et construire ainsi tout un arbre de trajectoires. Pour l'apprentissage de préférences, c'est de l'or : chaque paire de branches est déjà une comparaison étiquetée, puisque vous êtes revenu en arrière précisément parce que vous jugiez la branche A mauvaise, ce qui fait de la branche B le chemin préféré à partir du point de bifurcation.

yaml
# Branching configuration
live_coding_agent:
  branching:
    enabled: true
    max_branches_per_session: 10
    auto_name_branches: true     # "branch-A", "branch-B", etc.
    require_reason_on_rollback: true  # Annotator must explain why they rolled back
    compare_branches_view: true  # Side-by-side view of branch outcomes

Formats d'exportation

Une session en direct produit des données de trajectoire détaillées, que vous pouvez exporter sous plusieurs formes selon ce que vous entraînez.

Exportation de trajectoires linéaires

Exportez chaque branche comme une trajectoire indépendante :

bash
potato export \
  --format trajectories \
  --project ./output/ \
  --output ./training_data/trajectories.jsonl \
  --flatten_branches true
json
{
  "session_id": "session_001",
  "branch": "branch-A",
  "task": "Fix the failing test in tests/test_parser.py",
  "steps": [
    {"step_idx": 0, "type": "file_read", "path": "tests/test_parser.py", "...": "..."},
    {"step_idx": 1, "type": "thinking", "content": "The test expects..."},
    {"step_idx": 2, "type": "file_edit", "path": "src/parser.py", "diff": "..."},
    {"step_idx": 3, "type": "bash_command", "command": "pytest tests/test_parser.py"}
  ],
  "human_interventions": [
    {"after_step": 2, "type": "instruction", "content": "Use a migration instead"}
  ],
  "rollback_from_step": null,
  "outcome": "resolved"
}

Paires de préférence issues des branches

Exportez les paires de branches comme données de préférence pour du DPO ou du RLHF :

bash
potato export \
  --format branch_preferences \
  --project ./output/ \
  --output ./training_data/branch_preferences.jsonl
json
{
  "session_id": "session_001",
  "task": "Fix the failing test in tests/test_parser.py",
  "branch_point_step": 2,
  "branch_point_reason": "Agent started modifying the wrong file",
  "rejected_branch": "branch-A",
  "rejected_steps": [
    {"step_idx": 3, "type": "file_edit", "path": "src/wrong_file.py", "...": "..."},
    {"step_idx": 4, "type": "bash_command", "command": "pytest", "exit_code": 1}
  ],
  "chosen_branch": "branch-B",
  "chosen_steps": [
    {"step_idx": 3, "type": "file_edit", "path": "src/parser.py", "...": "..."},
    {"step_idx": 4, "type": "bash_command", "command": "pytest", "exit_code": 0}
  ]
}

Étiquettes PRM issues de l'observation en direct

Vous pouvez associer l'observation en direct à un étiquetage PRM, puisqu'un point de retour arrière est en général l'étape de la première erreur :

bash
potato export \
  --format prm_from_branches \
  --project ./output/ \
  --output ./training_data/prm_live.jsonl

Ici, l'étape depuis laquelle vous êtes revenu en arrière est étiquetée comme première erreur, et les étapes de la nouvelle branche sont étiquetées correctes, puisque vous les avez acceptées.

Jeux de données de revue de code

Exportez les instructions des annotateurs et les motifs de retour arrière comme données d'entraînement de revue de code :

bash
potato export \
  --format code_review \
  --project ./output/ \
  --output ./training_data/code_review.jsonl

Démarrage rapide complet

La séquence entière, de rien du tout à une session Ollama qui tourne :

bash
# 1. Install Potato with live agent support
pip install potato-annotation[live-agents]
 
# 2. Install and start Ollama
curl -fsSL https://ollama.ai/install.sh | sh
ollama pull qwen2.5-coder:32b
 
# 3. Set up a workspace with a repo to work on
mkdir -p workspace/
git clone https://github.com/example/test-project workspace/repo
 
# 4. Create the config file
cat > config.yaml << 'YAML'
project_name: "Live Agent Observation"
port: 8000
 
live_coding_agent:
  enabled: true
  backend: "ollama"
  ollama:
    model: "qwen2.5-coder:32b"
    host: "http://localhost:11434"
    temperature: 0.2
    num_ctx: 32768
  sandbox:
    type: "local"
    workspace: "./workspace/repo"
    timeout: 600
  streaming:
    update_interval_ms: 100
  checkpoints:
    enabled: true
    strategy: "git"
    auto_commit_on_file_change: true
  controls:
    pause_enabled: true
    instruction_enabled: true
    rollback_enabled: true
    branch_enabled: true
  branching:
    enabled: true
    max_branches_per_session: 5
    require_reason_on_rollback: true
 
annotation_schemes:
  - annotation_type: radio
    name: outcome
    label: "Final outcome"
    options:
      - value: "resolved"
        text: "Task Fully Resolved"
      - value: "partial"
        text: "Partially Resolved"
      - value: "failed"
        text: "Failed"
 
  - annotation_type: text_input
    name: notes
    label: "Session Notes"
    placeholder: "Key observations about agent behavior..."
    required: false
 
output:
  path: "./output/"
  format: "jsonl"
  export_formats:
    - "trajectories"
    - "branch_preferences"
    - "prm_from_branches"
 
annotators:
  - username: "observer1"
    password: "observer_pw_1"
YAML
 
# 5. Start Potato
potato start config.yaml -p 8000
 
# 6. Open http://localhost:8000 in your browser

Une fois connecté, collez une tâche du genre « Ajouter la validation des entrées au point d'entrée POST /api/users » et cliquez sur « Start Agent ». Regardez l'agent travailler, mettez en pause quand quelque chose cloche, envoyez des instructions pour l'orienter, et revenez en arrière pour tester d'autres approches. À la fin, notez le résultat et consignez vos observations.

Bonnes pratiques

Commencez par des tâches claires et cadrées. Le bon calibre est un travail qui occupe l'agent de 5 à 15 minutes. Plus court, la trajectoire produite ne vaut pas la peine d'être annotée ; beaucoup plus long, l'annotateur s'épuise.

Utilisez le bac à sable Docker en production. Le mode bac à sable local convient pendant le développement, mais Docker empêche l'agent de toucher à votre système hôte. Utilisez-le systématiquement avec des modèles non fiables.

Consignez les motifs de retour arrière. Activez require_reason_on_rollback pour que chaque point de bifurcation s'accompagne d'une note humaine sur ce qui a dérapé. Ces notes sont un signal d'entraînement utile en soi, et elles améliorent les données de préférence.

Comparez plusieurs backends. Passez les mêmes tâches par Ollama, l'API Anthropic et le Claude Agent SDK pour obtenir des données de préférence entre agents. Comme seule la section backend de la config change, c'est simple à mettre en place.

Exportez tôt et souvent. Lancez une exportation après chaque session plutôt que de tout garder pour la fin. Vous perdez moins en cas de plantage, et vous gardez un œil sur la qualité des données au fil de l'eau.