🤖 Developer Cookbook - FASE 6: Fundamentos de IA/ML
Recetas prácticas para entender IA, sesgos éticos y limitaciones de los LLMs
📚 Tabla de Contenidos
- Receta 6.1: ML vs Deep Learning vs LLMs - ¿Qué son?
- Receta 6.2: Entrenamiento, Inferencia y Fine-tuning
- Receta 6.3: Sesgos Algorítmicos y Ética en IA
- Receta 6.4: Alucinaciones y Limitaciones de LLMs
Fundamentos de IA/ML
Receta 6.1: ML vs Deep Learning vs LLMs - ¿Qué son?
Definiciones:
| Término | Definición | Ejemplo |
|---|---|---|
| Machine Learning (ML) | Algoritmos que aprenden patrones de datos sin programación explícita | Regresión lineal, Random Forest |
| Deep Learning (DL) | Subset de ML que usa redes neuronales profundas | CNN para imágenes, RNN para texto |
| Large Language Models (LLM) | Modelos de DL entrenados en texto masivo | GPT-4, Claude, Gemini |
Jerarquía:
Inteligencia Artificial (IA)
└── Machine Learning (ML)
└── Deep Learning (DL)
└── Large Language Models (LLM)
Comparación:
| Característica | ML Tradicional | Deep Learning | LLMs |
|---|---|---|---|
| Datos necesarios | 🟢 Miles | 🟡 Millones | 🔴 Billones |
| Poder de cómputo | 🟢 CPU suficiente | 🟡 GPU recomendada | 🔴 GPU/TPU necesarias |
| Interpretabilidad | 🟢 Alta | 🟡 Media | 🔴 Baja |
| Feature engineering | 🔴 Manual | 🟡 Semi-automático | 🟢 Automático |
| Casos de uso | Clasificación simple | Visión, audio | Texto, conversación |
Ejemplo de diferencias:
# 1. Machine Learning Tradicional (Scikit-learn)
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import pandas as pd
# Datos de entrenamiento
df = pd.read_csv('customer_data.csv')
X = df[['age', 'income', 'purchase_history']]
y = df['will_buy']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Modelo tradicional ML
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)
# Predicción
prediction = model.predict([[35, 75000, 5]])
print(f"¿Comprará? {prediction[0]}")
# 2. Deep Learning (TensorFlow/Keras)
import tensorflow as tf
from tensorflow import keras
# Red neuronal para clasificación de imágenes
model = keras.Sequential([
keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),
keras.layers.MaxPooling2D((2,2)),
keras.layers.Conv2D(64, (3,3), activation='relu'),
keras.layers.MaxPooling2D((2,2)),
keras.layers.Flatten(),
keras.layers.Dense(64, activation='relu'),
keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# Entrenamiento
model.fit(train_images, train_labels, epochs=5)
# 3. LLMs (API de OpenAI/Anthropic)
import anthropic
client = anthropic.Anthropic(api_key="your-api-key")
# Usar LLM para clasificación de texto
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=100,
messages=[{
"role": "user",
"content": "¿Este comentario es positivo o negativo? 'El producto es terrible, no funciona'"
}]
)
print(message.content[0].text)
Receta 6.2: Entrenamiento, Inferencia y Fine-tuning
Definiciones:
Entrenamiento (Training):
- Proceso de enseñar al modelo usando datos
- Actualiza los pesos/parámetros del modelo
- Computacionalmente costoso (días/semanas)
- Requiere dataset grande
# Ejemplo conceptual de entrenamiento
import torch
import torch.nn as nn
# Modelo simple
model = nn.Sequential(
nn.Linear(10, 50),
nn.ReLU(),
nn.Linear(50, 1)
)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.MSELoss()
# Loop de entrenamiento
for epoch in range(100):
for batch_x, batch_y in train_loader:
# Forward pass
predictions = model(batch_x)
loss = criterion(predictions, batch_y)
# Backward pass (actualiza pesos)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"Epoch {epoch}, Loss: {loss.item()}")
Inferencia (Inference):
- Usar el modelo entrenado para hacer predicciones
- NO actualiza pesos
- Rápido (milisegundos/segundos)
- Solo requiere modelo pre-entrenado
# Inferencia: usar modelo ya entrenado
model.eval() # Modo evaluación (no training)
with torch.no_grad(): # No calcular gradientes
prediction = model(new_data)
print(f"Predicción: {prediction}")
Fine-tuning:
- Tomar modelo pre-entrenado y “ajustarlo” con datos específicos
- Más rápido y barato que entrenar desde cero
- Requiere menos datos (cientos/miles vs millones)
# Fine-tuning conceptual
# 1. Cargar modelo pre-entrenado
from transformers import AutoModelForSequenceClassification, AutoTokenizer
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased")
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
# 2. Congelar capas tempranas (opcional)
for param in model.bert.encoder.layer[:8].parameters():
param.requires_grad = False
# 3. Entrenar solo las últimas capas con tus datos
# (código de training aquí)
Comparación:
| Aspecto | Entrenamiento | Fine-tuning | Inferencia |
|---|---|---|---|
| Tiempo | 🔴 Días/semanas | 🟡 Horas/días | 🟢 Segundos |
| Costo | 🔴 $$$$ | 🟡 $$ | 🟢 $ |
| Datos necesarios | 🔴 Millones | 🟡 Miles | 🟢 0 |
| Actualiza pesos | ✅ Sí | ✅ Sí | ❌ No |
| GPU necesaria | ✅ Sí | ✅ Sí | 🟡 Opcional |
Receta 6.3: Sesgos Algorítmicos y Ética en IA
¿Qué son los sesgos algorítmicos? Cuando un modelo de IA produce resultados sistemáticamente injustos o discriminatorios hacia ciertos grupos.
Tipos de sesgos:
- Sesgo en datos de entrenamiento:
# Ejemplo: Dataset de contratación sesgado
training_data = [
{"name": "John", "experience": 5, "hired": True},
{"name": "Michael", "experience": 5, "hired": True},
{"name": "Mary", "experience": 5, "hired": False},
{"name": "Jennifer", "experience": 5, "hired": False},
]
# Problema: El modelo aprenderá a preferir hombres
- Sesgo de representación:
# Dataset de reconocimiento facial
face_dataset = {
"white_males": 10000, # Sobre-representado
"white_females": 8000,
"black_males": 500, # Sub-representado
"black_females": 300,
}
# Resultado: Peor performance en grupos minoritarios
- Sesgo de confirmación:
# Sistema de recomendación
def recommend_news(user_history):
# Problema: Solo recomienda noticias similares
# Crea cámara de eco
return similar_articles(user_history)
Cómo detectar y mitigar sesgos:
import pandas as pd
from sklearn.metrics import confusion_matrix
import numpy as np
def analyze_fairness(model, X_test, y_test, sensitive_attribute):
"""
Analizar si modelo es justo entre diferentes grupos
"""
# Hacer predicciones
y_pred = model.predict(X_test)
# Agrupar por atributo sensible (ej: género, raza)
groups = X_test[sensitive_attribute].unique()
results = {}
for group in groups:
# Filtrar por grupo
mask = X_test[sensitive_attribute] == group
y_true_group = y_test[mask]
y_pred_group = y_pred[mask]
# Calcular métricas
from sklearn.metrics import accuracy_score, precision_score
results[group] = {
'accuracy': accuracy_score(y_true_group, y_pred_group),
'precision': precision_score(y_true_group, y_pred_group),
'sample_size': len(y_true_group),
'positive_rate': y_pred_group.mean()
}
# Comparar disparidad entre grupos
df_results = pd.DataFrame(results).T
print("\n📊 Análisis de equidad:")
print(df_results)
# Calcular disparate impact
max_positive_rate = df_results['positive_rate'].max()
min_positive_rate = df_results['positive_rate'].min()
disparate_impact = min_positive_rate / max_positive_rate
print(f"\n⚖️ Disparate Impact: {disparate_impact:.2f}")
print(" (< 0.8 indica posible discriminación)")
return df_results
# Uso
# analyze_fairness(model, X_test, y_test, sensitive_attribute='gender')
Principios éticos:
class EthicalAIChecklist:
"""Checklist de ética para proyectos de IA"""
@staticmethod
def evaluate_project(project_info):
checks = {
"transparency": "¿Los usuarios saben que están interactuando con IA?",
"explainability": "¿Puedes explicar por qué el modelo tomó una decisión?",
"fairness": "¿El modelo trata a todos los grupos equitativamente?",
"privacy": "¿Proteges los datos personales adecuadamente?",
"accountability": "¿Hay un humano responsable de las decisiones?",
"safety": "¿Has evaluado posibles daños?",
"human_oversight": "¿Hay supervisión humana en decisiones críticas?",
}
print("🤔 Checklist Ético de IA:\n")
for key, question in checks.items():
answer = input(f"{question} (s/n): ")
if answer.lower() != 's':
print(f"⚠️ ADVERTENCIA: Considera revisar {key}")
print("\n✅ Evaluación ética completada")
# Uso
# EthicalAIChecklist.evaluate_project(my_ai_project)
Casos de uso reales con problemas éticos:
| Caso | Problema | Solución |
|---|---|---|
| Sistema de contratación de Amazon | Discriminaba contra mujeres | Retirado y rediseñado |
| Reconocimiento facial | Peor accuracy en personas no-blancas | Diversificar dataset |
| Crédito financiero | Negaba préstamos a minorías | Auditoría algorítmica |
| Predicción criminal | Sesgado contra afroamericanos | Revisión humana obligatoria |
Receta 6.4: Alucinaciones y Limitaciones de LLMs
¿Qué son las alucinaciones? Cuando un LLM genera información falsa o inventada con confianza, como si fuera real.
Tipos de alucinaciones:
from anthropic import Anthropic
client = Anthropic(api_key="your-api-key")
# 1. Alucinaciones factuales
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=100,
messages=[{
"role": "user",
"content": "¿Cuándo murió el presidente Joe Biden?"
}]
)
# Problema: Puede inventar una fecha (Joe Biden está vivo)
# 2. Alucinaciones de fuentes
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=200,
messages=[{
"role": "user",
"content": "Dame la cita exacta donde Einstein dijo 'La imaginación es más importante que el conocimiento' con la fuente"
}]
)
# Problema: Puede inventar una fuente específica
# 3. Alucinaciones en código
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=300,
messages=[{
"role": "user",
"content": "Muéstrame cómo usar la función pandas.magical_transform()"
}]
)
# Problema: Esta función no existe, pero puede inventar documentación
Cómo detectar alucinaciones:
def detect_hallucination_risks(prompt: str) -> dict:
"""
Identificar si un prompt tiene riesgo alto de alucinaciones
"""
risks = {
'factual_claims': False,
'specific_dates': False,
'citations_needed': False,
'technical_specifics': False,
'statistics': False,
}
# Detectar patrones de riesgo
import re
# Preguntas sobre hechos específicos
if re.search(r'(cuándo|dónde|quién|qué año)', prompt.lower()):
risks['factual_claims'] = True
# Solicitudes de fechas
if re.search(r'\b(fecha|día|año|mes)\b', prompt.lower()):
risks['specific_dates'] = True
# Solicitudes de citas o fuentes
if re.search(r'(cita|fuente|referencia|estudio)', prompt.lower()):
risks['citations_needed'] = True
# APIs o funciones específicas
if re.search(r'(función|método|API|clase)\s+\w+\.\w+', prompt):
risks['technical_specifics'] = True
# Estadísticas
if re.search(r'(porcentaje|estadística|cuántos)', prompt.lower()):
risks['statistics'] = True
# Evaluar riesgo total
risk_count = sum(risks.values())
return {
'risks': risks,
'risk_level': 'HIGH' if risk_count >= 3 else 'MEDIUM' if risk_count >= 1 else 'LOW',
'recommendation': 'Verificar respuesta' if risk_count >= 1 else 'Probablemente seguro'
}
# Uso
prompt = "¿Cuándo murió Einstein y qué dijo en su lecho de muerte?"
analysis = detect_hallucination_risks(prompt)
print(f"Riesgo: {analysis['risk_level']}")
print(f"Recomendación: {analysis['recommendation']}")
Técnicas para reducir alucinaciones:
# 1. Pedir al modelo que admita incertidumbre
prompt_safe = """
Responde la siguiente pregunta. Si no estás seguro o no tienes información
confiable, di explícitamente "No tengo información confiable sobre esto".
Pregunta: ¿Cuál es el PIB de Andorra en 2024?
"""
# 2. Proporcionar contexto (RAG - Retrieval Augmented Generation)
from typing import List
def query_with_context(question: str, context_docs: List[str]) -> str:
"""
Usar RAG para reducir alucinaciones
"""
# Construir prompt con contexto
context = "\n\n".join([f"Documento {i+1}:\n{doc}"
for i, doc in enumerate(context_docs)])
prompt = f"""
Basándote ÚNICAMENTE en los siguientes documentos, responde la pregunta.
Si la información no está en los documentos, di "No puedo responder basándome en la información proporcionada".
{context}
Pregunta: {question}
"""
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=500,
messages=[{"role": "user", "content": prompt}]
)
return response.content[0].text
# 3. Verificación de hechos post-generación
def verify_response(response: str, knowledge_base: dict) -> dict:
"""
Verificar afirmaciones en la respuesta
"""
import re
# Extraer afirmaciones numéricas
numbers = re.findall(r'\d+(?:\.\d+)?', response)
dates = re.findall(r'\b(19|20)\d{2}\b', response)
verification = {
'response': response,
'numbers_found': numbers,
'dates_found': dates,
'warnings': []
}
# Verificar contra knowledge base
for claim, truth in knowledge_base.items():
if claim in response and truth not in response:
verification['warnings'].append(
f"⚠️ Posible error: se menciona '{claim}' pero debería ser '{truth}'"
)
return verification
# Uso
knowledge_base = {
"Einstein murió": "1955",
"Newton nació": "1643"
}
response_text = "Einstein murió en 1950" # Incorrecto
verification = verify_response(response_text, knowledge_base)
print(verification['warnings'])
Limitaciones de los LLMs:
class LLMLimitations:
"""
Documentar limitaciones conocidas de LLMs
"""
LIMITATIONS = {
"knowledge_cutoff": {
"descripción": "No saben eventos después de su fecha de entrenamiento",
"ejemplo": "No saben quién ganó elecciones recientes",
"solución": "Usar web search o proporcionar contexto actualizado"
},
"arithmetic": {
"descripción": "Pueden cometer errores en cálculos complejos",
"ejemplo": "234 * 567 = ? (puede equivocarse)",
"solución": "Usar herramientas externas (calculadoras, Python)"
},
"context_length": {
"descripción": "Límite en tokens que pueden procesar",
"ejemplo": "No pueden analizar libro completo de 500 páginas",
"solución": "Chunking, summarización incremental"
},
"inconsistency": {
"descripción": "Pueden dar respuestas diferentes a la misma pregunta",
"ejemplo": "Pregunta X puede tener respuesta Y o Z",
"solución": "Temperature=0 para más determinismo, múltiples samples"
},
"no_learning": {
"descripción": "No aprenden de conversaciones pasadas (sin fine-tuning)",
"ejemplo": "Olvidan lo que les dijiste en chats anteriores",
"solución": "Embeddings, vector DBs para 'memoria'"
},
"visual_limitations": {
"descripción": "Limitaciones en tareas visuales complejas",
"ejemplo": "Contar objetos exactos en imagen",
"solución": "Modelos especializados (YOLO, SAM)"
}
}
@classmethod
def check_limitations(cls, task_description: str):
"""
Verificar si una tarea puede tener limitaciones
"""
print(f"🔍 Analizando tarea: '{task_description}'\n")
warnings = []
# Verificar diferentes limitaciones
if any(keyword in task_description.lower() for keyword in ['calcular', 'multiplicar', 'sumar']):
warnings.append(cls.LIMITATIONS['arithmetic'])
if any(keyword in task_description.lower() for keyword in ['reciente', 'actual', 'hoy', '2024', '2025']):
warnings.append(cls.LIMITATIONS['knowledge_cutoff'])
if any(keyword in task_description.lower() for keyword in ['libro', 'documento largo', 'análisis completo']):
warnings.append(cls.LIMITATIONS['context_length'])
if warnings:
print("⚠️ Limitaciones detectadas:\n")
for i, warning in enumerate(warnings, 1):
print(f"{i}. {warning['descripción']}")
print(f" Ejemplo: {warning['ejemplo']}")
print(f" Solución: {warning['solución']}\n")
else:
print("✅ No se detectaron limitaciones obvias")
# Uso
LLMLimitations.check_limitations("Analiza este documento de 1000 páginas y dame las ventas de enero 2025")