Guía gratuita · Actualizada en septiembre de 2026

Guía práctica de IA para empresas: de la primera llamada a producción

13 capítulos para aprender a construir soluciones reales con inteligencia artificial. Con ejemplos en TypeScript listos para desplegar en Vercel y Supabase.

13 capítulosTypeScriptVercel + SupabasePor Gerardo Sanz Pérez

Para quién es: perfiles técnicos y responsables de pymes y organizaciones que ya han probado un chat de IA y quieren dar el paso a integrarla en sus procesos. Los capítulos 1, 2 y 13 no requieren programar.

Cómo usarla: cada capítulo termina con algo que funciona. Todo el código está comprobado con TypeScript en modo estricto.

Capítulo 01

Qué es (y qué no es) un modelo de lenguaje

Un modelo de lenguaje como Claude predice, palabra a palabra, la continuación más probable de un texto. Ha aprendido de enormes cantidades de texto y código, y por eso redacta, resume, traduce, razona sobre documentos y escribe programas.

Tres ideas que evitan el 80 % de las decepciones:

  • No es una base de datos. No «sabe» tus precios ni tu horario. Si se lo das en el contexto, lo usa; si no, puede inventarlo.
  • Trabaja con tokens. Un token son unas ¾ partes de una palabra. Pagas por tokens de entrada y de salida, y cada modelo tiene un límite de contexto.
  • No recuerda entre llamadas. Cada petición a la API es independiente. La «memoria» de una conversación es el historial que tú le reenvías.

Qué modelo usar

Anthropic ofrece varias familias. Como regla práctica: un modelo rápido y barato (Haiku) para clasificar, extraer y resumir en volumen; uno equilibrado (Sonnet) para la mayoría de aplicaciones; y los más potentes (Opus y superiores) para razonamiento complejo y agentes. En esta guía usamos claude-sonnet-5. Consulta la página oficial de modelos antes de elegir, porque cambian a menudo.

↑ Índice

Capítulo 02

Pedir bien: prompts que funcionan

La calidad de la respuesta depende sobre todo de la calidad de la petición. Un buen prompt de sistema tiene cuatro partes: rol, contexto, reglas y ejemplos. Separarlas con etiquetas tipo XML ayuda al modelo a no mezclarlas.

Prompt de sistematext
Eres el asistente de atención al cliente de una clínica dental de Gijón.

<contexto>
Horario: L-V 9:00-14:00 y 16:00-20:00. Urgencias: 985 000 000.
</contexto>

<reglas>
- Responde en español, en menos de 80 palabras.
- Nunca des diagnósticos: deriva siempre al dentista.
- Si no sabes algo, dilo y ofrece llamar a recepción.
</reglas>

<ejemplo>
Paciente: ¿Abrís el sábado?
Asistente: Los sábados no abrimos. Te esperamos de lunes a viernes, de 9 a 14 y de 16 a 20 h.
</ejemplo>

Buenas prácticas

  • Sé explícito: «en menos de 80 palabras» funciona mejor que «sé breve».
  • Explica el porqué de las reglas: el modelo generaliza mejor cuando entiende la intención.
  • Da uno o dos ejemplos del formato exacto que esperas.
  • Para tareas complejas, pide que razone antes de responder.
  • Pon los documentos largos al principio y la pregunta al final.

↑ Índice

Capítulo 03

Tu primera llamada a la API con TypeScript

Necesitas Node.js 20 o superior y una clave de API de la consola de Anthropic. Crea un proyecto e instala el SDK oficial:

Terminalbash
npm init -y
npm pkg set type=module
npm i @anthropic-ai/sdk
npm i -D typescript tsx @types/node
.env.localbash
# .env.local  (nunca al repositorio; en Vercel: Settings → Environment Variables)
ANTHROPIC_API_KEY=sk-ant-...
primera-llamada.tsts
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic(); // lee ANTHROPIC_API_KEY del entorno

const msg = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  system: "Eres el asistente de una academia de Oviedo. Respondes en español, breve y claro.",
  messages: [{ role: "user", content: "¿Qué horario tiene el curso de ofimática?" }],
});

for (const block of msg.content) {
  if (block.type === "text") console.log(block.text);
}
console.log(msg.usage); // tokens de entrada y salida: tu coste real

Ejecútalo con npx tsx --env-file=.env.local primera-llamada.ts. Fíjate en tres piezas: system define el comportamiento, messages es la conversación y usage te dice cuántos tokens has gastado.

