Notas prácticas: Actualice su agente avanzado con un entorno de pruebas local de código abierto
Guía paso a paso práctica: Mejore su agente avanzado con un entorno de pruebas local de código abierto: contratos, verificaciones y espacios para código integrable para los equipos que implementan este patrón.
Úselo como una versión reestructurada dirigida a los operadores de las ideas presentadas en “Mejore su agente avanzado con un entorno de pruebas local de código abierto”: etapas claras, espacios ordenados para el código y notas de recuperación que perduran tras la transferencia de tareas. La etapa de Resumen funciona mejor si se considera como una superficie medible. Capture una transcripción clave, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un único lugar al que los operadores puedan auditar sin tener que leer todo el sistema.
Qué es un entorno de pruebas y por qué los agentes lo necesitan
En la etapa de “¿Qué es una sandbox?”, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Incluya la aprobación humana en aquellos casos que impliquen gastos o cambios en los datos de producción. La configuración en tiempo de compilación no equivale a la completitud del proceso empresarial.
El problema
En la fase de captura, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el error debe indicar una única responsabilidad y no un proceso complicado. Incluya la aprobación humana en aquellos casos que impliquen gastos o cambios en los datos de producción. La conexión en tiempo de compilación no equivale a la completitud del proceso empresarial.
Ingresa a OpenSandbox
En la etapa de Entrada a OpenSandbox, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas. Incorpore la aprobación humana en aquellos casos que impliquen gastos o cambios en datos de producción. La conexión en tiempo de compilación no equivale a la completitud del proceso empresarial. En la etapa de Entrada a OpenSandbox, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un lugar que los operadores puedan auditar sin necesidad de leer todo el sistema.
Punto de extensión para el entorno de pruebas de Deep Agents
Al trabajar en la fase de extensión del entorno de pruebas de Deep Agents, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Documente tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Haga un punto de control después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador vuelve a intentar un nodo posterior.
class BaseSandbox(ABC):
def execute(self, command: str, *, timeout: int | None = None) -> ExecuteResponse: ...
@property
def id(self) -> str: ...
def upload_files(self, files: list[tuple[str, bytes]]) -> list[FileUploadResponse]: ...
def download_files(self, paths: list[str]) -> list[FileDownloadResponse]: ...
Construcción de la integración
Al trabajar en la fase de construcción de la integración, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de un fallo parcial. Esa lista de verificación ayuda a mantener honestos los cambios posteriores en el código. Prefiera unidades pequeñas y probables sobre scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado. Haga una verificación después de los pasos costosos. El sistema de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior.
¿Cómo funciona OpenSandbox?
Al trabajar en la etapa de funcionamiento de How OpenSandbox, primero escribe el contrato: los ingresos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Considera esta etapa como un contrato entre los ingresos y las salidas validadas. Nombra los artefactos, define las verificaciones de éxito y rechaza las completaciones parciales silenciosas. Haz una verificación después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior. Al trabajar en la etapa de funcionamiento de How OpenSandbox, primero escribe el contrato: los ingresos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Mantén la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo.
# Generate a starter config
uvx opensandbox-server init-config ~/.sandbox.toml --example docker
# Start the server
uvx opensandbox-server
Código de integración simplificado
La etapa del código de integración simplificado funciona mejor cuando se trata como una superficie medible. Capture una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino óptimo como el camino de recuperación juntos. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Mantenga el estado del grafo plano y tipado; los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación después de las interrupciones.
.create()
La etapa de creación funciona mejor cuando se trata como una superficie medible. Capture un registro exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado. Mantenga el estado del grafo simple y tipado; los bloques anidados ocultan qué nodo escribió qué campo y causan interrupciones en la continuación del proceso.
class MinimalOpenSandboxBackend(BaseSandbox):
def __init__(self, sandbox: Sandbox, runner: AsyncRunner):
self._sandbox = sandbox
self._runner = runner
from opensandbox import Sandbox
from opensandbox.config import ConnectionConfig
IMAGE = "opensandbox/code-interpreter:v1.1.0"
ENTRYPOINT = ["/opt/code-interpreter/code-interpreter.sh"]
@classmethod
def create(cls, api_key: str | None = None) -> "MinimalOpenSandboxBackend":
runner = AsyncRunner()
config = ConnectionConfig(domain="localhost:8080", api_key=api_key)
sandbox = runner.run(
Sandbox.create(IMAGE, entrypoint=ENTRYPOINT, connection_config=config, timeout=timedelta(minutes=30))
)
return cls(sandbox, runner)
.id()
Esta etapa funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Trate esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace completaciones parciales silenciosas. Mantenga el estado del grafo plano y tipado. Los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación del proceso. Esta etapa funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo.
@property
def id(self) -> str:
return self._sandbox.id
.execute()
En la fase de ejecución, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de correos no entregados forman parte del producto, no son mejoras posteriores. Incluya la aprobación humana en aquellos casos que impliquen gastos o cambios en los datos de producción. La configuración en tiempo de compilación no equivale a la completitud del proceso empresarial.
from deepagents.backends.protocol import ExecuteResponse
def execute(self, command: str, *, timeout: int | None = None) -> ExecuteResponse:
execution = self._runner.run(self._sandbox.commands.run(command))
stdout = "\n".join(c.text for c in execution.logs.stdout)
stderr = "\n".join(c.text for c in execution.logs.stderr)
output = "\n".join(p for p in (stdout, stderr) if p)
return ExecuteResponse(output=output, exit_code=execution.exit_code or 0)
.upload_files()
En la etapa de uploadfiles, defina las entradas, el responsable de dicha etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando una etapa falla, el error debe indicar una única responsabilidad y no un proceso complicado. Incluya la aprobación humana en aquellos casos en que se gastan fondos o se modifican datos de producción. La configuración en tiempo de compilación no equivale a la completitud del proceso empresarial.
from opensandbox.models import WriteEntry
from deepagents.backends.protocol import FileUploadResponse
def upload_files(self, files: list[tuple[str, bytes]]) -> list[FileUploadResponse]:
entries = [WriteEntry(path=path, data=data, mode=644) for path, data in files]
try:
self._runner.run(self._sandbox.files.write_files(entries))
return [FileUploadResponse(path=p) for p, _ in files]
except Exception as exc:
return [FileUploadResponse(path=p, error=str(exc)) for p, _ in files]
.download_files()
En la fase de descarga de archivos, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Considere esta fase como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Incluya la aprobación humana en aquellos casos que impliquen gastos o cambios en datos de producción. La conexión en tiempo de compilación no equivale a la completitud del proceso empresarial.
from deepagents.backends.protocol import FileDownloadResponse
def download_files(self, paths: list[str]) -> list[FileDownloadResponse]:
results = []
for path in paths:
try:
content = self._runner.run(self._sandbox.files.read_bytes(path))
results.append(FileDownloadResponse(path=path, content=content))
except Exception as exc:
results.append(FileDownloadResponse(path=path, error=str(exc)))
return results
En la etapa de descarga de archivos, defina las entradas, el responsable de esa fase y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la fase a partir de un punto de control conocido sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema.
.kill()
Al trabajar en la etapa de finalización, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras adicionales. Coloque un punto de control después de las etapas costosas. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intente nuevamente ejecutar un nodo posterior.
def kill(self) -> None:
self._runner.run(self._sandbox.kill())
self._runner.shutdown()
El puente sincrónico/asincrónico
Al trabajar en la etapa del puente sincrónico/asincrónico, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación ayuda a mantener honestos los cambios posteriores en el código. Prefiera unidades pequeñas y verificables sobre scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado. Haga puntos de control después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior.
Un agente de análisis de datos en el entorno de pruebas
Al trabajar en la etapa del agente de análisis de datos A, primero escribe el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Considera esta etapa como un contrato entre las entradas y los resultados validados. Nombra los artefactos, define las comprobaciones de éxito y rechaza las completaciones parciales silenciosas. Haz puntos de control después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior. Al trabajar en la etapa del agente de análisis de datos A, primero escribe el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Mantén la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo.
import asyncio
import nest_asyncio
import threading
from datetime import timedelta
from pathlib import Path
from deepagents import create_deep_agent
from deepagents.backends.protocol import ExecuteResponse, FileDownloadResponse, FileUploadResponse
from deepagents.backends.sandbox import BaseSandbox
from langchain.chat_models import init_chat_model
from opensandbox import Sandbox
from opensandbox.config import ConnectionConfig
from opensandbox.models import WriteEntry
# nest_asyncio for running async functions in Jupyter.
nest_asyncio.apply()
IMAGE = "opensandbox/code-interpreter:v1.1.0"
ENTRYPOINT = ["/opt/code-interpreter/code-interpreter.sh"]
backend = MinimalOpenSandboxBackend.create(api_key="SANDBOX_API_KEY")
print("Sandbox ready:", backend.id)
llm = init_chat_model(
model="gemini-3.5-flash",
model_provider="google_genai",
api_key=os.environ["GOOGLE_API_KEY"],
max_tokens=14750,
max_retries=5,
)
agent = create_deep_agent(
model=llm,
system_prompt=(
"You are a Python coding assistant with sandbox access. "
"You specialize in performing data analysis and data visualization with python,"
"you generate clear reports with good looking charts using seaborn."
),
backend=backend,
)
csv_bytes = Path("customers-1000.csv").read_bytes()
results = backend.upload_files([("/workspace/customers-1000.csv", csv_bytes)])
for r in results:
if r.error:
print(f"Upload failed for {r.path}: {r.error}")
else:
print(f"Uploaded {r.path}")
result = agent.invoke({
"messages": "Perform a deep exploratory data analysis on the customers-1000.csv file "
"and summarize the findings in a markdown report with clear charts."
})
# Deep Exploratory Data Analysis: Customer Acquisition and Profiling
**Dataset:** `customers-1000.csv`
**Analysis Period:** Jan 2020 – May 2022
---
## 1. Executive Summary
This report presents a comprehensive exploratory data analysis (EDA) of a customer database containing 1,000 unique records. The analysis delves into geographical distributions, sign-up temporal trends, domain & technical alignments, and name demographics to uncover actionable insights for strategic growth.
### Key Takeaways
1. **Unprecedented Global Reach:** The customer base is extraordinarily decentralized, spanning **240 countries** across all **7 continents** (including Antarctica). No single country represents more than 1.2% of the customer base. Africa (24.7%) and Asia (22.6%) are the leading regions, followed by Europe (18.5%) and North America (16.1%).
2. **Stable Acquisition Trends:** Customer subscriptions are remarkably stable, averaging roughly **34-35 new customers per month** across 2020 and 2021. This consistency is maintained across all continents year-over-year, indicating a highly standardized, globally distributed customer acquisition channel.
3. **Mid-Week and Weekend Consistency:** Subscriptions are evenly spread across the days of the week, with a minor peak on Friday and Saturday, and a minor trough on Thursday.
4. **B2B / Synthetic Profile Characteristics:** The dataset shows zero domain overlap between customer email domains and company websites (0.0% exact match across 923 unique domains). Combined with the near 1-to-1 ratio of customers to companies, this suggests a highly B2B-centric profile (one representative per enterprise) or synthetically generated profiles with randomized fields.
5. **Standardized TLD Footprint:** The `.com` top-level domain (TLD) dominates both emails (61.2%) and corporate websites (58.8%). The remaining distribution is evenly split among `.org`, `.net`, `.biz`, and `.info`.
---
## 2. Dataset Structure & Data Integrity
The initial dataset contains **1,000 rows** and **12 columns**. An inspection of data integrity reveals excellent completeness:
- **Zero Missing Values:** Every column is 100% populated.
- **Zero Duplicates:** There are no duplicate rows, and the `Customer Id` column contains 1,000 unique identifiers.
- **Data Types:** All columns are stored as object/string types except for `Index` (integer).
### Data Preprocessing & Feature Engineering
To enable deep exploratory analysis, several features were engineered:
1. **Temporal Features:** `Subscription Date` was parsed as a datetime object, allowing the extraction of `Sub_Year`, `Sub_Month`, `Sub_Month_Name`, `Sub_Day_of_Week`, and `Sub_Year_Month` (period).
2. **Geographical Mapping:** Using the `pycountry` and `pycountry-convert` libraries, coupled with a manual fallback dictionary for territories, each of the 240 countries was successfully mapped to its respective **Continent**.
3. **Domain & Technical Profiles:** Email domains (`Email_Domain`), email TLDs (`Email_TLD`), and website TLDs (`Website_TLD`) were extracted to analyze the technical profiling of users.
---
## 3. Geographical Analysis
### Continent-Level Distribution
The geographic reach of this customer base is truly global. Rather than being concentrated in a single dominant market like North America or Europe, customers are spread across all continents:
| Continent | Customer Count | Percentage |
| :--- | :---: | :---: |
| **Africa** | 247 | 24.7% |
| **Asia** | 226 | 22.6% |
| **Europe** | 185 | 18.5% |
| **North America** | 161 | 16.1% |
| **Oceania** | 107 | 10.7% |
| **South America** | 54 | 5.4% |
| **Antarctica** | 20 | 2.0% |
#### Chart 1: Customer Distribution by Continent

