De ABAP a Python: Guía del Desarrollador SAP para la Integración de IA/ML

De ABAP a Python: Guía del Desarrollador SAP para la Integración de IA/ML

La Incómoda Verdad que Todo Desarrollador ABAP Necesita Escuchar

Llevo 12 años escribiendo ABAP. Con eso pagué la hipoteca, financié dos coches y construí una carrera de la que estoy genuinamente orgulloso. Informes ALV complejos, BAPIs personalizadas, enhancement spots enterrados en los módulos de logística — lo he construido todo. Y te lo digo ahora, sin más agenda que la honestidad: si no estás aprendiendo Python en 2026, estás construyendo una carrera sobre cimientos que se están reduciendo.

Esto no es una predicción catastrofista. SAP no va a ningún sitio. La base instalada es enorme — más de 400.000 clientes, billones de dólares de datos empresariales gestionados en sistemas ECC y S/4HANA en todo el mundo. Los desarrolladores ABAP serán necesarios durante años. Pero la forma de lo que hacemos está cambiando más rápido de lo que la mayoría de consultores está dispuesta a admitir. SAP Business AI, Joule, analíticas embebidas, clean core — cada uno de estos pilares estratégicos funciona sobre Python, no ABAP. El nuevo SAP se está construyendo en un lenguaje que quizás todavía no conoces.

La buena noticia — y esta es la parte que realmente me entusiasma — es que los desarrolladores ABAP están en una posición única para ganar en la era de la IA/ML. No a pesar de nuestro bagaje SAP, sino gracias a él. El problema de la mayoría de equipos de ciencia de datos que construyen integraciones SAP es que no entienden qué significa MARD o VBRP. No saben por qué un período de contabilización importa. No pueden distinguir un indicador de débito de un documento de compensación. Tú sí puedes. Ese conocimiento de dominio vale más que cualquier tutorial de NumPy.

Esta guía es lo que ojalá alguien me hubiera dado cuando empecé mi transición. Es práctica, tiene código real y respeta el hecho de que ya sabes programar. No necesitas que te traten como a un principiante — necesitas un puente.


Por Qué los Desarrolladores ABAP Tienen una Ventaja Injusta en IA/ML

Antes de escribir una sola línea de Python, seamos honestos sobre lo que ya tienes y que a la mayoría de científicos de datos les falta por completo.

Entiendes los Datos a Profundidad Empresarial

Cuando se entrena un modelo de machine learning con datos de ventas SAP, alguien tiene que decidir qué tablas usar, cómo gestionar las entregas parciales, cómo es un documento de cancelación y por qué ciertos registros deben excluirse. Un científico de datos externo a SAP pasará meses descubriendo que VBRP-FKIMG es la cantidad facturada real y que necesitas unirte a través de VBRK para la moneda a nivel de cabecera. Tú ya lo sabes. Has escrito las sentencias SELECT. Has depurado los datos.

Conoces los Procesos Detrás de los Números

Los modelos de IA/ML son inútiles sin ingeniería de características, y la ingeniería de características requiere entender qué significan los datos. Sabes que un pedido de compra con entrada de mercancías pero sin factura es un riesgo de devengo. Sabes que un bloqueo de entrega en un pedido de venta significa cosas distintas en diferentes sociedades. Esta inteligencia contextual es la diferencia entre un modelo que puntúa bien en validación y uno que realmente funciona en producción.

Ya Piensas en Flujos de Datos

La programación ABAP consiste fundamentalmente en mover datos a través de procesos empresariales: leer de tablas de base de datos, transformar tablas internas, llamar módulos de función, escribir de vuelta. La ciencia de datos en Python sigue exactamente el mismo patrón: extraer datos de una fuente, transformarlos en un DataFrame, pasarlos por un modelo, escribir resultados de vuelta. El modelo mental se transfiere casi directamente.

Tienes Confianza Organizacional

Introducir IA/ML en producción en un entorno SAP requiere navegar por equipos de Basis, seguridad, gestión de transportes y aprobación del negocio. Ya has hecho todo esto antes. Un científico de datos junior llegado de fuera no tiene nada de esto. Tus relaciones existentes y tu conocimiento institucional son una ventaja enorme cuando llega el momento de desplegar.


ABAP vs Python: Una Comparación Honesta

Antes de elegir qué lenguaje usar para una tarea dada, necesitas una imagen honesta de ambos. Esto es lo que 12 años de ABAP y varios años de Python realmente se ven lado a lado:

Dimensión ABAP Python
Caso de uso principal Lógica empresarial SAP, desarrollo personalizado dentro de sistemas SAP Uso general: ciencia de datos, APIs web, automatización, IA/ML
Dónde se ejecuta Dentro del servidor de aplicaciones SAP (pila ABAP) En cualquier lugar — local, nube, contenedores, Raspberry Pi
Acceso a datos Acceso directo a BD mediante Open SQL, tablas transparentes Via RFC (pyrfc), REST (SAP APIs), JDBC o conexión directa a BD
Librerías IA/ML Ninguna de forma nativa. SAP AI Core existe pero se ejecuta fuera de ABAP scikit-learn, TensorFlow, PyTorch, Hugging Face, LangChain — todo el ecosistema
Curva de aprendizaje sintáctico Verboso, basado en palabras clave, parecido al inglés (familiar tras una semana) Conciso, basado en indentación, algo abstracto (familiar tras 2-4 semanas)
Equivalente a tabla interna TYPES, DATA, FIELD-SYMBOL — integrado en el lenguaje pandas DataFrame — mucho más potente para analítica
Depuración Depurador SAP — excelente, integrado Depurador VS Code, notebooks Jupyter, pdb — excelente, flexible
Testing ABAP Unit (poco utilizado en la práctica) pytest — ampliamente adoptado, ecosistema maduro
Ecosistema open-source Prácticamente ninguno — SAP controla todo 400.000+ paquetes en PyPI — capacidad casi ilimitada
Mercado laboral 2026 Estable, bien remunerado, pero con descenso de nuevas vacantes interanual Fuerte crecimiento, roles de IA/ML con prima del 30-50%
Roles híbridos SAP+Python Segmento de mayor crecimiento — mayores salarios, menor competencia
Transport/change management CTS, órdenes de transporte, gobernanza bien comprendida Git, pipelines CI/CD, registros de contenedores — tendrás que aprenderlos
Cuándo usar ABAP User exits, BADIs, integración profunda con procesos SAP, lógica en sistema crítica de rendimiento No aplica — ABAP solo se ejecuta dentro de SAP
Cuándo usar Python No aplica — Python se ejecuta fuera de SAP Modelos ML, APIs externas, pipelines de datos, informes, automatización fuera de SAP

La conclusión: estos lenguajes no son competidores. Son socios. ABAP gestiona el interior de SAP; Python gestiona todo lo que ocurre con esos datos fuera de SAP. Los profesionales más valiosos en 2026 conocen ambos.


Configurar tu Entorno de Desarrollo Python-SAP

Antes de cualquier código, necesitas un entorno de trabajo. Esta es exactamente la configuración que uso y recomiendo.

Requisitos Previos

  • Python 3.11+ (descárgalo desde python.org — evita la versión de Microsoft Store en Windows)
  • SAP NetWeaver RFC SDK 7.50 (descarga desde SAP Software Downloads — necesitas un usuario S)
  • Librería pyrfc (wrapper Python para el RFC SDK)
  • Un sistema SAP de desarrollo con acceso RFC (pide al equipo de Basis un destino RFC)
  • VS Code con la extensión Python (opcional pero muy recomendable)

Paso 1: Crear un Entorno Virtual

Usa siempre un entorno virtual. Es el equivalente Python de mantener limpio el espacio de nombres de desarrollo — no contaminas la instalación global de Python con librerías específicas del proyecto.

# Create a project directory
mkdir sap-python-dev
cd sap-python-dev

# Create a virtual environment
python -m venv venv

# Activate it (Linux/Mac)
source venv/bin/activate

# Activate it (Windows)
venv\Scripts\activate

# Your prompt should now show (venv) prefix

Paso 2: Instalar el SAP RFC SDK

