Introduction
Une équipe d’exploitation a besoin d’un résumé structuré d’un court rapport d’incident. Le modèle peut produire une prose plausible, mais l’application attend des champs prévisibles et doit rejeter les sorties invalides. Vous demanderez un résumé JSON avec Bedrock Converse, l’analyserez en Python et testerez le rejet avec des cas locaux clairement identifiés.
Vous devez connaître les bases de Python, JSON et les requêtes Converse du laboratoire précédent. Chaque nouvelle VM fournit son document, son identité configurée et son quota d’inférence. Aucun fichier ni identifiant d’une VM antérieure n’est requis.
Lien avec la certification
| Certification | Tâche d’examen | Pratique |
|---|---|---|
| AI Practitioner (AIF-C01) | Tâche 3.2 | Définir le format de sortie et valider la réponse avant son utilisation par une application. |

Examiner le document et les champs requis
Dans cette étape, vous examinerez un rapport synthétique fourni et définirez la structure attendue par l’application utilisatrice.
Placez-vous dans l’espace de travail :
cd /home/labex/project
Le document fourni est du texte brut. Lisez-le avec cat, qui affiche le fichier :
cat incident.txt
Il décrit l’incident INC-204 : une erreur de configuration du paiement a provoqué 30 minutes d’échecs de paiement. L’équipe a rétabli la configuration précédente et le service. Un test de configuration complémentaire est prévu, mais pas encore terminé. Ces faits bornent votre résumé.
L’application attend exactement trois champs : incident_id, impact et next_action. Chacun doit contenir une chaîne non vide. Un schéma décrit cette forme ; un JSON valide ne suffit pas, car une liste, un champ absent ou un nombre peuvent être du JSON valide. Lisez la référence fournie :
cat summary-schema.json
La référence explique la sortie souhaitée. Vous imposerez ses champs en Python ordinaire ; elle ne garantit pas automatiquement que le modèle les respecte. Demander du JSON et le valider sont deux responsabilités distinctes.
Générer et valider un résumé structuré
Dans cette étape, vous construirez une petite commande Python qui demande un résumé et valide le texte reçu avant d’annoncer un succès.
boto3 est le SDK AWS pour Python. Il est installé dans l’environnement fourni et utilise les identifiants et le point d’accès configurés. Le code utilise converse, l’opération déjà pratiquée avec CLI. maxTokens borne la sortie et le client désactive les nouvelles tentatives automatiques, pour qu’un échec ambigu ne déclenche pas silencieusement une autre inférence.
Créez summary.py avec le code suivant. parse_response contrôle le motif de fin, analyse le texte avec json.loads, valide les clés exactes et leurs types. ValueError représente un rejet contrôlé ; un ClientError ou une erreur de connexion est signalé sans exposer les identifiants ni l’exception complète. Le mode facultatif --response-file lit une réponse locale pour tester l’analyseur, sans requête d’inférence :
cat > summary.py <<'EOF'
import argparse
import json
from pathlib import Path
import boto3
from botocore.config import Config
from botocore.exceptions import BotoCoreError, ClientError
def parse_response(response):
if not isinstance(response, dict):
raise ValueError("invalid_response")
if response.get("stopReason") != "end_turn":
raise ValueError("incomplete_response")
try:
text = response["output"]["message"]["content"][0]["text"]
value = json.loads(text)
expected = {"incident_id", "impact", "next_action"}
if not isinstance(value, dict) or set(value) != expected:
raise ValueError("invalid_fields")
if any(not isinstance(v, str) or not v.strip() for v in value.values()):
raise ValueError("invalid_field_type")
if value["incident_id"] != "INC-204":
raise ValueError("unexpected_incident")
return value
except (KeyError, IndexError, TypeError, json.JSONDecodeError) as error:
raise ValueError("invalid_response") from error
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--response-file", type=Path)
args = parser.parse_args()
try:
if args.response_file:
response = json.loads(args.response_file.read_text())
else:
client = boto3.client("bedrock-runtime", config=Config(
connect_timeout=5, read_timeout=150,
retries={"total_max_attempts": 1}))
response = client.converse(
modelId="labex.text-v1:0",
system=[{"text": "Summarize only facts supplied in the incident document. Return exactly one JSON object with string fields incident_id, impact and next_action. No Markdown fences, extra keys or surrounding prose. Do not turn planned work into completed work."}],
messages=[{"role": "user", "content": [
{"text": Path("incident.txt").read_text()}]}],
inferenceConfig={"maxTokens": 768, "temperature": 0})
Path("response.json").write_text(json.dumps(response, indent=2))
value = parse_response(response)
except (ValueError, KeyError, TypeError):
print(json.dumps({"status": "rejected", "reason": "invalid_model_output"}))
return 2
except (BotoCoreError, ClientError):
print(json.dumps({"status": "unavailable", "reason": "inference_failed"}))
return 3
print(json.dumps({"status": "ok", "summary": value}, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())
EOF
Exécutez le script avec l’environnement Python AWS installé. Le dernier > summary.json enregistre le résultat affiché :
/opt/labex/aws/venv/bin/python summary.py > summary.json
Attendez l’invite, puis examinez le résultat :
cat summary.json
Un succès contient "status": "ok" et un objet summary avec les trois chaînes requises. Lisez aussi la réponse Converse brute :
python3 -m json.tool response.json
response.json conserve la sortie réelle, le motif de fin et l’utilisation des tokens. Développez la requête terminée dans AWS View et comparez son texte. Les mots peuvent varier. Vérifiez que impact reflète les échecs de paiement et que next_action décrit du travail prévu. Un schéma valide ne prouve pas l’exactitude de ces affirmations.

Si le script indique un rejet, lisez la réponse brute avant de réessayer. Le modèle peut tronquer la sortie ou ignorer le format demandé ; ne remplacez pas le résumé par un succès codé en dur. Une inférence échouée peut consommer du quota.
Tester la limite des réponses invalides
Dans cette étape, vous confirmerez le rejet de réponses mal formées, mal typées et tronquées sans nouvelle requête au modèle.
Le répertoire fixtures/ contient des entrées délibérées de test de l’analyseur. Ce sont des données locales, pas des résultats d’inférence. Listez-les :
ls fixtures
Exécutez le script sur le cas JSON mal formé :
/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/malformed.json
La sortie attendue est {"status": "rejected", "reason": "invalid_model_output"}. Le code de sortie 2 identifie ce rejet contrôlé. echo $? affiche le code de la commande immédiatement précédente :
echo $?
Une réponse peut être du JSON valide tout en violant le schéma. Testez le cas où impact est numérique :
/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/wrong-type.json
Il doit produire le même rejet. Même un objet apparemment complet doit être rejeté si le modèle a atteint son plafond de tokens. Testez cette limite :
/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/truncated.json
Le résultat doit être rejeté, car son stopReason est max_tokens. Ces tests n’affichent aucun résumé réussi et n’ajoutent pas de requêtes à AWS View.
Enfin, analysez à nouveau la réponse réelle enregistrée :
/opt/labex/aws/venv/bin/python summary.py --response-file response.json
Elle doit toujours retourner status: ok. Vous avez testé la réponse réelle exploitable et des entrées d’échec contrôlées. Les cas de l’analyseur ne prouvent pas que l’inférence a fonctionné : la requête terminée et la réponse brute l’établissent séparément.
Supprimer les artefacts créés pendant l’exercice
Dans cette étape, vous supprimerez votre script et ses deux fichiers de résultats après les contrôles fonctionnels.
Le document, le schéma et les cas de test appartiennent à l’environnement neuf. Préservez-les ainsi que le service backend. rm supprime uniquement les trois artefacts de l’apprenant nommés :
rm summary.py summary.json response.json
Confirmez que les entrées fournies restent présentes :
ls
Converse ne crée pas de serveur persistant à supprimer. Effacer des fichiers locaux ne rembourse pas les crédits consommés et n’efface pas les enregistrements réels conservés par AWS View.
Résumé
Vous avez utilisé une réponse Bedrock Converse réelle pour produire un résumé structuré, imposé les noms et types des champs, contrôlé le motif de fin et rejeté des réponses invalides de test. Vous avez aussi examiné les faits indépendamment du schéma et supprimé uniquement vos fichiers.
Pour approfondir ce sujet, consultez la documentation AWS : Contenu, raisons d’arrêt et utilisation des réponses Converse.