↑ Índice

Capítulo 04

Conversaciones y respuestas en tiempo real

Para un chat necesitas dos cosas: guardar el historial y mostrar la respuesta mientras se genera (streaming). La experiencia de usuario cambia por completo: el primer texto aparece en menos de un segundo.

conversacion.tsts
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const historial: Anthropic.MessageParam[] = [];

export async function responder(texto: string): Promise<string> {
  historial.push({ role: "user", content: texto });

  const stream = client.messages.stream({
    model: "claude-sonnet-5",
    max_tokens: 1024,
    messages: historial,
  });
  stream.on("text", (t) => process.stdout.write(t)); // se ve mientras escribe

  const final = await stream.finalMessage();
  const respuesta = final.content
    .map((b) => (b.type === "text" ? b.text : ""))
    .join("");
  historial.push({ role: "assistant", content: respuesta });
  return respuesta;
}

En producción, el historial no vive en memoria sino en una tabla de Supabase (por ejemplo mensajes con conversacion_id, rol y contenido). Así cada cliente recupera su conversación aunque vuelva días después. Es exactamente lo que hace un asistente de WhatsApp con historial por contacto.

↑ Índice

Capítulo 05

Datos estructurados y herramientas (tool use)

Aquí la IA deja de ser un chat y empieza a trabajar dentro de tus procesos. Dos técnicas:

1. Salida estructurada

Pides un JSON con un esquema concreto y el SDK te lo devuelve validado y tipado. Ideal para leer facturas, clasificar correos o rellenar fichas.

extraer-factura.tsts
import Anthropic from "@anthropic-ai/sdk";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { z } from "zod";

const client = new Anthropic();

const Factura = z.object({
  proveedor: z.string(),
  fecha: z.string().describe("Formato AAAA-MM-DD"),
  total: z.number(),
  iva: z.number(),
});

const texto = "Suministros Nalón SL · 12/09/2026 · Base 200 € · IVA 21 % 42 € · Total 242 €";

const res = await client.messages.parse({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: `Extrae los datos de esta factura:\n${texto}` }],
  output_config: { format: zodOutputFormat(Factura) },
});

console.log(res.parsed_output); // objeto tipado: { proveedor, fecha, total, iva }

2. Herramientas

Describes funciones de tu sistema y el modelo decide cuándo llamarlas. Tu código las ejecuta y le devuelve el resultado. El modelo nunca toca tu base de datos directamente: tú controlas qué hace cada herramienta.

herramientas.tsts
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const tools: Anthropic.Tool[] = [
  {
    name: "consultar_plazas",
    description: "Devuelve las plazas libres de un curso por su código.",
    input_schema: {
      type: "object",
      properties: { codigo: { type: "string", description: "Código del curso, p. ej. ADGG0208" } },
      required: ["codigo"],
    },
  },
];

async function consultarPlazas(codigo: string) {
  // Aquí iría tu consulta real (Supabase, ERP, hoja de cálculo…)
  return { codigo, plazasLibres: 4 };
}

const messages: Anthropic.MessageParam[] = [
  { role: "user", content: "¿Quedan plazas en el ADGG0208?" },
];

let res = await client.messages.create({ model: "claude-sonnet-5", max_tokens: 1024, tools, messages });

while (res.stop_reason === "tool_use") {
  messages.push({ role: "assistant", content: res.content });
  const resultados: Anthropic.ToolResultBlockParam[] = [];
  for (const b of res.content) {
    if (b.type === "tool_use" && b.name === "consultar_plazas") {
      const { codigo } = b.input as { codigo: string };
      resultados.push({ type: "tool_result", tool_use_id: b.id, content: JSON.stringify(await consultarPlazas(codigo)) });
    }
  }
  messages.push({ role: "user", content: resultados });
  res = await client.messages.create({ model: "claude-sonnet-5", max_tokens: 1024, tools, messages });
}

console.log(res.content.find((b) => b.type === "text")?.text);

↑ Índice

Capítulo 06

Conectar la IA con tus documentos (RAG con Supabase)

RAG (Retrieval-Augmented Generation) significa: antes de preguntar al modelo, buscas en tus documentos los fragmentos relevantes y se los pasas como contexto. Así responde con tu información y no con la de internet.

  1. Divide tus documentos (normativa, catálogo, preguntas frecuentes) en trozos de unos pocos párrafos.
  2. Convierte cada trozo en un vector numérico (embedding) y guárdalo en Postgres con pgvector.
  3. Con cada pregunta, calcula su vector, busca los trozos más parecidos y pásalos a Claude.