Descarga nwrfc750P_13-70002755.zip (o la última versión) desde el SAP Software Downloads Center. Extráelo en una ruta conocida — yo uso /opt/sap/nwrfcsdk en Linux o C:\nwrfcsdk en Windows.

# Linux: add the SDK library path to your environment
export SAPNWRFC_HOME=/opt/sap/nwrfcsdk
export LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib:$LD_LIBRARY_PATH

# Or add these permanently to ~/.bashrc

Paso 3: Instalar las Librerías Python

pip install pyrfc pandas scikit-learn matplotlib anthropic python-dotenv

Resumen breve de qué hace cada una:

  • pyrfc — conecta Python a SAP mediante RFC (el puente principal)
  • pandas — tu nueva tabla interna. Los DataFrames son esenciales para todo lo que sigue
  • scikit-learn — la librería estándar de machine learning para datos estructurados/tabulares
  • matplotlib — gráficos y visualización
  • anthropic — cliente de la API de Claude para integración con LLM (usado en el Proyecto #3)
  • python-dotenv — carga credenciales desde un archivo .env, mantiene los secretos fuera del código

Paso 4: Almacenar tus Credenciales SAP de Forma Segura

Crea un archivo .env en la raíz de tu proyecto. Añádelo a .gitignore inmediatamente.

SAP_HOST=your-sap-hostname.company.com
SAP_SYSNR=00
SAP_CLIENT=100
SAP_USER=RFC_USER
SAP_PASSWORD=your-password
SAP_LANG=EN
ANTHROPIC_API_KEY=sk-ant-your-key-here

Tu Primer Script Python-SAP: Leer un Maestro de Materiales

Empecemos con algo que conoces completamente en ABAP y lo replicamos en Python. Leeremos datos básicos de material usando RFC_READ_TABLE — el primer paso de cualquier desarrollador ABAP cuando conecta herramientas externas a SAP.

La Forma ABAP

*&---------------------------------------------------------------------*
*& Report: Read material master data
*&---------------------------------------------------------------------*
REPORT z_material_read.

DATA: lt_mara TYPE TABLE OF mara,
      ls_mara TYPE mara.

SELECT matnr mtart matkl meins
  FROM mara
  INTO TABLE lt_mara
  WHERE mtart = 'FERT'
  AND   maktx NE space
  UP TO 100 ROWS.

LOOP AT lt_mara INTO ls_mara.
  WRITE: / ls_mara-matnr,
           ls_mara-mtart,
           ls_mara-matkl,
           ls_mara-meins.
ENDLOOP.

El Equivalente Python (usando pyrfc)

import pyrfc
import pandas as pd
from dotenv import load_dotenv
import os

load_dotenv()

# Establish RFC connection — equivalent to setting up a trusted RFC destination
conn = pyrfc.Connection(
    ashost=os.getenv("SAP_HOST"),
    sysnr=os.getenv("SAP_SYSNR"),
    client=os.getenv("SAP_CLIENT"),
    user=os.getenv("SAP_USER"),
    passwd=os.getenv("SAP_PASSWORD"),
    lang=os.getenv("SAP_LANG", "EN")
)

# Call RFC_READ_TABLE — the universal SAP data extraction function
result = conn.call(
    "RFC_READ_TABLE",
    QUERY_TABLE="MARA",
    DELIMITER="|",
    FIELDS=[
        {"FIELDNAME": "MATNR"},
        {"FIELDNAME": "MTART"},
        {"FIELDNAME": "MATKL"},
        {"FIELDNAME": "MEINS"},
    ],
    OPTIONS=[
        {"TEXT": "MTART = 'FERT'"}
    ],
    ROWCOUNT=100
)

# Parse results into a pandas DataFrame
rows = []
for entry in result["DATA"]:
    fields = entry["WA"].split("|")
    rows.append({
        "MATNR": fields[0].strip(),
        "MTART": fields[1].strip(),
        "MATKL": fields[2].strip(),
        "MEINS": fields[3].strip(),
    })

df = pd.DataFrame(rows)
print(df.head(10))
print(f"\nTotal materials retrieved: {len(df)}")

conn.close()

Observa la similitud estructural: conectar, definir qué quieres, ejecutar, iterar sobre los resultados. Los conceptos son idénticos — solo cambia la sintaxis. Después de una semana de Python, este patrón se vuelve tan natural como respirar para cualquier desarrollador ABAP con experiencia.

Usar BAPI_MATERIAL_GET_ALL para Datos más Completos

Para uso en producción, llamar a una BAPI adecuada es más limpio que RFC_READ_TABLE:

result = conn.call(
    "BAPI_MATERIAL_GET_ALL",
    MATERIAL="000000000010000001",
    PLANT="1000"
)

# BAPIs return structured output — access fields directly
general_data = result.get("GENERALDATA", {})
print(f"Material: {general_data.get('MATERIAL')}")
print(f"Type: {general_data.get('MATL_TYPE')}")
print(f"Base Unit: {general_data.get('BASE_UOM')}")

Extracción de Datos para IA: Llevar Datos SAP a DataFrames de pandas

El poder real comienza cuando empiezas a extraer conjuntos de datos más grandes para su análisis. Los DataFrames de pandas son el equivalente Python de las tablas internas ABAP, pero con capacidades integradas de analítica, agrupación, pivotado y operaciones estadísticas que requerirían cientos de líneas de código ABAP.

Mapeo de Tipos ABAP a Python/pandas

Tipo ABAP Declaración ABAP Equivalente pandas/Python Notas
Character (C) DATA lv_text TYPE c LENGTH 40. dtype=object (str) Eliminar espacios finales de strings ABAP
Integer (I) DATA lv_count TYPE i. dtype=int64 Mapeo directo
Packed Decimal (P) DATA lv_amount TYPE p DECIMALS 2. dtype=float64 pyrfc convierte a Decimal Python — hacer cast a float para scikit-learn
Date (D) DATA lv_date TYPE d. pd.to_datetime() La fecha SAP es un string YYYYMMDD — convertir con pd.to_datetime(col, format='%Y%m%d')
Float (F) DATA lv_float TYPE f. dtype=float64 Mapeo directo
Boolean (N, 1 char) DATA lv_flag TYPE c LENGTH 1. df['col'].map({'X': True, ' ': False}) Los flags 'X' de SAP necesitan mapeo explícito
Quantity (MENGE) DATA lv_qty TYPE menge_d. dtype=float64 Atención a las necesidades de conversión de unidades de medida
Amount (WERT) DATA lv_value TYPE wertv8. dtype=float64 Almacenar siempre la moneda origen en una columna paralela

Una Función de Extracción de Datos de Calidad Productiva

import pyrfc
import pandas as pd
from decimal import Decimal
import os
from dotenv import load_dotenv

load_dotenv()

def get_sap_connection():
    """Return a reusable RFC connection."""
    return pyrfc.Connection(
        ashost=os.getenv("SAP_HOST"),
        sysnr=os.getenv("SAP_SYSNR"),
        client=os.getenv("SAP_CLIENT"),
        user=os.getenv("SAP_USER"),
        passwd=os.getenv("SAP_PASSWORD"),
        lang="EN"
    )

def extract_table_to_df(conn, table_name, fields, where_clauses=None, max_rows=50000):
    """
    Extract any SAP transparent table into a pandas DataFrame.

    Args:
        conn: active pyrfc.Connection
        table_name: SAP table name (e.g. 'VBRP')
        fields: list of field names to extract
        where_clauses: list of WHERE clause strings (max 72 chars each!)
        max_rows: row limit (be careful with large tables)

    Returns:
        pandas DataFrame
    """
    options = []
    if where_clauses:
        for clause in where_clauses:
            # SAP RFC_READ_TABLE requires clauses under 72 characters
            if len(clause) > 72:
                raise ValueError(f"WHERE clause too long (>72 chars): {clause}")
            options.append({"TEXT": clause})

    result = conn.call(
        "RFC_READ_TABLE",
        QUERY_TABLE=table_name,
        DELIMITER="|",
        FIELDS=[{"FIELDNAME": f} for f in fields],
        OPTIONS=options,
        ROWCOUNT=max_rows
    )

    # Get field metadata for accurate parsing
    field_meta = result["FIELDS"]
    field_names = [f["FIELDNAME"] for f in field_meta]

    rows = []
    for entry in result["DATA"]:
        parts = entry["WA"].split("|")
        row = {field_names[i]: parts[i].strip() if i < len(parts) else ""
               for i in range(len(field_names))}
        rows.append(row)

    return pd.DataFrame(rows) if rows else pd.DataFrame(columns=field_names)

El límite de 72 caracteres en las cláusulas WHERE es una trampa clásica de SAP que atrapa a cada desarrollador que comienza con RFC_READ_TABLE. Ahora tú no serás uno de ellos.


Proyecto Real de IA/ML #1: Previsión de Demanda con scikit-learn

Aquí es donde la inversión da sus frutos. Construiremos un modelo de previsión de demanda usando datos históricos de ventas de SAP — algo que tiene cualquier entorno SAP pero que pocas organizaciones usan realmente para previsión basada en ML.

El Problema de Negocio

Un responsable de logística quiere saber: para cada material de producto terminado, ¿cuántas unidades venderemos el mes que viene? Actualmente esto se hace en Excel o mediante la planificación integrada de SAP (que requiere consultores de MM/PP y configuración costosa). Vamos a construir un modelo Python que lee datos históricos de facturación de VBRP y produce previsiones.

Paso 1: Extraer Datos Históricos de Ventas

conn = get_sap_connection()

# Extract billing document line items — VBRP joined with VBRK for dates
# Note: RFC_READ_TABLE can't do JOINs, so we extract separately and merge in pandas
vbrp_df = extract_table_to_df(
    conn,
    table_name="VBRP",
    fields=["VBELN", "MATNR", "FKIMG", "VRKME", "NETWR", "WAERK"],
    where_clauses=["VBTYP = 'M'"],  # M = Invoice (billing document)
    max_rows=200000
)

vbrk_df = extract_table_to_df(
    conn,
    table_name="VBRK",
    fields=["VBELN", "FKDAT", "BUKRS"],
    where_clauses=["VBTYP = 'M'", "AND FKDAT >= '20230101'"],
    max_rows=200000
)

conn.close()

# Merge on billing document number
df = pd.merge(vbrp_df, vbrk_df, on="VBELN", how="inner")

# Type conversions — critical step for ABAP developers new to pandas
df["FKIMG"] = pd.to_numeric(df["FKIMG"], errors="coerce").fillna(0)
df["FKDAT"] = pd.to_datetime(df["FKDAT"], format="%Y%m%d", errors="coerce")
df["MATNR"] = df["MATNR"].str.strip()

# Remove cancellations (negative quantities)
df = df[df["FKIMG"] > 0]

print(f"Extracted {len(df):,} billing line items")
print(df.head())

Paso 2: Ingeniería de Características

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score
import numpy as np

# Aggregate to monthly sales per material
df["year_month"] = df["FKDAT"].dt.to_period("M")
monthly = df.groupby(["MATNR", "year_month"])["FKIMG"].sum().reset_index()
monthly.columns = ["MATNR", "year_month", "quantity_sold"]

# Focus on one material for demonstration — in production you'd loop or use a model per material
material = "000000000010000001"
mat_df = monthly[monthly["MATNR"] == material].copy()
mat_df = mat_df.sort_values("year_month")

# Convert period to numeric index for regression (month number from start)
mat_df["month_index"] = range(len(mat_df))

# Add seasonal features — month of year matters for many products
mat_df["month_of_year"] = mat_df["year_month"].dt.month
mat_df["quarter"] = mat_df["year_month"].dt.quarter

# One-hot encode month of year (captures seasonality)
month_dummies = pd.get_dummies(mat_df["month_of_year"], prefix="month")
mat_df = pd.concat([mat_df, month_dummies], axis=1)

print(f"Training data: {len(mat_df)} months of history")

Paso 3: Entrenar el Modelo de Previsión

# Define features — trend (month_index) + seasonality (month dummies)
feature_cols = ["month_index"] + [c for c in mat_df.columns if c.startswith("month_")]
X = mat_df[feature_cols]
y = mat_df["quantity_sold"]

# Train/test split — use last 3 months as holdout (time-respecting split)
X_train, X_test = X.iloc[:-3], X.iloc[-3:]
y_train, y_test = y.iloc[:-3], y.iloc[-3:]

# Train Linear Regression model
model = LinearRegression()
model.fit(X_train, y_train)

# Evaluate
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print(f"Mean Absolute Error: {mae:.0f} units")
print(f"R² Score: {r2:.3f}")

# Forecast next month
last_index = mat_df["month_index"].max() + 1
next_month_num = (mat_df["year_month"].max() + 1).month
next_features = {"month_index": last_index}
for col in feature_cols:
    if col.startswith("month_"):
        month_num = int(col.split("_")[1])
        next_features[col] = 1 if month_num == next_month_num else 0

next_X = pd.DataFrame([next_features])
forecast = model.predict(next_X)[0]
print(f"\nForecast for next month: {forecast:.0f} units")

En un despliegue en producción, envolverías esto en un script Python programado que escribe las previsiones de vuelta a SAP usando una tabla Z personalizada mediante BAPI_PRODORD_CREATE o similar, o en un InfoObject de BW mediante carga de archivo plano. La lógica de previsión se queda en Python; los resultados vuelven a SAP donde los planificadores pueden usarlos.


Proyecto Real de IA/ML #2: Detección de Anomalías en Documentos FI

El fraude en cuentas a pagar y los errores de contabilización cuestan millones a las organizaciones. La revisión manual es imposible a escala. Isolation Forest — un algoritmo de machine learning no supervisado — es excelente para encontrar los documentos que "no se parecen a los demás". Vamos a construirlo sobre datos de BKPF/BSEG.

Extraer Datos de Contabilización FI

conn = get_sap_connection()

# BKPF: FI document header
bkpf_df = extract_table_to_df(
    conn,
    table_name="BKPF",
    fields=["BELNR", "GJAHR", "BUKRS", "BLDAT", "BUDAT", "BLART", "USNAM", "BKTXT"],
    where_clauses=["GJAHR = '2025'", "AND BUKRS = '1000'"],
    max_rows=100000
)

# BSEG: FI document line items
bseg_df = extract_table_to_df(
    conn,
    table_name="BSEG",
    fields=["BELNR", "GJAHR", "BUZEI", "KOART", "DMBTR", "SHKZG", "HKONT", "LIFNR", "KUNNR"],
    where_clauses=["GJAHR = '2025'", "AND BUKRS = '1000'"],
    max_rows=500000
)

conn.close()

# Type conversions
bkpf_df["BLDAT"] = pd.to_datetime(bkpf_df["BLDAT"], format="%Y%m%d", errors="coerce")
bkpf_df["BUDAT"] = pd.to_datetime(bkpf_df["BUDAT"], format="%Y%m%d", errors="coerce")
bseg_df["DMBTR"] = pd.to_numeric(bseg_df["DMBTR"], errors="coerce").fillna(0)

# Sign convention: SHKZG='S' is debit, 'H' is credit
bseg_df["signed_amount"] = bseg_df.apply(
    lambda r: r["DMBTR"] if r["SHKZG"] == "S" else -r["DMBTR"], axis=1
)

Ingeniería de Características para Detección de Anomalías

from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import LabelEncoder
import warnings
warnings.filterwarnings("ignore")

# Merge header and line items
df_fi = pd.merge(bseg_df, bkpf_df, on=["BELNR", "GJAHR"], how="left")

# Create features that capture anomalous posting behavior
features_df = pd.DataFrame()

# Feature 1: Absolute amount (unusually large amounts are suspicious)
features_df["abs_amount"] = df_fi["signed_amount"].abs()

# Feature 2: Day of week when document was posted (weekend postings are risky)
features_df["day_of_week"] = df_fi["BUDAT"].dt.dayofweek

# Feature 3: Difference between document date and posting date (large gaps = suspicious)
features_df["date_gap_days"] = (df_fi["BUDAT"] - df_fi["BLDAT"]).dt.days.abs().fillna(0)

# Feature 4: Document type encoded as numeric
le = LabelEncoder()
features_df["doc_type_encoded"] = le.fit_transform(df_fi["BLART"].fillna("XX"))

# Feature 5: Account type (vendor, customer, GL) encoded
features_df["acct_type_encoded"] = le.fit_transform(df_fi["KOART"].fillna("X"))

# Feature 6: Log-transformed amount (reduces impact of extreme outliers on model training)
features_df["log_amount"] = np.log1p(features_df["abs_amount"])

# Drop rows with NaN (documents with missing dates, etc.)
features_clean = features_df.dropna()
print(f"Training on {len(features_clean):,} FI line items")

Entrenar y Puntuar el Isolation Forest

from sklearn.preprocessing import StandardScaler

# Scale features — Isolation Forest is not sensitive to scale, but it's good practice
scaler = StandardScaler()
X_scaled = scaler.fit_transform(features_clean)

# Train Isolation Forest
# contamination=0.01 means we expect ~1% of postings to be anomalous
iso_forest = IsolationForest(
    n_estimators=200,
    contamination=0.01,
    random_state=42,
    n_jobs=-1
)
iso_forest.fit(X_scaled)

# Score all documents — lower score = more anomalous
anomaly_scores = iso_forest.decision_function(X_scaled)
predictions = iso_forest.predict(X_scaled)  # -1 = anomaly, 1 = normal

# Add results back to the original DataFrame
results_df = df_fi.loc[features_clean.index].copy()
results_df["anomaly_score"] = anomaly_scores
results_df["is_anomaly"] = predictions == -1

# Report top anomalies for human review
anomalies = results_df[results_df["is_anomaly"]].sort_values("anomaly_score")
print(f"\nFlagged {len(anomalies):,} documents for review ({len(anomalies)/len(results_df)*100:.1f}%)")
print("\nTop 10 most anomalous documents:")
print(anomalies[["BELNR", "GJAHR", "BLART", "signed_amount", "USNAM", "anomaly_score"]].head(10))

El resultado es una lista ordenada de documentos FI que parecen estadísticamente inusuales comparados con los patrones históricos de contabilización. No todos los documentos marcados son fraudulentos — algunos son transacciones grandes legítimas o ajustes de cierre de ejercicio. Pero el modelo reduce drásticamente la carga de revisión: en lugar de auditar 100.000 contabilizaciones, un auditor revisa los 1.000 más sospechosos. Eso es una reducción del 99% en el esfuerzo manual.


Proyecto Real de IA/ML #3: Descripciones de Informes SAP con LLM

Este es el que genuinamente sorprende a los usuarios de negocio cada vez. Tomamos la salida de un informe ABAP estándar — el tipo de tabla críptica llena de tipos de movimiento y claves de cuenta que solo un consultor de logística puede leer — y usamos Claude (el LLM de Anthropic) para traducirlo a inglés sencillo que cualquier directivo puede entender.

La Configuración

import anthropic
import pandas as pd
import json
from dotenv import load_dotenv
import os

load_dotenv()

client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

Extraer los Datos del Informe

conn = get_sap_connection()

# Example: Material movement data from MSEG
mseg_df = extract_table_to_df(
    conn,
    table_name="MSEG",
    fields=["MBLNR", "MJAHR", "ZEILE", "MATNR", "WERKS", "LGORT",
            "BWART", "MENGE", "MEINS", "DMBTR", "WAERS"],
    where_clauses=[
        "MJAHR = '2025'",
        "AND WERKS = '1000'",
        "AND BWART IN ('101', '102', '201', '261', '311', '312')"
    ],
    max_rows=10000
)

conn.close()

# Type conversions
mseg_df["MENGE"] = pd.to_numeric(mseg_df["MENGE"], errors="coerce").fillna(0)
mseg_df["DMBTR"] = pd.to_numeric(mseg_df["DMBTR"], errors="coerce").fillna(0)

# Summarize for the LLM (don't send 10,000 rows — summarize first)
summary = mseg_df.groupby("BWART").agg(
    movement_count=("MBLNR", "count"),
    total_qty=("MENGE", "sum"),
    total_value=("DMBTR", "sum")
).reset_index()

# Convert to a JSON-like string for the prompt
summary_text = summary.to_string(index=False)
print("Movement summary prepared for LLM:")
print(summary_text)

Generar la Explicación en Lenguaje Sencillo

def explain_sap_report(report_data: str, report_context: str) -> str:
    """
    Send SAP report data to Claude for plain-English explanation.

    Args:
        report_data: The actual data (as formatted string or CSV)
        report_context: Context about what the report shows

    Returns:
        Human-readable explanation from Claude
    """
    prompt = f"""You are an SAP business analyst assistant. A user has run an SAP materials
management report and needs it explained in plain English for a non-technical business audience.

Report context: {report_context}

Report data:
{report_data}

SAP movement type reference:
- 101: Goods receipt for purchase order
- 102: Reversal of goods receipt for purchase order
- 201: Goods issue for cost center
- 261: Goods issue for production order
- 311: Transfer posting plant to plant (in)
- 312: Transfer posting plant to plant (out)

Please provide:
1. A 2-3 sentence executive summary of what this report shows
2. Key observations (what stands out — volumes, values, unusual patterns)
3. Any recommended actions or questions a business owner should ask
4. Plain-English explanation of each movement type present in the data

Write in clear, jargon-free language suitable for a supply chain manager who does not know SAP."""

    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        messages=[
            {"role": "user", "content": prompt}
        ]
    )

    return message.content[0].text


