Skip to content
Tutorials13 min read

Observar, pausar y rebobinar: observación de agentes de coding en vivo en Potato

Tutorial para montar la observación de agentes de coding en vivo con Ollama, la API de Anthropic o el Claude Agent SDK. Incluye pausa, reversión, ramificación y exportación de trayectorias.

Potato Team

Qué distingue a la observación en vivo

Casi toda la evaluación de agentes de coding ocurre a posteriori: el agente se ejecuta, produce una traza y los revisores repasan la grabación más tarde. La observación en vivo funciona al revés. El anotador ve trabajar al agente en tiempo real y presencia cada edición de archivo, cada comando de terminal y cada paso de razonamiento según van ocurriendo.

Eso cambia lo que puedes hacer. Si el agente empieza a ir por el camino equivocado, el anotador puede intervenir antes de que pierda tiempo ahí. Puede pausar para leer un diff con calma antes de que el agente siga, o enviar una instrucción en lenguaje llano para reconducirlo. La parte que a mí me resulta más útil es la reversión: desde cualquier punto de control anterior puedes rebobinar y dejar que el agente pruebe otro enfoque. Esas ramas son justo el tipo de datos que pide el aprendizaje de preferencias.

Esto no sustituye a la anotación de trazas estáticas. Es otro modo, y produce otro tipo de datos. La anotación estática gana cuando quieres mucha cantidad a un coste predecible. La observación en vivo gana cuando buscas datos concretos, intentas entender cómo falla un agente o construyes pares de preferencia por ramificación.

Para la referencia completa de la funcionalidad, consulta la documentación fuente.

La interfaz de agente de coding en vivo transmite las acciones del agente en tiempo real y muestra los diffs de código y la salida del terminal según trabaja:

Live coding agent interface showing real-time code diffs and terminal outputObservación de agente de coding en vivo con renderizado de diffs y salida de terminal en tiempo real

Tres backends

Potato ofrece tres backends para la observación en vivo. Cada uno ejecuta un agente de coding en un entorno aislado y transmite sus acciones a la interfaz según se producen.

Ollama (totalmente local)

El backend de Ollama se ejecuta por completo en tu máquina, sin claves de API ni llamadas de red. Es la opción cuando el código base es sensible o cuando solo quieres experimentar sin acumular factura de API.

Primero, instala Ollama y descarga un modelo con capacidad de uso de herramientas:

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

Configura Potato para usar el backend de 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 de Anthropic (Claude con uso de herramientas)

El backend de la API de Anthropic se conecta a modelos Claude con uso de herramientas. Obtienes mejor razonamiento y generación de código que con la mayoría de modelos locales y, a cambio, pagas las llamadas a la 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 (todas las capacidades de Claude Code)

El backend del Claude Agent SDK es el más capaz de los tres, con el conjunto completo de herramientas de Claude Code y comportamiento autónomo. Requiere el paquete 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

El flujo de trabajo de anotación

Con el servidor levantado, una sesión de observación en vivo pasa por unas cuantas etapas.

Iniciar una sesión

El anotador abre la interfaz de Potato y ve un campo para introducir la descripción de la tarea. Pega o escribe la tarea que debe completar el agente, por ejemplo «Arreglar la prueba que falla en tests/test_parser.py por el nuevo formato de configuración» o «Añadir paginación al endpoint /api/users».

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

El anotador pulsa «Start Agent» y el agente de coding empieza a trabajar. Cada acción aparece en tiempo real en el panel del CodingTraceDisplay.

Ver trabajar al agente

Según se ejecuta el agente, cada paso aparece en el visor de trazas:

  • Los pasos de razonamiento aparecen como bloques grises plegables con el razonamiento del agente.
  • Las lecturas de archivos aparecen como bloques de código con resaltado de sintaxis, números de línea y la ruta del archivo.
  • Las ediciones de archivos aparecen como diffs unificados con resaltado en rojo y verde.
  • Los comandos de terminal aparecen como bloques oscuros de terminal con el comando, la salida y el código de salida.
  • El árbol de archivos de la barra lateral se actualiza según se crean, modifican o leen archivos.

Un indicador de progreso en la parte superior muestra el número de paso actual y el tiempo transcurrido. El estado del agente se muestra como «Thinking...», «Editing file...», «Running command...», etc.

Controles de pausa e instrucción

Mientras el agente trabaja, el anotador puede intervenir desde la barra de controles:

Pause: congela el agente cuando termine el paso en curso. El agente no pasa al siguiente paso hasta que se reanude. Sirve para examinar con calma un diff o una salida de terminal antes de que el agente siga.

