pipeline NLP mainframe : gérer le flux de traitement dans un environnement transactionnel lourd
Prérequis
Pour exécuter ce type d’intégration hybride, il faut maîtriser trois environnements distincts. Je me base sur les versions suivantes :
- z/OS (Mainframe) : Niveau R17 ou supérieur. Nécessite l’accès à IBM MQ Series et des capacités d’appel sortant via CICS Transaction Gateway ou équivalent JCL CALL.
- COBOL Compiler : Compilateur COBOL compatible z/OS, avec support de la manipulation binaire (packed decimal). Pour les tests hors-mainframe, GnuCOBOL 3.2 sur Debian 12 est suffisant pour simuler le parsing des structures data.
# Exemple d'installation GNU: sudo apt install gnu-cobol - Intermédiaire : Python 3.13 (ou plus récent) installé dans un conteneur Docker ou une machine de service dédiée, capable d’exposer via REST/MQ un endpoint NLP minimaliste. Il doit gérer la conversion EBCDIC <-> UTF-8 et le parsing JSON en mémoire.
Comprendre pipeline NLP mainframe
Le cœur du problème dans tout pipeline NLP mainframe est le passage de l’état transactionnel (ACID) au flux asynchrone (EDA/Microservices). Dans les années 90, un traitement était synchrone : lire -> traiter en interne -> écrire. Aujourd’hui, on doit faire : lire (z/OS) -> mettre en file d’attente (MQ) -> service externe traite (Python/LLM) -> résultat revient et est traité de manière transactionnelle.
Je décris ici le modèle ‘Request-Reply via MQ’.
[COBOL z/OS] ---> (Input Record EBCDIC) --> [MQ Queue Q_INPUT]
[Service Python NLP] <--- Consomme Q_INPUT, analyse le texte, génère un JSON
[Service Python NLP] ---> (Result Message JSON) --> [MQ Queue Q_OUTPUT]
[COBOL z/OS] <--- Consume Q_OUTPUT & traite la réponse dans sa transaction.
Ce modèle est crucial car il découple le temps de traitement du réseau et de l'IA (souvent plusieurs secondes) de la fenêtre de commit métier critique (quelques centaines de millisecondes). Le COBOL ne bloque plus en attendant une réponse synchrone, il poste un message. Il attend ensuite que ce résultat soit marqué comme disponible dans sa propre transaction.
Le code — pipeline NLP mainframe
IDENTIFICATION DIVISION.
PROGRAM-ID NLPPROC.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-INPUT-RECORD PIC X(80).
01 WS-STATUS PIC XX.
PROCEDURE DIVISION.
MAIN-LOGIC.
* 1. Lecture de la donnée métier (ex: un identifiant client, une note transactionnelle)
MOVE SPACES TO WS-INPUT-RECORD.
PERFORM READ-DATA INTO WS-INPUT-RECORD.
*> Simulation d'envoi du message dans MQ (commande z/OS ou routine CICS).
CALL 'MQ_SEND_SERVICE'(WS-INPUT-RECORD, QLC_NLP_IN)
RETURNING STATUS-CODE.
IF STATUS-CODE = 0 THEN
*> Lancement d'une tâche de suivi pour récupérer le résultat plus tard.
PERFORM LOGICIEN-WAIT-FOR-RESULT.
END-IF.
QUIT.
Explication
Dans le premier bloc COBOL, la routine MQ_SEND_SERVICE est une abstraction. Sur z/OS réel, ceci serait implémenté via un programme CICS ou par l'utilisation de CLIST/REXX appelant des utilitaires MQ spécifiques (comme runmqsc). L'important n'est pas le ‘comment’ mais le ‘quoi’ : on ne veut pas bloquer la transaction métier.
Le passage du message au format JSON en Python est critique. La fonction process_nlp reçoit une chaîne de caractères qui *représente* les données textuelles après conversion EBCDIC -> UTF-8 dans l'environnement z/OS. Le piège à éviter, c'est le « mất mát de contexte » (loss of context). Si la donnée initiale contenait des champs binaires complexes (comme un numéro d’identification en Packed Decimal), on ne doit pas juste envoyer la chaîne textuelle associée ; il faut encapsuler l'ID binaire dans le JSON pour que le service NLP sache quelle source récupérer.
Le second bloc Python montre comment gérer ce flux. Il reçoit une donnée structurée (simulée ici) et renvoie un objet bien défini (score, sentiment). C’est la garantie de contrat : COBOL s'attend à recevoir des champs nommés, pas juste une chaîne brute.
Documentation officielle : COBOL
Second exemple
import json
def process_nlp(input_data: str) -> dict:
# Simulation d'un appel à un modèle LLM (ex: via OpenAI SDK ou HuggingFace)
print("[INFO] Début du traitement NLP pour la donnée : " + input_data[:20] + "...")
if 'résiliation' in input_data.lower():
# Score de risque élevé détecté.
result = {"score": 0.95, "sentiment": "Négatif", "action_recommandee": "ALERTE"}
else:
result = {"score": 0.32, "sentiment": "Neutre", "action_recommandee": "OK"}
print("[INFO] Fin du traitement NLP.")
return result
def main():
# Ceci simule la réception d'un message MQ (format JSON)
mock_message = '{"text":"Le client a demandé une résiliation de compte."}'
try:
data = json.loads(mock_message)
nlp_result = process_nlp(data['text'])
# Le résultat est ensuite sérialisé en JSON pour le retour MQ.
print(f"Résultat prêt à être renvoyé : {json.dumps(nlp_result)}")
except json.JSONDecodeError:
pass
if __name__ == "__main__":
main()
Exemple d'utilisation
Scénario : Un agent métier veut vérifier le sentiment après une réclamation client. Le code COBOL lit la note (format EBCDIC), l'envoie via MQ, attend un résultat sur Q_OUTPUT, et met à jour le statut du dossier.
// Exécution COBOL : Le système lance la transaction. CALL 'MQ_SEND_SERVICE'(NoteClient='Le service est inacceptable.', QLC_NLP_IN) // --- Attente de résultat (simulée par le framework MQ/CICS) ---\n\n/* Après quelques secondes, un message arrive dans Q_OUTPUT */{ "score": 0.95, "sentiment": "Négatif", "action_recommandee": "ALERTE" }// Le programme COBOL parse ce résultat et met à jour le dossier client (COMMIT).
MOVE 'ALERTE' TO WS-ACTION-CODE.
UPDATE CLIENT-FILE WITH NEW STATUS.STATUS = 'TRAITEMENT_COMPLET'; COMMIT WORK;
Cas d'usage avancés
1. KYC (Know Your Customer) Screening: Lors de l'onboarding client, on reçoit un bloc de texte libre décrivant la source de richesse ou le métier du client. Le pipeline NLP mainframe doit analyser ce texte pour détecter des entités sensibles (noms d'entreprises étrangères, secteurs à risque). Contrainte : Latence critique (< 500 ms) et conformité réglementaire absolue (auditabilité du flux de données).
2. Détection de fraude transactionnelle: Un message MQ est déclenché après chaque transfert important (> 10k EUR). Le pipeline NLP mainframe analyse le texte libre joint (ex : la raison du virement) pour détecter des patterns anormaux qui ne passent pas par les règles classiques de scoring. Contrainte : Débit élevé (plusieurs centaines/seconde), traitement quasi-temps réel.
3. Extraction documentaire légale: Un contrat PDF scanné est ingéré dans le système z/OS via un batch job. Le pipeline NLP mainframe doit extraire des entités structurées (dates de validité, montants contractuels). Contrainte : Gestion du volume très important et nécessité d'une haute précision taxonomique.
Erreurs courantes
Mismatch EBCDIC/UTF-8
Symptôme : Le résultat NLP est corrompu ou contient des caractères '?' inattendus. Cause racine : Une conversion manuelle incomplète, ne gérant pas tous les jeux de caractères (accents). Impact mesurable : Perte d'information critique pour la classification.
MOVE INPUT-STRING TO EXTERNAL-PROGRAM('utf8_convert').
PERFORM CONVERT-EBCDIC: READ CHAR BY CHAR, CHECKING ACCENTS.
Timeout Synchrone CICS
Symptôme : La transaction métier échoue avec un code 801 (Task Timeout). Cause racine : Tenter de faire appel à l'IA synchrone. L'attente dépasse le temps alloué par la couche applicative CICS/IMS. Impact mesurable : Interruption du processus en cours, perte d'atomicité si non géré.
CALL 'NLP_API'(data) WAITING 30 SECONDS
MQ PUT message sur Q_INPUT; COMMIT WORK; ASYNCHRONOUS TASK ID = ...
Gestion des limites MQ
Symptôme : L'envoi du message échoue avec un code 312 ('Message too long'). Cause racine : Le payload est trop volumineux (ex: plus de 50 Ko), dépassant les limites physiques ou logiques définies par la queue. Impact mesurable : Blocage total du flux entrant dans le pipeline NLP mainframe.
SEND MESSAGE TEXTUAL ENTIRE BLOC
Compresser/Hash les données brutes (ex: envoyer l'ID + un Hash SHA-256 du texte) et récupérer le contenu par ID.
Bonnes pratiques
- Utiliser MQ pour la déconnexion : Ne jamais faire d'appel synchrone longue durée. L'asynchronisme via IBM MQ est le standard de facto du pipeline NLP mainframe résilient.
- Contrat Data Stricte (Schema Registry) : Traitez la structure JSON renvoyée par l'IA comme un contrat API inviolable. Le parsing COBOL doit toujours valider les types de données attendus avant utilisation des champs.
- Mécanisme d'Auditabilité Complète : Chaque étape du flux, de la lecture EBCDIC à la réception du résultat NLP (score), doit être journalisée dans une table DB2/VSAM dédiée avec l'ID transactionnel original et les timestamps précis. C'est vital en banque.
- Séparer le Traitement Lourd : Le moteur LLM ne doit jamais être appelé directement depuis le monolithe métier z/OS. Il doit résider derrière un service d’orchestration (ex: Kubernetes) qui gère son propre pool de ressources et les timeouts intermédiaires.
- Optimisation EBCDIC <-> UTF-8 : Pour la conversion, utilisez des routines optimisées au niveau du système ou du langage hôte plutôt que des fonctions génériques ; le contrôle bit à bit est nécessaire pour garantir l'intégrité des données de départ.
Questions fréquentes
Est-ce que je peux utiliser un service LLM directement depuis COBOL sans MQ ?
Comment gérer les dépendances Python (ex: PyTorch) si elles doivent être appelées depuis une machine réseau ? Par des conteneurs ?
Le fait que je doive convertir EBCDIC en UTF-8 ajoute une latence non négligeable au <strong style="color: #0066cc;">pipeline NLP mainframe</strong> ? Quelle est l'impact ?
Si je dois traiter 1 million d'enregistrements par jour, quel est le meilleur débit cible pour mon <strong style="color: #0066cc;">pipeline NLP mainframe</strong> ?
Sur le même blog
Conclusion
L'intégration du pipeline NLP mainframe est un exercice d'ingénierie transactionnelle : il faut respecter l'ancien monde (ACID, EBCDIC) tout en exploitant la puissance des outils modernes. La clé réside dans le découplage asynchrone via MQ et une gestion méticuleuse du contrat de données entre les couches.
Pour aller plus loin sur ces mécanismes complexes d'interopérabilité ou pour revoir l'utilisation avancée des fichiers VSAM/DB2 en COBOL, je vous recommande cette ressource : documentation COBOL.
Marc Levasseur — 28 ans dont 22 sur mainframe IBM z/OS en banque, GnuCOBOL le week-end