LangChain y Vercel AI¶
Rayito como herramienta de un agente: el modelo escribe Python, la herramienta lo ejecuta en un sandbox con estado y le devuelve el resultado. Dos adaptadores de unas cincuenta líneas, listos para copiar.
Cuándo usarlo¶
- Tu agente usa LangChain (Python) o el Vercel AI SDK (TypeScript) y quieres darle un intérprete de código seguro.
- Para hosts que hablan MCP (Claude Code, Claude Desktop, Cursor, VS Code) no hace falta código: usa el servidor MCP.
- Si lo que quieres es que el agente entero (el bucle del modelo y sus
herramientas) corra dentro del sandbox, con el modelo detrás de la
pasarela de secretos, no necesitas estos adaptadores: usa
sbx.agent, con OpenCode o con un grafo de deepagents (LangChain).
Ejemplo¶
Cada adaptador crea el sandbox en la primera llamada, lo reutiliza (las
variables sobreviven entre llamadas, como en un notebook) y lo destruye al
salir del proceso. Devuelve al modelo un JSON con text, stdout,
stderr y error.
Instalación: pip install rayito langchain y el paquete del proveedor de
tu modelo.
"""Un sandbox de Rayito como herramienta de LangChain, en cincuenta líneas.
Instalación: `pip install rayito langchain` (y el proveedor de tu modelo).
Entorno: `RAYITO_TEMPLATE` (nombre o ARN de la imagen), `AWS_REGION` y
`AWS_PROFILE` o las credenciales de boto3. El sandbox se crea en la primera
llamada, vive como mucho 900 s y se destruye al salir del proceso.
"""
from __future__ import annotations
import atexit
import json
from langchain.tools import tool
from rayito import Sandbox
SANDBOX_TIMEOUT_SECONDS = 900
_sandbox: Sandbox | None = None
def sandbox() -> Sandbox:
global _sandbox
if _sandbox is None:
_sandbox = Sandbox.create(timeout=SANDBOX_TIMEOUT_SECONDS)
atexit.register(_sandbox.kill)
return _sandbox
@tool
def run_python(code: str) -> str:
"""Ejecuta código Python en un sandbox aislado con estado entre llamadas
(Linux, internet, matplotlib y pandas instalados). Devuelve un JSON con
`text` (valor de la última expresión), `stdout`, `stderr` y `error`
(nombre y valor si la celda lanzó una excepción)."""
execution = sandbox().run_code(code)
error = execution.error
summary = {
"text": execution.text,
"stdout": "".join(execution.logs.stdout),
"stderr": "".join(execution.logs.stderr),
"error": None if error is None else {"name": error.name, "value": error.value},
}
return json.dumps(summary, ensure_ascii=False)
if __name__ == "__main__":
from langchain.agents import create_agent
agent = create_agent("anthropic:claude-opus-5", tools=[run_python])
print(agent.invoke({"messages": [("user", "Calcula 2**100 en Python.")]}))
Instalación: pnpm add rayito ai zod y el paquete del proveedor de tu
modelo.
/**
* Un sandbox de Rayito como herramienta del Vercel AI SDK, en cincuenta líneas.
*
* Instalación: `pnpm add ai zod rayito` (y el proveedor de tu modelo).
* Entorno: `RAYITO_TEMPLATE` (nombre o ARN de la imagen), `AWS_REGION` y
* `AWS_PROFILE` o las credenciales del SDK de AWS. El sandbox se crea en la
* primera llamada, vive como mucho 900 s y se destruye al salir del proceso.
*/
import { tool } from "ai";
import { Sandbox } from "rayito";
import { z } from "zod";
const SANDBOX_TIMEOUT_MS = 900_000;
let pending: Promise<Sandbox> | undefined;
function sandbox(): Promise<Sandbox> {
pending ??= Sandbox.create({ timeoutMs: SANDBOX_TIMEOUT_MS });
return pending;
}
process.on("beforeExit", () => {
void pending?.then((sbx) => sbx.kill());
});
export const runPython = tool({
description:
"Ejecuta código Python en un sandbox aislado con estado entre llamadas " +
"(Linux, internet, matplotlib y pandas instalados). Devuelve text (valor de " +
"la última expresión), stdout, stderr y error (nombre y valor si la celda " +
"lanzó una excepción).",
inputSchema: z.object({ code: z.string().describe("Código Python que ejecutar.") }),
execute: async ({ code }) => {
const execution = await (await sandbox()).runCode(code);
return {
text: execution.text ?? null,
stdout: execution.logs.stdout.join(""),
stderr: execution.logs.stderr.join(""),
error: execution.error ? { name: execution.error.name, value: execution.error.value } : null,
};
},
});
// Uso: `generateText({ model, tools: { runPython }, prompt: "Calcula 2**100 en Python." })`.
Los dos leen la imagen de RAYITO_TEMPLATE y las credenciales de la cadena
estándar de AWS (AWS_PROFILE, AWS_REGION).
Paso a paso¶
- Un sandbox por proceso. La primera llamada a la herramienta crea el
sandbox con un
timeoutde 900 s; las siguientes reutilizan el mismo kernel. - Errores como datos. Si el código del modelo lanza una excepción, la
herramienta devuelve
errorcon su nombre y valor en vez de fallar: el modelo puede leerlo y corregirse. - Limpieza. El sandbox se mata al salir del proceso (
atexiten Python,beforeExiten Node). Si el proceso muere de golpe, el sandbox vive hasta sutimeout.
Ajustes habituales¶
- Un sandbox por conversación: guarda el sandbox en el estado de la sesión en vez de en una variable global, y mátalo al cerrar la sesión.
- Latencia: con un pool, la primera llamada tarda < 1 s en vez de 5–6 s; cada plaza ociosa tiene un coste fijo al mes (Precios).
- Sin internet: crea el sandbox en
rayito-base-capsconallow_internet_access=False(Red saliente). - Gráficos: devuelve también
execution.results[i].png(base64) si tu modelo acepta imágenes.
Ver también¶
- Servidor MCP
- Ejecutar código
- Seguridad: qué puede hacer el código del modelo dentro del sandbox