Send Instruction: con el agente en pausa (o incluso en marcha), escribe un mensaje en lenguaje natural que se inyecta en el contexto del agente. Por ejemplo: «No modifiques el esquema de la base de datos, usa una migración» o «Revisa el registro de errores en /var/log/app.log antes de hacer cambios».

Resume: continúa la ejecución del agente tras una pausa.

Stop: termina la sesión del agente por completo. La trayectoria hasta ese momento se guarda.

Los anotadores pueden evaluar el trabajo del agente con anotación PRM junto a la vista de la traza:

Process reward annotation alongside coding agent traceInterfaz de anotación PRM para etiquetar la corrección por paso junto a la traza 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"

Sistema de puntos de control basado en git

El sistema de puntos de control es lo que hace posible el resto. La reversión, la ramificación y la exportación de trayectorias dependen de él, y cumple su función haciendo un commit tras cada cambio de archivo del agente.

Cómo funciona

Cuando arranca una sesión, Potato inicializa un repositorio de git en el espacio de trabajo aislado, o usa el que ya haya. Tras cada edición de archivo hace un commit automático con un mensaje estructurado:

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

El resultado es un historial de commits lineal que se corresponde uno a uno con los pasos de la trayectoria. Cada punto de control captura el estado completo del espacio de trabajo en ese momento.

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

Reversión

Pulsa «Rollback» y elige cualquier punto de control anterior del desplegable. Potato devuelve el espacio de trabajo a ese estado con git checkout y rebobina la vista de la trayectoria para que coincida; a partir de ahí el agente sigue con su contexto recortado hasta ese paso.

Es la jugada cuando ves que el agente toma un desvío equivocado. En lugar de dejarlo correr y quemar tiempo, rebobinas al último estado bueno y dejas que lo intente de nuevo, quizá con una instrucción que lo empuje hacia otro sitio.

Trayectorias ramificadas

Ramificar es revertir conservando los dos caminos. Cuando reviertes y el agente toma otra dirección, Potato crea una rama de git con nombre y sigue la pista a ambas trayectorias:

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)

Puedes ramificar desde cualquier punto de control y montar así todo un árbol de trayectorias. Para el aprendizaje de preferencias esto es oro, porque cada par de ramas ya viene siendo una comparación etiquetada: reviertes precisamente porque juzgaste que la rama A estaba mal, lo que convierte a la rama B en el camino preferido a partir del punto de ramificación.

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

Formatos de exportación

Una sesión en vivo produce datos de trayectoria detallados, y puedes exportarlos con varias formas según lo que quieras entrenar.

Exportación de trayectorias lineales

Exporta cada rama como una trayectoria independiente:

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"
}

Pares de preferencia a partir de ramas

Exporta pares de ramas como datos de preferencia para DPO o 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}
  ]
}

Etiquetas PRM a partir de la observación en vivo

Puedes combinar la observación en vivo con el etiquetado PRM, ya que un punto de reversión suele ser el paso del primer error:

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

Aquí el paso desde el que reviertes se etiqueta como primer error, y los pasos de la nueva rama se etiquetan como correctos, porque los aceptaste.

Conjuntos de datos de revisión de código

Exporta las instrucciones del anotador y los motivos de reversión como datos de entrenamiento de revisión de código:

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

Inicio rápido completo

La secuencia entera, de cero a una sesión de Ollama en marcha:

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

Tras iniciar sesión, pega una tarea como «Añadir validación de entrada al endpoint POST /api/users» y pulsa «Start Agent». Míralo trabajar, pausa cuando algo no cuadre, envía instrucciones para reconducirlo y revierte para probar otros enfoques. Al terminar, valora el resultado y apunta tus notas.

Buenas prácticas

Empieza con tareas claras y acotadas. El punto óptimo es trabajo que le lleve al agente entre 5 y 15 minutos. Menos que eso no da trayectoria suficiente para que merezca la pena anotarla; mucho más agota al anotador.

Usa el aislamiento con Docker en producción. El modo de aislamiento local vale mientras desarrollas, pero Docker impide que el agente toque tu sistema anfitrión. Úsalo siempre con modelos no confiables.

Registra los motivos de reversión. Activa require_reason_on_rollback para que cada punto de ramificación venga con una nota humana sobre qué salió mal. Esas notas son señal de entrenamiento útil por sí mismas y mejoran los datos de preferencia.

Compara varios backends. Pasa las mismas tareas por Ollama, la API de Anthropic y el Claude Agent SDK para obtener datos de preferencia entre agentes. Como solo cambia la sección del backend en la configuración, montarlo cuesta poco.

Exporta pronto y a menudo. Lanza una exportación después de cada sesión en lugar de dejarlo todo para el final. Pierdes menos si algo se cae y puedes vigilar la calidad de los datos sobre la marcha.