Supabase · SQL Editorsql
-- 1) Activa pgvector y crea la tabla de trozos de documentos
create extension if not exists vector;

create table documentos (
  id bigint generated always as identity primary key,
  contenido text not null,
  embedding vector(384)          -- 384 dimensiones = modelo gte-small
);

create index on documentos using hnsw (embedding vector_cosine_ops);

-- 2) Función de búsqueda por similitud que llamarás con supabase.rpc()
create or replace function buscar_documentos(consulta vector(384), limite int default 5)
returns table (id bigint, contenido text, similitud float)
language sql stable as $$
  select id, contenido, 1 - (embedding <=> consulta) as similitud
  from documentos
  order by embedding <=> consulta
  limit limite;
$$;

-- 3) Seguridad: sin políticas, nadie lee la tabla desde el navegador
alter table documentos enable row level security;

Supabase incluye un modelo de embeddings pequeño (gte-small) que puedes usar desde una Edge Function, sin contratar otro proveedor:

supabase/functions/embedding/index.tsts
// supabase/functions/embedding/index.ts  (Edge Function, Deno)
const session = new Supabase.ai.Session("gte-small");

Deno.serve(async (req) => {
  const { texto } = await req.json();
  const embedding = await session.run(texto, { mean_pool: true, normalize: true });
  return Response.json({ embedding });
});
preguntar.tsts
import Anthropic from "@anthropic-ai/sdk";
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);
const client = new Anthropic();

// embedding: vector de la pregunta, calculado con el mismo modelo que usaste al indexar
export async function preguntar(pregunta: string, embedding: number[]) {
  const { data: trozos, error } = await supabase.rpc("buscar_documentos", {
    consulta: embedding,
    limite: 5,
  });
  if (error) throw error;

  const contexto = (trozos as { contenido: string }[]).map((t) => t.contenido).join("\n---\n");

  const res = await client.messages.create({
    model: "claude-sonnet-5",
    max_tokens: 1024,
    system:
      "Responde solo con la información del contexto. Si no está, di que no lo sabes.\n\n<contexto>\n" +
      contexto + "\n</contexto>",
    messages: [{ role: "user", content: pregunta }],
  });
  return res.content.find((b) => b.type === "text")?.text;
}

↑ Índice

Capítulo 07

MCP: un enchufe estándar para herramientas y datos

El Model Context Protocol es un estándar abierto para conectar asistentes de IA con sistemas externos. En lugar de programar la integración para cada aplicación, escribes un servidor MCP una vez y lo usan Claude Desktop, Claude Code, tus agentes y otros clientes compatibles.

Ejemplo: un servidor MCP que da acceso a la ficha de alumnos de una academia.

Terminalbash
npm i @modelcontextprotocol/sdk zod
server.tsts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({ name: "academia", version: "1.0.0" });

server.registerTool(
  "buscar_alumno",
  {
    title: "Buscar alumno",
    description: "Busca un alumno por DNI y devuelve sus matrículas activas",
    inputSchema: { dni: z.string().length(9) },
  },
  async ({ dni }) => {
    const matriculas = [{ curso: "ADGG0208", estado: "activa" }]; // tu consulta real
    return { content: [{ type: "text", text: JSON.stringify({ dni, matriculas }) }] };
  }
);

await server.connect(new StdioServerTransport());

Para usarlo desde Claude Desktop o Claude Code, se registra en su configuración:

Configuración MCPjson
{
  "mcpServers": {
    "academia": {
      "command": "npx",
      "args": ["tsx", "/ruta/a/mcp-academia/server.ts"]
    }
  }
}

↑ Índice

Capítulo 08

Agentes: la IA que ejecuta tareas de principio a fin

Un agente es un modelo en bucle: planifica, usa herramientas, revisa el resultado y decide el siguiente paso hasta terminar. Programar ese bucle a mano (capítulo 5) es posible, pero el Claude Agent SDK te lo da hecho, con herramientas para leer y escribir archivos, buscar, ejecutar comandos y conectar servidores MCP.