# Generate the explanation
context = "Material movements at Plant 1000 for fiscal year 2025, showing all goods receipts, issues, and transfers."
explanation = explain_sap_report(summary_text, context)

print("\n" + "="*60)
print("PLAIN-ENGLISH REPORT EXPLANATION")
print("="*60)
print(explanation)

El resultado es un resumen directivo generado automáticamente de cualquier informe SAP. Puedes envolver esto en una interfaz web sencilla usando FastAPI y tenerlo desplegado en días. Los usuarios de negocio ejecutan una transacción, hacen clic en "Explicar este informe" y obtienen un párrafo que pueden pegar directamente en un correo a la dirección. Este tipo de augmentación con IA es donde el conocimiento ABAP y las habilidades Python se combinan para crear valor empresarial genuino e inmediato.


El Plan de Aprendizaje de 90 Días: De Cero Python a Tu Primer Modelo ML en Producción

Aprender Python mientras mantienes tu carrera SAP no requiere dejar tu trabajo ni hacer un bootcamp. Este es el camino realista que daría a un desarrollador ABAP senior que empieza hoy.

Días 1–15: Fundamentos Python (Mapeados a ABAP)

  • Día 1-2: Instala Python, VS Code y tu entorno virtual. Ejecuta tu primer script. El objetivo es un entorno funcional, no aprender sintaxis.
  • Día 3-5: Sintaxis básica de Python a través de la lente ABAP. Variables (sin declaración DATA), bucles (FOR en lugar de LOOP AT), funciones (el equivalente de FORM/FUNCTION es def). Usa el libro Python Crash Course o el tutorial oficial de Python — omite todo lo de scraping web o juegos y céntrate en tipos de datos y funciones.
  • Día 6-8: Diccionarios y listas. Estos son tus equivalentes a tablas internas. Un diccionario Python es una estructura única como un área de trabajo; una lista de diccionarios es una tabla interna. Este modelo mental acelerará todo lo demás.
  • Día 9-12: Fundamentos de pandas. Lee la introducción oficial de pandas en 10 minutos. Practica: df.head(), df.describe(), df.groupby(), df.merge(). Estas cuatro operaciones cubrirán el 80% de lo que necesitas para trabajo con datos SAP.
  • Día 13-15: Conecta Python a tu sistema SAP de desarrollo usando pyrfc. Haz funcionar el script de maestro de materiales de este artículo. Cuando funcione, sentirás la misma satisfacción que al escribir tu primera sentencia SELECT funcional en ABAP.

