RAG vs Fine-Tuning: Cuándo Usar Cada Técnica en Aplicaciones LLM

El mes pasado un compañero me preguntó si debería hacer fine-tuning de un modelo con la documentación interna de su empresa o usar RAG. Le respondí sin dudar: “RAG, casi seguro.” Me miró con cara de que esperaba algo más elaborado. Pero es que después de haber probado ambos enfoques en producción — y de haber elegido mal en más de una ocasión — la respuesta por defecto se ha simplificado bastante.

No siempre tuve tanta claridad. Hace año y medio estaba convencido de que fine-tuning era la solución sofisticada y RAG era el atajo del que te arrepentirías más adelante. Esa intuición me costó semanas de trabajo y bastante dinero en tokens de entrenamiento. Así que esto es lo que aprendí, con los errores incluidos.

La distinción que nadie explica bien al principio

Pues antes de entrar en cuándo usar cada uno, hay algo que me hubiera ahorrado mucho tiempo si lo hubiera entendido desde el principio: RAG y fine-tuning no compiten por el mismo problema.

RAG — Retrieval-Augmented Generation — le da al modelo acceso a información externa en el momento de la consulta. Cuando el usuario pregunta algo, el sistema busca primero documentos relevantes en una base de vectores y los mete en el contexto del modelo. El modelo no “sabe” esas cosas de antemano — las tiene disponibles justo cuando las necesita.

Fine-tuning modifica los pesos del modelo con datos de entrenamiento específicos. No amplía su conocimiento de forma confiable — cambia su comportamiento. Le estás enseñando cómo hablar, qué tono usar, qué estructura dar a sus respuestas, o cómo ejecutar un tipo de tarea de forma consistente.

La confusión típica — y yo caí en ella — es pensar en fine-tuning como “bañar al modelo en mis datos para que aprenda sobre mi empresa.” Eso no es lo que hace. O, más precisamente, no es lo que hace bien.

Por qué RAG es casi siempre el punto de partida correcto

Mira, la mayoría de los casos de uso que veo en startups y equipos de producto se reducen a esto: “queremos que el modelo sepa cosas que él no sabe.” Documentación técnica interna. Base de conocimiento de soporte. Políticas que cambian cada trimestre. Catálogo de productos actualizado cada semana.

Para todos esos casos, RAG es la herramienta correcta. El flujo básico no es complicado:

from openai import OpenAI
from pinecone import Pinecone

client = OpenAI()
pc = Pinecone(api_key="...")
index = pc.Index("docs-index")

def consulta_con_rag(pregunta: str) -> str:
    # 1. Convertir la pregunta a embedding
    embedding = client.embeddings.create(
        model="text-embedding-3-small",
        input=pregunta
    ).data[0].embedding

    # 2. Recuperar los chunks más relevantes
    resultados = index.query(
        vector=embedding,
        top_k=5,
        include_metadata=True
    )

    # 3. Construir el contexto con los documentos recuperados
    contexto = "\n\n---\n\n".join(
        r["metadata"]["text"] for r in resultados["matches"]
    )

    # 4. Generar respuesta usando el contexto como grounding
    respuesta = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": (
                    "Responde basándote únicamente en el contexto proporcionado. "
                    "Si el contexto no contiene la respuesta, dilo explícitamente."
                )
            },
            {
                "role": "user",
                "content": f"Contexto:\n{contexto}\n\nPregunta: {pregunta}"
            }
        ]
    )

    return respuesta.choices[0].message.content

Funciona. Pero — y aquí viene lo que los tutoriales de introducción no mencionan suficiente — la calidad de esto depende enormemente de tu estrategia de chunking. La primera vez que implementé RAG en serio, dividí los documentos en chunks de 512 tokens sin mucho criterio. El resultado: el modelo recuperaba fragmentos a mitad de párrafo, sin el contexto necesario para dar una buena respuesta.

Pasé a chunks de 1024 tokens con 200 de solapamiento y mejoró notablemente. Después agregué una etapa de reranking (probé Cohere’s Rerank API) y fue el cambio que más impacto tuvo en la calidad, más que cualquier ajuste de prompts. El truco de recuperar 20 candidatos y rerankear a 5 antes de pasarlos al modelo es algo que desearía haber sabido desde el principio.

