Ir al contenido

La Mentalidad de Ingeniería de IA: Qué Cambia Cuando Construyes con LLMs

La ingeniería de IA no es solo ingeniería de software con un modelo adjunto. Los bucles de retroalimentación, los modos de fallo y las señales de calidad son fundamentalmente diferentes. Así es como debes pensar al respecto.

Durval Pereira
Durval Pereira
6 min

Un tipo diferente de ingeniería

La ingeniería de software tradicional es determinista en su esencia. Dada la misma entrada, esperas la misma salida. Las pruebas son binarias: pasan o fallan. Las implementaciones funcionan o no.

La ingeniería de IA rompe esta suposición. Cuando integras un LLM en un sistema de producción, estás trabajando con un componente que es:

  • No determinista: el mismo prompt puede producir diferentes salidas
  • Costoso por llamada: órdenes de magnitud más caro que una consulta a una base de datos
  • Latencia variable: los tiempos de respuesta varían de milisegundos a decenas de segundos
  • Opaco: no puedes inspeccionar el "razonamiento" de una manera depurable
  • Evolutivo: el comportamiento del modelo cambia con actualizaciones que no controlas

Esto no significa que la ingeniería de IA sea más difícil o más fácil que la ingeniería tradicional. Significa que las habilidades, los patrones y los instintos son diferentes.

El problema de la evaluación

En el software tradicional, escribes una prueba:

expect(calculateTax(100, 'CA')).toBe(7.25)

En la ingeniería de IA, el equivalente es mucho más difícil:

const response = await llm.complete('Summarize this article...')
// What does "correct" mean here?
// How do you assert quality programmatically?

Este es el desafío central. Necesitas frameworks de evaluación que sean lo suficientemente rigurosos para detectar regresiones, pero lo suficientemente flexibles para adaptarse a la variación natural en las salidas del modelo.

El patrón que mejor funciona en la práctica es la evaluación basada en rúbricas: define un conjunto de criterios, puntúa las salidas según esos criterios y haz un seguimiento de las puntuaciones a lo largo del tiempo.

interface EvaluationRubric {
  criteria: EvaluationCriterion[]
  passingScore: number
}

interface EvaluationCriterion {
  name: string
  description: string
  weight: number
  scorer: (input: string, output: string) => Promise<number>
}

const summarizationRubric: EvaluationRubric = {
  criteria: [
    {
      name: 'completeness',
      description: 'Covers all key points from the source',
      weight: 0.3,
      scorer: async (input, output) => {
        // Extract key entities from input, check coverage in output
        const keyPoints = await extractKeyPoints(input)
        const covered = keyPoints.filter((p) =>
          output.toLowerCase().includes(p.toLowerCase())
        )
        return covered.length / keyPoints.length
      },
    },
    {
      name: 'conciseness',
      description: 'Significantly shorter than the original',
      weight: 0.2,
      scorer: async (input, output) => {
        const ratio = output.length / input.length
        if (ratio < 0.2) return 1.0
        if (ratio < 0.4) return 0.7
        return 0.3
      },
    },
    {
      name: 'accuracy',
      description: 'No hallucinated facts',
      weight: 0.5,
      scorer: async (input, output) => {
        // Use a separate model call to check factual consistency
        return await checkFactualConsistency(input, output)
      },
    },
  ],
  passingScore: 0.75,
}

Este enfoque te proporciona un número que puedes rastrear, sobre el que puedes configurar alertas y usar en CI. No es perfecto, pero es mucho mejor que la revisión manual o ninguna evaluación en absoluto.

La ingeniería de prompts es diseño de API

Trata tus prompts como interfaces, no como cadenas de texto. Un prompt es el contrato API entre la lógica de tu aplicación y el modelo. Merece el mismo rigor que cualquier otra API.

interface PromptTemplate<TInput, TOutput> {
  name: string
  version: string
  template: (input: TInput) => string
  parser: (raw: string) => TOutput
  examples: Array<{ input: TInput; expectedOutput: TOutput }>
}