Días 16–45: Ingeniería de Datos SAP

  • Día 16-20: Extrae 3 conjuntos de datos SAP distintos que conoces bien (materiales, clientes, pedidos de compra). Construye DataFrames. Practica joins, agregaciones y conversiones de tipos. El objetivo es la fluidez con tus propios datos.
  • Día 21-30: Aprende pandas para limpieza de datos. Los datos SAP reales son desordenados — entradas duplicadas, espacios finales, formatos de fecha incorrectos, registros de valor cero que deberían excluirse. Construye un pipeline de limpieza reutilizable para datos SAP.
  • Día 31-38: matplotlib y plotly para visualización. Construye 5 gráficos con datos SAP: tendencia de ventas en el tiempo, top materiales por ingresos, desglose de tipos de movimiento, antigüedad de pagos a proveedores, consumo de material por centro. La visualización es donde los usuarios de negocio ven el valor por primera vez.
  • Día 39-45: Programa un script Python para ejecutarse diariamente mediante cron (Linux) o Programador de Tareas (Windows). Extrae datos SAP, produce un CSV de resumen, envíalo por correo usando smtplib de Python. Este es tu primer despliegue "en producción".

Días 46–75: Machine Learning sobre Datos SAP

  • Día 46-55: Fundamentos de scikit-learn. Trabaja la guía oficial del usuario en la sección de aprendizaje supervisado. Céntrate en: LinearRegression, RandomForestRegressor y el patrón train/test split. No intentes aprenderlo todo — aprende el flujo de trabajo.
  • Día 56-60: Construye el modelo de previsión de demanda de este artículo con tus propios datos. Adáptalo para un material o grupo de materiales relevante en tu organización. Muestra el resultado a alguien de planificación — el feedback real acelera el aprendizaje más que cualquier curso.
  • Día 61-68: Construye el modelo de detección de anomalías sobre tus datos FI. Siéntate con el equipo de finanzas y revisad juntos los documentos marcados. Aprenderás más sobre qué significa "anómalo" en tu contexto específico en una reunión que en cualquier tutorial.
  • Día 69-75: Aprende los fundamentos de evaluación de modelos: matriz de confusión, precisión/recall (para clasificación), MAE/RMSE (para regresión) y validación cruzada. No necesitas dominar la estadística — necesitas saber cómo determinar si tu modelo está funcionando.