### Country-Level Distribution (Top 15 Countries)
The country-level distribution exhibits a heavy tail, with the 1,000 customers distributed across **240 distinct nations**. This indicates that the average number of customers per country is only **4.17**.
The top countries by customer density are:
- **Liechtenstein:** 12 customers (1.2%)
- **Gabon:** 10 customers (1.0%)
- **China, Bangladesh, Reunion, Nigeria, Luxembourg:** 9 customers each (0.9%)
This extreme dispersion suggests a borderless, digital-first product that appeals universally across jurisdictions without localized geographic bias.
#### Chart 2: Top 15 Countries by Customer Count

---
## 4. Temporal Analysis (Subscription Trends)
... (Trimmed to keep blog (estimated read time short))
De cuaderno de notas a un paquete PyPi
El proceso de transformar un cuaderno de notas en un paquete funciona mejor cuando se trata como una superficie medible. Capture una transcripción exitosa, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino exitoso como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son ajustes realizados posteriormente. Mantenga el estado del grafo simple y tipado. Los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación del proceso.
!pip install deepagents-opensandbox-backend
Eche un vistazo
La etapa “Chequealo” funciona mejor cuando se trata como una superficie medible. Capture un registro exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una sola responsabilidad y no a un proceso complicado. Mantenga el estado del grafo simple y tipado; los bloques anidados ocultan qué nodo escribió qué campo y causan problemas al reanudar después de interrupciones.
Lista de verificación operativa
Al trabajar en la etapa de la lista de verificación operativa, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista garantiza que los cambios posteriores en el código sean transparentes.
Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas al pasar del entorno de demostración a los entornos compartidos.
Punto de control después de pasos costosos. La reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior.
Fije las versiones de las dependencias y registre el resumen de la imagen que ejecutó la demostración. La reproducibilidad es mejor que el conocimiento basado en prácticas internas.
Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo.
Punto de control después de pasos costosos. La reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior.
Antes de promocionar la pila, congele las versiones, capture una transcripción de referencia para el camino crítico y confirme los pasos de reversión. Los entornos compartidos necesitan límites de velocidad, verificaciones de tenencia y un responsable claro para la rotación de secretos. Prefiera una fiabilidad sencilla a demostraciones ingeniosas pero únicas.
Nota por lotes para 43662eb4f13d: mantenga las claves del proveedor fuera del repositorio, establezca un límite para los tokens por sesión y almacene las transcripciones junto a los archivos de evaluación para que los cambios posteriores en el modelo sigan siendo comparables.
Al trabajar en la etapa 0 de las notas de fortalecimiento, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
Detalle de fortalecimiento 0/814: mida el tiempo de ejecución, la clase del error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en observaciones anecdóticas.