TechLead
Lección 17 de 18
5 min de lectura
LangChain

Despliegue en Producción y LangSmith

Despliega apps LangChain a producción con mejores prácticas de caché, manejo de errores, control de costos y monitoreo con LangSmith

Desafíos de Producción

Mover aplicaciones LangChain de desarrollo a producción implica manejar latencia, costos, confiabilidad y observabilidad. Esta guía cubre los patrones esenciales para aplicaciones LLM listas para producción.

🚨 Consideraciones de Producción

💰 Costo: Las llamadas a GPT-4 se acumulan rápido a escala
⏱️ Latencia: Las llamadas LLM son lentas (2-30 segundos)
🔄 Confiabilidad: Límites de tasa y caídas de API
📊 Monitoreo: Depurar salidas no deterministas

Caché de Respuestas

import { ChatOpenAI } from "@langchain/openai";

// Caché en memoria (desarrollo)
const cache = new Map<string, string>();

async function invocarConCache(model: ChatOpenAI, input: string) {
  const cacheKey = input.trim().toLowerCase();
  
  if (cache.has(cacheKey)) {
    console.log("¡Hit de caché!");
    return cache.get(cacheKey)!;
  }
  
  const response = await model.invoke(input);
  const content = response.content as string;
  cache.set(cacheKey, content);
  return content;
}

// Caché Redis (producción)
import { Redis } from "ioredis";
const redis = new Redis(process.env.REDIS_URL!);

async function invocarConCacheRedis(model: ChatOpenAI, input: string) {
  const cacheKey = `llm:${Buffer.from(input).toString("base64")}`;
  const cached = await redis.get(cacheKey);
  
  if (cached) return cached;
  
  const response = await model.invoke(input);
  const content = response.content as string;
  
  // Caché por 1 hora
  await redis.set(cacheKey, content, "EX", 3600);
  return content;
}

Lógica de Reintento y Rate Limiting

import { ChatOpenAI } from "@langchain/openai";

// Reintento integrado con backoff exponencial
const model = new ChatOpenAI({
  modelName: "gpt-4",
  maxRetries: 3,
  maxConcurrency: 5,
});

// Wrapper personalizado con timeout
async function invocarConReintento(
  model: ChatOpenAI,
  input: string,
  maxReintentos = 3,
  timeoutMs = 30000
) {
  for (let intento = 1; intento <= maxReintentos; intento++) {
    try {
      const controller = new AbortController();
      const timeout = setTimeout(() => controller.abort(), timeoutMs);
      const response = await model.invoke(input, { signal: controller.signal });
      clearTimeout(timeout);
      return response;
    } catch (error: any) {
      console.error(`Intento ${intento} falló:`, error.message);
      if (error.status === 429) {
        await new Promise((r) => setTimeout(r, intento * 5000));
      } else if (intento === maxReintentos) {
        throw error;
      }
    }
  }
}

Control de Costos

// Estrategias de ahorro de costos:
// 1. Usar modelos más baratos para tareas simples
const modelBarato = new ChatOpenAI({ modelName: "gpt-4o-mini" }); // 20x más barato
const modelPotente = new ChatOpenAI({ modelName: "gpt-4" });

// 2. Enrutar según complejidad
async function enrutamientoInteligente(input: string) {
  const esComplejo = input.length > 200 || input.includes("analiza");
  const model = esComplejo ? modelPotente : modelBarato;
  return await model.invoke(input);
}

Cadenas de Respaldo

import { ChatOpenAI } from "@langchain/openai";
import { ChatAnthropic } from "@langchain/anthropic";

const modelPrimario = new ChatOpenAI({ modelName: "gpt-4" });
const modelRespaldo = new ChatAnthropic({ modelName: "claude-3-sonnet-20240229" });
const ultimoRecurso = new ChatOpenAI({ modelName: "gpt-4o-mini" });

// Respaldo integrado de LangChain
const modelConRespaldo = modelPrimario
  .withFallbacks({
    fallbacks: [modelRespaldo, ultimoRecurso],
  });

// Prueba automáticamente cada modelo en orden
const result = await modelConRespaldo.invoke("Explica las redes de Docker");
// Si GPT-4 falla → intenta Claude → intenta GPT-4o-mini

Arquitectura de Producción

// lib/ai-service.ts — Servicio de IA listo para producción
class ServicioIA {
  private model: ChatOpenAI;
  private cache: Map<string, { respuesta: string; timestamp: number }>;
  private readonly CACHE_TTL = 3600000; // 1 hora

  constructor() {
    this.model = new ChatOpenAI({
      modelName: "gpt-4",
      maxRetries: 3,
      maxConcurrency: 10,
    }).withFallbacks({
      fallbacks: [new ChatOpenAI({ modelName: "gpt-4o-mini" })],
    });
    this.cache = new Map();
  }

  async consultar(input: string, userId?: string): Promise<string> {
    const cacheKey = input.toLowerCase().trim();
    const cached = this.cache.get(cacheKey);
    if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
      return cached.respuesta;
    }

    const prompt = ChatPromptTemplate.fromMessages([
      ["system", "Eres un asistente de programación útil."],
      ["human", "{input}"],
    ]);
    const chain = prompt.pipe(this.model).pipe(new StringOutputParser());

    const respuesta = await chain.invoke(
      { input },
      { metadata: { userId, feature: "chat" }, tags: ["produccion"] }
    );

    this.cache.set(cacheKey, { respuesta, timestamp: Date.now() });
    return respuesta;
  }
}

export const servicioIA = new ServicioIA();

🚀 Checklist de Producción

  • ✓ Caché de respuestas (Redis o en memoria)
  • ✓ Rate limiting por usuario
  • ✓ Modelos de respaldo configurados
  • ✓ Manejo de errores con mensajes amigables
  • ✓ Monitoreo de costos y alertas
  • ✓ Trazado LangSmith habilitado
  • ✓ Validación y sanitización de entrada
  • ✓ Límites de presupuesto de tokens por solicitud

💡 Puntos Clave

  • • Cachea consultas idénticas para reducir costos en un 50-80%
  • • Usa cadenas de respaldo para confiabilidad (GPT-4 → Claude → GPT-4o-mini)
  • • Enruta tareas simples a modelos más baratos para reducir costos
  • • LangSmith proporciona observabilidad esencial para depurar problemas en producción
  • • Siempre implementa rate limiting, timeouts y seguimiento de costos

Continuar aprendiendo