Días 76–90: Despliegue y Posicionamiento

  • Día 76-80: Fundamentos de FastAPI. Envuelve tu modelo ML en una API REST simple — un endpoint que acepta un número de material y devuelve una previsión. Esto hace tu modelo accesible para cualquiera que pueda hacer una petición HTTP, incluidas las aplicaciones Fiori.
  • Día 81-85: Git y GitHub. El control de versiones es imprescindible en el desarrollo Python. Aprende git init, git add, git commit, git push. Crea una cuenta de GitHub y sube tus proyectos SAP-Python. Este se convierte en tu portfolio.
  • Día 86-90: Presenta tu modelo de previsión de demanda o detección de anomalías a un stakeholder de negocio. No tiene que ser perfecto — tiene que ser útil. Un modelo funcional que detecta una sola factura fraudulenta o mejora un ciclo de planificación en un 10% es prueba de concepto que abre puertas.

Qué Estudiar (Recursos Específicos)

Tema Recurso Inversión de Tiempo
Python básico Python Crash Course, 3ª Ed. (Matthes) — solo capítulos 1-9 15 horas
pandas Documentación oficial de pandas + micro-curso Kaggle Pandas (gratuito) 10 horas
Integración SAP-Python Ejemplos del repositorio GitHub de pyrfc + posts del blog SAP Community sobre RFC 8 horas
Machine learning Hands-On Machine Learning (Géron) — capítulos 1-7, omite redes neuronales por ahora 30 horas
Desarrollo de API Tutorial oficial FastAPI — las primeras 5 secciones son todo lo que necesitas 6 horas
Git Documentación oficial Git "Getting Started" + Pro Git book Ch. 1-3 5 horas
APIs de LLM Documentación de Anthropic + Claude API cookbook en GitHub 4 horas

La Hoja de Ruta de 12 Meses: Del Primer Script a la IA/ML en Producción

El plan de 90 días te lleva a tu primer modelo desplegado. Esta es la visión extendida de 12 meses — a dónde vas después de que esa base sea sólida, y qué hitos indican que estás en el camino correcto hacia los roles híbridos SAP+Python que pagan al nivel más alto del mercado.

Mes Enfoque Hito Objetivo Indicador de Éxito
Mes 1 Python + pyrfc fundamentos Leer 3 tablas SAP desde Python; construir tu primer DataFrame con datos SAP Puedes reproducir cualquier SELECT ABAP en Python mediante RFC
Mes 2 Ingeniería de datos con pandas Construir un informe semanal de datos SAP como script Python automatizado El script se ejecuta sin atención mediante cron; el equipo de finanzas recibe el resultado
Mes 3 ML básico con scikit-learn Desplegar el primer modelo ML sobre datos SAP (previsión de demanda o detección de anomalías) El modelo supera la línea base en al menos un 10%; stakeholder de negocio ha revisado los resultados
Mes 4 Integración con API de LLM Construir una automatización con LLM (clasificador de tickets o explicador de anomalías) Endpoint API funcional que devuelve JSON estructurado; probado con muestras de datos reales
Mes 5 FastAPI + servicios REST Envolver el modelo ML en una API REST; conectarla a un consumidor real (Fiori, Teams o email) Al menos 5 personas usando tu API regularmente; uptime controlado
Mes 6 Portfolio y posicionamiento 3 repositorios GitHub con proyectos SAP-Python; LinkedIn actualizado con skills de Python y ML Primer contacto espontáneo de un recruiter para un rol híbrido SAP+Python
Mes 7 OData y APIs REST Reemplazar al menos una integración basada en pyrfc por la API OData equivalente de S/4HANA La integración funciona sin RFC SDK; puede ejecutarse en BTP o cloud sin librería RFC
Mes 8 ML avanzado: series temporales y clasificación Construir una previsión de demanda de calidad productiva cubriendo al menos un horizonte de planificación completo MAE de previsión mejor que la línea base del planificador; presentado al equipo de planificación
Mes 9 BTP Python runtime (si aplica) Desplegar un servicio Python existente en BTP Cloud Foundry Servicio accesible dentro de Fiori o mediante URL de BTP; conectividad via Cloud Connector confirmada
Mes 10 Pipelines de datos y programación Construir un pipeline programado que extrae, transforma y carga datos SAP a un sistema destino El pipeline se ejecuta diariamente sin intervención manual; los fallos alertan automáticamente
Mes 11 Consultoría interna y difusión de conocimiento Presentar un proyecto de IA/ML completado en una comunidad SAP interna o reunión de equipo Al menos un colega empieza a usar tus herramientas o te pide colaborar en su proyecto
Mes 12 Posicionamiento y entrada al mercado Solicitar al menos 3 roles híbridos SAP+Python o SAP+IA; objetivo EUR 120K+ o equivalente Al menos una entrevista para un rol que no existía en el mercado SAP hace 3 años

Dos cosas hacen esta hoja de ruta realista que planes similares ignoran. Primero, estás construyendo cosas reales que usuarios reales pueden ver — no proyectos de tutorial. Cada hito anterior tiene una salida visible para un stakeholder de negocio. Esto importa porque construye tu reputación interna y crea la base de evidencia que necesitas cuando te posiciones para mejores roles. Segundo, los hitos se acumulan: la integración LLM del Mes 4 se construye sobre el modelo del Mes 3, que se construye sobre la ingeniería de datos del Mes 2. No empiezas de cero cada mes — estás compoundando.

Los datos salariales respaldan esta hoja de ruta. Los desarrolladores ABAP que completan este camino de 12 meses y pueden demostrarlo con un portfolio de GitHub y un despliegue real típicamente acceden a roles híbridos que pagan de EUR 120.000 a EUR 145.000 en mercados de Europa Occidental, frente a EUR 85.000 a EUR 100.000 para perfiles equivalentes solo ABAP. En el mercado estadounidense el diferencial es de $115K-$145K frente a $90K-$115K. Los 12 meses de inversión se amortizan en el primer año del nuevo nivel de compensación.


