initial commit: slides + practica_resueltos + README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
|
||||
Reference in New Issue
Block a user