Una cosa que noté: RAG también añade latencia real. En mi setup con Pinecone y GPT-4o, estábamos hablando de 800ms a 1.2s adicionales sobre el tiempo de inferencia del modelo. Para tareas asíncronas no importa. Para algo que debe sentirse interactivo, se nota.

Takeaway concreto: si el problema es que el modelo no tiene acceso a cierta información, empieza con RAG. Es más fácil de iterar, más fácil de debuggear (puedes ver exactamente qué documentos se recuperaron), y actualizar la base de conocimiento no requiere reentrenar nada.

Cuándo fine-tuning sí tiene sentido

El tema es que fine-tuning gana cuando el problema no es de conocimiento sino de comportamiento. Y hay casos donde eso es real.

El caso más claro que he vivido: necesitábamos que un modelo de clasificación de tickets respondiera siempre en un formato JSON muy específico, con campos exactos, ciertas categorías predefinidas, y una lógica de prioridad que era particular a nuestro sistema. Con prompting, incluso con ejemplos few-shot detallados, teníamos alrededor de un 11% de respuestas mal formateadas en producción — errores de parsing que rompían el pipeline downstream.

Preparamos un dataset de entrenamiento con ejemplos en formato JSONL y entrenamos un modelo con la API de fine-tuning de OpenAI (gpt-4o-mini en este caso):

{"messages": [{"role": "user", "content": "Ticket #2341: El usuario no puede iniciar sesión después del despliegue de ayer"}, {"role": "assistant", "content": "{\"ticket_id\": \"2341\", \"categoria\": \"autenticacion\", \"prioridad\": \"alta\", \"accion\": \"escalar_a_backend\", \"confianza\": 0.94}"}]}
{"messages": [{"role": "user", "content": "Ticket #2342: La imagen de perfil no se actualiza en mobile"}, {"role": "assistant", "content": "{\"ticket_id\": \"2342\", \"categoria\": \"ui_mobile\", \"prioridad\": \"media\", \"accion\": \"revisar_cdn\", \"confianza\": 0.81}"}]}

Después del fine-tuning, los errores de parsing bajaron a menos del 1%. Para ese caso de uso específico, valió completamente la pena.

Pero preparar ese dataset tomó tres semanas. Limpiar ejemplos, validar la consistencia de los labels, hacer varias corridas de evaluación para detectar casos edge donde el modelo aún se equivocaba, iterar el formato. No es algo que haces en un par de días.

Algo que noté también: el problema de evaluación es más difícil de lo que parece. ¿Cómo sabes que tu modelo fine-tuneado es realmente mejor? Sin un benchmark claro y un conjunto de evaluación bien curado, básicamente estás adivinando. Gastamos casi tanto tiempo en infraestructura de evaluación como en el entrenamiento en sí.

Takeaway concreto: fine-tuning es la herramienta correcta cuando el problema es consistencia de comportamiento — tono, formato de output, estructura de respuesta — y cuando ese comportamiento cambia con poca frecuencia. Si tienes el prompt perfecto pero el modelo sigue fallando de forma sistemática, entonces fine-tuning empieza a tener sentido.

El error que cometí (y que veo constantemente)

Mira, voy a ser directo sobre esto porque lo hice yo y lo veo hacer a otros equipos: intenté usar fine-tuning para “meterle conocimiento” al modelo sobre nuestra empresa.

La idea era tomar toda nuestra documentación interna — guías de producto, specs técnicos, políticas — convertirla en pares de pregunta-respuesta, y entrenar el modelo con eso. Preparé el dataset, pagué el training job, hice varias iteraciones… y el resultado fue frustrante. El modelo generaba respuestas que sonaban confiadas pero eran factualmente incorrectas. Inventaba detalles que no estaban en los datos de entrenamiento, interpolaba entre conceptos de forma que producía información falsa pero plausible.

El problema fundamental: los modelos de lenguaje no memorizan hechos de los datos de entrenamiento de forma perfecta y recuperable como una base de datos. Lo que aprenden es una distribución de texto. Cuando le preguntas algo, no “busca” la respuesta en sus datos de entrenamiento — genera texto que estadísticamente tiene sentido dado lo que aprendió. Eso no es confiable para casos donde la precisión factual importa.