Implicaciones Profesionales: El Mercado Híbrido SAP+Python en 2026

Hablemos de dinero y oportunidades, porque esto es en última instancia lo que hace que la inversión en aprendizaje valga la pena.

La Brecha Salarial es Real

En 2026, las bolsas de trabajo cuentan una historia clara. Los roles de desarrollador ABAP puro (sin Python, sin IA) en Europa Occidental pagan €80.000–€105.000 anuales para perfiles senior. Añade habilidades demostradas de Python y pandas — incluso sin ML — y esos mismos perfiles saltan a €95.000–€125.000. Añade un modelo ML desplegado o dos en el portfolio, y estás mirando €120.000–€160.000 para roles híbridos SAP+IA en consultoras, grandes empresas y partners SAP. En el mercado estadounidense, el equivalente es aproximadamente $115K–$195K según la ubicación y el empleador.

La prima existe porque la oferta de personas que entienden ambos lados es mínima. Un científico de datos que no conoce SAP no puede construir lo que tú construirás después de leer este artículo. Un desarrollador ABAP que no ha aprendido Python está excluido de la ola de IA. La intersección — personas que pueden hacer ambas cosas — es donde la compensación alcanza su pico.

Dónde Están Apareciendo Estos Roles

  • Partners SAP e Integradores de Sistemas: Accenture, Deloitte, Capgemini, IBM tienen prácticas dedicadas de SAP+IA. Estos roles se etiquetan como "SAP Data Engineer", "SAP ML Developer" o "SAP AI Consultant". Pagan tarifas de consultoría y dan exposición a múltiples clientes.
  • SAP SE: SAP está construyendo agresivamente capacidades de Business AI en S/4HANA. Contratan desarrolladores ABAP que pueden trabajar con sus plataformas de analítica embebida y AI Core. Busca en LinkedIn roles de "SAP Business AI".
  • Grandes Clientes SAP: Las empresas de fabricación, farmacia y automoción que ejecutan entornos SAP complejos están construyendo equipos de IA internos. Quieren personas que entiendan los procesos empresariales codificados en sus sistemas SAP — no científicos de datos que necesitan 18 meses para aprender el modelo de datos.
  • Startups: Un número creciente de empresas está construyendo productos de analítica basados en IA sobre datos SAP (analítica de compras, optimización del capital circulante, inteligencia de cadena de suministro). Estas startups pagan por debajo de las tarifas enterprise pero ofrecen equity y la aceleración de aprendizaje más rápida que encontrarás.

Cómo Posicionarte

La clave no es presentarte como "un desarrollador ABAP que también sabe Python". Esa formulación infravalora la combinación. Preséntate como "un ingeniero de procesos empresariales que puede construir soluciones de IA sobre datos SAP" — porque eso es lo que realmente eres después de completar este camino de aprendizaje.

Tu perfil de LinkedIn debería mencionar: los módulos SAP que conoces en profundidad (FI, MM, SD, PP — lo que aplique), Python, pandas, scikit-learn y cualquier modelo o automatización desplegados que hayas construido. Incluso un proyecto personal cuenta. Un repositorio GitHub con notebooks de análisis de datos SAP es un portfolio que el 95% de los desarrolladores ABAP no pueden producir, lo que te diferencia inmediatamente.

La Pregunta de las Certificaciones

Las certificaciones importan menos que el código desplegado. Una certificación Python Institute PCEP indica que aprendiste Python. Un repositorio GitHub con un modelo funcional de previsión de demanda SAP indica que puedes aplicarlo. Prioriza lo segundo. Si quieres una credencial, SAP Certified Technology Associate — SAP Analytics Cloud es más relevante para el mercado que una certificación Python genérica, porque demuestra contexto SAP junto con capacidad analítica.


Errores Habituales que Cometen los Desarrolladores ABAP al Aprender Python

Yo cometí la mayoría. Tú no tienes que hacerlo.

Error 1: Iterar en Lugar de Vectorizar

Los desarrolladores ABAP instintivamente escriben bucles Python igual que escribirían LOOP AT en ABAP. Esto funciona, pero es lento con conjuntos de datos grandes y poco pythónico. Aprende las operaciones vectorizadas de pandas pronto. En lugar de:

# ABAP-brain Python (slow, un-Pythonic)
for index, row in df.iterrows():
    if row["BWART"] == "101":
        df.at[index, "movement_desc"] = "Goods Receipt"

Escribe:

# Pythonic vectorized operation (fast, clean)
movement_map = {"101": "Goods Receipt", "102": "GR Reversal", "261": "Goods Issue"}
df["movement_desc"] = df["BWART"].map(movement_map)

Error 2: Ignorar los Tipos de Datos Después de la Extracción

RFC_READ_TABLE devuelve todo como strings. Los desarrolladores ABAP que no convierten explícitamente los tipos de datos descubren que las agregaciones devuelven 0 o errores. Convierte siempre los campos numéricos con pd.to_numeric() y las fechas con pd.to_datetime() inmediatamente después de la extracción.

Error 3: Entrenar con Todos los Datos Disponibles Sin Validación

En ABAP, haces SELECT con los datos y los muestras — no hay concepto de overfitting. En ML, un modelo entrenado sin un conjunto de validación adecuado puede puntuar perfectamente en los datos de entrenamiento y fallar completamente con datos nuevos. Usa siempre train_test_split, y para datos SAP de series temporales, divide siempre cronológicamente (no aleatoriamente).

Error 4: Intentar Aprenderlo Todo Antes de Construir Algo

El camino de aprendizaje ABAP está estructurado — estudias la sintaxis, los tipos de datos, el modelo de objetos. El ecosistema Python es suficientemente vasto como para que intentar aprenderlo todo antes de empezar te paralice. Construye algo real con lo que sabes tras dos semanas. Las lagunas en tu conocimiento se volverán obvias y específicas en cuanto te enfrentes a un problema real.


Reflexiones Finales: El Puente es Más Corto de lo que Crees

Cuando ejecuté mi primer script con pyrfc y vi datos SAP aparecer en un DataFrame de pandas, recuerdo pensar: estos son los mismos datos que he estado mirando durante 12 años, pero ahora puedo hacer cosas con ellos de verdad. Los datos no habían cambiado. Los problemas empresariales no habían cambiado. Pero las herramientas que podía aplicarles se habían expandido enormemente.

Ya entiendes algo que ningún tutorial de Python puede enseñar: por qué los datos en SAP tienen el aspecto que tienen, qué representan en un proceso empresarial real y qué cambios en esos datos significan para las personas que dependen de ellos. Ese conocimiento es tu fundamento. Python es simplemente un conjunto de herramientas más potentes para construir sobre él.

El plan de 90 días de este artículo es alcanzable junto a una carrera ABAP a tiempo completo. No necesitas noches y fines de semana — necesitas 30-45 minutos concentrados al día, de forma constante. Después de tres meses, tendrás código funcional, un portfolio en GitHub y la confianza para empezar a posicionarte para los roles que están emergiendo en la intersección de SAP e IA.

Los desarrolladores ABAP que prosperen en la próxima década no serán los que abandonaron su experiencia SAP. Serán los que la conservaron y añadieron Python encima. Esa combinación — conocimiento profundo de procesos empresariales más herramientas modernas de IA/ML — es genuinamente escasa, genuinamente valiosa y está al alcance de cualquier desarrollador dispuesto a invertir el tiempo.


BTP Python Runtime vs. Scripts Python en Local: ¿Cuál Deberías Usar?

Una de las decisiones más prácticas que enfrentan los desarrolladores ABAP al construir sus primeras integraciones Python-SAP es dónde ejecutar el código. La respuesta depende de tu entorno, tu postura de seguridad y la criticidad de la carga de trabajo. Esta es una comparación honesta basada en el despliegue de ambas opciones en entornos de producción.

Scripts Python en Local: Empieza por Aquí