Terminalbash
npm i @anthropic-ai/claude-agent-sdk
agente.tsts
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const mensaje of query({
  prompt: "Revisa los CSV de ./ventas, detecta duplicados y escribe un resumen en informe.md",
  options: {
    model: "claude-sonnet-5",
    allowedTools: ["Read", "Glob", "Grep", "Write"],
    permissionMode: "acceptEdits",
    maxTurns: 20,
  },
})) {
  if (mensaje.type === "result" && mensaje.subtype === "success") {
    console.log(mensaje.result);
    console.log(`Coste: ${mensaje.total_cost_usd} USD`);
  }
}

Cuándo usar un agente

  • Sí: tareas de varios pasos con resultado verificable (conciliar ficheros, preparar informes, migrar datos, revisar documentación).
  • No: respuestas que deben ser inmediatas o que siguen siempre el mismo camino. Ahí basta una llamada con herramientas.

↑ Índice

Capítulo 09

Skills: enseñar procedimientos a la IA

Una skill es una carpeta con un archivo SKILL.md (instrucciones) y, si hace falta, plantillas, scripts o datos. El modelo solo ve el nombre y la descripción; cuando la tarea encaja, carga el resto. Así puedes tener decenas de procedimientos sin llenar el contexto.

.claude/skills/presupuestos/SKILL.mdmd
---
name: presupuestos
description: Prepara presupuestos de formación y consultoría con las tarifas
  y condiciones vigentes. Úsala cuando pidan un presupuesto o una propuesta económica.
---

# Presupuestos

1. Lee `tarifas.md` para el precio por jornada y los descuentos.
2. Usa siempre la plantilla `plantilla.md` (no inventes apartados).
3. IVA: 21 % salvo formación exenta (indícalo si aplica).
4. Validez de la oferta: 30 días.
5. Guarda el resultado como `presupuesto-<cliente>.md`.

La descripción es lo más importante: decide cuándo se activa la skill. Escríbela como «qué hace + cuándo usarla».

usar-skill.tsts
import { query } from "@anthropic-ai/claude-agent-sdk";

// Carga las skills de .claude/skills/ del proyecto y activa solo la que queremos
for await (const m of query({
  prompt: "Prepara el presupuesto para Talleres Llanera: 3 jornadas de formación en IA",
  options: {
    settingSources: ["project"],
    skills: ["presupuestos"],
    allowedTools: ["Read", "Write"],
  },
})) {
  if (m.type === "result" && m.subtype === "success") console.log(m.result);
}

↑ Índice

Capítulo 10

Programar con un asistente: Claude Code

Claude Code es un asistente de programación que trabaja en tu terminal o editor: lee el proyecto, propone cambios, ejecuta pruebas y hace commits. No sustituye a quien programa. Multiplica a quien sabe qué quiere construir.

Terminalbash
npm i -g @anthropic-ai/claude-code
cd mi-proyecto
claude

La pieza clave es el archivo CLAUDE.md en la raíz del proyecto: las reglas que el asistente leerá siempre.

CLAUDE.mdmd
# CLAUDE.md — reglas del proyecto

- Stack: Next.js (App Router) + TypeScript estricto + Supabase.
- Nunca uses la service_role key en código de cliente.
- Toda tabla nueva lleva RLS activado y sus políticas en la misma migración.
- Textos de la interfaz en español de España.
- Antes de terminar: `npm run lint && npm run build` sin errores.

Flujo de trabajo que funciona

  1. Explorar: «Lee el módulo de reservas y explícame cómo funciona». Aún sin tocar nada.
  2. Planificar: «Propón un plan para añadir cancelaciones». Revisa el plan antes de aprobarlo.
  3. Implementar en pasos pequeños, con pruebas.
  4. Revisar el diff como revisarías el de un compañero.

↑ Índice

Capítulo 11

Tareas programadas y automatizaciones

Gran parte del valor de la IA en una pyme no está en el chat, sino en procesos que corren solos: el resumen diario de consultas, la clasificación del correo entrante, el aviso de facturas pendientes.

Con Vercel, una tarea programada es una ruta de tu aplicación más una línea en vercel.json:

vercel.json · lunes a viernes a las 7:00 UTCjson
{
  "crons": [
    { "path": "/api/resumen-diario", "schedule": "0 7 * * 1-5" }
  ]
}
app/api/resumen-diario/route.tsts
// app/api/resumen-diario/route.ts (Next.js en Vercel)
import Anthropic from "@anthropic-ai/sdk";
import { createClient } from "@supabase/supabase-js";