RAG, en cambio, literalmente te muestra qué texto usó para generar la respuesta. Puedes auditar. Puedes agregar fuentes. Puedes ver cuando la recuperación falla y arreglarlo. La grounding es explícita y verificable.

Después de ese experimento fallido, migré ese caso de uso a RAG y los resultados fueron significativamente mejores desde la primera semana. No estoy 100% seguro de que esto aplique a todos los escenarios imaginables — probablemente con suficientes datos, técnicas de evaluación robustas y un equipo de ML dedicado, fine-tuning para conocimiento puede funcionar en ciertos contextos. Pero para la mayoría de equipos con documentación que evoluciona, es una apuesta arriesgada.

El factor que subestimé: el costo de mantenimiento en seis meses

Esta es la pregunta que me faltó hacerme al principio: ¿qué pasa con esto en medio año?

Con RAG, actualizar la base de conocimiento es manejable. Cambió un documento — lo re-embedeas, lo subes al índice vectorial, listo. Puedes instrumentar qué queries no encuentran buenos resultados (scores de similitud bajos) y mejorar esos casos específicos. El debugging es concreto: ves qué se recuperó, ves qué no se recuperó, puedes mejorarlo.

Con fine-tuning, si tu caso de uso evoluciona — nuevos ejemplos de edge cases, formato de output actualizado, cambios en la lógica de negocio — necesitas reentrenar. Eso significa volver a preparar y validar datos, hacer el training job, evaluar, deployar el nuevo checkpoint. Y cuando el proveedor depreca el modelo base sobre el que entrenaste, tienes que migrar. Eso es overhead real para un equipo pequeño.

Tu situación puede ser diferente. Si tienes un equipo de ML dedicado, datos bien estructurados y un caso de uso estable, ese overhead es perfectamente manejable. Pero para equipos de dos o tres personas iterando rápido, el costo de mantenimiento de fine-tuning no es despreciable.

También está el costo económico: fine-tuning tiene un costo de entrenamiento upfront más el costo de inferencia en el checkpoint resultante. RAG tiene el costo de los embeddings más el almacenamiento vectorial más la inferencia del modelo base. Para volúmenes bajos a medios, RAG suele salir más barato. Si estás haciendo millones de llamadas al día con prompts muy largos por el contexto recuperado, la ecuación puede cambiar — pero ese es un problema que la mayoría de equipos no tiene todavía.

Mi recomendación real, sin rodeos

Después de todo esto, mi proceso de decisión es bastante directo. Me hago tres preguntas, en orden:

¿El modelo necesita saber cosas que cambian más rápido de lo que puedo reentrenar? Si la respuesta es sí, necesito RAG. Esto cubre la gran mayoría de casos reales: bots de soporte, asistentes de documentación, cualquier cosa que toca contenido que un equipo está actualizando activamente.

¿El modelo tiene un problema de comportamiento que el prompting no resuelve? O sea, ¿probé variaciones del system prompt, intenté few-shot con buenos ejemplos, y el output sigue siendo inconsistente de forma sistemática? Si sí, fine-tuning vale la pena explorar. Si no probé en serio el prompting primero, ahí empiezo — es más barato y más rápido de iterar.

¿La diferencia de calidad justifica el overhead operacional? Fine-tuning significa ser responsable de un checkpoint. Cuando el proveedor actualiza modelos, tengo que decidir si migro. Para la mayoría de equipos internos y startups con las que he trabajado, ese overhead no se justifica a menos que el delta de calidad sea muy claro y medible.

Para la gran mayoría de aplicaciones, RAG es el punto de partida correcto. La combinación de ambos — fine-tuning para comportamiento, RAG para conocimiento — tiene sentido en casos avanzados cuando tienes un problema conductual claro que el prompting no puede resolver más un corpus de datos dinámico. Pero eso es complejidad adicional que hay que justificar, no el punto de partida.

Si alguien en tu equipo propone “fine-tunear el modelo con todos nuestros documentos”, la pregunta que corta el debate rápido es: ¿cómo vamos a mantener eso actualizado cuando los documentos cambien? Esa pregunta sola suele clarificar bastante.

Empieza con RAG. Invierte en el pipeline de recuperación. Y si después de eso sigues teniendo un problema de comportamiento que persiste, entonces es momento de hablar de fine-tuning.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top