Ejecutar Python en un servidor dentro de tu red significa conectar a SAP mediante pyrfc o una conexión directa a HANA desde una VM Linux o Windows dentro de tu DMZ SAP. Este enfoque es el más rápido para comenzar: sin aprovisionamiento de nueva infraestructura, sin configuración de cuenta BTP, sin proceso de aprobación en cloud. Instala Python, instala pyrfc, escribe un script, ejecútalo. Un cron job en un servidor Linux que ejecuta extracciones de datos nocturnas, informes semanales y trabajos mensuales de puntuación ML es fiable, económico y no requiere nuevos contratos con proveedores.

Para entornos aislados en gobierno, defensa o fabricación farmacéutica, el local es a menudo la única opción. Para el 80% de los casos de uso que los desarrolladores ABAP construyen en sus primeros 12 meses de Python, el Python local es suficiente y dramáticamente más rápido de desplegar que cualquier alternativa basada en cloud.

SAP BTP Python Runtime: Cuándo lo Necesitas Realmente

SAP Business Technology Platform ofrece un runtime Python (basado en Cloud Foundry) donde despliegas aplicaciones Python como microservicios. BTP Python es necesario en escenarios específicos: cuando tu modelo ML necesita servir predicciones dentro de una aplicación Fiori en tiempo real, cuando quieres usar SAP AI Core para entrenamiento y servicio gestionados de ML, o cuando necesitas conectar a múltiples sistemas SAP y quieres que el servicio de conectividad de BTP gestione las credenciales de forma centralizada.

El coste es mayor. Las instancias de aplicación Cloud Foundry, el servicio de conectividad BTP y la capacidad de AI Core están todas medidas. En la práctica, espera de $500 a $2.000 al mes a escala de producción. La configuración en un entorno empresarial típicamente lleva de 2 a 4 semanas incluyendo aprobaciones de IT y revisiones de seguridad.

Factor Python en Local BTP Python Runtime
Tiempo de configuración Horas a días Semanas (sobrecarga de aprobaciones enterprise)
Coste mensual $50-200 (solo hosting de servidor) $500-2000+ (consumo BTP medido)
Conectividad SAP pyrfc o HANA directo (misma red) BTP Cloud Connector + destino RFC
Integración Fiori Posible pero requiere config de enrutamiento de red Nativa (mismo entorno BTP)
Escalabilidad horizontal Escalado manual de VM necesario Auto-scaling integrado
SAP AI Core / Joule No disponible Nativo
Mejor para Jobs batch, puntuación ML programada, sistemas aislados APIs en tiempo real, IA embebida en Fiori, cargas de trabajo AI Core

El camino práctico: construye en local primero para desarrollar habilidades y demostrar valor empresarial. Una vez que tengas un modelo funcional y el apoyo de los stakeholders, migra la capa de servicio a BTP si se requiere integración Fiori en tiempo real. El código Python es idéntico entre entornos. Solo cambia el destino de despliegue.


Ingeniería de Prompts LLM para Casos de Uso SAP

La ingeniería de prompts es la habilidad más subestimada en el espacio SAP+Python en 2026. Para los desarrolladores ABAP, piénsalo como escribir una especificación de módulo de función que la IA ejecuta. La calidad de tu especificación determina la calidad del resultado. Los prompts vagos producen salidas vagas. Los prompts precisos con esquemas de salida explícitos producen JSON que puedes parsear y sobre el que puedes actuar.

Caso de Uso: Clasificación de Tickets de Soporte SAP

Los entornos SAP empresariales generan cientos de tickets de soporte por semana. Triajearlos manualmente consume de 2 a 4 horas diarias de tiempo de soporte L1. Un LLM puede clasificar y enrutar el 95% de los tickets en menos de un segundo con una precisión que iguala o supera el triaje humano L1. Coste via Claude Haiku: aproximadamente $0,0003 por ticket.

import anthropic
import json
import re

client = anthropic.Anthropic()  # Reads ANTHROPIC_API_KEY from environment

PROMPT = (
    "You are an SAP support ticket classifier.\n"
    "Classify the ticket below. Respond with valid JSON only.\n\n"
    "VALID CATEGORIES: BASIS, FI, MM, SD, PP, HR, CUSTOM, UNKNOWN\n\n"
    "Required JSON:\n"
    '{"category":"...","confidence":0.0,"priority":"LOW|MEDIUM|HIGH|CRITICAL",'
    '"routing_team":"...","issue_summary":"one sentence","draft_response":"2-3 sentences"}\n\n'
    "Ticket: {ticket_text}"
)

def classify_ticket(ticket_text: str) -> dict:
    message = client.messages.create(
        model="claude-haiku-4-5",    # Haiku: fastest and cheapest for high-volume
        max_tokens=400,
        messages=[{"role": "user",
                   "content": PROMPT.format(ticket_text=ticket_text)}]
    )
    raw = message.content[0].text
    try:
        return json.loads(raw)
    except json.JSONDecodeError:
        match = re.search(r'\{.*\}', raw, re.DOTALL)
        return json.loads(match.group()) if match else {"error": "parse_failed"}

# Example: classify_ticket("Cannot post GR - authorization error on movement type 101 plant 1010")
# Returns: {"category":"MM","priority":"HIGH","routing_team":"MM Functional + BASIS",...}

Caso de Uso: Explicación de Anomalías para Equipos de Finanzas

Los modelos de detección de anomalías ML producen puntuaciones que solo los científicos de datos pueden interpretar. Combinar la salida del modelo con un LLM que explica las anomalías en lenguaje de negocio convierte una puntuación numérica en un hallazgo de auditoría accionable que un controller puede investigar sin necesitar entender el machine learning:

ANOMALY_PROMPT = (
    "You are an SAP financial auditor. An ML model flagged this posting as anomalous.\n"
    "Explain in plain business English (3-4 sentences) why it may be suspicious\n"
    "and what a controller should investigate.\n\n"
    "Vendor: {vendor_name} (created: {vendor_created_date})\n"
    "Amount: {currency} {amount}\n"
    "Posted by {user_id} at {posting_time}\n"
    "Bank account last changed: {bank_changed_date}\n"
    "Days from vendor creation to first invoice: {days_to_invoice}\n"
    "Anomaly score: {score} (-1.0=most anomalous, 0.0=normal)"
)

# Example output for a real flagged transaction:
# "This posting warrants investigation for three specific reasons.
# The vendor was created just 4 days before this invoice, consistent with
# fictitious vendor creation. The bank account was changed 2 days after
# creation and 2 days before payment, the classic account-takeover timeline.
# This posting was made at 11:47 PM on a Friday by a user who makes 94% of
# postings during business hours. The controller should verify vendor legitimacy
# and confirm the bank account change had documented dual approval."

Principios de Ingeniería de Prompts para Contextos SAP

  • Especifica el formato de salida con un esquema. Incluye la estructura JSON exacta que esperas en el prompt. "Responde solo con JSON válido" previene el preámbulo conversacional que rompe los parsers downstream.
  • Incluye contexto específico de SAP. Dile al modelo qué módulos están en alcance, qué moneda se usa, qué sociedades importan. Sin contexto, el modelo hace suposiciones genéricas de empresa.
  • Usa ejemplos few-shot para tareas de clasificación. Incluir de 3 a 5 ejemplos correctamente clasificados en el prompt reduce las tasas de mala clasificación entre un 30 y un 50% frente al prompting zero-shot.
  • Restringe el vocabulario de salida explícitamente. Si necesitas uno de 8 valores de categoría, lista los 8. La salida abierta crea problemas de mantenimiento cuando el modelo devuelve un valor que tu código no gestiona.
  • Prueba con tus propios casos extremos. Los benchmarks genéricos son irrelevantes. Prueba los prompts contra los 20 tickets más confusos o las contabilizaciones más ambiguas de tu sistema SAP real.

3 Proyectos SAP Reales que Puedes Construir en un Fin de Semana

La teoría acelera la práctica, pero la práctica es lo que crea evidencia en el portfolio e impacto empresarial. Estos son tres proyectos concretos alcanzables en 8 a 12 horas de trabajo concentrado durante un fin de semana. Cada uno produce algo desplegable, demostrable e inmediatamente útil para un equipo SAP real.

