initial commit: slides ready + upgraded
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Módulo 5: Agentes
|
||||
|
||||
Tools, Structured Output, Runtime y Human-in-the-Loop
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
LLMs que pueden actuar en el mundo real
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Qué es un Agente?
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
Un **agente** es un sistema que usa un LLM para decidir qué acciones tomar
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<div class="grid grid-cols-2 gap-8">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-red-500 pl-4 bg-red-50 dark:bg-red-900/20 p-4">
|
||||
<h3 class="text-base font-bold mb-3">❌ Sin Agentes</h3>
|
||||
<p class="text-xs mb-2">Flujo fijo y predecible</p>
|
||||
<p class="text-xs mb-2">Usuario → LLM → Respuesta</p>
|
||||
<p class="text-xs opacity-70">El LLM solo genera texto</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-4">
|
||||
<h3 class="text-base font-bold mb-3">✅ Con Agentes</h3>
|
||||
<p class="text-xs mb-2">Flujo dinámico y adaptativo</p>
|
||||
<p class="text-xs mb-2">Usuario → LLM → Tool → LLM → Respuesta</p>
|
||||
<p class="text-xs opacity-70">El LLM decide qué herramientas usar</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Casos de Uso de Agentes
|
||||
|
||||
<div class="mt-6 grid grid-cols-2 gap-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-3 bg-blue-50 dark:bg-blue-900/20 p-2">
|
||||
<h3 class="text-sm font-bold mb-1">🔍 Búsqueda y análisis</h3>
|
||||
<p>Buscar información en APIs, bases de datos o web</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-3 bg-green-50 dark:bg-green-900/20 p-2">
|
||||
<h3 class="text-sm font-bold mb-1">🛠️ Automatización</h3>
|
||||
<p>Enviar emails, crear tickets, actualizar sistemas</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-3 bg-purple-50 dark:bg-purple-900/20 p-2">
|
||||
<h3 class="text-sm font-bold mb-1">💼 Asistentes empresariales</h3>
|
||||
<p>Consultar CRM, generar reportes, analizar datos</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-3 bg-orange-50 dark:bg-orange-900/20 p-2">
|
||||
<h3 class="text-sm font-bold mb-1">🤖 Agentes autónomos</h3>
|
||||
<p>Tomar decisiones complejas con múltiples pasos</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# createAgent: Creando el Agente
|
||||
|
||||
<div class="mt-6 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-4">
|
||||
|
||||
**createAgent** es la forma estándar de crear agentes en LangChain v1
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { createAgent } from "langchain";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest", // Modelo como string
|
||||
tools: [weatherTool], // Array de tools
|
||||
systemPrompt: "Eres un asistente útil.",
|
||||
});
|
||||
|
||||
const result = await agent.invoke({
|
||||
messages: [{ role: "user", content: "¿Qué tiempo hace en Madrid?" }]
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs opacity-70">
|
||||
El agente automatiza el ciclo: llamar al LLM -> ejecutar tools -> procesar resultados -> repetir
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Configuración del Modelo
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**Opción 1: String con formato `provider:model`**
|
||||
|
||||
```typescript
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest", // Mistral
|
||||
// model: "openai:gpt-4.1", // OpenAI
|
||||
// model: "anthropic:claude-sonnet-4-6", // Anthropic
|
||||
tools: [],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Opción 2: Instancia del modelo con configuración avanzada**
|
||||
|
||||
```typescript
|
||||
import { ChatMistralAI } from "@langchain/mistralai";
|
||||
|
||||
const model = new ChatMistralAI({
|
||||
model: "mistral-large-latest",
|
||||
temperature: 0.1,
|
||||
maxTokens: 1000,
|
||||
});
|
||||
|
||||
const agent = createAgent({ model, tools: [] });
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# systemPrompt: Configurando el Comportamiento
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**String simple:**
|
||||
|
||||
```typescript
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [weatherTool],
|
||||
systemPrompt: "Eres un asistente meteorológico. Sé conciso y preciso.",
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**SystemMessage (para features avanzados como cache de Anthropic):**
|
||||
|
||||
```typescript
|
||||
import { SystemMessage } from "langchain";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "anthropic:claude-sonnet-4-6",
|
||||
tools: [weatherTool],
|
||||
systemPrompt: new SystemMessage({
|
||||
content: [
|
||||
{ type: "text", text: "Eres un experto en clima...", cache_control: { type: "ephemeral" } }
|
||||
],
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Tools: Definiendo Herramientas
|
||||
|
||||
<div class="mt-6 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const weatherTool = tool(
|
||||
async ({ location }) => {
|
||||
// Llamar a API del tiempo
|
||||
return `El tiempo en ${location} es soleado, 22°C`;
|
||||
},
|
||||
{
|
||||
name: "get_weather",
|
||||
description: "Obtiene el tiempo actual de una ubicación",
|
||||
schema: z.object({
|
||||
location: z.string().describe("Ciudad o ubicación"),
|
||||
}),
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
// El agente decide automáticamente cuándo usar cada tool
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [weatherTool, calculatorTool, searchTool],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Streaming: Modos de Transmisión
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**`updates`**: Emite evento después de cada paso del agente
|
||||
|
||||
```typescript
|
||||
for await (const chunk of await agent.stream(
|
||||
{ messages: [{ role: "user", content: "¿Tiempo en Madrid?" }] },
|
||||
{ streamMode: "updates" }
|
||||
)) {
|
||||
console.log(chunk);
|
||||
// { model: { messages: [AIMessage con tool_call] } }
|
||||
// { tools: { messages: [ToolMessage con resultado] } }
|
||||
// { model: { messages: [AIMessage respuesta final] } }
|
||||
}
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**`values`**: Emite el estado completo después de cada paso
|
||||
|
||||
```typescript
|
||||
for await (const chunk of await agent.stream(
|
||||
{ messages: [{ role: "user", content: "¿Tiempo en Madrid?" }] },
|
||||
{ streamMode: "values" }
|
||||
)) {
|
||||
console.log(chunk.messages); // Array completo de mensajes hasta ese punto
|
||||
}
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Streaming: Tokens y Mensajes
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**`messages`**: Stream de tokens del LLM + metadata
|
||||
|
||||
```typescript
|
||||
for await (const [mode, chunk] of await agent.stream(
|
||||
{ messages: [{ role: "user", content: "Explica qué es TypeScript" }] },
|
||||
{ streamMode: ["updates", "messages"] }
|
||||
)) {
|
||||
if (mode === "messages") {
|
||||
const [token, metadata] = chunk;
|
||||
if (token.content) {
|
||||
process.stdout.write(token.content); // Token a token
|
||||
}
|
||||
} else if (mode === "updates") {
|
||||
// Paso completo del agente
|
||||
console.log("\n[Paso completado]", Object.keys(chunk));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs opacity-80">
|
||||
Combina múltiples modos: `streamMode: ["updates", "messages"]`
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Checkpointer: MemorySaver
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**MemorySaver**: Persistencia en memoria (desarrollo/testing)
|
||||
|
||||
```typescript
|
||||
import { createAgent } from "langchain";
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [weatherTool],
|
||||
checkpointer: new MemorySaver(), // En memoria RAM
|
||||
});
|
||||
|
||||
const config = { configurable: { thread_id: "conv-1" } };
|
||||
|
||||
// Primera conversación
|
||||
await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "Hola, soy María" }] }, config
|
||||
);
|
||||
|
||||
// Segunda conversación - recuerda el contexto
|
||||
await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "¿Cómo me llamo?" }] }, config
|
||||
);
|
||||
// "Tu nombre es María"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Checkpointer: SqliteSaver
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**SqliteSaver**: Persistencia en SQLite (local)
|
||||
|
||||
```bash
|
||||
npm install @langchain/langgraph-checkpoint-sqlite
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { createAgent } from "langchain";
|
||||
import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
|
||||
|
||||
const checkpointer = SqliteSaver.fromConnString("./agent_memory.db");
|
||||
await checkpointer.setup(); // Crear tablas
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [weatherTool],
|
||||
checkpointer,
|
||||
});
|
||||
|
||||
// El estado persiste aunque reinicies la aplicación
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs opacity-80">
|
||||
Ideal para desarrollo local y aplicaciones de usuario único
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Checkpointer: PostgresSaver
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
**PostgresSaver**: Persistencia en PostgreSQL (producción)
|
||||
|
||||
```bash
|
||||
npm install @langchain/langgraph-checkpoint-postgres
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { createAgent } from "langchain";
|
||||
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
|
||||
|
||||
const DB_URI = "postgresql://user:pass@localhost:5432/mydb";
|
||||
const checkpointer = PostgresSaver.fromConnString(DB_URI);
|
||||
await checkpointer.setup();
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [weatherTool],
|
||||
checkpointer,
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs opacity-80">
|
||||
También disponibles: **MongoDB** (`@langchain/langgraph-checkpoint-mongodb`),
|
||||
**Redis** (`@langchain/langgraph-checkpoint-redis`), y **Custom** (implementar `BaseCheckpointSaver`)
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Middleware: Arquitectura
|
||||
|
||||
<div class="mt-6 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-4">
|
||||
|
||||
**Middleware**: Hooks que interceptan el flujo del agente en puntos clave
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="space-y-3 text-xs">
|
||||
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-2">
|
||||
<code class="font-bold">beforeAgent</code> - Antes de iniciar el agente
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-2">
|
||||
<code class="font-bold">beforeModel</code> - Antes de cada llamada al LLM
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-2">
|
||||
<code class="font-bold">wrapModelCall</code> - Envuelve la llamada al LLM (interceptar/modificar)
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 p-2">
|
||||
<code class="font-bold">wrapToolCall</code> - Envuelve la ejecución de tools
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-red-500 pl-4 bg-red-50 dark:bg-red-900/20 p-2">
|
||||
<code class="font-bold">afterModel</code> - Después de cada respuesta del LLM
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-cyan-500 pl-4 bg-cyan-50 dark:bg-cyan-900/20 p-2">
|
||||
<code class="font-bold">afterAgent</code> - Después de completar el agente
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Middleware Custom
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { createAgent, createMiddleware } from "langchain";
|
||||
|
||||
const loggingMiddleware = createMiddleware({
|
||||
name: "LoggingMiddleware",
|
||||
beforeModel: (state) => {
|
||||
console.log(`Llamando modelo con ${state.messages.length} mensajes`);
|
||||
return; // No modificar estado
|
||||
},
|
||||
afterModel: (state) => {
|
||||
const lastMsg = state.messages[state.messages.length - 1];
|
||||
console.log(`Modelo respondió: ${lastMsg.content?.slice(0, 50)}...`);
|
||||
return;
|
||||
},
|
||||
});
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [weatherTool],
|
||||
middleware: [loggingMiddleware],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# dynamicSystemPromptMiddleware
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import * as z from "zod";
|
||||
import { createAgent, dynamicSystemPromptMiddleware } from "langchain";
|
||||
|
||||
const contextSchema = z.object({
|
||||
userRole: z.enum(["expert", "beginner"]),
|
||||
});
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [searchTool],
|
||||
contextSchema,
|
||||
middleware: [
|
||||
dynamicSystemPromptMiddleware<z.infer<typeof contextSchema>>((state, runtime) => {
|
||||
const userRole = runtime.context.userRole;
|
||||
let prompt = "Eres un asistente útil.";
|
||||
|
||||
if (userRole === "expert") {
|
||||
prompt += " Proporciona respuestas técnicas detalladas.";
|
||||
} else {
|
||||
prompt += " Explica conceptos de forma simple, sin jerga técnica.";
|
||||
}
|
||||
return prompt;
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "Explica machine learning" }] },
|
||||
{ context: { userRole: "beginner" } }
|
||||
);
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# toolCallLimitMiddleware: Limitar Tools
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { createAgent, toolCallLimitMiddleware } from "langchain";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [searchTool, databaseTool, scraperTool],
|
||||
middleware: [
|
||||
// Límite global: máx 20 por thread, 10 por run
|
||||
toolCallLimitMiddleware({ threadLimit: 20, runLimit: 10 }),
|
||||
|
||||
// Límite específico para búsquedas
|
||||
toolCallLimitMiddleware({
|
||||
toolName: "search",
|
||||
threadLimit: 5,
|
||||
runLimit: 3,
|
||||
}),
|
||||
|
||||
// Límite estricto para scraping (lanza error si excede)
|
||||
toolCallLimitMiddleware({
|
||||
toolName: "scrape_webpage",
|
||||
runLimit: 2,
|
||||
exitBehavior: "error", // "continue" | "error" | "end"
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-3 text-xs opacity-80">
|
||||
Requiere checkpointer para `threadLimit`. `runLimit` se resetea en cada invocación.
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# summarizationMiddleware: Resumir Historial
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { createAgent, summarizationMiddleware } from "langchain";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [searchTool, calculatorTool],
|
||||
middleware: [
|
||||
summarizationMiddleware({
|
||||
model: "mistral:mistral-small-latest", // Modelo para resumir (más barato)
|
||||
trigger: { tokens: 4000 }, // Resumir cuando supere 4000 tokens
|
||||
keep: { messages: 20 }, // Mantener los últimos 20 mensajes
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs opacity-80">
|
||||
|
||||
**Funcionamiento automático:**
|
||||
|
||||
1. Detecta cuando el historial supera el límite de tokens
|
||||
2. Resume los mensajes antiguos usando el modelo especificado
|
||||
3. Reemplaza permanentemente los mensajes antiguos por el resumen
|
||||
4. Mantiene los mensajes recientes intactos para contexto
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Middleware: Limitar Historial (Trim)
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { RemoveMessage } from "@langchain/core/messages";
|
||||
import { createAgent, createMiddleware } from "langchain";
|
||||
import { MemorySaver, REMOVE_ALL_MESSAGES } from "@langchain/langgraph";
|
||||
|
||||
const trimMessages = createMiddleware({
|
||||
name: "TrimMessages",
|
||||
beforeModel: (state) => {
|
||||
const messages = state.messages;
|
||||
if (messages.length <= 5) return; // No recortar si hay pocos
|
||||
|
||||
// Mantener primer mensaje + últimos 4
|
||||
const firstMsg = messages[0];
|
||||
const recentMsgs = messages.slice(-4);
|
||||
const newMessages = [firstMsg, ...recentMsgs];
|
||||
|
||||
return {
|
||||
messages: [
|
||||
new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),
|
||||
...newMessages,
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [],
|
||||
middleware: [trimMessages],
|
||||
checkpointer: new MemorySaver(),
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Middleware: wrapModelCall
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
Permite interceptar y modificar la llamada al modelo:
|
||||
|
||||
```typescript
|
||||
import { ChatMistralAI } from "@langchain/mistralai";
|
||||
import { createAgent, createMiddleware } from "langchain";
|
||||
|
||||
const basicModel = new ChatMistralAI({ model: "mistral-small-latest" });
|
||||
const advancedModel = new ChatMistralAI({ model: "mistral-large-latest" });
|
||||
|
||||
const dynamicModelSelection = createMiddleware({
|
||||
name: "DynamicModelSelection",
|
||||
wrapModelCall: (request, handler) => {
|
||||
// Elegir modelo según complejidad de la conversación
|
||||
const messageCount = request.messages.length;
|
||||
const model = messageCount > 10 ? advancedModel : basicModel;
|
||||
|
||||
return handler({ ...request, model });
|
||||
},
|
||||
});
|
||||
|
||||
const agent = createAgent({
|
||||
model: basicModel,
|
||||
tools: [searchTool],
|
||||
middleware: [dynamicModelSelection],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Middleware: wrapToolCall
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
Intercepta la ejecución de tools para manejo de errores:
|
||||
|
||||
```typescript
|
||||
import { createAgent, createMiddleware, ToolMessage } from "langchain";
|
||||
|
||||
const handleToolErrors = createMiddleware({
|
||||
name: "HandleToolErrors",
|
||||
wrapToolCall: async (request, handler) => {
|
||||
try {
|
||||
return await handler(request);
|
||||
} catch (error) {
|
||||
// Devolver mensaje de error al modelo para que reintente
|
||||
return new ToolMessage({
|
||||
content: `Error en tool: ${error}. Por favor revisa los parámetros.`,
|
||||
tool_call_id: request.toolCall.id!,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [databaseTool, apiTool],
|
||||
middleware: [handleToolErrors],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Middleware Built-in: Resumen
|
||||
|
||||
<div class="mt-6 text-xs space-y-3">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-2">
|
||||
<code class="font-bold">summarizationMiddleware</code> - Resumir historial cuando supera tokens
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-2">
|
||||
<code class="font-bold">humanInTheLoopMiddleware</code> - Pausar para aprobación humana
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-2">
|
||||
<code class="font-bold">toolCallLimitMiddleware</code> - Limitar llamadas a tools
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 p-2">
|
||||
<code class="font-bold">modelCallLimitMiddleware</code> - Limitar llamadas al modelo
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-red-500 pl-4 bg-red-50 dark:bg-red-900/20 p-2">
|
||||
<code class="font-bold">modelFallbackMiddleware</code> - Fallback a modelos alternativos
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-cyan-500 pl-4 bg-cyan-50 dark:bg-cyan-900/20 p-2">
|
||||
<code class="font-bold">modelRetryMiddleware</code> - Reintentar con backoff exponencial
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-yellow-500 pl-4 bg-yellow-50 dark:bg-yellow-900/20 p-2">
|
||||
<code class="font-bold">piiRedactionMiddleware</code> - Redactar información personal
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Combinando Middleware
|
||||
|
||||
<div class="mt-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import {
|
||||
createAgent,
|
||||
summarizationMiddleware,
|
||||
humanInTheLoopMiddleware,
|
||||
toolCallLimitMiddleware,
|
||||
modelRetryMiddleware,
|
||||
} from "langchain";
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "mistral:mistral-large-latest",
|
||||
tools: [searchTool, sendEmailTool, databaseTool],
|
||||
checkpointer: new MemorySaver(),
|
||||
middleware: [
|
||||
modelRetryMiddleware({ maxRetries: 3, backoffFactor: 2 }),
|
||||
summarizationMiddleware({ model: "mistral:mistral-small-latest", trigger: { tokens: 4000 } }),
|
||||
toolCallLimitMiddleware({ toolName: "search", runLimit: 5 }),
|
||||
humanInTheLoopMiddleware({
|
||||
interruptOn: { send_email: { allowedDecisions: ["approve", "reject"] } },
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-3 text-xs opacity-80">
|
||||
El orden de los middleware importa: se ejecutan en secuencia
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<h1 class="!text-2xl">Human-in-the-Loop</h1>
|
||||
|
||||
<div class="mt-1">
|
||||
|
||||
<v-click>
|
||||
|
||||
````md magic-move
|
||||
```typescript
|
||||
import { createAgent, humanInTheLoopMiddleware } from "langchain";
|
||||
import { Command, MemorySaver } from "@langchain/langgraph";
|
||||
|
||||
const agent = createAgent({
|
||||
model: "gpt-4.1",
|
||||
tools: [sendEmailTool, deleteRecordTool],
|
||||
checkpointer: new MemorySaver(),
|
||||
middleware: [
|
||||
humanInTheLoopMiddleware({
|
||||
interruptOn: {
|
||||
send_email: { allowedDecisions: ["approve", "edit", "reject"] },
|
||||
delete_record: { allowedDecisions: ["approve", "reject"] },
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
```typescript
|
||||
const config = { configurable: { thread_id: "thread-1" } };
|
||||
|
||||
// Se pausa antes de ejecutar tools sensibles
|
||||
let result = await agent.invoke({ messages: [...] }, config);
|
||||
|
||||
// Aprobar y continuar
|
||||
result = await agent.invoke(
|
||||
new Command({ resume: { decisions: [{ type: "approve" }] } }),
|
||||
config
|
||||
);
|
||||
```
|
||||
````
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
---
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Resumen: Agentes LangChain v1
|
||||
|
||||
<div class="mt-6 text-xs space-y-3">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-2">
|
||||
<code class="font-bold">createAgent</code> - Punto de entrada principal
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-2">
|
||||
<code class="font-bold">model</code> - String ("mistral:mistral-large-latest") o instancia ChatModel
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-2">
|
||||
<code class="font-bold">systemPrompt</code> - String o SystemMessage
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 p-2">
|
||||
<code class="font-bold">tools</code> - Array de tools definidas con Zod
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-red-500 pl-4 bg-red-50 dark:bg-red-900/20 p-2">
|
||||
<code class="font-bold">checkpointer</code> - MemorySaver | SqliteSaver | PostgresSaver
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-cyan-500 pl-4 bg-cyan-50 dark:bg-cyan-900/20 p-2">
|
||||
<code class="font-bold">middleware</code> - Array para customización (prompts, límites, HITL)
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-yellow-500 pl-4 bg-yellow-50 dark:bg-yellow-900/20 p-2">
|
||||
<code class="font-bold">stream()</code> - updates | values | messages
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Alternativas en el Ecosistema JS/TS
|
||||
|
||||
Frameworks y SDKs para aplicaciones LLM en TypeScript
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
Pinceladas rápidas del mercado actual (Mayo 2026)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-sm opacity-60">
|
||||
Nota: Nos centramos exclusivamente en opciones JavaScript/TypeScript
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# El Panorama JS/TS para LLMs
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Tres niveles de abstracción
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Frameworks (LangChain, LlamaIndex) │ ← Mayor abstracción
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ SDKs unificados (Vercel AI SDK) │ ← Abstracción media
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ APIs nativas (OpenAI SDK, Anthropic SDK, etc.) │ ← Control total
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### La pregunta no es "cuál es mejor"
|
||||
|
||||
Es: **¿qué nivel de abstracción necesito?**
|
||||
|
||||
- **Prototipo rápido** → API nativa o Vercel AI
|
||||
- **RAG complejo** → LlamaIndex o LangChain
|
||||
- **Agentes sofisticados** → LangGraph / DeepAgents o Vercel AI SDK 6
|
||||
- **UI streaming en React** → Vercel AI SDK
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# LlamaIndex.TS
|
||||
|
||||
El "hermano pequeño" de LlamaIndex (Python)
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Realidad del ecosistema TS
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
|
||||
**Lo bueno**
|
||||
- Especializado en RAG
|
||||
- API similar a la versión Python
|
||||
- Conectores de datos incluidos
|
||||
- Activamente desarrollado
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
**La realidad**
|
||||
- Mejorando rápido (agentes, LiteParse)
|
||||
- Documentación aún por detrás de Python
|
||||
- Comunidad más pequeña
|
||||
- Features llegan después
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Ejemplo básico
|
||||
|
||||
```typescript
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
const doc = new Document({ text: "Contenido..." });
|
||||
const index = await VectorStoreIndex.fromDocuments([doc]);
|
||||
const response = await index.asQueryEngine().query({ query: "Mi pregunta" });
|
||||
```
|
||||
|
||||
<div class="p-3 bg-yellow-500/10 rounded text-sm">
|
||||
⚠️ Ha mejorado mucho, pero si tu proyecto permite Python, LlamaIndex Python sigue siendo más completo.
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Vercel AI SDK
|
||||
|
||||
El SDK moderno para aplicaciones AI en JS/TS
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Por qué destaca
|
||||
|
||||
- **Provider-agnostic**: OpenAI, Anthropic, Google, Mistral, Groq...
|
||||
- **Streaming nativo**: Pensado para UIs reactivas
|
||||
- **React-first**: Hooks listos para usar (`useChat`, `useCompletion`)
|
||||
- **Edge-ready**: Funciona en Vercel, Cloudflare Workers, etc.
|
||||
- **Ligero**: Pocas abstracciones, código directo
|
||||
|
||||
### Ya en v6 — El SDK que más ha crecido
|
||||
|
||||
```typescript
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
import { generateText } from 'ai';
|
||||
|
||||
const { text } = await generateText({
|
||||
model: openai('gpt-4.1'),
|
||||
prompt: 'Explica qué es RAG',
|
||||
});
|
||||
```
|
||||
|
||||
<div class="mt-4 p-3 bg-green-500/10 rounded">
|
||||
✅ Excelente para: Apps Next.js/React, APIs serverless, prototipos rápidos
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Vercel AI SDK 6 - Agentes
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Agent class (nuevo en v6)
|
||||
|
||||
```typescript
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
import { Agent, tool } from 'ai';
|
||||
import { z } from 'zod';
|
||||
|
||||
const agent = new Agent({
|
||||
model: openai('gpt-4.1'),
|
||||
tools: {
|
||||
weather: tool({
|
||||
description: 'Obtiene el clima',
|
||||
parameters: z.object({ city: z.string() }),
|
||||
execute: async ({ city }) => ({ temp: 22, condition: 'Soleado' }),
|
||||
}),
|
||||
},
|
||||
maxSteps: 5,
|
||||
});
|
||||
```
|
||||
|
||||
### ¿Agentes completos?
|
||||
|
||||
| Tiene ✅ | No tiene ❌ |
|
||||
|----------|-------------|
|
||||
| Agent class reutilizable | Persistencia de estado (threads) |
|
||||
| Human-in-the-loop (`needsApproval`) | Tools built-in (code interpreter) |
|
||||
| Tools custom + Streaming | Orquestación multi-agente nativa |
|
||||
|
||||
</v-clicks>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# APIs Nativas de los Providers
|
||||
|
||||
Cada provider tiene su SDK oficial para Node.js/TS
|
||||
|
||||
<v-clicks>
|
||||
|
||||
<div class="grid grid-cols-2 gap-6 mt-4">
|
||||
|
||||
<div>
|
||||
|
||||
### OpenAI SDK
|
||||
```typescript
|
||||
import OpenAI from "openai";
|
||||
const openai = new OpenAI();
|
||||
|
||||
// Function calling nativo
|
||||
const response = await openai.chat.completions.create({
|
||||
model: "gpt-4.1",
|
||||
messages: [...],
|
||||
tools: [{ type: "function", function: {...} }],
|
||||
});
|
||||
```
|
||||
- Assistants API (agentes con estado)
|
||||
- File search, code interpreter built-in
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
### Anthropic SDK + Agent SDK
|
||||
```typescript
|
||||
import Anthropic from "@anthropic-ai/sdk";
|
||||
const anthropic = new Anthropic();
|
||||
|
||||
const message = await anthropic.messages.create({
|
||||
model: "claude-sonnet-4-6",
|
||||
messages: [...],
|
||||
tools: [{ name: "...", input_schema: {...} }],
|
||||
});
|
||||
```
|
||||
- Tool use muy potente
|
||||
- **Claude Agent SDK** (`@anthropic-ai/claude-agent-sdk`)
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Agentes con APIs Nativas?
|
||||
|
||||
Cada provider tiene su propio enfoque
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### OpenAI: Assistants API
|
||||
|
||||
```typescript
|
||||
const assistant = await openai.beta.assistants.create({
|
||||
name: "Analyst", tools: [{ type: "code_interpreter" }], model: "gpt-4.1",
|
||||
});
|
||||
const thread = await openai.beta.threads.create();
|
||||
const run = await openai.beta.threads.runs.create(thread.id, { assistant_id: assistant.id });
|
||||
```
|
||||
|
||||
- Agentes con estado, tools built-in (code interpreter, file search)
|
||||
|
||||
### Anthropic: Claude Agent SDK
|
||||
- Agent SDK con tools built-in (Bash, Read, Edit, Web...)
|
||||
- O tool use manual si prefieres control total
|
||||
|
||||
### Google (Gemini): @google/genai SDK
|
||||
|
||||
```typescript
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
||||
const response = await ai.models.generateContent({
|
||||
model: "gemini-2.5-flash", contents: "Explica RAG",
|
||||
});
|
||||
```
|
||||
|
||||
- Function calling similar a OpenAI
|
||||
- Vertex AI Agents Builder para low-code enterprise
|
||||
|
||||
</v-clicks>
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Comparativa Rápida: Ecosistema JS/TS
|
||||
|
||||
| | LangChain.js | LlamaIndex.TS | Vercel AI | APIs Nativas |
|
||||
|---|:---:|:---:|:---:|:---:|
|
||||
| **Madurez TS** | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||||
| **RAG** | ✅ Completo | ✅ Especializado | ⚠️ Básico | 🔧 Manual |
|
||||
| **Agentes** | ✅ LangGraph | ⚠️ Básico | ✅ Agent class | 🔧 Varía |
|
||||
| **Streaming UI** | ✅ | ⚠️ | ✅✅ | ✅ |
|
||||
| **Curva aprendizaje** | Media-Alta | Media | Baja | Baja |
|
||||
| **Vendor lock-in** | Bajo | Bajo | Bajo | Alto |
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Recomendación Pragmática
|
||||
|
||||
<v-clicks>
|
||||
|
||||
| Caso de uso | Recomendación |
|
||||
|-------------|---------------|
|
||||
| **Prototipo/MVP** | Vercel AI SDK o API nativa |
|
||||
| **RAG** | LangChain.js (o Python si puedes) |
|
||||
| **Agentes complejos** | LangGraph / DeepAgents |
|
||||
| **App React con chat** | Vercel AI SDK |
|
||||
| **Control total** | APIs nativas del provider |
|
||||
|
||||
<div class="p-3 bg-blue-500/10 rounded mt-2 text-sm">
|
||||
|
||||
1. **Empieza simple** → API nativa o Vercel AI
|
||||
2. **Añade complejidad cuando la necesites** → LangChain/LangGraph
|
||||
3. **No sobre-ingenierices** → La herramienta mínima que resuelva el problema
|
||||
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Reflexión Final
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### El ecosistema JS/TS para LLMs está madurando
|
||||
|
||||
- **2023**: LangChain dominaba, pocas alternativas
|
||||
- **2024**: Explosión de opciones, Vercel AI despega
|
||||
- **2025**: Vercel AI SDK 5/6, Claude Agent SDK, DeepAgents
|
||||
- **2026**: Ecosistema TS ya compite seriamente con Python
|
||||
|
||||
### Pero seamos honestos...
|
||||
|
||||
<div class="p-4 bg-yellow-500/10 rounded mt-4">
|
||||
|
||||
**Python sigue adelante** en el ecosistema LLM:
|
||||
- Más ejemplos, tutoriales, comunidad
|
||||
- Features nuevas llegan antes
|
||||
- Mejor soporte de ML/embeddings locales
|
||||
|
||||
Si tu stack lo permite, Python puede ser más productivo para AI.
|
||||
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Cuándo JS/TS es viable para AI?
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Casos donde tiene sentido
|
||||
|
||||
- Tu equipo es **JS/TS puro** y no quieres añadir Python
|
||||
- Necesitas **edge computing** (Cloudflare Workers, Vercel Edge)
|
||||
- Tu aplicación es **web-first** con mucho frontend
|
||||
- Quieres un **stack unificado** (mismo lenguaje front y back)
|
||||
|
||||
### El ecosistema está mejorando
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 mt-4">
|
||||
<div class="p-3 bg-green-500/10 rounded">
|
||||
|
||||
**Vercel AI SDK** está muy maduro y bien mantenido
|
||||
|
||||
</div>
|
||||
<div class="p-3 bg-green-500/10 rounded">
|
||||
|
||||
**LangChain.js** sigue de cerca a Python
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 p-4 bg-blue-500/10 rounded">
|
||||
|
||||
**Conclusión**: JS/TS ya es una opción seria para aplicaciones LLM en producción, especialmente si tu contexto lo favorece.
|
||||
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Eskerrik asko! 🎉
|
||||
|
||||
<div class="mt-12 text-xl">
|
||||
|
||||
Gracias por vuestra atención
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-10 text-base opacity-80">
|
||||
|
||||
¿Dudas o consultas?
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-lg">
|
||||
|
||||
📧 **jabi@nykk.io**
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-10 text-sm opacity-60">
|
||||
|
||||
LangChain.js: De cero a producción
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# ¿Qué es LangChain?
|
||||
|
||||
Framework para desarrollar aplicaciones con Modelos de Lenguaje (LLMs)
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="px-2 py-1 rounded cursor-pointer opacity-80">
|
||||
Conectando LLMs con el mundo real
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Historia de LangChain
|
||||
|
||||
<div class="text-sm">
|
||||
|
||||
<v-clicks>
|
||||
|
||||
<div class="mb-3">
|
||||
<p><strong>Octubre 2022</strong>: Nace LangChain en <strong>Python</strong> 🐍</p>
|
||||
<p class="text-xs opacity-80 ml-4">Creado por Harrison Chase • Enfoque inicial: encadenar prompts y LLMs</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<p><strong>Diciembre 2022</strong>: Lanzamiento de <strong>LangChain.js</strong> ⚡</p>
|
||||
<p class="text-xs opacity-80 ml-4">Apenas 2 meses después • Port oficial • Para desarrolladores web</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<p><strong>2023</strong>: Explosión de adopción en ambos ecosistemas</p>
|
||||
<p class="text-xs opacity-80 ml-4">Múltiples proveedores de LLMs • 110K+ stars en GitHub</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<p><strong>2024-2025</strong>: Maduración hacia producción</p>
|
||||
<p class="text-xs opacity-80 ml-4"><strong>LangGraph</strong>: Control de bajo nivel • <strong>LangSmith</strong>: Observabilidad y testing</p>
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Filosofía de LangChain
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 mt-8">
|
||||
|
||||
<div v-click class="border border-main rounded p-4">
|
||||
<div class="text-2xl mb-2">🔌</div>
|
||||
<div class="font-bold">Flexibilidad</div>
|
||||
<div class="text-sm opacity-80">Sin vendor lock-in</div>
|
||||
</div>
|
||||
|
||||
<div v-click class="border border-main rounded p-4">
|
||||
<div class="text-2xl mb-2">🔗</div>
|
||||
<div class="font-bold">Integración</div>
|
||||
<div class="text-sm opacity-80">LLMs + Datos externos</div>
|
||||
</div>
|
||||
|
||||
<div v-click class="border border-main rounded p-4">
|
||||
<div class="text-2xl mb-2">🤖</div>
|
||||
<div class="font-bold">Agentes</div>
|
||||
<div class="text-sm opacity-80">Decisiones autónomas</div>
|
||||
</div>
|
||||
|
||||
<div v-click class="border border-main rounded p-4">
|
||||
<div class="text-2xl mb-2">🏗️</div>
|
||||
<div class="font-bold">Producción</div>
|
||||
<div class="text-sm opacity-80">Del prototipo a la realidad</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Principios Fundamentales
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 mt-8">
|
||||
|
||||
<div class="border-l-4 border-blue-500 pl-4">
|
||||
<h3 class="text-xl font-bold">1. Flexibilidad de Modelos</h3>
|
||||
<p class="opacity-80">
|
||||
Estandarización de inputs/outputs entre proveedores de LLMs.
|
||||
Cambia fácilmente entre OpenAI, Anthropic, Google, etc.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-green-500 pl-4">
|
||||
<h3 class="text-xl font-bold">2. Orquestación Compleja</h3>
|
||||
<p class="opacity-80">
|
||||
Los modelos coordinan flujos de trabajo con datos externos y herramientas.
|
||||
Más allá de la simple generación de texto.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-purple-500 pl-4">
|
||||
<h3 class="text-xl font-bold">3. Fiabilidad en Producción</h3>
|
||||
<p class="opacity-80">
|
||||
Observabilidad, testing y debugging para aplicaciones reales.
|
||||
El prototipo es fácil, producción es el reto.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Creencias Fundamentales
|
||||
|
||||
<div class="text-sm">
|
||||
|
||||
<v-clicks>
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg">🚀 Los LLMs son tecnología poderosa</h3>
|
||||
<p class="opacity-80">Una innovación que vale la pena construir sobre ella</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg">🔗 Los LLMs son mejores con datos externos</h3>
|
||||
<p class="opacity-80">Combinar LLMs con fuentes de datos externas potencia sus capacidades</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg">🤖 El futuro es agéntico</h3>
|
||||
<p class="opacity-80">Las aplicaciones exhibirán capacidades autónomas y de toma de decisiones</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg">🌱 Estamos en una etapa temprana</h3>
|
||||
<p class="opacity-80">El campo está en constante evolución con espacio sustancial para crecer</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg">💪 Producción es difícil</h3>
|
||||
<p class="opacity-80">Prototipar es fácil, lograr fiabilidad en producción es el verdadero desafío</p>
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Ecosistema LangChain
|
||||
|
||||
<div class="grid grid-cols-3 gap-8 mt-12">
|
||||
|
||||
<div v-click>
|
||||
<div class="text-4xl mb-4">⛓️</div>
|
||||
<div class="font-bold text-xl">LangChain (v1)</div>
|
||||
<div class="text-sm opacity-70 mt-2">Interfaz productiva para agentes</div>
|
||||
<div class="text-sm opacity-70">createAgent + Middleware</div>
|
||||
</div>
|
||||
|
||||
<div v-click>
|
||||
<div class="text-4xl mb-4">🕸️</div>
|
||||
<div class="font-bold text-xl">LangGraph</div>
|
||||
<div class="text-sm opacity-70 mt-2">Motor de runtime confiable</div>
|
||||
<div class="text-sm opacity-70">Persistencia, streaming, control granular</div>
|
||||
</div>
|
||||
|
||||
<div v-click>
|
||||
<div class="text-4xl mb-4">🔍</div>
|
||||
<div class="font-bold text-xl">LangSmith</div>
|
||||
<div class="text-sm opacity-70 mt-2">Observabilidad + Evaluación</div>
|
||||
<div class="text-sm opacity-70">Tracing automático, debugging visual</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Quién usa LangChain?
|
||||
|
||||
<div class="grid grid-cols-2 gap-6 mt-6">
|
||||
|
||||
<div>
|
||||
|
||||
## 🏢 Empresas en Producción
|
||||
|
||||
- **LinkedIn** - Agentes con LangGraph
|
||||
- **Uber** - Sistemas agénticos
|
||||
- **Replit** - Asistentes de código
|
||||
- **Klarna** - Chatbots de atención
|
||||
- **Snowflake** - Integración de datos
|
||||
- **J.P. Morgan** - Aplicaciones financieras
|
||||
- **BCG** - Consultoría con IA
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
## 📊 Números de Adopción
|
||||
|
||||
- **1,306** empresas verificadas
|
||||
- **132K+** aplicaciones LLM construidas
|
||||
- **130M+** descargas totales
|
||||
- **51%** usando agentes en producción
|
||||
- **78%** planean usar agentes pronto
|
||||
|
||||
### 💼 Casos de Uso Comunes
|
||||
|
||||
- Chat sobre documentos
|
||||
- Atención al cliente
|
||||
- Asistentes personalizados
|
||||
- Análisis de datos
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Modelo de Negocio de LangChain
|
||||
|
||||
<div class="grid grid-cols-2 gap-6 mt-4 text-sm">
|
||||
|
||||
<div>
|
||||
|
||||
## 🏢 La Empresa
|
||||
|
||||
|
||||
- **Fundadores**: Harrison Chase y Ankush Gola
|
||||
- **Fundación**: Octubre 2022
|
||||
- **Sede**: San Francisco, CA
|
||||
- **CEO**: Harrison Chase
|
||||
- **Equipo**: ~136 empleados (2025)
|
||||
|
||||
### 💰 Financiación
|
||||
|
||||
- **$260M** levantados en total
|
||||
- **$1.25B** de valoración (Oct 2025)
|
||||
- **Inversores**: Sequoia, Benchmark, IVP, CapitalG
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
## 💼 Modelo de Negocio
|
||||
|
||||
|
||||
**Freemium B2B**
|
||||
- Framework open-source (gratis)
|
||||
- Monetización vía LangSmith
|
||||
|
||||
**Revenue 2025**: $16M ARR
|
||||
- Crecimiento: $8.5M → $16M en 1 año
|
||||
- **1,000+** clientes empresariales
|
||||
|
||||
|
||||
### 💎 LangSmith Pricing
|
||||
|
||||
- **Developer**: Gratis (5k traces/mes)
|
||||
- **Plus**: $39/usuario/mes (10k traces)
|
||||
- **Enterprise**: Personalizado + self-hosted
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
layout: two-cols
|
||||
---
|
||||
|
||||
# LangChain.js
|
||||
|
||||
La implementación JavaScript/TypeScript del framework LangChain
|
||||
|
||||
::right::
|
||||
|
||||
<v-clicks>
|
||||
|
||||
## ¿Por qué LangChain.js?
|
||||
|
||||
- **Desarrollo web nativo**
|
||||
- Frontend y backend con la misma tecnología
|
||||
|
||||
- **Ecosistema JavaScript**
|
||||
- NPM, TypeScript, Node.js
|
||||
|
||||
- **Paridad con Python**
|
||||
- Mismos conceptos y APIs
|
||||
|
||||
- **Comunidad activa**
|
||||
- Mantenido oficialmente
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# LangChain.js: Entornos de Ejecución
|
||||
|
||||
<div class="grid grid-cols-2 gap-6 mt-6">
|
||||
|
||||
<div>
|
||||
|
||||
## 🖥️ Runtimes Soportados
|
||||
|
||||
<v-clicks>
|
||||
|
||||
- **Node.js** (20.x, 22.x, 24.x)
|
||||
- ESM y CommonJS
|
||||
|
||||
- **Deno** - Runtime seguro
|
||||
|
||||
- **Bun** - Runtime ultra-rápido
|
||||
|
||||
- **Navegadores** - Client-side
|
||||
|
||||
</v-clicks>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
## ☁️ Edge & Serverless
|
||||
|
||||
<v-clicks>
|
||||
|
||||
- **Cloudflare Workers**
|
||||
|
||||
- **Vercel Edge Functions**
|
||||
|
||||
- **Next.js** (Server, Edge, Browser)
|
||||
|
||||
- **Supabase Edge Functions**
|
||||
|
||||
</v-clicks>
|
||||
|
||||
<v-click>
|
||||
|
||||
### 💪 Ventaja Clave
|
||||
|
||||
**Una sola codebase** para frontend, backend, edge y serverless
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Arquitectura de Componentes
|
||||
|
||||
<p class="text-sm opacity-80 -mt-2">Los componentes trabajan juntos para crear aplicaciones AI sofisticadas</p>
|
||||
|
||||
<div class="mt-4">
|
||||
|
||||
## 🧩 Seis Categorías Principales
|
||||
|
||||
<div class="grid grid-cols-3 gap-3 mt-4 text-sm">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-3 py-1">
|
||||
<h3 class="font-bold text-base">📝 Models</h3>
|
||||
<p class="text-xs opacity-80">Chat, LLMs, embeddings</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-3 py-1">
|
||||
<h3 class="font-bold text-base">🔧 Tools</h3>
|
||||
<p class="text-xs opacity-80">APIs, búsquedas, DBs</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-3 py-1">
|
||||
<h3 class="font-bold text-base">🤖 Agents</h3>
|
||||
<p class="text-xs opacity-80">Orquestación y razonamiento</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-yellow-500 pl-3 py-1">
|
||||
<h3 class="font-bold text-base">💾 Memory</h3>
|
||||
<p class="text-xs opacity-80">Historia y estado</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-red-500 pl-3 py-1">
|
||||
<h3 class="font-bold text-base">🔍 Retrievers</h3>
|
||||
<p class="text-xs opacity-80">Búsqueda vectorial y web</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-3 py-1">
|
||||
<h3 class="font-bold text-base">📄 Documents</h3>
|
||||
<p class="text-xs opacity-80">Loaders, splitters</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Módulo 6: LangSmith
|
||||
|
||||
Observabilidad, debugging y evaluación
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
Llevando tu aplicación a producción
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Qué es LangSmith?
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
**LangSmith**: Plataforma de observabilidad y testing para aplicaciones LLM
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<div class="space-y-4 text-xs">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-3">
|
||||
<h3 class="text-sm font-bold mb-2">🔍 Observabilidad</h3>
|
||||
<p>Ver cada paso del agente: prompts, respuestas, tools ejecutadas</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-3">
|
||||
<h3 class="text-sm font-bold mb-2">🐛 Debugging</h3>
|
||||
<p>Identificar errores, latencias y costos en producción</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-3">
|
||||
<h3 class="text-sm font-bold mb-2">✅ Evaluación</h3>
|
||||
<p>Datasets de prueba y métricas de calidad</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Por qué LangSmith?
|
||||
|
||||
<div class="mt-10 text-xs space-y-4">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-red-500 pl-4 bg-red-50 dark:bg-red-900/20 p-3">
|
||||
<h3 class="text-sm font-bold mb-2">❌ Sin LangSmith</h3>
|
||||
<p>• No sabes qué prompts se enviaron exactamente</p>
|
||||
<p>• Difícil reproducir errores</p>
|
||||
<p>• Imposible saber el costo real por usuario</p>
|
||||
<p>• Testing manual y tedioso</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-3">
|
||||
<h3 class="text-sm font-bold mb-2">✅ Con LangSmith</h3>
|
||||
<p>• Trazas completas de cada ejecución</p>
|
||||
<p>• Replay de conversaciones problemáticas</p>
|
||||
<p>• Dashboard de costos y latencias</p>
|
||||
<p>• Datasets y evaluaciones automáticas</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Configuración de LangSmith
|
||||
|
||||
<div class="mt-8 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
**Paso 1:** Crear cuenta gratuita en [smith.langchain.com](https://smith.langchain.com)
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Paso 2:** Obtener API Key desde Settings → API Keys
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Paso 3:** Configurar variables de entorno
|
||||
|
||||
```bash
|
||||
# .env
|
||||
LANGCHAIN_TRACING_V2=true
|
||||
LANGCHAIN_API_KEY=lsv2_pt_...
|
||||
LANGCHAIN_PROJECT=mi-proyecto
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-6 text-xs opacity-80">
|
||||
✨ Automático: LangChain detecta las variables y envía trazas a LangSmith
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Ejemplo con LangSmith
|
||||
|
||||
<div class="text-xs mt-6">
|
||||
|
||||
```typescript
|
||||
import { createAgent } from "langchain";
|
||||
|
||||
// Con las variables de entorno configuradas,
|
||||
// las trazas se envían automáticamente a LangSmith
|
||||
|
||||
const agent = createAgent({
|
||||
model: "openai:gpt-4.1-mini",
|
||||
tools: [weatherTool],
|
||||
});
|
||||
|
||||
const result = await agent.invoke({
|
||||
messages: [{ role: "user", content: "¿Qué tiempo hace en Madrid?" }]
|
||||
});
|
||||
|
||||
// ✅ Ve la traza completa en https://smith.langchain.com
|
||||
// - Input del usuario
|
||||
// - Decisión del LLM de usar la tool
|
||||
// - Ejecución de la tool
|
||||
// - Respuesta final
|
||||
// - Tokens consumidos
|
||||
// - Latencia de cada paso
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Plan Gratuito
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-4 mb-6">
|
||||
<h3 class="text-base font-bold mb-3">🎁 Developer (Gratis)</h3>
|
||||
<p class="text-xs mb-2">• 5,000 traces/mes</p>
|
||||
<p class="text-xs mb-2">• Retención de 14 días</p>
|
||||
<p class="text-xs mb-2">• 1 usuario</p>
|
||||
<p class="text-xs">• Perfecto para desarrollo y testing</p>
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="text-xs opacity-70">
|
||||
📚 Planes de pago desde $39/mes (Plus) para equipos y producción
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-6 text-center text-sm">
|
||||
[smith.langchain.com/pricing](https://smith.langchain.com/pricing)
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Próximos Pasos
|
||||
|
||||
<div class="mt-10 text-sm space-y-5">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-4">
|
||||
<h3 class="text-base font-bold mb-2">🚀 En producción</h3>
|
||||
<p class="text-xs">Activa LangSmith para monitorear tu aplicación en real-time</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-4">
|
||||
<h3 class="text-base font-bold mb-2">📚 Explora datasets</h3>
|
||||
<p class="text-xs">Crea casos de prueba y evalúa mejoras en tus prompts</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-4">
|
||||
<h3 class="text-base font-bold mb-2">📖 Documentación</h3>
|
||||
<p class="text-xs">[docs.smith.langchain.com](https://docs.smith.langchain.com)</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Módulo 4: Mensajes y Prompts
|
||||
|
||||
Sistema de mensajes, templates y gestión de contexto
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
Comunicándote efectivamente con los LLMs
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Tipos de Mensajes
|
||||
|
||||
<div class="mt-4 text-sm">
|
||||
|
||||
Los **Chat Models** trabajan con mensajes tipados, no con texto plano. Cada tipo tiene una **carga semántica** que el modelo interpreta de forma diferente
|
||||
|
||||
<div class="mt-4 space-y-4">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-3 bg-blue-50 dark:bg-blue-900/20 py-2 px-3">
|
||||
<span class="font-bold text-base">💼 SystemMessage</span> <span class="text-xs opacity-70">(role: "system")</span>
|
||||
<p class="text-sm mt-2 mb-0">Instrucciones iniciales que <b>condicionan todo el comportamiento</b> del modelo. Define persona, reglas, restricciones y formato de respuesta. Tiene la <b>mayor prioridad</b> en la atención del modelo.</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-3 bg-green-50 dark:bg-green-900/20 py-2 px-3">
|
||||
<span class="font-bold text-base">👤 HumanMessage</span> <span class="text-xs opacity-70">(role: "user")</span>
|
||||
<p class="text-sm mt-2 mb-0">Input del usuario. Es lo que el modelo debe <b>responder directamente</b>. Puede contener texto, imágenes, audio y archivos (multimodal).</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Tipos de Mensajes (cont.)
|
||||
|
||||
<div class="mt-4 text-sm">
|
||||
|
||||
<div class="mt-4 space-y-4">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-3 bg-purple-50 dark:bg-purple-900/20 py-2 px-3">
|
||||
<span class="font-bold text-base">🤖 AIMessage</span> <span class="text-xs opacity-70">(role: "assistant")</span>
|
||||
<p class="text-sm mt-2 mb-0">Respuesta previa del modelo. Se usa para <b>historial de conversación</b> y para <b>few-shot learning</b>. Puede incluir <code>tool_calls</code>, <code>usage_metadata</code> y <code>response_metadata</code>.</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-3 bg-orange-50 dark:bg-orange-900/20 py-2 px-3">
|
||||
<span class="font-bold text-base">🔧 ToolMessage</span> <span class="text-xs opacity-70">(role: "tool")</span>
|
||||
<p class="text-sm mt-2 mb-0">Resultado de una herramienta ejecutada. Requiere <code>tool_call_id</code> que enlaza con el <code>AIMessage</code> que solicitó la herramienta. Cierra el <b>ciclo de tool-calling</b>.</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="mt-4 text-xs bg-gray-100 dark:bg-gray-800 rounded p-3">
|
||||
💡 También puedes usar la <b>notación abreviada</b> con tuplas: <code>["system", "..."]</code>, <code>["human", "..."]</code>, <code>["ai", "..."]</code> dentro de <code>ChatPromptTemplate</code>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Implicaciones: System vs Human
|
||||
|
||||
<div class="mt-6 text-sm">
|
||||
|
||||
El tipo de mensaje **no es solo una etiqueta**, cambia cómo el modelo procesa la información
|
||||
|
||||
<div class="mt-4 grid grid-cols-2 gap-4">
|
||||
|
||||
<v-click>
|
||||
<div class="border rounded-lg p-4 bg-blue-50 dark:bg-blue-900/20">
|
||||
<h3 class="text-base font-bold mb-2">💼 System vs Human</h3>
|
||||
<p class="text-xs mb-2">Poner instrucciones en <code>SystemMessage</code> vs en <code>HumanMessage</code> <b>no es equivalente</b>:</p>
|
||||
<ul class="text-xs list-disc pl-4 space-y-1">
|
||||
<li>System tiene <b>mayor prioridad</b> — el modelo lo trata como "ley"</li>
|
||||
<li>Human se trata como "petición" — puede ser ignorado si contradice al system</li>
|
||||
<li>En Anthropic, system va en un <b>parámetro separado</b> de la API</li>
|
||||
</ul>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border rounded-lg p-4 bg-purple-50 dark:bg-purple-900/20">
|
||||
<h3 class="text-base font-bold mb-2">🤖 AIMessage manual</h3>
|
||||
<p class="text-xs mb-2">Puedes <b>inyectar AIMessages falsos</b> en el historial:</p>
|
||||
<ul class="text-xs list-disc pl-4 space-y-1">
|
||||
<li>El modelo "cree" que él mismo dijo eso</li>
|
||||
<li>Útil para <b>few-shot</b>: enseñar el patrón de respuesta deseado</li>
|
||||
<li>Útil para <b>prefilling</b>: forzar el inicio de la respuesta</li>
|
||||
</ul>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Implicaciones: Tool Calling y Orden
|
||||
|
||||
<div class="mt-6 text-sm">
|
||||
|
||||
<div class="mt-4 grid grid-cols-2 gap-4">
|
||||
|
||||
<v-click>
|
||||
<div class="border rounded-lg p-4 bg-orange-50 dark:bg-orange-900/20">
|
||||
<h3 class="text-base font-bold mb-2">🔧 Ciclo de Tool Calling</h3>
|
||||
<p class="text-xs mb-2">El flujo completo requiere <b>3 mensajes</b>:</p>
|
||||
<ol class="text-xs list-decimal pl-4 space-y-1">
|
||||
<li><code>AIMessage</code> con <code>tool_calls</code> → modelo pide ejecutar</li>
|
||||
<li><code>ToolMessage</code> con resultado → tu app ejecuta y devuelve</li>
|
||||
<li><code>AIMessage</code> final → modelo interpreta el resultado</li>
|
||||
</ol>
|
||||
<p class="text-xs mt-2 opacity-70">Lo veremos en detalle en el módulo de <b>Agentes</b></p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border rounded-lg p-4 bg-green-50 dark:bg-green-900/20">
|
||||
<h3 class="text-base font-bold mb-2">📋 El orden importa</h3>
|
||||
<p class="text-xs mb-2">La <b>secuencia</b> de mensajes define el contexto:</p>
|
||||
<ul class="text-xs list-disc pl-4 space-y-1">
|
||||
<li>Los mensajes recientes tienen <b>más peso</b> que los antiguos</li>
|
||||
<li>El modelo espera alternancia <code>Human → AI → Human</code></li>
|
||||
<li>Romper la alternancia puede causar comportamiento inesperado</li>
|
||||
</ul>
|
||||
<p class="text-xs mt-2 opacity-70">Por eso la <b>gestión del historial</b> es clave</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Ejemplo: Usando Mensajes
|
||||
|
||||
<div class="text-sm mt-6">
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
import {
|
||||
SystemMessage,
|
||||
HumanMessage
|
||||
} from "@langchain/core/messages";
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });
|
||||
|
||||
const messages = [
|
||||
new SystemMessage("Eres un experto en JavaScript y TypeScript"),
|
||||
new HumanMessage("¿Qué es async/await?")
|
||||
];
|
||||
|
||||
const response = await model.invoke(messages);
|
||||
|
||||
console.log(response.content);
|
||||
// Respuesta contextualizada como experto en JS/TS
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Prompt Templates
|
||||
|
||||
<div class="mt-4 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-4">
|
||||
|
||||
**ChatPromptTemplate** permite reutilizar prompts con variables dinámicas y la notación abreviada de roles
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatPromptTemplate } from "@langchain/core/prompts";
|
||||
|
||||
const template = ChatPromptTemplate.fromMessages([
|
||||
["system", "Eres un experto en {topic}"], // ← shorthand de SystemMessage
|
||||
["human", "{question}"] // ← shorthand de HumanMessage
|
||||
]);
|
||||
|
||||
const prompt = await template.invoke({
|
||||
topic: "JavaScript",
|
||||
question: "¿Qué es async/await?"
|
||||
});
|
||||
|
||||
const response = await model.invoke(prompt);
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-3 text-xs bg-gray-100 dark:bg-gray-800 rounded p-2">
|
||||
💡 Los templates son útiles para <b>reutilización</b>, <b>testing</b> y separar prompts de la lógica. Pero para casos simples, puedes usar mensajes directamente.
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Ventajas de Templates
|
||||
|
||||
<div class="mt-6 text-sm space-y-3">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 py-2 px-3">
|
||||
<h3 class="text-base font-bold mb-1">✅ Reutilización</h3>
|
||||
<p class="text-xs">El mismo template con diferentes variables</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 py-2 px-3">
|
||||
<h3 class="text-base font-bold mb-1">✅ Mantenibilidad</h3>
|
||||
<p class="text-xs">Cambiar el prompt en un solo lugar</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 py-2 px-3">
|
||||
<h3 class="text-base font-bold mb-1">✅ Testing</h3>
|
||||
<p class="text-xs">Probar con múltiples combinaciones de variables</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 py-2 px-3">
|
||||
<h3 class="text-base font-bold mb-1">✅ Separación de Responsabilidades</h3>
|
||||
<p class="text-xs">Prompts independientes de la lógica de negocio</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Few-Shot Prompting
|
||||
|
||||
<div class="mt-8 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-6">
|
||||
|
||||
**Few-shot**: Dar ejemplos al LLM para que aprenda el patrón deseado
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatPromptTemplate } from "@langchain/core/prompts";
|
||||
|
||||
const template = ChatPromptTemplate.fromMessages([
|
||||
["system", "Clasifica el sentimiento de tweets"],
|
||||
["human", "Me encanta este producto!"],
|
||||
["ai", "positivo"],
|
||||
["human", "No funciona bien :("],
|
||||
["ai", "negativo"],
|
||||
["human", "{tweet}"] // El tweet a clasificar
|
||||
]);
|
||||
|
||||
const response = await model.invoke(
|
||||
await template.invoke({ tweet: "Buena experiencia" })
|
||||
);
|
||||
// → "positivo"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Historial de Conversación
|
||||
|
||||
<div class="mt-8 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-6">
|
||||
|
||||
Para mantener **contexto** entre mensajes, acumula el historial
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
import { HumanMessage, AIMessage } from "@langchain/core/messages";
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });
|
||||
|
||||
const history = [
|
||||
new HumanMessage("Hola, me llamo Juan"),
|
||||
new AIMessage("Hola Juan, ¿en qué puedo ayudarte?"),
|
||||
new HumanMessage("¿Cuál es mi nombre?")
|
||||
];
|
||||
|
||||
const response = await model.invoke(history);
|
||||
console.log(response.content);
|
||||
// → "Tu nombre es Juan"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Gestión de Historial
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
**Problema**: El historial crece indefinidamente → Tokens infinitos → Costos altos
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<div class="space-y-5">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">📏 Limitar por cantidad</h3>
|
||||
<p class="text-xs">Mantener solo los últimos N mensajes</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">📊 Limitar por tokens</h3>
|
||||
<p class="text-xs">Mantener solo los últimos N tokens</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">📝 Resumir</h3>
|
||||
<p class="text-xs">Comprimir conversaciones antiguas en un resumen</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Ejemplo: Limitando Historial
|
||||
|
||||
<div class="text-sm mt-6">
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
import { HumanMessage, AIMessage } from "@langchain/core/messages";
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });
|
||||
|
||||
// Simular un historial largo
|
||||
const fullHistory = [
|
||||
new HumanMessage("Mensaje 1"),
|
||||
new AIMessage("Respuesta 1"),
|
||||
new HumanMessage("Mensaje 2"),
|
||||
new AIMessage("Respuesta 2"),
|
||||
new HumanMessage("Mensaje 3"),
|
||||
new AIMessage("Respuesta 3"),
|
||||
];
|
||||
|
||||
// Mantener solo los últimos 4 mensajes (2 turnos)
|
||||
const recentHistory = fullHistory.slice(-4);
|
||||
|
||||
const response = await model.invoke([
|
||||
...recentHistory,
|
||||
new HumanMessage("Nueva pregunta")
|
||||
]);
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Placeholder Variables
|
||||
|
||||
<div class="mt-8 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-6">
|
||||
|
||||
**MessagesPlaceholder**: Insertar arrays de mensajes dinámicamente en templates
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
|
||||
|
||||
const template = ChatPromptTemplate.fromMessages([
|
||||
["system", "Eres un asistente útil"],
|
||||
new MessagesPlaceholder("history"), // Array de mensajes
|
||||
["human", "{input}"]
|
||||
]);
|
||||
|
||||
const response = await model.invoke(
|
||||
await template.invoke({
|
||||
history: [
|
||||
new HumanMessage("Hola"),
|
||||
new AIMessage("¡Hola! ¿En qué puedo ayudarte?")
|
||||
],
|
||||
input: "¿Qué tiempo hace?"
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-2 text-xs text-gray-500">
|
||||
💡 <code>["system", "..."]</code> y <code>["human", "..."]</code> son la forma abreviada de <code>SystemMessage</code> y <code>HumanMessage</code> en <code>ChatPromptTemplate</code>
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Partial Templates
|
||||
|
||||
<div class="mt-8 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-6">
|
||||
|
||||
**Partial**: Pre-rellenar algunas variables, completar otras después
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatPromptTemplate } from "@langchain/core/prompts";
|
||||
|
||||
const template = ChatPromptTemplate.fromMessages([
|
||||
["system", "Eres un experto en {topic} que habla {language}"],
|
||||
["human", "{question}"]
|
||||
]);
|
||||
|
||||
// Pre-configurar topic y language
|
||||
const spanishJSTemplate = await template.partial({
|
||||
topic: "JavaScript",
|
||||
language: "español"
|
||||
});
|
||||
|
||||
// Ahora solo necesitas la pregunta
|
||||
const response = await model.invoke(
|
||||
await spanishJSTemplate.invoke({ question: "¿Qué es async/await?" })
|
||||
);
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Módulo 3: Modelos
|
||||
|
||||
Trabajando con LLMs y Chat Models en LangChain.js
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
La base de cualquier aplicación con IA
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Chat Models
|
||||
|
||||
<div class="mt-8">
|
||||
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-4 mb-6">
|
||||
<h3 class="text-lg font-bold mb-3">💬 La interfaz estándar en LangChain</h3>
|
||||
<p class="text-sm mb-2">Todos los modelos en LangChain se usan como <strong>Chat Models</strong></p>
|
||||
<p class="text-xs opacity-80 mb-2">📥 <strong>Entrada:</strong> Lista de mensajes (System, Human, AI)</p>
|
||||
<p class="text-xs opacity-80 mb-2">📤 <strong>Salida:</strong> Mensaje estructurado (AIMessage)</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
|
||||
<div class="text-center p-3 rounded bg-yellow-50 dark:bg-yellow-900/20">
|
||||
<p class="text-sm font-bold">Mistral</p>
|
||||
<p class="text-xs opacity-80">Mistral Large, Small</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center p-3 rounded bg-orange-50 dark:bg-orange-900/20">
|
||||
<p class="text-sm font-bold">Anthropic</p>
|
||||
<p class="text-xs opacity-80">Claude Sonnet, Haiku</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center p-3 rounded bg-blue-50 dark:bg-blue-900/20">
|
||||
<p class="text-sm font-bold">Google</p>
|
||||
<p class="text-xs opacity-80">Gemini Pro, Flash</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-6 text-center text-sm border-t pt-4">
|
||||
✅ Misma interfaz para todos → fácil cambiar de proveedor
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Qué es un Token?
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
**Token** = Unidad básica de texto que procesa un LLM
|
||||
|
||||
No es exactamente una palabra, ni un carácter
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="grid grid-cols-2 gap-8 text-xs">
|
||||
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-4">
|
||||
<h3 class="text-sm font-bold mb-3">Ejemplos de Tokenización</h3>
|
||||
<p class="mb-2"><code>"Hola mundo"</code> → <strong>2 tokens</strong></p>
|
||||
<p class="mb-2"><code>"LangChain"</code> → <strong>2 tokens</strong> (Lang + Chain)</p>
|
||||
<p class="mb-2"><code>"desarrollador"</code> → <strong>3 tokens</strong></p>
|
||||
<p class="mb-2"><code>"🚀"</code> → <strong>1-2 tokens</strong></p>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 p-4">
|
||||
<h3 class="text-sm font-bold mb-3">Regla General</h3>
|
||||
<p class="mb-2">1 token ≈ <strong>4 caracteres</strong> en inglés</p>
|
||||
<p class="mb-2">1 token ≈ <strong>¾ de palabra</strong> en inglés</p>
|
||||
<p class="mb-2">100 tokens ≈ <strong>75 palabras</strong></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Cómo se Cuentan los Tokens?
|
||||
|
||||
<div class="mt-4 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-4">
|
||||
|
||||
Los tokens se cuentan en **entrada (input)** y **salida (output)** por separado
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-3 mb-4 text-xs">
|
||||
<h3 class="text-sm font-bold mb-2">💰 Costos</h3>
|
||||
<p class="mb-2">Los LLMs cobran por tokens procesados</p>
|
||||
<p class="mb-2">Output suele ser <strong>más caro</strong> que input (3-5x)</p>
|
||||
<p class="mb-2">Ejemplo: GPT-4o → $2.50/1M tokens input, $10/1M tokens output</p>
|
||||
<p>📊 <a href="https://raw.githubusercontent.com/BerriAI/litellm/refs/heads/main/model_prices_and_context_window.json" target="_blank">Precios actualizados por modelo (JSON)</a></p>
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-3 text-xs">
|
||||
<h3 class="text-sm font-bold mb-2">🔧 Herramienta para Contar Tokens</h3>
|
||||
<p class="mb-2">OpenAI Tokenizer (funciona para la mayoría de modelos):</p>
|
||||
<p><a href="https://platform.openai.com/tokenizer" target="_blank">platform.openai.com/tokenizer</a></p>
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Parámetros Principales
|
||||
|
||||
<div class="mt-10 space-y-5 text-sm">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-orange-500 pl-4 bg-orange-50 dark:bg-orange-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">🌡️ temperature</h3>
|
||||
<p class="text-xs mb-1">Controla la aleatoriedad de las respuestas</p>
|
||||
<p class="text-xs opacity-80">0.0 = Determinista | 1.0 = Creativo | 2.0 = Muy aleatorio</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">📏 maxTokens</h3>
|
||||
<p class="text-xs mb-1">Límite máximo de tokens en la respuesta</p>
|
||||
<p class="text-xs opacity-80">Ejemplo: 500 (aprox. 375 palabras)</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Parámetros Principales
|
||||
|
||||
<div class="mt-10 space-y-5 text-sm">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">🎯 topP</h3>
|
||||
<p class="text-xs mb-1">Nucleus sampling (alternativa a temperature)</p>
|
||||
<p class="text-xs opacity-80">0.1 = Conservador | 0.9 = Diverso</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-purple-500 pl-4 bg-purple-50 dark:bg-purple-900/20 p-3">
|
||||
<h3 class="text-base font-bold mb-2">🔁 n</h3>
|
||||
<p class="text-xs mb-1">Número de respuestas a generar</p>
|
||||
<p class="text-xs opacity-80">Útil para comparar variaciones</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="mt-4 text-xs opacity-70 italic text-center">
|
||||
⚠️ Estos parámetros dependen de cada modelo y pueden no estar disponibles en todos los proveedores.
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Ejemplo: Configurando Parámetros
|
||||
|
||||
<div class="text-sm mt-6">
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
const model = new ChatOpenAI({
|
||||
model: "gpt-4.1-mini",
|
||||
temperature: 0.7, // Balance entre creatividad y coherencia
|
||||
maxTokens: 500, // Limitar longitud de respuesta
|
||||
topP: 0.9, // Nucleus sampling
|
||||
});
|
||||
|
||||
const response = await model.invoke(
|
||||
"Explica qué es un agente en LangChain"
|
||||
);
|
||||
|
||||
console.log(response.content);
|
||||
```
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs opacity-80 text-center">
|
||||
💡 <strong>Tip:</strong> Usa <code>temperature: 0</code> para respuestas deterministas (útil en tests)
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Streaming: Respuestas en Tiempo Real
|
||||
|
||||
<div class="mt-8">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="text-sm mb-6">
|
||||
|
||||
**¿Por qué streaming?**
|
||||
|
||||
- ✅ Experiencia de usuario mejorada (como ChatGPT)
|
||||
- ✅ Feedback inmediato (no esperar 10-20 segundos)
|
||||
- ✅ Procesar mientras se genera
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
const model = new ChatOpenAI({
|
||||
model: "gpt-4.1-mini",
|
||||
streaming: true,
|
||||
});
|
||||
|
||||
const stream = await model.stream("Explica qué es LangChain");
|
||||
|
||||
for await (const chunk of stream) {
|
||||
console.log(chunk.content); // Imprime palabra por palabra
|
||||
}
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Batch: Procesamiento en Lote
|
||||
|
||||
<div class="mt-8">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="text-sm mb-6">
|
||||
|
||||
**¿Cuándo usar batch?**
|
||||
|
||||
- ✅ Procesar múltiples inputs a la vez
|
||||
- ✅ Optimización de costos (algunos proveedores ofrecen descuentos)
|
||||
- ✅ Mejor throughput que llamadas individuales
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });
|
||||
|
||||
const inputs = [
|
||||
"¿Qué es un agente?",
|
||||
"¿Qué es RAG?",
|
||||
"¿Qué es LangSmith?"
|
||||
];
|
||||
|
||||
const responses = await model.batch(inputs);
|
||||
|
||||
responses.forEach((response, i) => {
|
||||
console.log(`Pregunta ${i + 1}:`, response.content);
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Structured Output
|
||||
|
||||
<div class="text-sm mt-6">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-4">
|
||||
|
||||
**Problema:** Las respuestas de LLMs son texto plano, difíciles de procesar
|
||||
|
||||
**Solución:** Forzar al modelo a responder con JSON estructurado
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
import { z } from "zod";
|
||||
|
||||
// Definir el esquema con Zod
|
||||
const schema = z.object({
|
||||
sentiment: z.enum(["positive", "negative", "neutral"]),
|
||||
score: z.number().min(0).max(1),
|
||||
keywords: z.array(z.string()),
|
||||
});
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1-mini" })
|
||||
.withStructuredOutput(schema);
|
||||
|
||||
const result = await model.invoke("Me encanta LangChain!");
|
||||
// { sentiment: "positive", score: 0.95, keywords: ["encanta", "langchain"] }
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Intercambiabilidad de Modelos
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
**Ventaja clave de LangChain:** Cambiar de proveedor sin reescribir código
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<div class="grid grid-cols-2 gap-8">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
// OpenAI
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
const model = new ChatOpenAI({
|
||||
model: "gpt-4.1-mini"
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
// Anthropic Claude
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
const model = new ChatAnthropic({
|
||||
model: "claude-sonnet-4-6"
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Intercambiabilidad de Modelos
|
||||
|
||||
<div class="mt-10 text-sm">
|
||||
|
||||
<div class="grid grid-cols-2 gap-8">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
// Google Gemini
|
||||
import { ChatGoogle } from "@langchain/google";
|
||||
|
||||
const model = new ChatGoogle({
|
||||
model: "gemini-2.5-flash"
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
// Ollama (Local)
|
||||
import { ChatOllama } from "@langchain/ollama";
|
||||
|
||||
const model = new ChatOllama({
|
||||
model: "llama3.2"
|
||||
});
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-8 text-center text-sm opacity-80">
|
||||
⚡ Todos usan la misma interfaz: <code>.invoke()</code>, <code>.stream()</code>, <code>.batch()</code>
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# initChatModel: Configuración Universal
|
||||
|
||||
<div class="mt-8 text-sm">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-6">
|
||||
|
||||
**Forma simplificada** de inicializar modelos sin imports específicos
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { initChatModel } from "langchain";
|
||||
|
||||
// En lugar de importar ChatOpenAI, ChatAnthropic, etc.
|
||||
const model = await initChatModel("gpt-4.1-mini", {
|
||||
modelProvider: "openai",
|
||||
temperature: 0.7,
|
||||
});
|
||||
|
||||
const response = await model.invoke("Hola!");
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-6 text-xs opacity-80">
|
||||
✅ Ventaja: Cambiar de proveedor modificando solo el string
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 p-3 bg-amber-500/10 border border-amber-500/30 rounded text-xs">
|
||||
⚠️ <strong>No es magia:</strong> aunque no veas el <code>import</code>, el paquete del proveedor (<code>@langchain/openai</code>, <code>@langchain/mistralai</code>, etc.) <strong>debe estar instalado</strong> en tu proyecto. <code>initChatModel</code> lo resuelve internamente (<em>under the hood</em>).
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Providers Disponibles
|
||||
|
||||
<div class="text-xs mt-8">
|
||||
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
|
||||
<div>
|
||||
|
||||
<v-click>
|
||||
|
||||
**OpenAI**
|
||||
```typescript
|
||||
modelProvider: "openai"
|
||||
// gpt-4.1, gpt-4.1-mini, gpt-5.2
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Anthropic**
|
||||
```typescript
|
||||
modelProvider: "anthropic"
|
||||
// claude-sonnet-4-6, claude-opus-4-6
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Google**
|
||||
```typescript
|
||||
modelProvider: "google"
|
||||
// gemini-2.5-flash, gemini-2.5-flash-lite
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Azure OpenAI**
|
||||
```typescript
|
||||
modelProvider: "azure_openai"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Mistral**
|
||||
```typescript
|
||||
modelProvider: "mistral"
|
||||
// mistral-large, mistral-small
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Groq**
|
||||
```typescript
|
||||
modelProvider: "groq"
|
||||
// llama-3.3-70b, mixtral-8x7b
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Ollama**
|
||||
```typescript
|
||||
modelProvider: "ollama"
|
||||
// llama3.2:7b, mistral:7b
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Cohere**
|
||||
```typescript
|
||||
modelProvider: "cohere"
|
||||
// command-r, command-r-plus
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Más Providers
|
||||
|
||||
<div class="text-xs mt-8">
|
||||
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
|
||||
<div>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Fireworks**
|
||||
```typescript
|
||||
modelProvider: "fireworks"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Together AI**
|
||||
```typescript
|
||||
modelProvider: "together_ai"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Bedrock (AWS)**
|
||||
```typescript
|
||||
modelProvider: "bedrock"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Vertex AI (Google Cloud)**
|
||||
```typescript
|
||||
modelProvider: "google-vertexai"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Cloudflare**
|
||||
```typescript
|
||||
modelProvider: "cloudflare"
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-8 text-center text-sm">
|
||||
|
||||
📚 Lista completa de providers
|
||||
|
||||
[docs.langchain.com/integrations/chat](https://docs.langchain.com/oss/javascript/integrations/chat)
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Binding Tools al Modelo
|
||||
|
||||
<div class="text-sm mt-8">
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mb-6">
|
||||
|
||||
Puedes vincular tools directamente al modelo con `.bindTools()`
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const weatherTool = tool(
|
||||
async ({ location }) => `El tiempo en ${location} es soleado`,
|
||||
{
|
||||
name: "get_weather",
|
||||
description: "Obtiene el tiempo de una ubicación",
|
||||
schema: z.object({ location: z.string() }),
|
||||
}
|
||||
);
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });
|
||||
const modelWithTools = model.bindTools([weatherTool]);
|
||||
|
||||
const response = await modelWithTools.invoke("¿Qué tiempo hace en Madrid?");
|
||||
console.log(response.tool_calls); // Tool que el LLM decidió usar
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Tools Integradas en LangChain.js
|
||||
|
||||
<div class="text-sm mt-6">
|
||||
|
||||
<v-click>
|
||||
|
||||
LangChain.js incluye numerosas **herramientas pre-construidas** listas para usar con agentes
|
||||
|
||||
</v-click>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 mt-6 text-xs">
|
||||
|
||||
<div>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Busqueda Web**
|
||||
- `TavilySearchResults` - Busqueda optimizada para LLMs
|
||||
- `DuckDuckGoSearch` - Busqueda gratuita
|
||||
- `SerpAPI` / `SearchApi` - Google Search
|
||||
- `ExaSearchResults` - Busqueda semantica
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Conocimiento**
|
||||
- `WikipediaQueryRun` - Consultas a Wikipedia
|
||||
- `WolframAlphaTool` - Calculos y datos
|
||||
- `GoogleScholar` - Articulos academicos
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Productividad**
|
||||
- `GmailTools` - Leer/enviar emails
|
||||
- `GoogleCalendarTools` - Gestionar eventos
|
||||
- `DiscordTool` - Integracion Discord
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
**Desarrollo**
|
||||
- `StackExchangeTool` - Q&A tecnico
|
||||
- `PythonInterpreter` - Ejecutar codigo
|
||||
- `WebBrowserTool` - Navegar paginas
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs text-center opacity-70">
|
||||
|
||||
Ver listado completo: [docs.langchain.com/integrations/tools](https://docs.langchain.com/oss/javascript/integrations/tools)
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Usando Tools Integradas
|
||||
|
||||
<div class="text-sm mt-6">
|
||||
|
||||
<v-click>
|
||||
|
||||
```typescript
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { WikipediaQueryRun } from "@langchain/community/tools/wikipedia_query_run";
|
||||
import { Calculator } from "@langchain/community/tools/calculator";
|
||||
|
||||
// Crear instancias de las tools
|
||||
const tavilySearch = new TavilySearchResults({
|
||||
apiKey: process.env.TAVILY_API_KEY,
|
||||
maxResults: 3,
|
||||
});
|
||||
|
||||
const wikipedia = new WikipediaQueryRun({
|
||||
topKResults: 2,
|
||||
maxDocContentLength: 4000,
|
||||
});
|
||||
|
||||
const calculator = new Calculator();
|
||||
|
||||
// Usar con un agente
|
||||
const tools = [tavilySearch, wikipedia, calculator];
|
||||
```
|
||||
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-4 text-xs bg-yellow-50 dark:bg-yellow-900/20 p-3 rounded">
|
||||
|
||||
**Paquete:** La mayoria de tools integradas estan en `@langchain/community`
|
||||
|
||||
```bash
|
||||
npm install @langchain/community
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Ejemplo: Agente con Tavily Search
|
||||
|
||||
<div class="text-xs mt-2">
|
||||
|
||||
```typescript
|
||||
import { createAgent } from "langchain";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
|
||||
const searchTool = new TavilySearchResults({ apiKey: process.env.TAVILY_API_KEY, maxResults: 5 });
|
||||
const agent = createAgent({
|
||||
model: "openai:gpt-4.1-mini",
|
||||
tools: [searchTool],
|
||||
});
|
||||
|
||||
const result = await agent.invoke({
|
||||
messages: [{ role: "user", content: "¿Cuales son las ultimas noticias sobre IA?" }],
|
||||
});
|
||||
```
|
||||
|
||||
<div class="mt-2 grid grid-cols-2 gap-3">
|
||||
|
||||
<div class="bg-blue-50 dark:bg-blue-900/20 p-2 rounded">
|
||||
|
||||
**Tavily** - Optimizado para LLMs: extrae contenido relevante, filtra anuncios/ruido, API key gratuita limitada
|
||||
|
||||
</div>
|
||||
|
||||
<div class="bg-green-50 dark:bg-green-900/20 p-2 rounded">
|
||||
|
||||
**Docs**: [langchain.com/integrations/tools](https://docs.langchain.com/oss/javascript/integrations/tools)
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Diferencia: bindTools vs createAgent
|
||||
|
||||
<div class="mt-10 text-xs">
|
||||
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-blue-500 pl-4 bg-blue-50 dark:bg-blue-900/20 p-4">
|
||||
<h3 class="text-sm font-bold mb-3">🔧 .bindTools()</h3>
|
||||
<p class="mb-2">• El LLM decide si usar la tool</p>
|
||||
<p class="mb-2">• Devuelve <code>tool_calls</code></p>
|
||||
<p class="mb-2">• Tú ejecutas la tool manualmente</p>
|
||||
<p class="mb-2">• Control total del flujo</p>
|
||||
<p class="text-xs opacity-70 mt-3">Ideal para flujos personalizados</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
<v-click>
|
||||
<div class="border-l-4 border-green-500 pl-4 bg-green-50 dark:bg-green-900/20 p-4">
|
||||
<h3 class="text-sm font-bold mb-3">🤖 createAgent() <span class="text-xs opacity-60">(LangChain v1)</span></h3>
|
||||
<p class="mb-2">• El agente decide y ejecuta</p>
|
||||
<p class="mb-2">• Loop automático</p>
|
||||
<p class="mb-2">• Ejecuta tools automáticamente</p>
|
||||
<p class="mb-2">• Estado persistente incluido</p>
|
||||
<p class="text-xs opacity-70 mt-3">Ideal para agentes autónomos</p>
|
||||
</div>
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
|
||||
<v-click>
|
||||
|
||||
<div class="mt-6 text-center text-xs opacity-70">
|
||||
💡 Usa <code>bindTools()</code> para control, <code>createAgent()</code> (LangChain v1) para simplicidad
|
||||
</div>
|
||||
|
||||
</v-click>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Temas Pendientes
|
||||
|
||||
Lo que nos dejamos en el tintero
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
Hay mucho más por explorar en el ecosistema LangChain...
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Sistemas Multi-Agente (Subagentes)
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Patrones principales en LangChain/LangGraph
|
||||
|
||||
| Patrón | Descripción |
|
||||
|--------|-------------|
|
||||
| **Subagents** | Un agente supervisor coordina subagentes como tools |
|
||||
| **Handoffs** | El comportamiento cambia dinámicamente según el estado |
|
||||
| **Skills** | Prompts y conocimiento especializado cargado bajo demanda |
|
||||
| **Router** | Clasifica input y lo dirige a agentes especializados |
|
||||
| **Custom Workflow** | Flujos con LangGraph mezclando lógica determinista y agéntica |
|
||||
|
||||
[Docs: Multi-agent](https://docs.langchain.com/oss/javascript/langchain/multi-agent/index)
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Deep Agents
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Librería standalone para agentes complejos
|
||||
|
||||
Inspirada en Claude Code, Deep Research y Manus.
|
||||
|
||||
### Características principales
|
||||
|
||||
- **Planificación**: Capacidad de planificar tareas multi-paso
|
||||
- **File systems**: Sistema de archivos virtual para gestión de contexto
|
||||
- **Subagentes**: Spawn de agentes especializados para subtareas
|
||||
- **Long-term memory**: Integración con almacenamiento persistente
|
||||
|
||||
### Ejemplo básico
|
||||
|
||||
```typescript
|
||||
import { createDeepAgent } from "@langchain/deepagents";
|
||||
|
||||
const agent = createDeepAgent({
|
||||
model: "gpt-4.1",
|
||||
filesystem: true,
|
||||
planning: true,
|
||||
});
|
||||
|
||||
await agent.invoke("Research and write a report about AI trends");
|
||||
```
|
||||
|
||||
[Docs: Deep Agents](https://docs.langchain.com/oss/javascript/deepagents/overview)
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Long-term Memory con Semantic Search
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### InMemoryStore con embeddings
|
||||
|
||||
```typescript
|
||||
import { InMemoryStore } from "@langchain/langgraph";
|
||||
import { OpenAIEmbeddings } from "@langchain/openai";
|
||||
|
||||
const embeddings = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
|
||||
|
||||
const store = new InMemoryStore({
|
||||
index: { embeddings, dims: 1536 }
|
||||
});
|
||||
|
||||
// Guardar memorias
|
||||
await store.put(["user_123", "memories"], "1", { text: "I love pizza" });
|
||||
|
||||
// Buscar por similitud semántica
|
||||
const items = await store.search(
|
||||
["user_123", "memories"],
|
||||
{ query: "I'm hungry", limit: 2 }
|
||||
);
|
||||
```
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Integración MCP (Model Context Protocol)
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### MCP en LangChain.js
|
||||
|
||||
Protocolo abierto que estandariza cómo las aplicaciones proporcionan tools y contexto a LLMs.
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI, tools } from "@langchain/openai";
|
||||
|
||||
const model = new ChatOpenAI({ model: "gpt-4.1" });
|
||||
|
||||
const response = await model.invoke("Roll 2d4+1", {
|
||||
tools: [
|
||||
tools.mcp({
|
||||
serverLabel: "dmcp",
|
||||
serverDescription: "A D&D MCP server for dice rolling",
|
||||
serverUrl: "https://dmcp-server.deno.dev/sse",
|
||||
requireApproval: "never",
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Context Engineering
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Inyección de dependencias en runtime
|
||||
|
||||
```typescript
|
||||
const contextSchema = z.object({
|
||||
userId: z.string(),
|
||||
apiKey: z.string(),
|
||||
});
|
||||
|
||||
const fetchUserData = tool(
|
||||
async ({ query }, runtime: ToolRuntime<any, typeof contextSchema>) => {
|
||||
const { userId, apiKey } = runtime.context;
|
||||
return await performQuery(query, apiKey, userId);
|
||||
},
|
||||
{ name: "fetch_user_data", schema: z.object({ query: z.string() }) }
|
||||
);
|
||||
|
||||
const agent = createAgent({
|
||||
model: "gpt-4.1",
|
||||
tools: [fetchUserData],
|
||||
contextSchema
|
||||
});
|
||||
|
||||
// Cada usuario tiene su propio contexto
|
||||
await agent.invoke(messages, {
|
||||
context: { userId: "user_123", apiKey: "sk-..." }
|
||||
});
|
||||
```
|
||||
|
||||
</v-clicks>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Tipos de Contexto en LangGraph
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Tres dimensiones de contexto
|
||||
|
||||
| Tipo | Mutabilidad | Alcance | Uso |
|
||||
|------|-------------|---------|-----|
|
||||
| **Static (config)** | Inmutable | Single run | user ID, API keys, DB connections |
|
||||
| **Dynamic (state)** | Mutable | Single run | historial, resultados intermedios |
|
||||
| **Store** | Mutable | Cross-conversation | memorias persistentes, preferencias |
|
||||
|
||||
### Casos de uso
|
||||
|
||||
- **Autenticación por usuario**: Inyectar API keys específicas por tenant
|
||||
- **Permisos dinámicos**: Ajustar herramientas disponibles según rol
|
||||
- **Personalización**: Cargar preferencias del usuario desde el store
|
||||
- **Multi-tenancy**: Aislar datos entre organizaciones
|
||||
|
||||
[Docs: Context Engineering](https://docs.langchain.com/oss/javascript/langchain/context-engineering)
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Testing de Aplicaciones LLM
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Dos enfoques complementarios
|
||||
|
||||
**Unit tests**: Componentes aislados con mocks, validaciones rápidas y predecibles.
|
||||
|
||||
**Integration tests**: Llamadas reales para confirmar que todo funciona junto.
|
||||
|
||||
### AgentEvals
|
||||
|
||||
```typescript
|
||||
import { createTrajectoryMatchEvaluator } from "agentevals";
|
||||
|
||||
// Trajectory Match: compara contra trayectoria de referencia
|
||||
const evaluator = createTrajectoryMatchEvaluator({ matchMode: "subset" });
|
||||
|
||||
// LLM-as-Judge: validación cualitativa con un modelo
|
||||
const llmEvaluator = createLLMJudgeEvaluator({ model: "gpt-4.1" });
|
||||
```
|
||||
|
||||
### Integración con LangSmith
|
||||
Configura `LANGSMITH_API_KEY` y `LANGSMITH_TRACING` para registrar experimentos automáticamente con Vitest/Jest.
|
||||
|
||||
[Docs: Testing](https://docs.langchain.com/oss/javascript/langchain/test)
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Recursos para continuar aprendiendo
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Documentación oficial
|
||||
- **LangChain.js Docs**: [docs.langchain.com](https://docs.langchain.com/oss/javascript)
|
||||
- **LangGraph.js**: [docs.langchain.com/langgraph](https://docs.langchain.com/langgraph)
|
||||
- **LangSmith**: [docs.smith.langchain.com](https://docs.smith.langchain.com)
|
||||
|
||||
### Cursos y tutoriales
|
||||
- **LangChain Academy**: Cursos oficiales gratuitos
|
||||
- **DeepLearning.AI**: Cursos sobre LLMs y LangChain
|
||||
- **YouTube**: Canal oficial de LangChain
|
||||
|
||||
### Comunidad
|
||||
- **Discord**: Comunidad activa de LangChain
|
||||
- **GitHub Discussions**: Preguntas y respuestas
|
||||
- **Twitter/X**: @LangChainAI para novedades
|
||||
|
||||
### Chat de LangChain
|
||||
- **Chat**: [chat.langchain.com](https://chat.langchain.com) - Asistente IA entrenado con la documentación oficial
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: cover
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Módulo 7: RAG
|
||||
|
||||
Retrieval Augmented Generation
|
||||
|
||||
<div class="pt-12">
|
||||
<span class="text-xl opacity-80">
|
||||
Extendiendo el conocimiento de los LLMs con tus datos
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ¿Qué es RAG?
|
||||
|
||||
<v-clicks>
|
||||
|
||||
**Retrieval Augmented Generation** combina búsqueda de información con generación de texto
|
||||
|
||||
- **Problema**: Los LLMs tienen conocimiento limitado
|
||||
- Datos de entrenamiento hasta cierta fecha
|
||||
- No conocen información específica de tu empresa
|
||||
- No pueden acceder a bases de datos en tiempo real
|
||||
|
||||
- **Solución RAG**:
|
||||
- Buscar información relevante en tus documentos
|
||||
- Proporcionar ese contexto al LLM
|
||||
- Generar respuestas basadas en tus datos
|
||||
|
||||
<div class="mt-8 p-4 bg-blue-500/10 rounded">
|
||||
💡 <b>En resumen</b>: Dale al LLM la información que necesita para responder correctamente
|
||||
</div>
|
||||
|
||||
</v-clicks>
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Flujo típico de RAG
|
||||
|
||||
<div class="mt-8">
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Pregunta del usuario] --> B[Convertir a embedding]
|
||||
B --> C[Buscar en BD vectorial]
|
||||
C --> D[Recuperar documentos relevantes]
|
||||
D --> E[Construir prompt con contexto]
|
||||
E --> F[LLM genera respuesta]
|
||||
F --> G[Respuesta al usuario]
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<v-clicks>
|
||||
|
||||
### Dos fases principales
|
||||
|
||||
1. **Indexación** (una vez): Convertir documentos a embeddings y almacenarlos
|
||||
2. **Recuperación** (cada consulta): Buscar documentos relevantes y generar respuesta
|
||||
|
||||
</v-clicks>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user