const classifyIntent: PromptTemplate<
  { message: string },
  { intent: string; confidence: number }
> = {
  name: 'classify-intent',
  version: '2.1',
  template: ({ message }) => `Classify the user intent for the following message.

Respond with a JSON object containing "intent" and "confidence" (0-1).

Valid intents: question, feedback, complaint, request, other

Message: "${message}"

JSON response:`,
  parser: (raw) => {
    const parsed = JSON.parse(raw.trim())
    return {
      intent: parsed.intent,
      confidence: Math.min(1, Math.max(0, parsed.confidence)),
    }
  },
  examples: [
    {
      input: { message: 'How do I reset my password?' },
      expectedOutput: { intent: 'question', confidence: 0.95 },
    },
  ],
}

Versionar los prompts, probarlos con ejemplos y tratar el análisis de salida como una preocupación de primera clase son las prácticas que separan los sistemas de IA de producción de los prototipos.

La ecuación del costo

Las llamadas a LLM son costosas. Un sistema que realiza una llamada de clase GPT-4 por cada interacción de usuario tendrá costos de infraestructura que escalan linealmente con el tráfico, a diferencia de los sistemas tradicionales donde los costos escalan sub-linealmente con el almacenamiento en caché y la optimización.

Las estrategias clave:

Caché agresivamente. Si dos usuarios hacen preguntas semánticamente similares, la respuesta probablemente sea la misma. El almacenamiento en caché semántico —utilizando la similitud de embeddings para detectar entradas equivalentes— puede reducir el volumen de llamadas entre un 30% y un 60%.

Usa el modelo más pequeño que funcione. GPT-4 no siempre es necesario. Para tareas de clasificación, extracción y formato, los modelos más pequeños son más rápidos, más baratos y a menudo igual de precisos.

Procesa en lotes cuando sea posible. Muchos proveedores de LLM ofrecen APIs de procesamiento por lotes con descuentos significativos. Si tu caso de uso tolera cierta latencia, el procesamiento por lotes puede reducir los costos en un 50% o más.

Precalcula donde puedas. Si estás utilizando un LLM para generar descripciones de productos, hazlo una vez en el momento de la publicación, no en cada vista de página.

Los modos de fallo son diferentes

Los sistemas tradicionales fallan con excepciones, tiempos de espera y códigos de error. Los sistemas de IA tienen un modo de fallo más sutil: devuelven algo que parece correcto pero no lo es.

Esto significa que necesitas barreras de seguridad:

async function safeLLMCall<T>(
  prompt: string,
  parser: (raw: string) => T,
  validator: (result: T) => boolean,
  retries = 2
): Promise<T | null> {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const raw = await llm.complete(prompt)
      const parsed = parser(raw)

      if (validator(parsed)) {
        return parsed
      }

      // Output parsed but failed validation — retry with adjusted prompt
      continue
    } catch {
      // Parse failure — retry
      continue
    }
  }

  return null // All attempts failed — fall back gracefully
}

La función validator es clave. Codifica tu lógica de negocio sobre cómo debe ser una salida válida. Sin ella, estás confiando completamente en el modelo, y esa confianza siempre debe ser verificada.

Qué significa esto para tu equipo

Si estás integrando IA en un sistema de producción, tu equipo necesita desarrollar nuevas habilidades:

  1. Comodidad con salidas probabilísticas. No todas las respuestas serán perfectas. Define explícitamente qué es "suficientemente bueno".
  2. Desarrollo impulsado por la evaluación. Escribe evaluaciones antes de escribir prompts, tal como escribirías pruebas antes del código.
  3. Conciencia de costos. Cada ingeniero debe comprender el costo por llamada y el costo total por característica.
  4. Degradación elegante. Cada característica impulsada por IA debe tener una alternativa no-IA.

La ingeniería de IA es ingeniería real. Simplemente requiere un conjunto diferente de instintos.


Próximo en esta serie: construyendo un sistema RAG de producción que realmente funcione.

Etiquetasaillmengineering-practicesproduction