Guía de desarrollo de aplicaciones de IA multimodal: de la selección de modelos al despliegue en producción

Quizá uses GPT-4 o Claude para escribir código o pulir textos, pero cuando el requisito pasa a ser “analizar los datos de esta captura” o “entender el vídeo que subió el usuario”, los modelos solo de texto se quedan cortos. La IA multimodal resuelve eso: el modelo entiende texto y también “ve” imágenes y vídeo.
En el último año, la IA multimodal avanzó más rápido de lo esperado. GPT-4o, Claude Vision y Gemini 1.5 Pro ampliaron el límite de lo posible. Para desarrolladores, la pregunta real no es “qué tan potente es”, sino “cómo usarla, qué modelo elegir y cómo controlar el costo”. Este artículo desglosa eso desde la práctica.
1. Conceptos clave de la IA multimodal
1.1 ¿Qué es la IA multimodal?
En pocas palabras, la IA multimodal procesa varios tipos de datos a la vez. Los modelos de solo texto consumen texto; los multimodales consumen texto, imágenes, audio y vídeo y devuelven el resultado que necesitas.
Ejemplo: subes una foto de producto y preguntas “¿Dónde está la etiqueta de precio? ¿Cuánto cuesta?”. El modelo entiende la imagen, localiza la etiqueta, lee el número y responde. Antes hacían falta detección de objetos, OCR y comprensión de texto; ahora basta una llamada multimodal.
1.2 Evolución de arquitectura: de “piezas sueltas” a fusión nativa
Las primeras soluciones eran tipo “lego”: encoders visuales (CLIP, ViT) convertían la imagen en vectores y se los pasaban al LLM. GPT-4V sigue esa línea, con un adaptador visual sobre GPT-4.
El problema: la visión “añadida” se siente desconectada. Al interpretar imágenes, el modelo en la práctica “adivina” con lógica de lenguaje y falla en razonamiento visual profundo.
Los modelos multimodales nativos lo corrigen. GPT-4o y Gemini nacieron multimodales: texto, imagen y audio se procesan de forma unificada en la base. La diferencia se nota en tareas como comparar dos imágenes o sacar conclusiones de un gráfico.
1.3 Tendencias tecnológicas 2025-2026
2025 se llama el “año del Agent”: la multimodalidad pasó de extra a imprescindible. Tendencias claras:
Contexto largo. Gemini 1.5 Pro admite más de 1M tokens y puede procesar más de una hora de vídeo de una vez. Antes había que analizar fotograma a fotograma; ahora el modelo puede “verlo” entero antes de responder.
Costos a la baja. Los modelos open source avanzan rápido. Qwen2-VL y GLM-4V se acercan al cerrado en varias tareas. En escenarios sensibles al costo, el despliegue privado ya es viable.
Agents multimodales. Ya no solo “describen” imágenes: actúan según lo que ven. Por ejemplo, “en esta captura, haz clic en Iniciar sesión” exige visión + herramientas + planificación.
2. Comparativa y selección de modelos multimodales
Al elegir modelo, no mires solo benchmarks. En desarrollo real importan estabilidad de la API, costo, facilidad de integración y cumplimiento normativo.
2.1 OpenAI: GPT-4V y GPT-4o
GPT-4V fue la primera solución multimodal de OpenAI: un adaptador visual le dio “ojos” a GPT-4. GPT-4o es la versión nativa posterior, con capacidades globales superiores.
¿Cuándo elegir GPT-4o?
- Razonamiento visual (sacar conclusiones de imágenes, comparar diferencias)
- Conversaciones multimodales de varias vueltas (la imagen sigue en contexto)
- Máxima precisión
¿Cuándo elegir GPT-4V?
- Descripción o clasificación simple de imágenes
- Aplicaciones sensibles a la latencia (a veces GPT-4V responde más rápido)
- Compatibilidad con sistemas antiguos
En llamadas API, ambos modelos son esencialmente iguales:
from openai import OpenAI
client = OpenAI()
# Método 1: URL de imagen
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "¿Qué hay en esta imagen?"},
{"type": "image_url", "image_url": {"url": "https://example.com/image.jpg"}}
]
}]
)
# Método 2: codificación Base64
import base64
with open("image.png", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Analiza esta imagen"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_data}"}}
]
}]
)
print(response.choices[0].message.content)
2.2 Anthropic: Claude Vision
Claude Vision destaca en análisis de documentos y extracción de detalle. Para sacar datos estructurados de PDF, gráficos o capturas, Claude es una buena opción.
Escenarios fuertes de Claude Vision:
- Análisis de documentos (PDF, escaneos, tablas complejas)
- Extracción de detalle (más “meticuloso” que otros modelos)
- Documentos largos (contexto 200K)
La llamada difiere un poco: Claude trata las imágenes como bloques de contenido independientes:
from anthropic import Anthropic
import base64
client = Anthropic()
# Leer imagen y convertir a Base64
with open("document.png", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=1024,
messages=[{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_data
}
},
{"type": "text", "text": "Extrae todos los datos de tablas del documento y devuélvelos en JSON"}
]
}]
)
print(response.content[0].text)
2.3 Google: serie Gemini
La baza de Gemini es el contexto largo. Gemini 1.5 Pro admite más de 1M tokens: vídeos muy largos y análisis multi-documento. Si hay mucho contenido visual, vale la pena probarlo.
Escenarios aplicables:
- Análisis de vídeo largo (más de 10 minutos)
- Procesamiento por lotes de varios documentos
- Tareas que relacionan varios contenidos visuales
2.4 Open source: Qwen2-VL, GLM-4V
En escenarios sensibles al costo, a los datos o con despliegue privado, el open source es una opción realista.
Qwen2-VL: open source de Alibaba, optimizado para chino, imágenes hasta 4K. Estable en empresa; costo de llamada ~1/10 del cerrado.
GLM-4V: open source de Zhipu, adecuado para cumplimiento en China; arquitectura MoE reduce costo de inferencia.
2.5 Matriz de decisión
¿Cómo elegir? Según el caso:
| Escenario | Modelo recomendado | Motivo |
|---|---|---|
| Prototipo rápido, MVP | GPT-4o | API madura, documentación amplia, fácil depuración |
| Análisis de documentos, extracción | Claude Vision | Detalle fino, tablas precisas |
| Vídeo largo | Gemini 1.5 Pro | Contexto muy largo, razonamiento multimodal |
| Costo bajo, alta concurrencia | Qwen2-VL | Open source controlable, bajo costo |
| Datos sensibles, despliegue privado | GLM-4V | Local, datos en tu perímetro |
| Escenarios en chino, presupuesto ajustado | Qwen2-VL | Optimizado para chino, buena relación costo-beneficio |
3. Comprensión y procesamiento de imágenes en la práctica
3.1 Fundamentos de llamadas API
El núcleo de las API multimodales es el formato de mensaje correcto. OpenAI o Anthropic: imágenes y texto como partes distintas del mensaje.
Cuida el tamaño de imagen: los tokens dependen de píxeles. GPT-4o escala automáticamente, pero para controlar el costo conviene preprocesar antes de subir.
3.2 Descripción y preguntas sobre imágenes
El caso más básico: describir la imagen o responder preguntas. Aquí un envoltorio completo de Q&A:
from openai import OpenAI
import base64
from pathlib import Path
class ImageAnalyzer:
def __init__(self, model="gpt-4o"):
self.client = OpenAI()
self.model = model
def analyze(self, image_path: str, question: str) -> str:
"""Analizar imagen y responder pregunta"""
# Leer imagen
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
# Determinar tipo de imagen
suffix = Path(image_path).suffix.lower()
media_type = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".gif": "image/gif",
".webp": "image/webp"
}.get(suffix, "image/jpeg")
# Construir solicitud
response = self.client.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": [
{"type": "text", "text": question},
{"type": "image_url", "image_url": {
"url": f"data:{media_type};base64,{image_data}"
}}
]
}],
max_tokens=1000
)
return response.choices[0].message.content
# Ejemplo de uso
analyzer = ImageAnalyzer()
result = analyzer.analyze("product.jpg", "¿Cuál es la marca de este producto? ¿Cuál es el precio?")
print(result)
3.3 Análisis de documentos (PDF/gráficos)
Con PDF, convierte cada página en imagen y analiza página a página. Parser práctico:
import fitz # PyMuPDF
from PIL import Image
import io
import base64
from openai import OpenAI
def pdf_to_images(pdf_path: str, dpi: int = 150) -> list:
"""Convertir PDF en lista de imágenes"""
doc = fitz.open(pdf_path)
images = []
for page_num in range(len(doc)):
page = doc[page_num]
# Renderizar página como imagen
mat = fitz.Matrix(dpi / 72, dpi / 72)
pix = page.get_pixmap(matrix=mat)
# Convertir a PIL Image
img_data = pix.tobytes("png")
img = Image.open(io.BytesIO(img_data))
images.append(img)
doc.close()
return images
def extract_table_from_page(image: Image.Image, client: OpenAI) -> dict:
"""Extraer tablas de una página"""
# Convertir a base64
buffer = io.BytesIO()
image.save(buffer, format="PNG")
image_data = base64.b64encode(buffer.getvalue()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": """
Extrae los datos de tablas de la imagen y devuélvelos en JSON.
Si hay varias tablas, usa un array.
Ejemplo: {"tables": [{"headers": [...], "rows": [...]}]}
"""},
{"type": "image_url", "image_url": {
"url": f"data:image/png;base64,{image_data}"
}}
]
}],
response_format={"type": "json_object"}
)
import json
return json.loads(response.choices[0].message.content)
# Flujo completo
images = pdf_to_images("report.pdf")
for i, img in enumerate(images):
print(f"Procesando página {i+1}...")
tables = extract_table_from_page(img, OpenAI())
print(f"Se extrajeron {len(tables.get('tables', []))} tablas")
3.4 Procesamiento por lotes de imágenes
Con muchas imágenes, el control de concurrencia es crítico. Las API tienen límites; concurrencia a ciegas te limita:
import asyncio
from openai import AsyncOpenAI
import aiofiles
import base64
class BatchImageProcessor:
def __init__(self, model="gpt-4o", max_concurrent=5):
self.client = AsyncOpenAI()
self.model = model
self.semaphore = asyncio.Semaphore(max_concurrent)
async def process_single(self, image_path: str, prompt: str) -> dict:
"""Procesar una imagen"""
async with self.semaphore:
try:
async with aiofiles.open(image_path, "rb") as f:
image_bytes = await f.read()
image_data = base64.b64encode(image_bytes).decode("utf-8")
response = await self.client.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{image_data}"
}}
]
}]
)
return {
"path": image_path,
"result": response.choices[0].message.content,
"success": True
}
except Exception as e:
return {
"path": image_path,
"error": str(e),
"success": False
}
async def process_batch(self, image_paths: list, prompt: str) -> list:
"""Procesar imágenes en lote"""
tasks = [self.process_single(p, prompt) for p in image_paths]
return await asyncio.gather(*tasks)
# Ejemplo de uso
async def main():
processor = BatchImageProcessor(max_concurrent=3)
results = await processor.process_batch(
["img1.jpg", "img2.jpg", "img3.jpg"],
"Describe esta imagen en no más de 50 palabras"
)
for r in results:
print(f"{r['path']}: {r.get('result', r.get('error'))}")
asyncio.run(main())
4. Comprensión de vídeo en la práctica
El núcleo del vídeo es “reducir dimensiones”: fotogramas clave discretos y análisis por lotes. El reto es equilibrar información y costo.
4.1 Extracción y procesamiento de fotogramas
import cv2
import base64
from pathlib import Path
class VideoProcessor:
def __init__(self, video_path: str):
self.video_path = video_path
self.cap = cv2.VideoCapture(video_path)
self.fps = self.cap.get(cv2.CAP_PROP_FPS)
self.total_frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
self.duration = self.total_frames / self.fps
def extract_frames(self, strategy="interval", **kwargs):
"""Extraer fotogramas de vídeo
Args:
strategy: Estrategia de extracción
- interval: un fotograma cada N segundos
- scene: en cambios de escena
- uniform: N fotogramas uniformes
"""
frames = []
if strategy == "interval":
interval_sec = kwargs.get("interval", 1.0)
interval_frames = int(interval_sec * self.fps)
frame_idx = 0
while self.cap.isOpened():
ret, frame = self.cap.read()
if not ret:
break
if frame_idx % interval_frames == 0:
frames.append((frame_idx / self.fps, frame))
frame_idx += 1
elif strategy == "uniform":
num_frames = kwargs.get("num_frames", 10)
interval = max(1, self.total_frames // num_frames)
for i in range(num_frames):
self.cap.set(cv2.CAP_PROP_POS_FRAMES, i * interval)
ret, frame = self.cap.read()
if ret:
frames.append((i * interval / self.fps, frame))
self.cap.release()
return frames
def frame_to_base64(self, frame) -> str:
"""Convertir fotograma a base64"""
_, buffer = cv2.imencode('.jpg', frame)
return base64.b64encode(buffer).decode('utf-8')
# Ejemplo de uso
processor = VideoProcessor("demo.mp4")
print(f"Duración del vídeo: {processor.duration:.1f} segundos")
# Un fotograma cada 2 segundos
frames = processor.extract_frames(strategy="interval", interval=2.0)
print(f"Se extrajeron {len(frames)} fotogramas")
4.2 Estrategias para vídeos largos
En vídeos largos el costo sube rápido. Estrategias prácticas:
Procesamiento jerárquico: revisión rápida a baja resolución y fps para localizar segmentos clave; luego análisis fino.
Detección de escenas: solo fotogramas con cambio de plano; OpenCV ayuda.
Resumen primero: resumir cada segmento y luego sintetizar.
4.3 Caso práctico: resumen de vídeo
from openai import OpenAI
def generate_video_summary(frames: list, client: OpenAI) -> str:
"""Generar resumen de vídeo desde fotogramas clave"""
# Lotes de máximo 5 fotogramas
batch_size = 5
segment_summaries = []
for i in range(0, len(frames), batch_size):
batch = frames[i:i+batch_size]
# Construir contenido del mensaje
content = [{"type": "text", "text": "Describe qué ocurre en estos fotogramas, de forma breve y clara"}]
for timestamp, frame in batch:
frame_base64 = VideoProcessor("").frame_to_base64(frame)
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{frame_base64}"}
})
# Llamar API
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": content}]
)
segment_summaries.append(response.choices[0].message.content)
# Sintetizar resúmenes de segmentos
final_prompt = f"""
Aquí están los resúmenes de cada segmento del vídeo:
{chr(10).join(f'{i+1}. {s}' for i, s in enumerate(segment_summaries))}
Sintetiza la información anterior y genera un resumen completo del vídeo, incluyendo:
1. Contenido principal
2. Eventos o información clave
3. Tema general
"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": final_prompt}]
)
return response.choices[0].message.content
5. Optimización de costos y rendimiento
El costo multimodal viene sobre todo de tokens visuales. Una imagen 1024×1024 ~765 tokens; mal gestionado, una solicitud puede costar mucho.
5.1 Cálculo de tokens visuales
Reglas de tokens de GPT-4o:
| Tamaño imagen | Modo baja resolución | Modo alta resolución |
|---|---|---|
| 512×512 | 85 tokens | 255 tokens |
| 1024×1024 | 170 tokens | 765 tokens |
| 2048×2048 | 255 tokens | 2550 tokens |
Baja resolución: tipo de imagen o descripción general. Alta resolución: leer texto o ver detalle.
5.2 Compresión y preprocesado
Preprocesar antes de subir controla costos:
from PIL import Image
from pathlib import Path
def optimize_image(image_path: str, max_size: int = 1024, quality: int = 85) -> str:
"""Optimizar tamaño y calidad de imagen"""
img = Image.open(image_path)
# Redimensionar
if max(img.size) > max_size:
ratio = max_size / max(img.size)
new_size = (int(img.size[0] * ratio), int(img.size[1] * ratio))
img = img.resize(new_size, Image.Resampling.LANCZOS)
# Recortar zona clave (si se conoce la posición)
# img = img.crop((left, top, right, bottom))
# Guardar imagen optimizada
optimized_path = f"optimized_{Path(image_path).name}"
img.save(optimized_path, "JPEG", quality=quality)
return optimized_path
# Ejemplo de uso
optimized = optimize_image("screenshot.png", max_size=1024)
# Original ~2 MB, optimizada ~200 KB
5.3 Caché y procesamiento por lotes
Caché de resultados: misma imagen, mismo resultado; usa hash como clave:
import hashlib
def get_image_hash(image_path: str) -> str:
"""Calcular hash de imagen"""
with open(image_path, "rb") as f:
return hashlib.md5(f.read()).hexdigest()
# Lógica de caché
cache = {}
image_hash = get_image_hash("product.jpg")
if image_hash in cache:
result = cache[image_hash]
else:
result = analyzer.analyze("product.jpg", "Describe este producto")
cache[image_hash] = result
Fusión en lote: varias imágenes relacionadas en una sola solicitud:
# No recomendado: varias solicitudes
for img in images:
result = analyze_image(img, "Describe la imagen")
# Recomendado: una solicitud
all_images_content = [{"type": "text", "text": "Describe estas imágenes"}]
for img in images:
all_images_content.append({
"type": "image_url",
"image_url": {"url": img_url}
})
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": all_images_content}]
)
5.4 Estrategia híbrida de modelos
No todo requiere el modelo más fuerte. Puedes escalonar:
def smart_analyze(image_path: str, task_type: str):
"""Elegir modelo según tipo de tarea"""
if task_type in ["classify", "detect"]:
# Clasificación/detection: modelo pequeño
model = "gpt-4o-mini"
elif task_type in ["ocr", "extract"]:
# OCR/extracción: modelo medio
model = "gpt-4o"
else:
# Razonamiento complejo: modelo fuerte
model = "gpt-4o"
# ... lógica de llamada
6. Mejores prácticas de despliegue en producción
Del demo a producción hay mucha ingeniería por delante.
6.1 Errores y reintentos
Las API fallan: timeout, límite de tasa, error de servidor. Hace falta manejo robusto:
import time
from openai import APIError, RateLimitError, APIConnectionError
def robust_api_call(func, max_retries=3, backoff_factor=2):
"""Llamada API con reintentos"""
for attempt in range(max_retries):
try:
return func()
except RateLimitError:
if attempt < max_retries - 1:
wait_time = backoff_factor ** attempt
print(f"Límite de tasa, esperando {wait_time} s antes de reintentar...")
time.sleep(wait_time)
else:
raise
except APIConnectionError as e:
print(f"Error de conexión: {e}")
if attempt < max_retries - 1:
time.sleep(1)
else:
raise
except APIError as e:
print(f"Error de API: {e}")
raise
6.2 Concurrencia y limitación de tasa
Los límites multimodales suelen ser más estrictos que en texto. Implementa token bucket:
import asyncio
import time
class RateLimiter:
def __init__(self, requests_per_minute: int):
self.interval = 60.0 / requests_per_minute
self.last_request = 0
self.lock = asyncio.Lock()
async def acquire(self):
async with self.lock:
now = time.time()
wait_time = self.last_request + self.interval - now
if wait_time > 0:
await asyncio.sleep(wait_time)
self.last_request = time.time()
# Ejemplo de uso
limiter = RateLimiter(requests_per_minute=100)
async def process_with_limit(image_path):
await limiter.acquire()
return await async_analyze(image_path)
6.3 Monitorización y logs
Registra datos clave por llamada para depurar:
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def log_api_call(model: str, input_tokens: int, output_tokens: int, latency: float):
logger.info(
f"Llamada API - Modelo: {model}, "
f"Tokens entrada: {input_tokens}, salida: {output_tokens}, "
f"Latencia: {latency:.2f}s"
)
# Registrar tras la llamada
start_time = time.time()
response = client.chat.completions.create(...)
latency = time.time() - start_time
log_api_call(
model="gpt-4o",
input_tokens=response.usage.prompt_tokens,
output_tokens=response.usage.completion_tokens,
latency=latency
)
6.4 Ejemplo de código completo
Integra lo anterior en una clase utilitaria lista para usar:
from openai import OpenAI
from pathlib import Path
import base64
import logging
import time
from typing import Optional, List, Dict
logger = logging.getLogger(__name__)
class MultimodalAnalyzer:
"""Clase utilitaria de análisis multimodal"""
def __init__(
self,
model: str = "gpt-4o",
max_retries: int = 3,
requests_per_minute: int = 100
):
self.client = OpenAI()
self.model = model
self.max_retries = max_retries
self.min_interval = 60.0 / requests_per_minute
self.last_request_time = 0
def _wait_for_rate_limit(self):
"""Limitación de tasa"""
now = time.time()
wait_time = self.last_request_time + self.min_interval - now
if wait_time > 0:
time.sleep(wait_time)
self.last_request_time = time.time()
def _read_image(self, image_path: str) -> str:
"""Read image and convert to base64"""
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
def _call_with_retry(self, messages: list) -> dict:
"""API call with retry"""
for attempt in range(self.max_retries):
try:
self._wait_for_rate_limit()
start_time = time.time()
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
max_tokens=1000
)
latency = time.time() - start_time
logger.info(
f"Llamada API exitosa - tokens: {response.usage.total_tokens}, "
f"latencia: {latency:.2f}s"
)
return {
"content": response.choices[0].message.content,
"tokens": {
"prompt": response.usage.prompt_tokens,
"completion": response.usage.completion_tokens
}
}
except Exception as e:
logger.error(f"Llamada API fallida (intento {attempt + 1}/{self.max_retries}): {e}")
if attempt == self.max_retries - 1:
raise
time.sleep(2 ** attempt)
def analyze_image(
self,
image_path: str,
prompt: str,
detail: str = "auto"
) -> dict:
"""Analizar una imagen"""
image_data = self._read_image(image_path)
messages = [{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{image_data}",
"detail": detail
}
}
]
}]
return self._call_with_retry(messages)
def analyze_multiple_images(
self,
image_paths: List[str],
prompt: str
) -> dict:
"""Analizar varias imágenes"""
content = [{"type": "text", "text": prompt}]
for path in image_paths:
image_data = self._read_image(path)
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{image_data}"}
})
return self._call_with_retry([{"role": "user", "content": content}])
def extract_text_from_image(self, image_path: str) -> str:
"""Extraer texto de imagen (OCR)"""
result = self.analyze_image(
image_path,
"Extrae todo el texto de la imagen en el formato original"
)
return result["content"]
def describe_image(self, image_path: str) -> str:
"""Generar descripción de imagen"""
result = self.analyze_image(
image_path,
"Describe el contenido de esta imagen en un párrafo"
)
return result["content"]
# Ejemplo de uso
if __name__ == "__main__":
analyzer = MultimodalAnalyzer()
# Analizar una imagen
result = analyzer.analyze_image(
"product.jpg",
"¿Cuál es la marca de este producto? ¿Cuál es el precio?"
)
print(result["content"])
# OCR: extraer texto
text = analyzer.extract_text_from_image("document.png")
print(text)
Conclusión
La IA multimodal pasa de “juguete novedoso” a “herramienta útil”. Al elegir modelo, mira el escenario: Gemini para vídeo largo, Claude para documentos, GPT-4o para prototipos, open source si el costo aprieta.
En desarrollo, controla el costo: preprocesar, elegir resolución y cachear. En producción: reintentos, límites de tasa y logs.
Los límites siguen ampliándose. En 2025: más agents multimodales, contextos más largos y open source más maduro. Dominar estas bases te permite adaptarte rápido.
Referencias
- GPT-4 Vision: A Comprehensive Guide - DataCamp
- Claude Vision for Document Analysis - GetStream
- GPT-4o Vision Guide - GetStream
- OpenAI Multimodal Cookbook
- Guía de desarrollo de agents de IA multimodal 2025
FAQ
¿Debo elegir GPT-4o o GPT-4V?
¿Cómo controlar el costo de las API multimodales?
• Preprocesar imágenes: comprimir tamaño y reducir resolución antes de subir
• Elegir resolución con criterio: modo baja resolución cuando no hagan falta detalles
• Implementar caché: guardar resultados de consultas sobre la misma imagen
¿Consejos para procesar vídeos largos?
¿Se pueden usar modelos multimodales open source?
¿Qué preparar para un entorno de producción?
15 min de lectura · Publicado el: 24 mar 2026 · Actualizado el: 21 ago 2026
Desarrollo de IA
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Refactorizar 10.000 líneas de código legacy con IA: retrospectiva real en 2 semanas
Relato completo de cómo refactoricé 10.000 líneas de código legacy en Vue con Claude Code. De asumir un monolito que nadie tocaba en 3 años a desplegar en 2 semanas sin incidentes, con plantillas de prompts y guía de errores comunes.
Parte 1 de 8
Siguiente
Desarrollo de aplicaciones de IA multimodal: guía completa de fusión de tres modalidades
Compara GPT-4V, Gemini y Claude con ejemplos de código completos para fusionar texto, imagen y voz. Aprende principios de arquitectura y técnicas de control de costos para dominar el desarrollo multimodal.
Parte 3 de 8



Comentarios
Inicia sesión con GitHub para dejar un comentario