{"schemaVersion":1,"id":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production","title":"MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción","description":"Guía técnica sobre feature stores en ML de producción, cubriendo Feast y Tecton, point-in-time joins, serving de features en tiempo real, detección de feature drift y la arquitectura que hace que todo funcione sin colapsar bajo su propia complejidad.","language":"es","datePublished":"2025-11-30","dateModified":null,"contentFormat":"text/markdown","content":"AI/ML\n\n# MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción\n\n2025-11-305 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/mlops-feature-stores-feast-tecton-production>)\n\n## El Problema Central\n\nLos modelos ML consumen features, variables derivadas computadas desde datos raw. Un modelo simple de recomendación podría necesitar:\n\n```\nuser_avg_session_duration_7d, de clickstream\nuser_purchase_count_30d, de transacciones\nitem_view_count_24h, de stream de eventos\nuser_item_category_affinity, de historial de compras\n```\n\nCada una tiene que computarse en al menos dos contextos:\n\n1. **Tiempo de entrenamiento**: desde datos históricos, con semántica point-in-time correcta\n2. **Tiempo de serving**: desde datos vivos, a baja latencia (usualmente \\<50ms)\n\nSi la lógica de computación difiere entre estos dos contextos, aunque sea un toque, teners training-serving skew, y tu modelo performa peor en producción que en evaluación. Esto no es una preocupación teórica. Una caída de 15% en accuracy por un mismatch de timezone de fecha entre un job batch de Spark y una función de serving en Python es un patrón documentado.\n\n## Feast: La Base Open-Source\n\n[Feast](<https://feast.dev/>) (Feature Store) es la opción open-source estándar. Maneja registro de features, almacenamiento offline/online, y materialización (copiar features del store offline al online).\n\n### Definiendo Features\n\n```python\n# feature_repo/features.py\nfrom feast import Entity, FeatureView, Field, FileSource\nfrom feast.types import Float32, Int64\nfrom datetime import timedelta\n\nuser = Entity(name=\"user_id\", join_keys=[\"user_id\"])\n\nuser_transaction_stats = FeatureView(\n name=\"user_transaction_stats\",\n entities=[user],\n schema=[\n Field(name=\"avg_transaction_amount_30d\", dtype=Float32),\n Field(name=\"transaction_count_30d\", dtype=Int64),\n Field(name=\"max_transaction_amount_30d\", dtype=Float32),\n Field(name=\"days_since_last_transaction\", dtype=Int64),\n ],\n source=FileSource(\n path=\"s3://ml-features/user_transaction_stats.parquet\",\n timestamp_field=\"event_timestamp\",\n ),\n ttl=timedelta(days=1),\n online=True,\n)\n```\n\n### Point-in-Time Joins\n\nAcá es donde los feature stores se ganan su sustento:\n\n```python\nfrom feast import FeatureStore\nimport pandas as pd\n\nstore = FeatureStore(repo_path=\"feature_repo/\")\n\nentity_df = pd.DataFrame({\n \"user_id\": [1001, 1002, 1001, 1003],\n \"event_timestamp\": [\n \"2025-11-15 10:30:00\",\n \"2025-11-15 14:00:00\",\n \"2025-12-01 09:00:00\",\n \"2025-12-02 16:45:00\",\n ],\n})\n\ntraining_df = store.get_historical_features(\n entity_df=entity_df,\n features=[\n \"user_transaction_stats:avg_transaction_amount_30d\",\n \"user_transaction_stats:transaction_count_30d\",\n \"user_session_stats:avg_session_duration_7d\",\n ],\n).to_df()\n```\n\nLa columna ` event_timestamp ` es la clave. Para user 1001 el 15 de noviembre, Feast devuelve los valores de features computados con datos disponibles hasta el 15 de noviembre. Para el mismo usuario el 1 de diciembre, devuelve valores diferentes, reflejando las dos semanas adicionales de datos. Sin point-in-time joins, usarías los valores más recientes y sin querer filtrarías información futura al entrenamiento.\n\n### Serving Online\n\n```python\nfeatures = store.get_online_features(\n features=[\n \"user_transaction_stats:avg_transaction_amount_30d\",\n \"user_transaction_stats:transaction_count_30d\",\n ],\n entity_rows=[{\"user_id\": 1001}],\n).to_dict()\n```\n\nCon Redis como online store, esto devuelve en menos de 5ms a p99. Los benchmarks muestran 2.000 requests/segundo en una sola instancia de servidor Feast con 50 features por request.\n\n## Tecton: La Plataforma Gestionada\n\n[Tecton](<https://www.tecton.ai/>) es la plataforma comercial de features construida por ex-ingenieros de Uber Michelangelo. La funcionalidad principal son las definiciones de transformación unificadas:\n\n```python\n@batch_feature_view(\n sources=[transactions_batch],\n entities=[user_entity],\n mode=\"pandas\",\n batch_schedule=timedelta(days=1),\n)\ndef user_transaction_stats(transactions):\n return transactions.groupby(\"user_id\").agg(\n avg_amount_30d=(\"amount\", \"mean\"),\n count_30d=(\"amount\", \"count\"),\n max_amount_30d=(\"amount\", \"max\"),\n )\n\n@stream_feature_view(\n source=transactions_stream,\n entities=[user_entity],\n mode=\"pandas\",\n aggregation_interval=timedelta(minutes=5),\n aggregations=[\n Aggregation(column=\"amount\", function=\"mean\", time_window=timedelta(days=30)),\n Aggregation(column=\"amount\", function=\"count\", time_window=timedelta(days=30)),\n ],\n)\ndef user_transaction_stats_realtime(transactions):\n return transactions\n```\n\nLa misma lógica de features, aplicada tanto como computación batch (para entrenamiento) como computación streaming (para serving). Tecton garantiza consistencia entre ambas.\n\n## Features en Tiempo Real: La Parte Difícil\n\nUn approach probado para features en tiempo real con Feast:\n\n```python\nfrom feast import FeatureStore\nfrom kafka import KafkaConsumer\nimport json\n\nstore = FeatureStore(repo_path=\"feature_repo/\")\nconsumer = KafkaConsumer(\"user-events\", bootstrap_servers=\"kafka:9092\")\n\nfrom collections import defaultdict\nimport time\n\nwindows = defaultdict(list)\nWINDOW_SIZE = 300 # 5 minutos\n\nfor message in consumer:\n event = json.loads(message.value)\n user_id = event[\"user_id\"]\n timestamp = event[\"timestamp\"]\n\n windows[user_id].append({\"ts\": timestamp, \"value\": event[\"amount\"]})\n cutoff = time.time() - WINDOW_SIZE\n windows[user_id] = [e for e in windows[user_id] if e[\"ts\"] > cutoff]\n\n values = [e[\"value\"] for e in windows[user_id]]\n features = {\n \"user_id\": user_id,\n \"event_count_5m\": len(values),\n \"avg_amount_5m\": sum(values) / len(values) if values else 0,\n }\n\n store.push(\"user_realtime_stats\", pd.DataFrame([features]))\n```\n\nEsto es viable en producción pero operacionalmente pesado. Estás manejando un consumer de Kafka, estado en memoria, y el push a Feast.\n\n## Detección de Feature Drift\n\nLas features driftean. El comportamiento de los usuarios cambia, las fuentes de datos se modifican, los schemas upstream evolucionan.\n\n```python\nfrom evidently.metric_preset import DataDriftPreset\nfrom evidently.report import Report\n\nreference_data = pd.read_parquet(\"training_features_snapshot.parquet\")\ncurrent_data = fetch_current_features(sample_size=10000)\n\nreport = Report(metrics=[DataDriftPreset()])\nreport.run(reference_data=reference_data, current_data=current_data)\nresult = report.as_dict()\n\nfor feature_name, drift_info in result[\"metrics\"][0][\"result\"][\"drift_by_columns\"].items():\n if drift_info[\"drift_detected\"]:\n alert(\n f\"Feature drift detectado: {feature_name}\",\n f\"Drift score: {drift_info['drift_score']:.4f}, \"\n f\"Método: {drift_info['stattest_name']}\"\n )\n```\n\nEsto típicamente corre diariamente como un job programado. Cuando se detecta drift, re-entrenar automáticamente no es aconsejable, investigar primero. Drift en ` user_avg_session_duration ` podría significar un cambio de UI, no un problema de calidad de datos. El contexto importa.\n\n## Arquitectura de Producción\n\nLa arquitectura completa para un sistema de detección de fraude con ~200 features:\n\n```\nFuentes de Datos Raw\n├── PostgreSQL (transacciones, cuentas)\n├── Kafka (eventos tiempo real)\n└── S3 (logs clickstream)\n │\n ▼\nComputación de Features\n├── Spark (features batch, diario)\n├── Flink (features streaming, tiempo real)\n└── Transforms Python (features on-demand)\n │\n ▼\nFeast Feature Store\n├── Offline: S3 Parquet (entrenamiento)\n├── Online: Redis Cluster (serving)\n└── Registry: PostgreSQL (metadata)\n │\n ├──► Pipeline de Entrenamiento\n │ └── get_historical_features() → Entrenamiento del Modelo\n │\n └──► Pipeline de Serving\n └── get_online_features() → Inferencia del Modelo (p99 < 10ms)\n```\n\nPresupuesto total de latencia para el path de detección de fraude: 50ms. Recuperación de features toma 4-8ms (Redis), inferencia del modelo toma 2-5ms (ONNX Runtime), y el resto es overhead de red y serialización.\n\n## Para Cerrar\n\nLos feature stores son infraestructura que no te hace quedar como un héroe. Nadie asciende por deployar Feast. Pero la alternativa, cada data scientist manteniendo sus propios pipelines de computación de features, con código diferente para entrenamiento vs serving, sin monitoreo, y con semántica point-in-time implementada ad hoc (o para nada), es como terminás con sistemas ML que funcionan en notebooks y fallan en producción.\n\nArrancar con Feast. Usar Redis para online, el warehouse existente para offline. Definir features una vez, usarlas en todos lados. Monitorear distribuciones. Graduar a Tecton cuando la carga operacional de manejar features streaming de forma independiente supere el costo de la plataforma.\n\nEl modelo es la parte fácil. Las features son la parte difícil. Y el feature store es lo que evita que la parte difícil se vuelva imposible.\n\n## Preguntas frecuentes\n\n### ¿Qué es un feature store y por qué lo necesito?\n\nUn feature store es un sistema centralizado para gestionar features de ML, las variables de entrada que tus modelos consumen. Maneja almacenamiento (online para serving de baja latencia, offline para entrenamiento), transformación (computar features desde datos raw), y consistencia (asegurar que entrenamiento y serving usen lógica de features idéntica). Lo se necesita cuando la duplicación de features entre equipos, el training-serving skew, o la frescura de features se convierte en cuello de botella.\n\n### ¿Cómo previenen los point-in-time joins el data leakage?\n\nLos point-in-time joins recuperan valores de features como existían al momento de cada ejemplo de entrenamiento, no como existen ahora. Si se está entrenando un detector de fraude con una transacción del 15 de enero, el join busca el gasto promedio del usuario al 15 de enero, no el valor de hoy, que incluye meses de datos que no hubieran estado disponibles al momento de la predicción.\n\n### ¿Feast está listo para producción para serving en tiempo real?\n\nSí, con el backend correcto de online store. Feast con Redis sirve features a menos de 5ms de latencia p99 para tamaños moderados de feature set. Para throughput muy alto (100K+ requests/segundo), se va a querer tunear la configuración del cluster Redis o considerar DynamoDB como online store. La limitación principal es que la ingesta streaming de Feast requiere que manejes el job de Spark/Flink usted mismo.\n\n## Tips\n\n1. **Tip:** Siempre computá features de entrenamiento con point-in-time joins, nunca con lookups del estado actual. Entrenar un modelo de fraude con 'balance actual de cuenta' en vez de 'balance al momento de la transacción' produce un modelo que se ve increíble en entrenamiento y es inútil en producción. Leakage clásico.\n2. **Tip:** Para features en tiempo real, mantener la lógica de transformación en un solo lugar. Si el pipeline batch computa ` avg_transactions_7d ` diferente que tu pipeline de streaming, hay un training-serving skew que destruirá silenciosamente la performance del modelo.\n3. **Tip:** Arrancar con Feast + Redis para online serving y Feast + el data warehouse existente para offline. Tecton se justifica una vez que la cantidad de features cruza 500 y hay un equipo dedicado de plataforma ML. El overhead operacional de un servicio gestionado solo rinde a escala.\n\n- mlops\n- feature-stores\n- feast\n- tecton\n- machine-learning\n- features-tiempo-real\n- point-in-time-joins\n- feature-drift\n- ml-pipelines\n- produccion-ml\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)","headings":[{"level":1,"text":"MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#title"},{"level":2,"text":"El Problema Central","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#el-problema-central"},{"level":2,"text":"Feast: La Base Open-Source","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#feast-la-base-open-source"},{"level":3,"text":"Definiendo Features","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#definiendo-features"},{"level":3,"text":"Point-in-Time Joins","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#point-in-time-joins"},{"level":3,"text":"Serving Online","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#serving-online"},{"level":2,"text":"Tecton: La Plataforma Gestionada","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#tecton-la-plataforma-gestionada"},{"level":2,"text":"Features en Tiempo Real: La Parte Difícil","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#features-en-tiempo-real-la-parte-difcil"},{"level":2,"text":"Detección de Feature Drift","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#deteccin-de-feature-drift"},{"level":2,"text":"Arquitectura de Producción","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#arquitectura-de-produccin"},{"level":2,"text":"Para Cerrar","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#para-cerrar"},{"level":2,"text":"Preguntas frecuentes","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#questions"},{"level":3,"text":"¿Qué es un feature store y por qué lo necesito?","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#question-1"},{"level":3,"text":"¿Cómo previenen los point-in-time joins el data leakage?","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#question-2"},{"level":3,"text":"¿Feast está listo para producción para serving en tiempo real?","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#question-3"},{"level":2,"text":"Tips","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#article-tips"}],"sections":[{"heading":"MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción","level":1,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production","content":"AI/ML"},{"heading":"MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción","level":1,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#title","content":"2025-11-305 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/mlops-feature-stores-feast-tecton-production>)"},{"heading":"El Problema Central","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#el-problema-central","content":"Los modelos ML consumen features, variables derivadas computadas desde datos raw. Un modelo simple de recomendación podría necesitar:\n\n```\nuser_avg_session_duration_7d, de clickstream\nuser_purchase_count_30d, de transacciones\nitem_view_count_24h, de stream de eventos\nuser_item_category_affinity, de historial de compras\n```\n\nCada una tiene que computarse en al menos dos contextos:\n\n1. **Tiempo de entrenamiento**: desde datos históricos, con semántica point-in-time correcta\n2. **Tiempo de serving**: desde datos vivos, a baja latencia (usualmente \\<50ms)\n\nSi la lógica de computación difiere entre estos dos contextos, aunque sea un toque, teners training-serving skew, y tu modelo performa peor en producción que en evaluación. Esto no es una preocupación teórica. Una caída de 15% en accuracy por un mismatch de timezone de fecha entre un job batch de Spark y una función de serving en Python es un patrón documentado."},{"heading":"Feast: La Base Open-Source","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#feast-la-base-open-source","content":"[Feast](<https://feast.dev/>) (Feature Store) es la opción open-source estándar. Maneja registro de features, almacenamiento offline/online, y materialización (copiar features del store offline al online)."},{"heading":"Definiendo Features","level":3,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#definiendo-features","content":"```python\n# feature_repo/features.py\nfrom feast import Entity, FeatureView, Field, FileSource\nfrom feast.types import Float32, Int64\nfrom datetime import timedelta\n\nuser = Entity(name=\"user_id\", join_keys=[\"user_id\"])\n\nuser_transaction_stats = FeatureView(\n name=\"user_transaction_stats\",\n entities=[user],\n schema=[\n Field(name=\"avg_transaction_amount_30d\", dtype=Float32),\n Field(name=\"transaction_count_30d\", dtype=Int64),\n Field(name=\"max_transaction_amount_30d\", dtype=Float32),\n Field(name=\"days_since_last_transaction\", dtype=Int64),\n ],\n source=FileSource(\n path=\"s3://ml-features/user_transaction_stats.parquet\",\n timestamp_field=\"event_timestamp\",\n ),\n ttl=timedelta(days=1),\n online=True,\n)\n```"},{"heading":"Point-in-Time Joins","level":3,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#point-in-time-joins","content":"Acá es donde los feature stores se ganan su sustento:\n\n```python\nfrom feast import FeatureStore\nimport pandas as pd\n\nstore = FeatureStore(repo_path=\"feature_repo/\")\n\nentity_df = pd.DataFrame({\n \"user_id\": [1001, 1002, 1001, 1003],\n \"event_timestamp\": [\n \"2025-11-15 10:30:00\",\n \"2025-11-15 14:00:00\",\n \"2025-12-01 09:00:00\",\n \"2025-12-02 16:45:00\",\n ],\n})\n\ntraining_df = store.get_historical_features(\n entity_df=entity_df,\n features=[\n \"user_transaction_stats:avg_transaction_amount_30d\",\n \"user_transaction_stats:transaction_count_30d\",\n \"user_session_stats:avg_session_duration_7d\",\n ],\n).to_df()\n```\n\nLa columna ` event_timestamp ` es la clave. Para user 1001 el 15 de noviembre, Feast devuelve los valores de features computados con datos disponibles hasta el 15 de noviembre. Para el mismo usuario el 1 de diciembre, devuelve valores diferentes, reflejando las dos semanas adicionales de datos. Sin point-in-time joins, usarías los valores más recientes y sin querer filtrarías información futura al entrenamiento."},{"heading":"Serving Online","level":3,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#serving-online","content":"```python\nfeatures = store.get_online_features(\n features=[\n \"user_transaction_stats:avg_transaction_amount_30d\",\n \"user_transaction_stats:transaction_count_30d\",\n ],\n entity_rows=[{\"user_id\": 1001}],\n).to_dict()\n```\n\nCon Redis como online store, esto devuelve en menos de 5ms a p99. Los benchmarks muestran 2.000 requests/segundo en una sola instancia de servidor Feast con 50 features por request."},{"heading":"Tecton: La Plataforma Gestionada","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#tecton-la-plataforma-gestionada","content":"[Tecton](<https://www.tecton.ai/>) es la plataforma comercial de features construida por ex-ingenieros de Uber Michelangelo. La funcionalidad principal son las definiciones de transformación unificadas:\n\n```python\n@batch_feature_view(\n sources=[transactions_batch],\n entities=[user_entity],\n mode=\"pandas\",\n batch_schedule=timedelta(days=1),\n)\ndef user_transaction_stats(transactions):\n return transactions.groupby(\"user_id\").agg(\n avg_amount_30d=(\"amount\", \"mean\"),\n count_30d=(\"amount\", \"count\"),\n max_amount_30d=(\"amount\", \"max\"),\n )\n\n@stream_feature_view(\n source=transactions_stream,\n entities=[user_entity],\n mode=\"pandas\",\n aggregation_interval=timedelta(minutes=5),\n aggregations=[\n Aggregation(column=\"amount\", function=\"mean\", time_window=timedelta(days=30)),\n Aggregation(column=\"amount\", function=\"count\", time_window=timedelta(days=30)),\n ],\n)\ndef user_transaction_stats_realtime(transactions):\n return transactions\n```\n\nLa misma lógica de features, aplicada tanto como computación batch (para entrenamiento) como computación streaming (para serving). Tecton garantiza consistencia entre ambas."},{"heading":"Features en Tiempo Real: La Parte Difícil","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#features-en-tiempo-real-la-parte-difcil","content":"Un approach probado para features en tiempo real con Feast:\n\n```python\nfrom feast import FeatureStore\nfrom kafka import KafkaConsumer\nimport json\n\nstore = FeatureStore(repo_path=\"feature_repo/\")\nconsumer = KafkaConsumer(\"user-events\", bootstrap_servers=\"kafka:9092\")\n\nfrom collections import defaultdict\nimport time\n\nwindows = defaultdict(list)\nWINDOW_SIZE = 300 # 5 minutos\n\nfor message in consumer:\n event = json.loads(message.value)\n user_id = event[\"user_id\"]\n timestamp = event[\"timestamp\"]\n\n windows[user_id].append({\"ts\": timestamp, \"value\": event[\"amount\"]})\n cutoff = time.time() - WINDOW_SIZE\n windows[user_id] = [e for e in windows[user_id] if e[\"ts\"] > cutoff]\n\n values = [e[\"value\"] for e in windows[user_id]]\n features = {\n \"user_id\": user_id,\n \"event_count_5m\": len(values),\n \"avg_amount_5m\": sum(values) / len(values) if values else 0,\n }\n\n store.push(\"user_realtime_stats\", pd.DataFrame([features]))\n```\n\nEsto es viable en producción pero operacionalmente pesado. Estás manejando un consumer de Kafka, estado en memoria, y el push a Feast."},{"heading":"Detección de Feature Drift","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#deteccin-de-feature-drift","content":"Las features driftean. El comportamiento de los usuarios cambia, las fuentes de datos se modifican, los schemas upstream evolucionan.\n\n```python\nfrom evidently.metric_preset import DataDriftPreset\nfrom evidently.report import Report\n\nreference_data = pd.read_parquet(\"training_features_snapshot.parquet\")\ncurrent_data = fetch_current_features(sample_size=10000)\n\nreport = Report(metrics=[DataDriftPreset()])\nreport.run(reference_data=reference_data, current_data=current_data)\nresult = report.as_dict()\n\nfor feature_name, drift_info in result[\"metrics\"][0][\"result\"][\"drift_by_columns\"].items():\n if drift_info[\"drift_detected\"]:\n alert(\n f\"Feature drift detectado: {feature_name}\",\n f\"Drift score: {drift_info['drift_score']:.4f}, \"\n f\"Método: {drift_info['stattest_name']}\"\n )\n```\n\nEsto típicamente corre diariamente como un job programado. Cuando se detecta drift, re-entrenar automáticamente no es aconsejable, investigar primero. Drift en ` user_avg_session_duration ` podría significar un cambio de UI, no un problema de calidad de datos. El contexto importa."},{"heading":"Arquitectura de Producción","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#arquitectura-de-produccin","content":"La arquitectura completa para un sistema de detección de fraude con ~200 features:\n\n```\nFuentes de Datos Raw\n├── PostgreSQL (transacciones, cuentas)\n├── Kafka (eventos tiempo real)\n└── S3 (logs clickstream)\n │\n ▼\nComputación de Features\n├── Spark (features batch, diario)\n├── Flink (features streaming, tiempo real)\n└── Transforms Python (features on-demand)\n │\n ▼\nFeast Feature Store\n├── Offline: S3 Parquet (entrenamiento)\n├── Online: Redis Cluster (serving)\n└── Registry: PostgreSQL (metadata)\n │\n ├──► Pipeline de Entrenamiento\n │ └── get_historical_features() → Entrenamiento del Modelo\n │\n └──► Pipeline de Serving\n └── get_online_features() → Inferencia del Modelo (p99 < 10ms)\n```\n\nPresupuesto total de latencia para el path de detección de fraude: 50ms. Recuperación de features toma 4-8ms (Redis), inferencia del modelo toma 2-5ms (ONNX Runtime), y el resto es overhead de red y serialización."},{"heading":"Para Cerrar","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#para-cerrar","content":"Los feature stores son infraestructura que no te hace quedar como un héroe. Nadie asciende por deployar Feast. Pero la alternativa, cada data scientist manteniendo sus propios pipelines de computación de features, con código diferente para entrenamiento vs serving, sin monitoreo, y con semántica point-in-time implementada ad hoc (o para nada), es como terminás con sistemas ML que funcionan en notebooks y fallan en producción.\n\nArrancar con Feast. Usar Redis para online, el warehouse existente para offline. Definir features una vez, usarlas en todos lados. Monitorear distribuciones. Graduar a Tecton cuando la carga operacional de manejar features streaming de forma independiente supere el costo de la plataforma.\n\nEl modelo es la parte fácil. Las features son la parte difícil. Y el feature store es lo que evita que la parte difícil se vuelva imposible."},{"heading":"Preguntas frecuentes","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#questions","content":""},{"heading":"¿Qué es un feature store y por qué lo necesito?","level":3,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#question-1","content":"Un feature store es un sistema centralizado para gestionar features de ML, las variables de entrada que tus modelos consumen. Maneja almacenamiento (online para serving de baja latencia, offline para entrenamiento), transformación (computar features desde datos raw), y consistencia (asegurar que entrenamiento y serving usen lógica de features idéntica). Lo se necesita cuando la duplicación de features entre equipos, el training-serving skew, o la frescura de features se convierte en cuello de botella."},{"heading":"¿Cómo previenen los point-in-time joins el data leakage?","level":3,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#question-2","content":"Los point-in-time joins recuperan valores de features como existían al momento de cada ejemplo de entrenamiento, no como existen ahora. Si se está entrenando un detector de fraude con una transacción del 15 de enero, el join busca el gasto promedio del usuario al 15 de enero, no el valor de hoy, que incluye meses de datos que no hubieran estado disponibles al momento de la predicción."},{"heading":"¿Feast está listo para producción para serving en tiempo real?","level":3,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#question-3","content":"Sí, con el backend correcto de online store. Feast con Redis sirve features a menos de 5ms de latencia p99 para tamaños moderados de feature set. Para throughput muy alto (100K+ requests/segundo), se va a querer tunear la configuración del cluster Redis o considerar DynamoDB como online store. La limitación principal es que la ingesta streaming de Feast requiere que manejes el job de Spark/Flink usted mismo."},{"heading":"Tips","level":2,"url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#article-tips","content":"1. **Tip:** Siempre computá features de entrenamiento con point-in-time joins, nunca con lookups del estado actual. Entrenar un modelo de fraude con 'balance actual de cuenta' en vez de 'balance al momento de la transacción' produce un modelo que se ve increíble en entrenamiento y es inútil en producción. Leakage clásico.\n2. **Tip:** Para features en tiempo real, mantener la lógica de transformación en un solo lugar. Si el pipeline batch computa ` avg_transactions_7d ` diferente que tu pipeline de streaming, hay un training-serving skew que destruirá silenciosamente la performance del modelo.\n3. **Tip:** Arrancar con Feast + Redis para online serving y Feast + el data warehouse existente para offline. Tecton se justifica una vez que la cantidad de features cruza 500 y hay un equipo dedicado de plataforma ML. El overhead operacional de un servicio gestionado solo rinde a escala.\n\n- mlops\n- feature-stores\n- feast\n- tecton\n- machine-learning\n- features-tiempo-real\n- point-in-time-joins\n- feature-drift\n- ml-pipelines\n- produccion-ml\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)"}],"links":[{"text":"English","url":"https://lucioduran.com/blog/mlops-feature-stores-feast-tecton-production"},{"text":"Feast","url":"https://feast.dev/"},{"text":"Tecton","url":"https://www.tecton.ai/"},{"text":"Volver al Blog","url":"https://lucioduran.com/es/blog"}],"structuredData":[{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production#article","mainEntityOfPage":{"@type":"WebPage","@id":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production"},"headline":"MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción","description":"Guía técnica sobre feature stores en ML de producción, cubriendo Feast y Tecton, point-in-time joins, serving de features en tiempo real, detección de feature drift y la arquitectura que hace que todo funcione sin colapsar bajo su propia complejidad.","datePublished":"2025-11-30","author":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"publisher":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"image":"https://statics.lucioduran.com/images/lucioduran-social-card.jpg","url":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production","inLanguage":"es","isPartOf":{"@id":"https://lucioduran.com/blog#blog"},"articleSection":"AI/ML","keywords":"mlops, feature-stores, feast, tecton, machine-learning, features-tiempo-real, point-in-time-joins, feature-drift, ml-pipelines, produccion-ml","wordCount":945,"timeRequired":"PT5M","workTranslation":[{"@type":"BlogPosting","inLanguage":"en","url":"https://lucioduran.com/blog/mlops-feature-stores-feast-tecton-production"}]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://lucioduran.com/es/blog"},{"@type":"ListItem","position":3,"name":"MLOps Feature Stores: Feast, Tecton, Features en Tiempo Real y Arquitectura de Pipelines ML en Producción","item":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production"}]},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"¿Qué es un feature store y por qué lo necesito?","acceptedAnswer":{"@type":"Answer","text":"Un feature store es un sistema centralizado para gestionar features de ML, las variables de entrada que tus modelos consumen. Maneja almacenamiento (online para serving de baja latencia, offline para entrenamiento), transformación (computar features desde datos raw), y consistencia (asegurar que entrenamiento y serving usen lógica de features idéntica). Lo se necesita cuando la duplicación de features entre equipos, el training-serving skew, o la frescura de features se convierte en cuello de botella."}},{"@type":"Question","name":"¿Cómo previenen los point-in-time joins el data leakage?","acceptedAnswer":{"@type":"Answer","text":"Los point-in-time joins recuperan valores de features como existían al momento de cada ejemplo de entrenamiento, no como existen ahora. Si se está entrenando un detector de fraude con una transacción del 15 de enero, el join busca el gasto promedio del usuario al 15 de enero, no el valor de hoy, que incluye meses de datos que no hubieran estado disponibles al momento de la predicción."}},{"@type":"Question","name":"¿Feast está listo para producción para serving en tiempo real?","acceptedAnswer":{"@type":"Answer","text":"Sí, con el backend correcto de online store. Feast con Redis sirve features a menos de 5ms de latencia p99 para tamaños moderados de feature set. Para throughput muy alto (100K+ requests/segundo), se va a querer tunear la configuración del cluster Redis o considerar DynamoDB como online store. La limitación principal es que la ingesta streaming de Feast requiere que manejes el job de Spark/Flink usted mismo."}}]}]}],"contentHash":"2b63fda2cc1f78d1dc07b802f3740083b4a2a1a839fd0f8f7d9284e58d2b0dd2","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/blog/mlops-feature-stores-feast-tecton-production","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":63522,"contentBytes":11663}}
