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.
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:
Observació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:
# 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 listConfigura Potato para usar el backend de Ollama:
# 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.
# Set your API key
export ANTHROPIC_API_KEY="sk-ant-..."# 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: trueClaude 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.
# Install the Claude Agent SDK
pip install claude-agent-sdk# 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: 100El 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».
# Start the server
potato start config.yaml -p 8000El 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:
Interfaz de anotación PRM para etiquetar la corrección por paso junto a la traza de coding
# 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:
[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.
# 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 stateReversió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:
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.
# 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 outcomesFormatos 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:
potato export \
--format trajectories \
--project ./output/ \
--output ./training_data/trajectories.jsonl \
--flatten_branches true{
"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:
potato export \
--format branch_preferences \
--project ./output/ \
--output ./training_data/branch_preferences.jsonl{
"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:
potato export \
--format prm_from_branches \
--project ./output/ \
--output ./training_data/prm_live.jsonlAquí 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:
potato export \
--format code_review \
--project ./output/ \
--output ./training_data/code_review.jsonlInicio rápido completo
La secuencia entera, de cero a una sesión de Ollama en marcha:
# 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 browserTras 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.