El Dino, la Llama y la Ballena

Llevaba tiempo queriendo entender qué se necesita para interactuar con un modelo de lenguaje grande (LLM) alojado localmente, y con el lanzamiento de DeepSeek R1, un modelo centrado en el razonamiento, encontré la excusa perfecta para investigarlo.

Mi trabajo diario es como Tecnólogo Principal en CTO Labs, donde asesoramos a inversores, ejecutivos y juntas directivas sobre tecnología.

Un tema recurrente es el impacto de las tecnologías emergentes en las organizaciones y en este momento no hay un tema más importante que la IA.

Una de las formas en las que nos mantenemos actualizados es a través de casos de uso reales.

Si bien sabía que Python es el lenguaje estándar en datos, ML e IA, también tenía curiosidad por el estado de TypeScript/JavaScript en este campo, ya que es el entorno con el que estoy más familiarizado.

Habiendo sido colaborador principal de Deno, siempre me ha gustado su enfoque de “herramienta de desarrollo con baterías incluidas”.

También me intrigaban los Jupyter Notebooks. Muchos de mis colegas científicos de datos los recomendaban, y en mi tiempo en Deno, abogué por integrar soporte para ellos, aunque nunca tuve un caso de uso personal para probarlos.

¿Podría combinar Deno, un entorno de desarrollo optimizado y un LLM local para aprender sobre IA de manera sencilla? La respuesta es sí.

Voy a compartir contigo el viaje que emprendí..

Primeros pasos

Hay varios elementos clave en este proceso:

  1. Un entorno para ejecutar el modelo – Si bien puedes conectarte a LLMs mediante API, aquí usaremos Ollama, un framework para ejecutar modelos de lenguaje en tu computadora.
  2. Un modelo de lenguaje grande – Usaremos una versión reducida de DeepSeek R1 que se puede ejecutar localmente.
  3. Un notebookJupyter Notebook para código y texto interactivo.
  4. Deno – Un runtime con soporte nativo para Jupyter Notebooks.
  5. Un IDE – Usaremos VSCode con soporte para Jupyter y la extensión de Deno.
  6. Una librería de IALangChain.js para facilitar la interacción con el LLM.
  7. Un validador de esquemas – Usaremos zod para estructurar las respuestas del LLM.

Requisito importante: El rendimiento variará según tu CPU, GPU y RAM. Asegúrate de tener suficiente potencia para ejecutar modelos locales.

Configurando un modelo local

1️⃣ Descarga e instala Ollama, si aún no lo tienes. Confirma que el comando ollama está disponible y que el servidor de Ollama se ejecuta en el puerto 11434.

2️⃣ Instala DeepSeek R1 (versión 8B):

ollama pull deepseek-r1:8b

3️⃣ Verifica que está disponible:

ollama list

Creando un notebook en Jupyter

1️⃣ Abre VSCode y crea una carpeta para tu notebook.
2️⃣ Instala o actualiza la extensión de Deno en VSCode.
3️⃣ Actívala con Deno: Enable en el paleta de comandos o crea un archivo deno.json.
4️⃣ Usa el comando “Create: New Jupyter Notebook” y selecciona Deno en el menú de selección de kernel. (Si no aparece, actualiza o reinstala la extensión de Deno).

Usando el modelo con LangChain.js

LangChain.js ofrece una interfaz consistente para interactuar con modelos de lenguaje como Ollama.

Ejemplo básico:

import { ChatOllama } from "npm:@langchain/ollama";

const model = new ChatOllama({
  model: "deepseek-r1:8b",
});

Creando una cadena en LangChain.js

LangChain.js facilita la creación de workflows modulares con IA.

import { z } from "npm:zod";
import { RunnableSequence } from "npm:@langchain/core/runnables";
import { StructuredOutputParser } from "npm:@langchain/core/output_parsers";
import { ChatPromptTemplate } from "npm:@langchain/core/prompts";

const zodSchema = z.object({
  answer: z.string().describe("respuesta a la pregunta del usuario"),
  source: z.string().describe("fuente utilizada para responder, debe ser un sitio web."),
});

const parser = StructuredOutputParser.fromZodSchema(zodSchema);

const chain = RunnableSequence.from([
  ChatPromptTemplate.fromTemplate(
    "Responde la pregunta del usuario lo mejor posible.n{format_instructions}n{question}",
  ),
  model,
  parser,
]);

// Mostrar las instrucciones de formato
Deno.jupyter.md`${parser.getFormatInstructions()}`;

Validación de JSON con zod

Un esquema JSON válido para estructurar la salida del LLM:

{
  "type": "object",
  "properties": {
    "answer": {
      "type": "string",
      "description": "respuesta a la pregunta del usuario"
    },
    "source": {
      "type": "string",
      "description": "fuente utilizada para responder, debe ser un sitio web."
    }
  },
  "required": ["answer", "source"],
  "additionalProperties": false,
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Cualquier salida generada por el LLM será analizada y validada con zod.

Documentando el proceso en Jupyter

Podemos generar un diagrama visual con LangChain.js:

const image = await chain.getGraph().drawMermaidPng();
const arrayBuffer = await image.arrayBuffer();

Deno.jupyter.image(new Uint8Array(arrayBuffer));

Haciendo una pregunta al modelo ❓

Ejemplo de consulta con la cadena creada:

const response = await chain.invoke({
  question: "¿Qué es Deno?",
  format_instructions: parser.getFormatInstructions(),
});

console.log(response);

Salida esperada:

{
  "answer": "Deno es un entorno de ejecución para JavaScript y TypeScript..",
  "source": "https://deno.dev"
}

Conclusión

Descubrí que Deno y Jupyter proporcionan un entorno productivo y divertido para experimentar con IA localmente.

Puntos clave:

✅ La mayor parte de la configuración se centra en correr un LLM local, pero puedes intercambiarlo por una API (como OpenAI o Anthropic).
Deno es increíblemente eficiente y sin fricciones.
Jupyter Notebooks facilita la exploración iterativa y la documentación.

Resultado: Se ha convertido en mi entorno preferido para aprender y prototipar con IA.

Vistas: 0