Un agente que funcionaba de manera confiable con un modelo frontier de OpenAI ayer falla con Claude hoy. No porque el código esté roto, sino porque OpenAI espera las llamadas a herramientas como un array tools, Anthropic usa content blocks tool_use, y Google utiliza function_declarations. Tres proveedores, tres esquemas incompatibles para el mismo concepto.
Acoplar tu agente a un solo proveedor significa aceptar sus cambios de precios, límites de tasa y deprecaciones de modelos como leyes inmutables de la naturaleza. El agnosticismo de LLM no es un nice-to-have. Es una cuestión de supervivencia.
TL;DR: Los patrones adaptadores (LiteLLM, LangChain) resuelven el problema sintáctico, haciendo que las llamadas a la API se vean iguales. MCP resuelve el problema de las herramientas, haciendo que funcionen con cualquier modelo. Pero ninguno resuelve el problema semántico: los modelos se comportan de manera diferente incluso con entradas idénticas. La verdadera portabilidad requiere las tres capas.
Una nota rápida sobre terminología: Proveedor = plataforma API (OpenAI, Anthropic, Google). Modelo = ID de modelo específico. Framework = capa de orquestación que abstrae ambos.
El patrón adaptador: Donde todos empiezan
La solución en la que todos los frameworks principales convergieron independientemente es el patrón adaptador.
Cómo lo hacen los tres grandes
- LiteLLM lo implementa de la manera más directa: una única llamada
completion()acepta una cadena de modelo y enruta de forma transparente a más de 100 proveedores. - El
BaseChatModelde LangChain invierte la dependencia. Todas las integraciones de proveedores implementan el mismo contrato de interfaz con objetosBaseMessagey un método unificadobind_tools(). - AutoGen v0.4 formaliza el límite a través de un diseño basado en protocolos donde los agentes se definen por sus roles y protocolos de comunicación, no por el modelo subyacente.
Suena como un problema resuelto. La realidad es considerablemente más compleja.
Dónde impacta la divergencia de API en la práctica
El verdadero desafío de ingeniería está en los detalles de la traducción bidireccional de esquemas.
Tres proveedores, tres esquemas
Un ejemplo simplificado hace visible el alcance:
# Pseudocode - simplified schema, real APIs differ in details
# OpenAI: tools array with function wrapper
tools = [{"type": "function", "function": {"name": "get_weather", "parameters": {...}}}]
# Anthropic: tool_use content blocks
tools = [{"name": "get_weather", "input_schema": {...}}]
# Google: function_declarations (format varies by API version/SDK)
tools = [{"function_declarations": [{"name": "get_weather", "parameters": {...}}]}]
# LiteLLM: accepts OpenAI-like inputs and normalizes internally
response = litellm.completion(
model="anthropic/claude-sonnet-4-20250514",
messages=messages,
tools=tools # OpenAI format - LiteLLM handles conversion
)
LiteLLM opera como adaptador en el límite HTTP/SDK: las solicitudes salientes se traducen al esquema respectivo del proveedor, las respuestas entrantes se convierten de vuelta a un objeto ModelResponse canónico. No se garantiza la paridad completa entre todos los proveedores y funciones, pero los casos comunes están cubiertos.
Normalización de respuestas
Las diferencias van más allá de los formatos de solicitud:
- Razones de parada: Anthropic retorna
stop_reason: "end_turn". LiteLLM lo reescribe en unfinish_reasonnormalizado. - Estructura de respuesta: La estructura profundamente anidada
candidates[0].content.partsde Gemini se aplana antes de que el código del agente la vea. - Acceso consistente: Tu código siempre lee
choices[0].message.contentychoices[0].message.tool_calls, independientemente del proveedor detrás.
Paso de resultados de herramientas
Pasar los resultados de herramientas también diverge fundamentalmente:
| Proveedor | Cómo se pasan los resultados de herramientas |
|---|---|
| OpenAI | Mensaje dedicado con rol tool |
| Anthropic | Mensajes user con content blocks tool_result |
Parts functionCall | |
| Sin soporte nativo | LiteLLM serializa esquemas en el system prompt, parsea texto libre via regex |
Esa última fila es reveladora. Funciona, pero muestra los límites de la normalización sintáctica.
Parsing de salida a nivel de framework
A nivel de framework, LangChain aborda la heterogeneidad de respuestas a través de una jerarquía BaseOutputParser por capas:
.with_structured_output()despacha automáticamente a OpenAI function calling, bloquestool_usede Anthropic, oresponse_schemade Google, según las capacidades de cada proveedor.- Un
OutputFixingParserimplementa bucles de reintento auto-reparadores para JSON malformado.
Esto refleja una verdad difícil: no puedes asumir que la salida del modelo será consistente.
Insight clave: La traducción de esquemas y la equivalencia semántica son dos problemas diferentes. El manejo de tool-calls paralelos, la aplicación de
tool_choice, las razones de finalización de streaming, todo esto sigue siendo específico del proveedor, incluso después de la normalización sintáctica.
MCP: El segundo eje de estandarización
Mientras LiteLLM y LangChain abstraen la capa del modelo, un segundo vector de estandarización surgió en paralelo, esta vez no para el modelo, sino para las herramientas.
El problema N x M
Antes de MCP, conectar N frameworks de agentes con M herramientas requería N x M integraciones personalizadas. Cada framework y cada proveedor usaba formatos de esquema de herramientas incompatibles.
El Model Context Protocol (MCP) de Anthropic, lanzado a finales de 2024, reduce esto a N+M al definir un único protocolo basado en JSON-RPC 2.0 a través del cual los servidores de herramientas exponen sus capacidades y los clientes agentes las consumen.
Cómo funciona
Agent Host → MCP tools/list → Tool Schemas → Model Call → Tool Call → Tool Result → next step
Piénsalo como el Language Server Protocol (LSP): así como LSP estandarizó la comunicación entre IDEs y servidores de lenguaje, MCP crea una interfaz universal entre agentes y herramientas. USB-C para IA: descubrimiento estandarizado, invocaciones unificadas, manejo de errores normalizado.
Por qué importa arquitectónicamente
MCP opera una capa debajo de la abstracción del proveedor LLM:
- Un servidor MCP no sabe ni le importa qué LLM llama a sus herramientas. Solo la aplicación host necesita código de integración específico del proveedor.
- Cambiar proveedores de LLM sin reescribir servidores de herramientas.
- Agregar nuevas herramientas sin tocar el código del agente.
El agnosticismo de modelo de MCP es una propiedad del protocolo, no una configuración de biblioteca. Los esquemas de herramientas viven en servidores MCP y se descubren dinámicamente en tiempo de ejecución a través de llamadas estandarizadas tools/list. El primitivo de sampling (sampling/createMessage) va más allá: los servidores MCP pueden solicitar completions de LLM a través del host sin incrustar un SDK de modelo.
El modelo de dos capas
Junto con LiteLLM, surge una separación clara:
| Capa | Qué normaliza | Ejemplo |
|---|---|---|
| Capa de framework | API de LLM (solicitudes, respuestas, auth) | LiteLLM, adaptadores de LangChain |
| Capa de herramientas | Descubrimiento, invocación, resultados de herramientas | Servidores MCP |
Ambas fuentes de lock-in del proveedor se eliminan simultáneamente.
Nota: MCP estandariza la interfaz, no el comportamiento del modelo. Cuán confiablemente un modelo sigue los esquemas de herramientas, cuántas llamadas a herramientas paralelas puede planificar, cómo maneja errores de herramientas, estas son propiedades de calidad del modelo que ningún protocolo puede resolver estructuralmente. MCP es una condición necesaria pero no suficiente para la portabilidad del proveedor.
La rápida integración por OpenAI, Google DeepMind y Microsoft dentro de un año del lanzamiento confirma: MCP abordó un problema de coordinación real y ampliamente sentido.
Cómo los frameworks combinan ambas capas
MCP y la abstracción del modelo son bloques de construcción. El panorama de frameworks muestra tres enfoques arquitectónicos que comparten el mismo núcleo.
El principio común
Todos los frameworks principales implementan inversión de dependencia: la lógica de agente de alto nivel depende de abstracciones, no de implementaciones concretas de LLM:
- LangChain usa
BaseChatModel - AutoGen usa
ChatCompletionClient - smolagents usa una interfaz
Modelunificada
En cada caso, cambiar de proveedor solo requiere cambiar la instanciación del modelo. La Guía de Ingeniería de Anthropic recomienda explícitamente mantener la capa de orquestación desacoplada del modelo subyacente.
Dónde difieren los enfoques
| Framework | Arquitectura | Abstracción de proveedor | ¿Dónde se rompe la abstracción? |
|---|---|---|---|
| LangChain / LangGraph | Orquestación basada en grafos | BaseChatModel + amplia biblioteca de adaptadores | Salida estructurada, comportamiento de streaming |
| AutoGen v0.4 | Modelo de actores dirigido por eventos | Protocolo ChatCompletionClient | Aplicación de tool_choice, llamadas paralelas |
| smolagents | Núcleo mínimo (~1,000 líneas) | Interfaz Model unificada | Features de grounding específicos del proveedor |
El auge de los grafos multi-modelo
La evolución arquitectónica más significativa es el cambio de bucles de agente de un solo proveedor a grafos heterogéneos multi-modelo.
LangGraph codifica flujos de trabajo de agentes como grafos dirigidos con estado donde diferentes nodos pueden usar diferentes backends de LLM: un modelo rápido y económico para enrutamiento y clasificación, uno más capaz para la generación.
AutoGen va más allá: un agente planificador en un modelo frontier puede delegar tareas a agentes de ejecución y críticos especializados en otros proveedores, todo dentro de un único flujo de trabajo multi-agente.
En el otro extremo del espectro está Amazon Bedrock Agents, donde la infraestructura misma impone la neutralidad del proveedor en lugar de requerir que los desarrolladores implementen patrones adaptadores.
Para una visión práctica de cómo estos grafos multi-modelo se despliegan en pipelines de producción con agentes especializados, Quality Gates y aislamiento de workspace, consulta Así funcionan los workflows de desarrollo basados en agentes.
La compatibilidad de interfaz no es portabilidad
Los frameworks resuelven el problema de la interfaz elegantemente. Pero la compatibilidad de interfaz y la verdadera portabilidad son dos cosas diferentes.
El mismo prompt y el mismo grafo de agente producen comportamientos emergentes diferentes dependiendo del modelo detrás.
Tres dimensiones de la varianza de comportamiento
1. Fidelidad en el seguimiento de instrucciones
Los modelos difieren en cuán precisamente siguen las instrucciones del bucle del agente como ReAct prompting o solicitudes de salida estructurada.
2. Confiabilidad de llamadas a herramientas
El comportamiento de llamadas a herramientas paralelas, la aplicación de tool_choice y las razones de finalización de streaming varían por proveedor, incluso después de la normalización sintáctica.
3. Portabilidad de prompts
Un system prompt optimizado para un modelo se comporta de manera diferente con otro proveedor. Las plantillas de prompt requieren reingeniería por familia de modelos. Esto no es un esfuerzo de configuración único. Es un costo continuo.
La caída no lineal
Estudios como AgentBench muestran que las brechas de rendimiento entre modelos frontier y de nivel medio no son degradaciones graduales sino a veces caídas drásticas y no lineales.
La Guía de Ingeniería de Anthropic lo dice directamente: los modelos por debajo de un umbral de confiabilidad rompen grafos de agente enteros en lugar de degradarse graciosamente.
Qué significa esto para tu arquitectura
Una capa dedicada de evaluación de modelos junto con la capa de abstracción no es un overhead opcional. Pertenece a la arquitectura.
Cuatro prácticas que importan
- Mantener registros de pares modelo/tarea conocidos para despliegues de producción confiables
- Configurar cadenas de fallback que se activan cuando un modelo falla una verificación de capacidad en tiempo de ejecución
- Implementar hooks de observabilidad para detectar la deriva de comportamiento antes de que se propague en fallos aguas abajo
- Escribir pruebas de comportamiento por proveedor que cubran el cumplimiento de esquemas de herramientas, la planificación paralela y la recuperación de errores
El compromiso fundamental
Cada framework agnóstico al proveedor te confronta con la misma tensión: abstracción universal versus acceso a capacidades específicas del modelo. Extended thinking, esquemas JSON forzados, capacidades de grounding, todo esto requiere rutas de código específicas del proveedor que rompen la abstracción.
Lista de verificación: Arquitectura de agente agnóstica al proveedor
Quien tome la portabilidad en serio necesita más que un patrón adaptador:
- Modelo de mensaje canónico + modelo de tool-call canónico: una representación interna unificada que no depende directamente de ningún proveedor
- Matriz de capacidades del proveedor: ¿qué proveedor soporta streaming, llamadas a herramientas paralelas, aplicación de esquemas, grounding?
- Pruebas de contrato para cumplimiento de herramientas: pruebas automatizadas que verifican por proveedor si los esquemas de herramientas se siguen correctamente
- Golden traces: ejecuciones de referencia (prompt + herramientas + llamadas esperadas) por proveedor que sirven como pruebas de regresión
- Política de fallback en tiempo de ejecución: escalación definida cuando un modelo falla verificaciones de capacidad en tiempo de ejecución
- Observabilidad: taxonomía de errores de tool-call + detección de deriva para capturar cambios de comportamiento entre versiones del proveedor
La conclusión
Empieza con la abstracción como predeterminado. Baja al código específico del proveedor cuando necesites las funcionalidades, pero documenta explícitamente cada uno de esos escapes.
Portabilidad como norma, optimización del proveedor como excepción deliberada.
La pregunta que debería guiar tu decisión arquitectónica no es "¿Cuál proveedor es el mejor?" sino "¿Qué partes de mi agente pueden depender del proveedor, y cuáles no?"