export async function GET(req: Request) {
  // Vercel envía este secreto en las llamadas del cron: así nadie más puede dispararlo
  if (req.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response("No autorizado", { status: 401 });
  }

  const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);
  const ayer = new Date(Date.now() - 86_400_000).toISOString();
  const { data: consultas } = await supabase
    .from("consultas")
    .select("texto, canal")
    .gte("creado_en", ayer);

  const res = await new Anthropic().messages.create({
    model: "claude-haiku-4-5",
    max_tokens: 800,
    messages: [{
      role: "user",
      content: `Resume en 5 viñetas los temas más repetidos:\n${JSON.stringify(consultas)}`,
    }],
  });

  const resumen = res.content.find((b) => b.type === "text")?.text ?? "";
  await supabase.from("resumenes").insert({ fecha: ayer.slice(0, 10), resumen });
  return Response.json({ ok: true });
}

Fíjate en dos decisiones: se protege con CRON_SECRET y usa claude-haiku-4-5, porque resumir es una tarea sencilla y así el coste es mínimo.

↑ Índice

Capítulo 12

Desplegar: Vercel + Supabase en producción

La arquitectura recomendada para una pyme es sencilla y barata de mantener:

  • Vercel: la web y las rutas de API en Next.js. Cada git push publica una versión nueva y cada rama tiene su URL de prueba.
  • Supabase: base de datos Postgres, autenticación, almacenamiento de archivos, pgvector y Edge Functions.
  • Anthropic API: llamada siempre desde el servidor, nunca desde el navegador.
Variables de entornobash
# .env.local  (nunca al repositorio; en Vercel: Settings → Environment Variables)
ANTHROPIC_API_KEY=...
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_ANON_KEY=...            # pública: solo sirve con RLS bien configurado
SUPABASE_SERVICE_ROLE_KEY=...    # secreta: solo en el servidor
CRON_SECRET=...                  # protege tus tareas programadas

Seguridad a nivel de fila (RLS)

En Supabase, la clave pública viaja al navegador. Lo que protege tus datos son las políticas RLS: reglas en la base de datos que deciden qué filas ve cada usuario.

Política RLSsql
-- Cada usuario ve solo las conversaciones de su empresa
alter table conversaciones enable row level security;

create policy "leer_mi_empresa" on conversaciones
  for select to authenticated
  using (empresa_id = (select empresa_id from perfiles where id = auth.uid()));

Controlar el coste

  • Guarda usage de cada llamada en una tabla y revisa el gasto por cliente y por función.
  • Fija límites de gasto en la consola de Anthropic.
  • Usa el modelo más pequeño que cumpla y aprovecha el prompt caching para prompts largos que se repiten.

↑ Índice

Capítulo 13

IA responsable: datos, normativa y calidad

Una solución de IA que funciona pero no cumple la normativa es un riesgo, no un activo. Cuatro frentes:

Protección de datos (RGPD)

  • Minimiza: envía al modelo solo los datos necesarios. Seudonimiza cuando puedas.
  • Informa en tu política de privacidad de qué proveedores tratan los datos (Anthropic, Vercel, Supabase) y firma sus acuerdos de encargado del tratamiento.
  • Elige región de datos en la UE para Supabase cuando trates datos personales.

Reglamento Europeo de IA (AI Act)

Desde febrero de 2025 es exigible la alfabetización en IA: las organizaciones que usan IA deben asegurar que su personal tiene conocimientos suficientes. Las demás obligaciones entran por fases, entre ellas la de transparencia (avisar de que se está hablando con una IA) y las de sistemas de alto riesgo. Revisa el calendario oficial antes de cada proyecto y, en cualquier caso, identifica siempre tu chatbot como IA: es buena práctica y genera confianza.

Evaluar antes de publicar

  • Crea un conjunto de 20 a 50 preguntas reales con la respuesta esperada.
  • Ejecútalo con cada cambio de prompt o de modelo y compara resultados.
  • Incluye preguntas trampa: fuera de tema, datos que no tiene, intentos de saltarse las reglas.

Supervisión humana

Define qué decisiones nunca toma la IA sola: precios especiales, reclamaciones, cualquier cosa con consecuencias legales o de salud. La IA prepara, la persona decide.

↑ Índice

¿Lo aplicamos a tu organización?

Formación a medida para tu equipo, auditoría tecnológica o acompañamiento en tu primer proyecto de IA.

Hablemos