Proyecto de Fin de Semana 1: Verificador de Completitud del Maestro de Proveedores

El problema: Los datos incompletos del maestro de proveedores causan fallos de pago, retrasos y acumulación de correcciones manuales. La mayoría de entornos SAP tienen miles de proveedores con maestros parcialmente rellenos que nadie ha auditado sistemáticamente. Un script Python cambia esa ecuación.

Lo que construyes: Un script que extrae todos los proveedores creados en los últimos 12 meses de LFA1, los puntúa en 15 criterios de completitud (datos bancarios presentes, número fiscal relleno, condiciones de pago asignadas, formato IBAN válido, detección de cuenta bancaria duplicada) y exporta un fichero Excel de remediación ordenado por prioridad según puntuación de riesgo.

import pyrfc
import pandas as pd
from dotenv import load_dotenv
import os

load_dotenv()

conn = pyrfc.Connection(
    ashost=os.getenv("SAP_HOST"), sysnr=os.getenv("SAP_SYSNR"),
    client=os.getenv("SAP_CLIENT"), user=os.getenv("SAP_USER"),
    passwd=os.getenv("SAP_PASSWORD")
)

result = conn.call("RFC_READ_TABLE",
    QUERY_TABLE="LFA1",
    DELIMITER="|",
    FIELDS=[{"FIELDNAME": f} for f in ["LIFNR", "NAME1", "LAND1", "STCEG", "KTOKK", "ERDAT"]],
    OPTIONS=[{"TEXT": "ERDAT >= '20250101'"}]
)

rows = [e["WA"].split("|") for e in result["DATA"]]
df = pd.DataFrame(rows, columns=["LIFNR", "NAME1", "LAND1", "STCEG", "KTOKK", "ERDAT"])

# Completeness scoring (0-100 scale)
df["score"] = 60
df["score"] += (df["STCEG"].str.strip() != "").astype(int) * 20   # Tax number present
df["score"] += (df["KTOKK"].str.strip() != "").astype(int) * 20   # Account group set

df_remediation = df.sort_values("score").head(200)
df_remediation.to_excel("/tmp/vendor_completeness_report.xlsx", index=False)
print(f"Exported {len(df_remediation)} vendors requiring attention")
print(f"Worst score: {df_remediation['score'].min()}")
conn.close()

Tiempo estimado: 8 horas en total. Impacto empresarial: Un cliente encontró 12 proveedores con números de cuenta bancaria duplicados — un riesgo de fraude en pagos no detectado durante 3 años. Los equipos de finanzas que reciben el resultado priorizado típicamente remedian de 30 a 50 proveedores por semana.

Proyecto de Fin de Semana 2: Informe de Antigüedad de Pedidos de Compra Vencidos con Alertas por Email

El problema: Los compradores pierden el seguimiento de las posiciones de pedido de compra donde la entrega está vencida pero no ha ocurrido la entrada de mercancías. Estas posiciones inflan los valores de compromiso, distorsionan la disponibilidad para promesa y desencadenan ejecuciones MRP incorrectas. La mayoría de compradores sabe que el problema existe; les falta una vista sistemática por comprador de su propia cartera.

Lo que construyes: Un script Python que extrae todas las posiciones de PC abiertas con fecha de entrega vencida de EKPO, las categoriza por tramos de antigüedad (0-30, 31-60, 61-90, 90+ días de retraso) y envía un email HTML formateado a cada grupo de compras con sus artículos específicos ordenados por días de retraso, más un deep-link Fiori a cada pedido de compra.

import pyrfc
import pandas as pd
from datetime import date
from dotenv import load_dotenv
import os

load_dotenv()
conn = pyrfc.Connection(
    ashost=os.getenv("SAP_HOST"), sysnr=os.getenv("SAP_SYSNR"),
    client=os.getenv("SAP_CLIENT"), user=os.getenv("SAP_USER"),
    passwd=os.getenv("SAP_PASSWORD")
)

result = conn.call("RFC_READ_TABLE",
    QUERY_TABLE="EKPO",
    DELIMITER="|",
    FIELDS=[{"FIELDNAME": f} for f in ["EBELN", "EBELP", "MATNR", "MENGE", "EINDT", "EKGRP"]],
    OPTIONS=[
        {"TEXT": "LOEKZ = ' '"},
        {"TEXT": "AND EINDT < '{}'".format(date.today().strftime('%Y%m%d'))},
        {"TEXT": "AND ELIKZ = ' '"}    # Not delivery-complete
    ]
)

rows = [e["WA"].split("|") for e in result["DATA"]]
df = pd.DataFrame(rows, columns=["EBELN", "EBELP", "MATNR", "MENGE", "EINDT", "EKGRP"])
df["EINDT"] = pd.to_datetime(df["EINDT"], format="%Y%m%d", errors="coerce")
df = df.dropna(subset=["EINDT"])
df["days_overdue"] = (pd.Timestamp.today() - df["EINDT"]).dt.days

for ekgrp, group in df.groupby("EKGRP"):
    critical = len(group[group["days_overdue"] >= 90])
    print(f"Group {ekgrp}: {len(group)} overdue PO lines | {critical} CRITICAL (90+ days)")
    # Connect SMTP here for the full email version

conn.close()

Tiempo estimado: 8 a 10 horas incluyendo formateo de email HTML y configuración SMTP. Impacto empresarial: En un cliente, este informe redujo el acumulado de PC vencidos abiertos de 4.200 a 890 posiciones en 60 días. La visibilidad por sí sola cambió el comportamiento de los compradores.

Proyecto de Fin de Semana 3: API REST de Auto-Clasificación de Tickets SAP

El problema: El triaje de soporte SAP L1 consume de 2 a 3 horas diarias de tiempo de equipo cualificado en puro reconocimiento de patrones: leer ticket, categorizar, enrutar. Es un objetivo textbook de automatización con LLM.

Lo que construyes: Un servicio FastAPI que acepta texto de ticket via HTTP POST, lo clasifica usando Claude Haiku y devuelve JSON estructurado con categoría, prioridad, equipo de enrutamiento y un borrador de primera respuesta. Conéctalo al webhook de entrada de tu sistema de tickets y el triaje L1 se automatiza.

from fastapi import FastAPI
from pydantic import BaseModel
import anthropic, json, re

app = FastAPI(title="SAP Ticket Classifier")
client = anthropic.Anthropic()

PROMPT = (
    "You are an SAP support ticket classifier. Classify the ticket below.\n"
    "Respond with valid JSON only. Required fields: category "
    "(BASIS/FI/MM/SD/PP/HR/CUSTOM/UNKNOWN), priority (LOW/MEDIUM/HIGH/CRITICAL), "
    "confidence (0.0-1.0), routing_team, issue_summary (one sentence), "
    "draft_response (2-3 sentences).\n\nTicket: {text}"
)

class Ticket(BaseModel):
    text: str
    submitted_by: str = ""

@app.post("/classify")
def classify(ticket: Ticket):
    msg = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=400,
        messages=[{"role": "user", "content": PROMPT.format(text=ticket.text)}]
    )
    raw = msg.content[0].text
    try:
        return json.loads(raw)
    except json.JSONDecodeError:
        match = re.search(r'\{.*\}', raw, re.DOTALL)
        return json.loads(match.group()) if match else {"error": "parse_failed"}

# Run: uvicorn ticket_api:app --host 0.0.0.0 --port 8080
# Cost: ~$0.0003 per ticket via Haiku
# ROI: 1,000 tickets/month = $0.30 API cost vs 60+ hours of L1 triage labor

Tiempo estimado: 7 horas en total incluyendo ajuste de prompts e integración de webhook. Impacto empresarial: Un cliente con 1.200 tickets al mes redujo el tiempo de triaje L1 de 3 horas diarias a menos de 20 minutos. El enrutamiento incorrecto de tickets cayó un 78%. Coste mensual total de la API: menos de $0,40.


Empieza con la instalación de pyrfc. Ejecuta el script del maestro de materiales. El resto viene de forma natural.